API Reference¶
This document provides detailed information about the opnDossier API and its components.
Migration Notice: New Validate Method¶
Important for downstream consumers: A new Validate method has been added to the XMLParser interface in this release.
What Changed¶
The XMLParser now includes a dedicated validation method:
Migration Guide¶
For Library Users¶
If you're using opnDossier as a library and have implemented custom parsers based on the XMLParser interface, you'll need to implement the new Validate method:
// Before: Your custom parser only needed Parse method
type CustomParser struct{}
func (p *CustomParser) Parse(ctx context.Context, r io.Reader) (*model.Opnsense, error) {
// Your implementation
}
// After: You must also implement Validate method
func (p *CustomParser) Validate(cfg *model.Opnsense) error {
// Your validation implementation
// You can return nil if no validation is needed
return nil
}
For CLI Users¶
No changes are required for CLI usage. The validation is automatically integrated into existing commands.
Recommended Integration¶
For new integrations, consider using the combined ParseAndValidate method:
// Recommended approach for new code
parser := parser.NewXMLParser()
cfg, err := parser.ParseAndValidate(ctx, reader)
if err != nil {
// Handle both parse and validation errors
return err
}
Backward Compatibility¶
Existing code using only the Parse method will continue to work without validation. Validation is opt-in through explicit method calls or CLI flags.
Overview¶
opnDossier is structured with clear separation between CLI interface (cmd/) and internal implementation (internal/). This design ensures maintainable code while providing stable interfaces for future extensions.
Package Structure¶
opndossier/
├── cmd/ # CLI commands (public interface)
├── internal/
│ ├── config/ # Configuration management
│ ├── parser/ # XML parsing
│ ├── converter/ # Data conversion
│ ├── display/ # Terminal output
│ ├── export/ # File operations
│ └── log/ # Logging utilities
└── main.go # Application entry point
CLI Package (cmd/)¶
Root Command¶
The root command provides the main CLI interface with global configuration management.
Functions¶
GetRootCmd() *cobra.Command¶
Returns the root Cobra command for the opnDossier CLI application.
GetLogger() *log.Logger¶
Returns the current application logger instance configured with user settings. This returns a *log.Logger from the internal/log package, which wraps charmbracelet/log.Logger for structured logging.
GetConfig() *config.Config¶
Returns the current application configuration instance with all precedence applied.
Global Flags¶
All commands inherit these global flags:
| Flag | Type | Default | Description |
|---|---|---|---|
--config |
string | ~/.opnDossier.yaml |
Configuration file path |
--verbose, -v |
bool | false | Enable debug logging |
--quiet, -q |
bool | false | Suppress non-error output |
Convert Command¶
The convert command processes OPNsense configuration files.
Usage¶
Flags¶
| Flag | Type | Default | Description |
|---|---|---|---|
--output, -o |
string | "" | Output file path |
Examples¶
// Programmatic usage (if needed for testing)
convertCmd := cmd.GetRootCmd().Commands()[0] // \"convert\" command
convertCmd.SetArgs([]string{\"config.xml\", \"-o\", \"output.md\"})
err := convertCmd.Execute()
Configuration Package (internal/config)¶
Types¶
Config¶
type Config struct {
InputFile string `mapstructure:\"input_file\"`
OutputFile string `mapstructure:\"output_file\"`
Verbose bool `mapstructure:\"verbose\"`
Quiet bool `mapstructure:\"quiet\"`
}
ValidationError¶
Functions¶
LoadConfig(cfgFile string) (*Config, error)¶
Loads configuration from file, environment variables, and defaults.
cfg, err := config.LoadConfig(\"\") // Use default location
if err != nil {
return fmt.Errorf(\"config load failed: %w\", err)
}
LoadConfigWithFlags(cfgFile string, flags *pflag.FlagSet) (*Config, error)¶
Loads configuration with CLI flag binding for proper precedence.
cfg, err := config.LoadConfigWithFlags(configFile, cmd.Flags())
if err != nil {
return fmt.Errorf(\"config load failed: %w\", err)
}
Methods¶
(*Config).Validate() error¶
Validates configuration for consistency and correctness.
(*Config).IsVerbose() bool¶
Returns true if verbose logging is enabled.
(*Config).IsQuiet() bool¶
Returns true if quiet mode is enabled.
Parser Package (internal/parser)¶
Interfaces¶
XMLParser¶
Types¶
OPNsense¶
type OPNsense struct {
XMLName xml.Name `xml:\"opnsense\"`
// Configuration structure mirrors OPNsense XML format
System System `xml:\"system\"`
Firewall Firewall `xml:\"filter\"`
// Additional fields as needed
}
Functions¶
NewXMLParser() XMLParser¶
Creates a new XML parser instance.
Converter Package (internal/converter)¶
Interfaces¶
MarkdownConverter¶
type MarkdownConverter interface {
ToMarkdown(ctx context.Context, opnsense *parser.OPNsense) (string, error)
}
Functions¶
NewMarkdownConverter() MarkdownConverter¶
Creates a new markdown converter instance.
converter := converter.NewMarkdownConverter()
markdown, err := converter.ToMarkdown(ctx, opnsenseConfig)
Export Package (internal/export)¶
Interfaces¶
FileExporter¶
Functions¶
NewFileExporter() FileExporter¶
Creates a new file exporter instance.
Log Package (internal/log)¶
The log package provides a wrapper around charmbracelet/log for structured logging with additional application-specific functionality.
Types¶
Logger¶
The Logger type wraps charmbracelet/log.Logger to provide structured logging capabilities with key-value pairs and context support.
Config¶
type Config struct {
Level string
Format string
Output io.Writer
ReportCaller bool
ReportTimestamp bool
}
Functions¶
New(config Config) (*Logger, error)¶
Creates a new logger instance with the specified configuration. Returns a *log.Logger from the internal/log package that wraps charmbracelet/log.Logger.
logger, err := log.New(log.Config{
Level: \"info\",
Format: \"text\",
Output: os.Stderr,
ReportCaller: true,
ReportTimestamp: true,
})
if err != nil {
return fmt.Errorf(\"failed to create logger: %w\", err)
}
Methods¶
(*Logger).Info(msg string, keyvals ...interface{})¶
Logs an info-level message with optional key-value pairs.
(*Logger).Debug(msg string, keyvals ...interface{})¶
Logs a debug-level message with optional key-value pairs.
(*Logger).Warn(msg string, keyvals ...interface{})¶
Logs a warning-level message with optional key-value pairs.
(*Logger).Error(msg string, keyvals ...interface{})¶
Logs an error-level message with optional key-value pairs.
(*Logger).WithContext(ctx context.Context) *Logger¶
Returns a logger that includes context information.
(*Logger).WithFields(keyvals ...interface{}) *Logger¶
Returns a logger with additional fields pre-configured.
fileLogger := logger.WithFields(\"operation\", \"convert\", \"file\", filename)
fileLogger.Info(\"Processing started\")
Configuration Precedence¶
The configuration system follows this precedence order (highest to lowest):
- CLI Flags - Immediate overrides via command-line
- Environment Variables -
OPNDOSSIER_*prefixed variables - Configuration File - YAML file at
~/.opnDossier.yamlor custom path - Default Values - Built-in defaults
Environment Variable Mapping¶
| Config Field | Environment Variable | Default |
|---|---|---|
input_file |
OPNDOSSIER_INPUT_FILE |
"" |
output_file |
OPNDOSSIER_OUTPUT_FILE |
"" |
verbose |
OPNDOSSIER_VERBOSE |
false |
quiet |
OPNDOSSIER_QUIET |
false |
Error Handling¶
Error Types¶
All packages use standard Go error handling with context-aware error wrapping:
Validation Errors¶
Configuration validation errors implement a specific type:
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf(\"validation error for field '%s': %s\", e.Field, e.Message)
}
Best Practices¶
- Always wrap errors with context
- Use structured logging for debugging
- Validate inputs early
- Return errors, don't log and return
Testing Interfaces¶
Test Helpers¶
For testing CLI commands:
func TestConvertCommand(t *testing.T) {
// Set up test command
cmd := cmd.GetRootCmd()
cmd.SetArgs([]string{\"convert\", \"testdata/config.xml\"})
// Capture output
var buf bytes.Buffer
cmd.SetOutput(&buf)
// Execute and verify
err := cmd.Execute()
assert.NoError(t, err)
assert.Contains(t, buf.String(), \"expected output\")
}
For testing configuration:
func TestConfigPrecedence(t *testing.T) {
// Set environment variable
t.Setenv(\"OPNDOSSIER_VERBOSE\", \"true\")
// Load config
cfg, err := config.LoadConfig(\"\")
require.NoError(t, err)
// Verify precedence
assert.True(t, cfg.Verbose)
}
Extension Points¶
Adding New Commands¶
- Create command file in
cmd/ - Implement command with proper configuration precedence
- Add to root command in init()
- Update help text with configuration info
Adding Configuration Options¶
- Add field to
Configstruct - Set default in
LoadConfigWithViper - Add CLI flag in
cmd/root.go - Add validation if needed
- Update documentation
Adding New Output Formats¶
- Create new converter implementing the interface
- Add format option to configuration
- Update convert command to handle new format
- Add tests and documentation
This API reference covers the current stable interfaces. For the most up-to-date information, refer to the source code and inline documentation.