package cli import ( "context" "fmt" "io" ) // runWorkspaceDryRun inspects the local repo at resolvedPath and // prints the file list that `vm run` / `workspace prepare` would ship // into the guest. Runs on the CLI side (no daemon RPC needed) since // the daemon is always local and the workspace inspection is a pure // git read. Git calls go through d.repoInspector so tests inject a // stub Runner via the deps struct instead of touching package globals. func (d *deps) runWorkspaceDryRun(ctx context.Context, out io.Writer, resolvedPath, branchName, fromRef string, includeUntracked bool) error { spec, err := d.repoInspector.InspectRepo(ctx, resolvedPath, branchName, fromRef, includeUntracked) if err != nil { return err } fmt.Fprintf(out, "dry-run: %d file(s) would be copied to guest\n", len(spec.OverlayPaths)) fmt.Fprintf(out, "repo: %s\n", spec.RepoRoot) if includeUntracked { fmt.Fprintln(out, "mode: tracked + untracked non-ignored (--include-untracked)") } else { fmt.Fprintln(out, "mode: tracked only (re-run with --include-untracked to also copy untracked non-ignored files)") } fmt.Fprintln(out, "---") for _, path := range spec.OverlayPaths { fmt.Fprintln(out, path) } if !includeUntracked { d.noteUntrackedSkipped(ctx, out, spec.RepoRoot) } return nil } // noteUntrackedSkipped prints a one-line notice when the repo holds // untracked non-ignored files that will NOT be copied because // --include-untracked was not passed. // // Best-effort: if sourcePath isn't inside a git repo, or git errors, // or there are no untracked files, the helper stays silent. The // notice is a courtesy — failing the whole operation over a courtesy // would be worse than the notice being missing. // // Resolves sourcePath to the repo root internally via `git rev-parse // --show-toplevel` so callers can pass whatever path the user typed. // Before this helper normalised, subdir inputs ran `ls-files // --others` scoped to the subdir, which silently underreported the // skipped files the user needed to know about. func (d *deps) noteUntrackedSkipped(ctx context.Context, out io.Writer, sourcePath string) { repoRoot, err := d.repoInspector.GitTrimmedOutput(ctx, sourcePath, "rev-parse", "--show-toplevel") if err != nil || repoRoot == "" { return } count, err := d.repoInspector.CountUntrackedPaths(ctx, repoRoot) if err != nil || count == 0 { return } fmt.Fprintf(out, "---\nnote: %d untracked non-ignored file(s) were NOT copied (git-tracked files only by default — pass --include-untracked to include them)\n", count) }