- Add global --quiet/-q flag to suppress non-error output - Add --json flag to verify, snapshot rm, and prune commands - Add config file permission check (warns if world/group readable) - Update TODO.md to remove completed items
137 lines
3.9 KiB
Go
137 lines
3.9 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
"git.eeqj.de/sneak/vaultik/internal/globals"
|
|
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
// RestoreOptions contains options for the restore command
|
|
type RestoreOptions struct {
|
|
TargetDir string
|
|
Paths []string // Optional paths to restore (empty = all)
|
|
Verify bool // Verify restored files after restore
|
|
}
|
|
|
|
// RestoreApp contains all dependencies needed for restore
|
|
type RestoreApp struct {
|
|
Globals *globals.Globals
|
|
Config *config.Config
|
|
Storage storage.Storer
|
|
Vaultik *vaultik.Vaultik
|
|
Shutdowner fx.Shutdowner
|
|
}
|
|
|
|
// NewRestoreCommand creates the restore command
|
|
func NewRestoreCommand() *cobra.Command {
|
|
opts := &RestoreOptions{}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "restore <snapshot-id> <target-dir> [paths...]",
|
|
Short: "Restore files from backup",
|
|
Long: `Download and decrypt files from a backup snapshot.
|
|
|
|
This command will restore files from the specified snapshot to the target directory.
|
|
If no paths are specified, all files are restored.
|
|
If paths are specified, only matching files/directories are restored.
|
|
|
|
Requires the VAULTIK_AGE_SECRET_KEY environment variable to be set with the age private key.
|
|
|
|
Examples:
|
|
# Restore entire snapshot
|
|
vaultik restore myhost_docs_2025-01-01T12:00:00Z /restore
|
|
|
|
# Restore specific file
|
|
vaultik restore myhost_docs_2025-01-01T12:00:00Z /restore /home/user/important.txt
|
|
|
|
# Restore specific directory
|
|
vaultik restore myhost_docs_2025-01-01T12:00:00Z /restore /home/user/documents/
|
|
|
|
# Restore and verify all files
|
|
vaultik restore --verify myhost_docs_2025-01-01T12:00:00Z /restore`,
|
|
Args: cobra.MinimumNArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
snapshotID := args[0]
|
|
opts.TargetDir = args[1]
|
|
if len(args) > 2 {
|
|
opts.Paths = args[2:]
|
|
}
|
|
|
|
// Use unified config resolution
|
|
configPath, err := ResolveConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Use the app framework like other commands
|
|
rootFlags := GetRootFlags()
|
|
return RunWithApp(cmd.Context(), AppOptions{
|
|
ConfigPath: configPath,
|
|
LogOptions: log.LogOptions{
|
|
Verbose: rootFlags.Verbose,
|
|
Debug: rootFlags.Debug,
|
|
Quiet: rootFlags.Quiet,
|
|
},
|
|
Modules: []fx.Option{
|
|
fx.Provide(fx.Annotate(
|
|
func(g *globals.Globals, cfg *config.Config,
|
|
storer storage.Storer, v *vaultik.Vaultik, shutdowner fx.Shutdowner) *RestoreApp {
|
|
return &RestoreApp{
|
|
Globals: g,
|
|
Config: cfg,
|
|
Storage: storer,
|
|
Vaultik: v,
|
|
Shutdowner: shutdowner,
|
|
}
|
|
},
|
|
)),
|
|
},
|
|
Invokes: []fx.Option{
|
|
fx.Invoke(func(app *RestoreApp, lc fx.Lifecycle) {
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
// Start the restore operation in a goroutine
|
|
go func() {
|
|
// Run the restore operation
|
|
restoreOpts := &vaultik.RestoreOptions{
|
|
SnapshotID: snapshotID,
|
|
TargetDir: opts.TargetDir,
|
|
Paths: opts.Paths,
|
|
Verify: opts.Verify,
|
|
}
|
|
if err := app.Vaultik.Restore(restoreOpts); err != nil {
|
|
if err != context.Canceled {
|
|
log.Error("Restore operation failed", "error", err)
|
|
}
|
|
}
|
|
|
|
// Shutdown the app when restore completes
|
|
if err := app.Shutdowner.Shutdown(); err != nil {
|
|
log.Error("Failed to shutdown", "error", err)
|
|
}
|
|
}()
|
|
return nil
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
log.Debug("Stopping restore operation")
|
|
app.Vaultik.Cancel()
|
|
return nil
|
|
},
|
|
})
|
|
}),
|
|
},
|
|
})
|
|
},
|
|
}
|
|
|
|
cmd.Flags().BoolVar(&opts.Verify, "verify", false, "Verify restored files by checking chunk hashes")
|
|
|
|
return cmd
|
|
}
|