From 79fc5cca6c6e10ae5741fdb46cd4665f6907f25d Mon Sep 17 00:00:00 2001 From: sneak Date: Wed, 17 Dec 2025 11:17:38 -0800 Subject: [PATCH] Add godoc strings to all exported types, functions, and fields Documents: - cli: NO_COLOR, RunOptions fields, CLIApp, VersionString - checker: Result fields, Status constants, CheckStatus fields - scanner: EnumerateStatus, ScanStatus, Options, FileEntry fields - log: Level alias, DisableStyling, Init, Info/Debug functions, verbosity helpers, GetLogger, GetLevel, WithError - mfer: ManifestScanOptions, New, NewFromPaths, NewFromFS, MAGIC --- internal/checker/checker.go | 30 +++++++++++++++--------------- internal/cli/entry.go | 19 +++++++++++-------- internal/cli/mfer.go | 14 +++++++------- internal/log/log.go | 17 +++++++++++++++++ internal/scanner/scanner.go | 30 +++++++++++++++--------------- mfer/manifest.go | 8 ++++++-- mfer/serialize.go | 4 +--- 7 files changed, 72 insertions(+), 50 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 7f7223a..3790c14 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -16,21 +16,21 @@ import ( // Result represents the outcome of checking a single file. type Result struct { - Path string - Status Status - Message string + Path string // Relative path from manifest + Status Status // Verification result status + Message string // Human-readable description of the result } // Status represents the verification status of a file. type Status int const ( - StatusOK Status = iota - StatusMissing - StatusSizeMismatch - StatusHashMismatch - StatusExtra // File exists on disk but not in manifest - StatusError + StatusOK Status = iota // File matches manifest (size and hash verified) + StatusMissing // File not found on disk + StatusSizeMismatch // File size differs from manifest + StatusHashMismatch // File hash differs from manifest + StatusExtra // File exists on disk but not in manifest + StatusError // Error occurred during verification ) func (s Status) String() string { @@ -54,12 +54,12 @@ func (s Status) String() string { // CheckStatus contains progress information for the check operation. type CheckStatus struct { - TotalFiles int64 - CheckedFiles int64 - TotalBytes int64 - CheckedBytes int64 - BytesPerSec float64 - Failures int64 + TotalFiles int64 // Total number of files in manifest + CheckedFiles int64 // Number of files checked so far + TotalBytes int64 // Total bytes to verify (sum of all file sizes) + CheckedBytes int64 // Bytes verified so far + BytesPerSec float64 // Current throughput rate + Failures int64 // Number of verification failures encountered } // Checker verifies files against a manifest. diff --git a/internal/cli/entry.go b/internal/cli/entry.go index d468e50..32ace65 100644 --- a/internal/cli/entry.go +++ b/internal/cli/entry.go @@ -7,6 +7,8 @@ import ( "github.com/spf13/afero" ) +// NO_COLOR disables colored output when set. Automatically true if the +// NO_COLOR environment variable is present (per https://no-color.org/). var NO_COLOR bool func init() { @@ -17,15 +19,16 @@ func init() { } // RunOptions contains all configuration for running the CLI application. +// Use DefaultRunOptions for standard CLI execution, or construct manually for testing. type RunOptions struct { - Appname string - Version string - Gitrev string - Args []string - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - Fs afero.Fs + Appname string // Application name displayed in help and version output + Version string // Version string (typically set at build time) + Gitrev string // Git revision hash (typically set at build time) + Args []string // Command-line arguments (typically os.Args) + Stdin io.Reader // Standard input stream + Stdout io.Writer // Standard output stream + Stderr io.Writer // Standard error stream + Fs afero.Fs // Filesystem abstraction for file operations } // DefaultRunOptions returns RunOptions configured for normal CLI execution. diff --git a/internal/cli/mfer.go b/internal/cli/mfer.go index bc6f74a..b89ba2c 100644 --- a/internal/cli/mfer.go +++ b/internal/cli/mfer.go @@ -11,6 +11,8 @@ import ( "sneak.berlin/go/mfer/internal/log" ) +// CLIApp is the main CLI application container. It holds configuration, +// I/O streams, and filesystem abstraction to enable testing and flexibility. type CLIApp struct { appname string version string @@ -19,13 +21,10 @@ type CLIApp struct { exitCode int app *cli.App - // I/O streams - all program input/output should go through these - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - - // Fs is the filesystem abstraction - defaults to OsFs for real filesystem - Fs afero.Fs + Stdin io.Reader // Standard input stream + Stdout io.Writer // Standard output stream for normal output + Stderr io.Writer // Standard error stream for diagnostics + Fs afero.Fs // Filesystem abstraction for all file operations } const banner = ` @@ -45,6 +44,7 @@ func (mfa *CLIApp) printBanner() { fmt.Fprintln(mfa.Stdout, banner) } +// VersionString returns the version and git revision formatted for display. func (mfa *CLIApp) VersionString() string { return fmt.Sprintf("%s (%s)", mfa.version, mfa.gitrev) } diff --git a/internal/log/log.go b/internal/log/log.go index cf69e31..5e56c4f 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -13,6 +13,7 @@ import ( "github.com/pterm/pterm" ) +// Level is an alias for apex/log.Level for use by callers without importing apex/log. type Level = log.Level var ( @@ -48,6 +49,7 @@ func GetStderr() io.Writer { return stderr } +// DisableStyling turns off colors and styling for terminal output. func DisableStyling() { pterm.DisableColor() pterm.DisableStyling() @@ -59,6 +61,7 @@ func DisableStyling() { pterm.Fatal.Prefix.Text = "" } +// Init initializes the logger with the CLI handler and default log level. func Init() { mu.RLock() w := stderr @@ -67,22 +70,27 @@ func Init() { log.SetLevel(log.InfoLevel) } +// Infof logs a formatted message at info level. func Infof(format string, args ...interface{}) { log.Infof(format, args...) } +// Info logs a message at info level. func Info(arg string) { log.Info(arg) } +// Debugf logs a formatted message at debug level with caller location. func Debugf(format string, args ...interface{}) { DebugReal(fmt.Sprintf(format, args...), 2) } +// Debug logs a message at debug level with caller location. func Debug(arg string) { DebugReal(arg, 2) } +// DebugReal logs at debug level with caller info from the specified stack depth. func DebugReal(arg string, cs int) { _, callerFile, callerLine, ok := runtime.Caller(cs) if !ok { @@ -92,14 +100,18 @@ func DebugReal(arg string, cs int) { log.Debug(tag + arg) } +// Dump logs a spew dump of the arguments at debug level. func Dump(args ...interface{}) { DebugReal(spew.Sdump(args...), 2) } +// EnableDebugLogging sets the log level to debug. func EnableDebugLogging() { SetLevel(log.DebugLevel) } +// VerbosityStepsToLogLevel converts a -v count to a log level. +// 0 returns InfoLevel, 1+ returns DebugLevel. func VerbosityStepsToLogLevel(l int) log.Level { switch l { case 0: @@ -111,14 +123,17 @@ func VerbosityStepsToLogLevel(l int) log.Level { return log.DebugLevel } +// SetLevelFromVerbosity sets the log level based on -v flag count. func SetLevelFromVerbosity(l int) { SetLevel(VerbosityStepsToLogLevel(l)) } +// SetLevel sets the global log level. func SetLevel(arg log.Level) { log.SetLevel(arg) } +// GetLogger returns the underlying apex/log Logger. func GetLogger() *log.Logger { if logger, ok := log.Log.(*log.Logger); ok { return logger @@ -126,10 +141,12 @@ func GetLogger() *log.Logger { panic("unable to get logger") } +// GetLevel returns the current log level. func GetLevel() log.Level { return GetLogger().Level } +// WithError returns a log entry with the error attached. func WithError(e error) *log.Entry { return GetLogger().WithError(e) } diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index 95ba6e7..252e16a 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -21,8 +21,8 @@ import ( // EnumerateStatus contains progress information for the enumeration phase. type EnumerateStatus struct { - FilesFound int64 - BytesFound int64 + FilesFound int64 // Number of files discovered so far + BytesFound int64 // Total size of discovered files (from stat) } // Phase 2: Scan (ToManifest) @@ -32,27 +32,27 @@ type EnumerateStatus struct { // ScanStatus contains progress information for the scan phase. type ScanStatus struct { - TotalFiles int64 - ScannedFiles int64 - TotalBytes int64 - ScannedBytes int64 - BytesPerSec float64 + TotalFiles int64 // Total number of files to scan + ScannedFiles int64 // Number of files scanned so far + TotalBytes int64 // Total bytes to read (sum of all file sizes) + ScannedBytes int64 // Bytes read so far + BytesPerSec float64 // Current throughput rate } // Options configures scanner behavior. type Options struct { - IgnoreDotfiles bool - FollowSymLinks bool - Fs afero.Fs // Filesystem to use, defaults to OsFs + IgnoreDotfiles bool // Skip files and directories starting with a dot + FollowSymLinks bool // Resolve symlinks instead of skipping them + Fs afero.Fs // Filesystem to use, defaults to OsFs if nil } // FileEntry represents a file that has been enumerated. type FileEntry struct { - Path string // Relative path (used in manifest) - AbsPath string // Absolute path (used for reading file content) - Size int64 - Mtime time.Time - Ctime time.Time + Path string // Relative path (used in manifest) + AbsPath string // Absolute path (used for reading file content) + Size int64 // File size in bytes + Mtime time.Time // Last modification time + Ctime time.Time // Creation time (platform-dependent) } // Scanner accumulates files and generates manifests from them. diff --git a/mfer/manifest.go b/mfer/manifest.go index 0e98e48..fb6315c 100644 --- a/mfer/manifest.go +++ b/mfer/manifest.go @@ -39,9 +39,10 @@ func (m *manifest) String() string { return fmt.Sprintf("", len(m.files), m.totalFileSize) } +// ManifestScanOptions configures behavior when scanning directories for manifest generation. type ManifestScanOptions struct { - IgnoreDotfiles bool - FollowSymLinks bool + IgnoreDotfiles bool // Skip files and directories starting with a dot + FollowSymLinks bool // Resolve symlinks instead of skipping them } func (m *manifest) HasError() bool { @@ -77,11 +78,13 @@ func (m *manifest) addInputFS(f afero.Fs) error { return nil } +// New creates an empty manifest. func New() *manifest { m := &manifest{} return m } +// NewFromPaths creates a manifest configured to scan the given filesystem paths. func NewFromPaths(options *ManifestScanOptions, inputPaths ...string) (*manifest, error) { log.Dump(inputPaths) m := New() @@ -95,6 +98,7 @@ func NewFromPaths(options *ManifestScanOptions, inputPaths ...string) (*manifest return m, nil } +// NewFromFS creates a manifest configured to scan the given afero filesystem. func NewFromFS(options *ManifestScanOptions, fs afero.Fs) (*manifest, error) { m := New() m.scanOptions = options diff --git a/mfer/serialize.go b/mfer/serialize.go index 1b8ea68..9adf6d4 100644 --- a/mfer/serialize.go +++ b/mfer/serialize.go @@ -10,9 +10,7 @@ import ( "google.golang.org/protobuf/proto" ) -// was go-generate protoc --go_out=. --go_opt=paths=source_relative mf.proto - -// rot13("MANIFEST") +// MAGIC is the file format magic bytes prefix (rot13 of "MANIFEST"). const MAGIC string = "ZNAVSRFG" func newTimestampFromTime(t time.Time) *Timestamp {