89 lines
2.8 KiB
Go
89 lines
2.8 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
|
)
|
|
|
|
var newObjectStoreFromConfigFn = storage.NewObjectStoreFromConfig
|
|
var discoverRemoteCurrentStateFn = discoverRemoteCurrentState
|
|
|
|
// Restore validates restore CLI/config inputs and storage preflight for future restore phases.
|
|
func Restore(ctx context.Context, args []string, out io.Writer) error {
|
|
fs := flag.NewFlagSet("restore", flag.ContinueOnError)
|
|
fs.SetOutput(out)
|
|
|
|
var pipelinePath string
|
|
var sessionPath string
|
|
var sessionID string
|
|
var dryRun bool
|
|
var force bool
|
|
var includeAudio bool
|
|
fs.StringVar(&pipelinePath, "config", "", "path to pipeline.yml (optional; defaults searched)")
|
|
fs.StringVar(&sessionPath, "session", "", "path to session.yml")
|
|
fs.StringVar(&sessionID, "session-id", "", "session identifier for session.yml templates")
|
|
fs.BoolVar(&dryRun, "dry-run", false, "plan restore actions without writing local files")
|
|
fs.BoolVar(&force, "force", false, "overwrite local conflicts with remote state")
|
|
fs.BoolVar(&includeAudio, "include-audio", false, "include archived session-level audio objects")
|
|
fs.Usage = func() {
|
|
_, _ = fmt.Fprintln(out, "Usage: narratio restore [--config <path>] [--session <path>] [--session-id <value>] [--dry-run] [--force] [--include-audio]")
|
|
_, _ = fmt.Fprintln(out)
|
|
_, _ = fmt.Fprintln(out, "Flags:")
|
|
fs.PrintDefaults()
|
|
}
|
|
|
|
if err := fs.Parse(args); err != nil {
|
|
if errors.Is(err, flag.ErrHelp) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("restore: invalid flags: %w", err)
|
|
}
|
|
if fs.NArg() != 0 {
|
|
return fmt.Errorf("restore: unexpected positional arguments")
|
|
}
|
|
resolvedPipelinePath, err := resolvePipelineConfigPath(pipelinePath)
|
|
if err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
resolvedSessionPath, err := resolveSessionConfigPath(sessionPath)
|
|
if err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
|
|
cfg, err := config.LoadWithSessionOptions(resolvedPipelinePath, resolvedSessionPath, config.SessionLoadOptions{
|
|
SessionID: sessionID,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
if err := config.Validate(cfg); err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
|
|
objectStore, err := newObjectStoreFromConfigFn(ctx, cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
current, err := discoverRemoteCurrentStateFn(ctx, cfg, objectStore)
|
|
if err != nil {
|
|
return fmt.Errorf("restore: %w", err)
|
|
}
|
|
|
|
// Phase 3 boundary: discovery is implemented; planning/execution is deferred.
|
|
_ = dryRun
|
|
_ = force
|
|
_ = includeAudio
|
|
return fmt.Errorf(
|
|
"restore: discovered remote current state for %s/%s (run %s); not yet implemented (phase 3: remote current-state discovery)",
|
|
current.Campaign,
|
|
current.SessionID,
|
|
current.RunID,
|
|
)
|
|
}
|