Documentation
¶
Overview ¶
Package clonepick implements `gitmap clone-pick <repo-url> <paths>`: a partial / sparse-checkout clone of a single git repository, fetching only the requested repo-relative paths into the current working directory (or --dest).
Why a separate package (not clonefrom / clonenow / cloner)?
- clonefrom is plan-driven from a manifest (rows of url+dest+branch).
- clonenow is round-trip from `gitmap scan` output.
- cloner is the in-memory pipeline cloner used during scan.
clone-pick sits orthogonal to all three: input is one URL + a path list, output is a sparse-checkout. Sharing code with the others would force them to grow path-filter awareness they don't need.
Persistence: every successful run writes one row to the CloneInteractiveSelection table so the same selection can be re-applied later via --replay <id|name>.
See spec/01-app/100-clone-pick.md.
Index ¶
- Constants
- Variables
- func BuildGitArgs(plan Plan, dest string) []string
- func IsAutoExcluded(path string) bool
- func ListRepoPathsKeep(plan Plan) ([]string, string, error)
- func Render(w io.Writer, plan Plan) error
- func RunPicker(plan Plan) ([]string, error)
- func RunPickerKeep(plan Plan) ([]string, string, error)
- func SaveSelection(p Persister, plan Plan) (int64, error)
- func TouchAfterReplay(loader Loader, id int64, dryRun bool) error
- type Flags
- type Loader
- type Persister
- type Plan
- type Result
Constants ¶
const ( StatusOK = "ok" StatusFailed = "failed" StatusCancelled = "cancelled" //nolint:misspell // stable JSON status value, do not rename. )
Status enum values mirror clonenow's vocabulary so downstream pipelines that grep "ok"/"failed" keep working.
Variables ¶
var ErrPickerCancelled = errors.New("clone-pick: picker cancelled") //nolint:misspell // stable exported API name + message, do not rename.
ErrPickerCancelled is returned by RunPicker when the user pressed q / ctrl-c. The cmd layer maps this to exit code 130 and prints MsgClonePickUserCancelled.
Functions ¶
func BuildGitArgs ¶
BuildGitArgs returns the argv (excluding the "git" binary) that gitClonePartial would pass to runGit for the given plan/dest. Order matches gitClonePartial in sparse.go exactly: `clone --filter=blob:none --no-checkout [--branch B] [--depth N] URL DEST`.
func IsAutoExcluded ¶
IsAutoExcluded reports whether path lives under any directory in the auto-exclude list (e.g. node_modules/, vendor/). Exported so the picker view layer can dim the row without re-implementing the match. Comparison is case-sensitive on purpose -- git paths are case-sensitive on every platform that matters here.
func ListRepoPathsKeep ¶
ListRepoPathsKeep is the keep-clone variant: returns the path list AND the temp dir that holds the metadata clone. The caller owns tmp and must remove it (directly or by promoting it to a final destination via PromotePreClonedSrc). On error tmp is already cleaned up.
func Render ¶
Render writes the dry-run preview for a single Plan. Stable output (no map iteration, no time/now, no random ordering) so the goldens don't churn between runs.
func RunPicker ¶
RunPicker enumerates plan.RepoUrl, opens the bubbletea picker, and returns the user-picked subset. plan.Paths seeds the initial selection so re-running with the same args is a no-op confirmation.
func RunPickerKeep ¶
RunPickerKeep is the clone-once variant: returns the picked paths AND the temp metadata-clone directory so the executor can promote it instead of re-cloning. The caller owns tmp and must remove it (or pass it to the executor via Plan.PreClonedSrc, which moves it into place). On error or cancellation tmp is already cleaned up.
func SaveSelection ¶
SaveSelection records the plan and returns the new SelectionId. Skipped (returns 0, nil) when plan.DryRun is true so dry-runs never touch the database.
Types ¶
type Flags ¶
type Flags struct {
Ask bool
Name string
Mode string
Branch string
Depth int
Cone bool
Dest string
KeepGit bool
DryRun bool
Quiet bool
Force bool
// Replay is the raw value of --replay (numeric SelectionId or
// Name). Empty means "no replay -- parse positional args
// normally". Non-empty short-circuits ParseArgs in the cmd
// dispatcher: the Plan is loaded from the DB instead.
Replay string
}
Flags is the cmd-side flag bundle, decoupled from the flag.FlagSet so the parser is testable without spinning up a full CLI.
func DefaultFlags ¶
func DefaultFlags() Flags
DefaultFlags returns the flag bundle with the spec'd defaults. Centralized so cmd/clonepick.go and tests stay in sync.
type Loader ¶
type Loader interface {
LoadClonePickByID(id int64) (Plan, int64, error)
LoadClonePickByName(name string) (Plan, int64, error)
TouchClonePickCreatedAt(id int64) error
}
Loader is the read surface needed by --replay. Split from Persister (the write surface) so a future read-only test fake can implement just the lookup half. The lookup methods return the SelectionId alongside the Plan so callers can bump CreatedAt without a second round-trip.
type Persister ¶
Persister is the surface needed to save + look up selections. Implemented by *store.DB at call time; mocked in tests.
type Plan ¶
type Plan struct {
// Name is an optional human label persisted with the row. Empty
// is fine -- the row still gets a SelectionId.
Name string
// RepoCanonicalId is the host/owner/repo form returned by
// gitutil.CanonicalRepoID(RepoUrl). Stored separately so
// --replay can match HTTPS↔SSH variants of the same repo.
RepoCanonicalId string
// RepoUrl is the canonical URL passed to `git clone`. Either the
// user-supplied URL verbatim (when it was full) or the expanded
// form built from the owner/repo shorthand + Mode.
RepoUrl string
// Mode is "https" | "ssh" -- only meaningful when the input was
// shorthand. Persisted so --replay reproduces the same URL form.
Mode string
// Branch is the optional --branch argument forwarded to git
// clone. Empty -> git uses remote HEAD.
Branch string
// Depth is the shallow-clone depth. 0 = full history, 1 = the
// classic shallow checkout used by most pickers.
Depth int
// Cone is true when sparse-checkout cone mode applies (folder-
// only patterns). Auto-flipped to false by ParseArgs when any
// path looks like a glob or carries a file extension after a /.
Cone bool
// KeepGit controls whether .git is preserved after checkout.
// false = files-only mode (rm -rf .git after sparse-checkout).
KeepGit bool
// DestDir is the destination directory relative to cwd. "."
// means clone into the current directory (no shell handoff).
DestDir string
// Paths is the deduplicated, sorted list of repo-relative paths
// to materialize. Already validated by ParseArgs (no empty,
// no absolute, no traversal, no oversized entries).
Paths []string
// UsedAsk records whether --ask was passed. Persisted so
// --replay can decide whether to re-launch the picker (for now
// it doesn't, but keeping the bit avoids a schema migration
// later).
UsedAsk bool
// DryRun, Quiet, Force are runtime-only flags (not persisted).
// Captured on the Plan so render + execute share one source of
// truth and don't need to thread the cmd-side cfg struct down.
DryRun bool
Quiet bool
Force bool
// PreClonedSrc, when non-empty, is a temp directory holding a
// metadata-only clone (filter=blob:none, no-checkout) that the
// executor will promote into DestDir instead of running a fresh
// `git clone`. Set by the --ask picker so we don't pay the
// clone cost twice. Always absolute. The executor takes
// ownership: on success the dir is moved away, on failure the
// caller is responsible for cleanup.
PreClonedSrc string
}
Plan is the validated, in-memory representation of one clone-pick invocation. Built by ParseArgs (or LoadFromDB for --replay) and consumed by Render (dry-run) and Execute.
Field order mirrors the CloneInteractiveSelection schema so the persist layer can build/destructure rows without a translation map.
func LoadFromDB ¶
LoadFromDB resolves ref to a saved Plan + its SelectionId. Numeric refs hit the ID index; everything else is treated as a Name lookup. Returns the user-facing "no saved selection" message when nothing matches so the cmd layer can print verbatim.
type Result ¶
type Result struct {
// Status is one of "ok" | "failed" | "canceled" (the wire value
// kept on the wire for backwards compat with existing JSON
// consumers). Numeric exit code mapping lives in the cmd layer
// (cmd/clonepick.go) so the constants stay co-located with the
// user-facing strings.
Status string
// SelectionId is the DB row id assigned by the persist layer.
// 0 when DryRun was set (no row written) or when the run failed
// before reaching the persist step.
SelectionId int64
// Detail is a single-line user-facing message that's already
// printed to stderr by Execute -- duplicated on the Result so
// callers can include it in JSON summaries without re-deriving.
Detail string
}
Result describes what Execute did with one Plan. Returned by Execute so the cmd layer can pick an exit code without re-implementing success/failure heuristics.