Documentation
¶
Overview ¶
Package clonenow implements the `gitmap clone-now <file>` workflow: re-run `git clone` against the JSON / CSV / text artifacts produced by `gitmap scan`, honoring the recorded folder structure and a user-selected SSH/HTTPS mode.
Why a separate package (not clonefrom or cloner)?
- clonefrom is plan-driven (user-authored row schema).
- cloner is the in-memory scan-pipeline cloner that runs as part of the scan command itself.
- clonenow is a round-trip cloner: the input is gitmap's own scan output, so the schema (RepoName, HTTPSUrl, SSHUrl, Branch, RelativePath, ...) is fixed and we honor RelativePath verbatim so the destination tree is byte-identical to the original.
Splitting keeps each cloner's contract tight and avoids forcing clone-from to grow scan-record-aware fields.
Index ¶
- func BuildGitArgs(r Row, url, dest string) []string
- func DeriveDest(url string) string
- func KnownScanFields() []string
- func Render(w io.Writer, plan Plan) error
- func RenderSummary(w io.Writer, results []Result) error
- func RequiredScanURLFields() []string
- type BeforeRowHook
- type Plan
- type Result
- type Row
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildGitArgs ¶
BuildGitArgs returns the argv (excluding the "git" binary) that Execute would pass to exec.Command for the given row. Mirrors the real call site in executeRow exactly — no recomputation.
func DeriveDest ¶
DeriveDest returns the directory git would create by default for the given URL: the trailing path segment, with a single trailing `.git` removed. Public so executor + parser agree on the fallback.
func KnownScanFields ¶
func KnownScanFields() []string
KnownScanFields returns the alphabetically-sorted list of JSON object keys / CSV header column names accepted by `gitmap clone <file>` (clone-now path). Returned slice is a fresh copy: callers may mutate it freely without affecting validation.
Stable ordering is part of the contract: the JSON-Schema emitter embeds these as enum-of-properties and golden tests pin the resulting bytes.
func Render ¶
Render writes the dry-run preview: a header echoing the source + format + mode, then one block per row showing the URL that would be used and the destination path it would land at. Returns any io.Writer error so the CLI can exit 1 on a broken pipe instead of silently truncating.
func RenderSummary ¶
RenderSummary writes the end-of-batch tally + the per-row status table. Always prints, even when every row is "ok", so users have a definitive "this is what happened" record without hunting through the per-row progress lines.
func RequiredScanURLFields ¶
func RequiredScanURLFields() []string
RequiredScanURLFields returns the names of the URL-bearing fields at least one of which MUST be present on every input row. Mirrors validateJSONElement / validateCSVBody. Sorted; fresh copy per call.
Types ¶
type BeforeRowHook ¶
BeforeRowHook is invoked once per row, just before the row's git clone runs. See file header for the parameter contract.
type Plan ¶
type Plan struct {
// Source is the absolute path the plan was read from. Echoed
// verbatim in the dry-run header.
Source string
// Format is "json" | "csv" | "text" -- used by the dry-run
// header so the user can confirm we parsed the file the way
// they expected.
Format string
// Mode is "https" | "ssh" -- the URL column the executor will
// prefer for each row. Captured on the Plan (not just on the
// CLI cfg) so the dry-run renderer and the executor see the
// same value, with no risk of drift.
Mode string
// OnExists is "skip" | "update" | "force" -- the policy applied
// when the destination already contains a git repository.
// Captured on the Plan for the same reason as Mode: a single
// source of truth shared by render + execute prevents the
// dry-run preview from advertising a behavior different from
// what the executor would actually do.
OnExists string
// Rows is the deduplicated, validated list of clones to perform.
// Order matches the on-disk order so dry-run output is stable
// across runs of the same file.
Rows []Row
}
Plan is the validated, in-memory representation of one input file. Built by ParseFile from JSON, CSV, or plain-text scan output and consumed by Render (dry-run) and Execute.
func ParseFile ¶
ParseFile is the package's only public parser entry point. `format` may be "" (auto-detect from extension) or one of constants.CloneNowFormat{JSON,CSV,Text}. `mode` and `onExists` must already be validated by the caller -- ParseFile records them on the Plan but does not interpret them (that's the executor / renderer's job).
type Result ¶
type Result struct {
Row Row
URL string // the URL actually used (after mode + fallback)
Dest string // the destination path actually used (after cwd join)
Status string
Detail string
Duration time.Duration
}
Result is one row's outcome. Status is one of "ok" | "skipped" | "failed". Detail carries human-readable context: empty for ok, MsgCloneNowDestExists for skipped, the trimmed git stderr for failed (capped at CloneNowErrTrimLimit chars).
func Execute ¶
Execute runs every row sequentially and writes per-row progress lines to `progress` (typically os.Stderr; pass io.Discard to silence). Returns the full result slice -- callers render the summary AFTER Execute returns so a write failure on `progress` doesn't truncate the result set.
Working directory: each clone runs in `cwd`. Empty `cwd` -> the process cwd at call time, captured once up-front so a row that shells out into a subprocess (which mutates cwd) doesn't shift where subsequent rows land.
func ExecuteWithHooks ¶
ExecuteWithHooks is Execute + a per-row BeforeRow callback. The body is a copy of Execute's loop with the hook insertion point; kept as a separate function (rather than refactoring Execute to accept an optional hook) so the existing Execute signature — and every test that calls it — stays untouched.
func ExecuteWithHooksConcurrent ¶
func ExecuteWithHooksConcurrent(plan Plan, cwd string, progress io.Writer, beforeRow BeforeRowHook, workers int) []Result
ExecuteWithHooksConcurrent is the parallel sibling of ExecuteWithHooks. See file header for the contract.
type Row ¶
type Row struct {
// RepoName is shown in progress + summary lines. Derived from
// the scan record's RepoName when present; falls back to the
// last URL segment for text-format inputs.
RepoName string
// HTTPSUrl is the recorded https-style clone URL (may be empty
// for text-format rows when the source line was an ssh URL).
HTTPSUrl string
// SSHUrl is the recorded ssh-style clone URL (may be empty for
// text-format rows when the source line was an https URL).
SSHUrl string
// Branch optionally pins the initial branch with --branch.
// Empty -> git uses the remote's HEAD. Honored for JSON / CSV
// rows; text-format rows always come through with empty Branch
// because the plain `git clone <url> <dir>` line carries no
// branch information.
Branch string
// RelativePath is the destination directory relative to cwd at
// execute time. Always non-empty after parsing -- ParseFile
// fills it in from the URL basename when the source row didn't
// supply one (text-format with no explicit destination arg).
RelativePath string
}
Row is one scan-record-shaped clone target. Unlike clonefrom.Row (which carries raw URL + optional branch/depth) this carries the full pair of HTTPS / SSH URLs + the recorded relative folder so the executor can pick a URL based on the mode flag without re- parsing or re-deriving anything.
func (Row) PickURL ¶
PickURL returns the URL to clone with for the given mode, falling back to the other mode if the preferred URL is missing on this row. Returns "" only when both URL fields are empty -- a row that reaches Execute with empty PickURL is reported as a failure with MsgCloneNowNoURL rather than silently skipped.
Centralized here (rather than duplicated in execute / render) so the dry-run preview and the actual git invocation always agree on which URL would be used.