Merge fix/usability-improvements
All checks were successful
check / check (push) Successful in 2m21s

This commit is contained in:
2026-06-17 01:41:09 +02:00
5 changed files with 33 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/adrg/xdg"
"github.com/spf13/cobra"
@@ -63,13 +64,21 @@ func GetRootFlags() RootFlags {
// ResolveConfigPath resolves the config file path from flags, environment, or default.
// Search order: --config flag, VAULTIK_CONFIG env, XDG config dir, /etc/vaultik/config.yml.
// Explicit paths from --config and $VAULTIK_CONFIG are checked for existence
// so the user gets a clear error instead of a downstream YAML parser failure.
func ResolveConfigPath() (string, error) {
if rootFlags.ConfigPath != "" {
return rootFlags.ConfigPath, nil
if path := rootFlags.ConfigPath; path != "" {
if _, err := os.Stat(path); err != nil {
return "", fmt.Errorf("config file from --config not found: %s (run 'vaultik config init --config %s' to create it)", path, path)
}
return path, nil
}
if envPath := os.Getenv("VAULTIK_CONFIG"); envPath != "" {
return envPath, nil
if path := os.Getenv("VAULTIK_CONFIG"); path != "" {
if _, err := os.Stat(path); err != nil {
return "", fmt.Errorf("config file from $VAULTIK_CONFIG not found: %s (unset VAULTIK_CONFIG, point it at an existing file, or run 'vaultik config init')", path)
}
return path, nil
}
for _, path := range defaultConfigPaths() {
@@ -78,7 +87,7 @@ func ResolveConfigPath() (string, error) {
}
}
return "", fmt.Errorf("no config file found; run 'vaultik config init' to create one, or specify with --config")
return "", fmt.Errorf("no config file found at %s (run 'vaultik config init' to create the default config, or pass --config <path>)", strings.Join(defaultConfigPaths(), " or "))
}
// defaultConfigPaths returns the ordered list of config paths to search.

View File

@@ -20,6 +20,12 @@ func NewVersionCommand() *cobra.Command {
fmt.Printf(" commit: %s\n", globals.Commit)
fmt.Printf(" go: %s\n", runtime.Version())
fmt.Printf(" os/arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
if globals.Version == "dev" {
fmt.Println()
fmt.Println("This is a development build (no version information embedded).")
fmt.Println("Build a release binary with 'make vaultik' or download from")
fmt.Println("https://sneak.berlin/go/vaultik for embedded version metadata.")
}
},
}

View File

@@ -1,6 +1,8 @@
package snapshot
import (
"io"
"github.com/spf13/afero"
"go.uber.org/fx"
"sneak.berlin/go/vaultik/internal/config"
@@ -11,6 +13,7 @@ import (
// ScannerParams holds parameters for scanner creation
type ScannerParams struct {
EnableProgress bool
Output io.Writer // Where one-off scanner messages go; nil disables them
Fs afero.Fs
Exclude []string // Exclude patterns (combined global + snapshot-specific)
SkipErrors bool // Skip file read errors (log loudly but continue)
@@ -46,6 +49,7 @@ func provideScannerFactory(cfg *config.Config, repos *database.Repositories, sto
CompressionLevel: cfg.CompressionLevel,
AgeRecipients: cfg.AgeRecipients,
EnableProgress: params.EnableProgress,
Output: params.Output,
Exclude: excludes,
SkipErrors: params.SkipErrors,
})

View File

@@ -92,10 +92,11 @@ type ScannerConfig struct {
Storage storage.Storer
MaxBlobSize int64
CompressionLevel int
AgeRecipients []string // Optional, empty means no encryption
EnableProgress bool // Enable progress reporting
Exclude []string // Glob patterns for files/directories to exclude
SkipErrors bool // Skip file read errors (log loudly but continue)
AgeRecipients []string // Optional, empty means no encryption
EnableProgress bool // Enable the live progress reporter (ETAs, throughput)
Output io.Writer // Where one-off scanner messages go; nil disables them
Exclude []string // Glob patterns for files/directories to exclude
SkipErrors bool // Skip file read errors (log loudly but continue)
}
// ScanResult contains the results of a scan operation
@@ -142,9 +143,9 @@ func NewScanner(cfg ScannerConfig) *Scanner {
// Compile exclude patterns
compiledExclude := compileExcludePatterns(cfg.Exclude)
output := io.Writer(io.Discard)
if cfg.EnableProgress {
output = os.Stdout
output := cfg.Output
if output == nil {
output = io.Discard
}
return &Scanner{

View File

@@ -156,6 +156,7 @@ func (v *Vaultik) createNamedSnapshot(opts *SnapshotCreateOptions, hostname, sna
scanner := v.ScannerFactory(snapshot.ScannerParams{
EnableProgress: !opts.Cron,
Output: v.Stdout,
Fs: v.Fs,
Exclude: v.Config.GetExcludes(snapName),
SkipErrors: opts.SkipErrors,