Documentation
¶
Overview ¶
Package clonefrom implements the `gitmap clone-from <file>` workflow: read a JSON or CSV plan from disk, validate every row, render a dry-run preview by default, and on `--execute` shell out to `git clone` for each row with a per-row pass/fail summary.
Why a separate package (not gitmap/cloner or gitmap/clonenext)?
- gitmap/cloner is the scan-driven cloner: it consumes records emitted by the scan workflow and assumes a DB-backed repo model. `clone-from` is plan-driven: input comes from a user- provided file, no scan, no model.CloneRecord round-trip.
- gitmap/clonenext is the version-bumping cloner for existing local repos (`vN+1` of an already-cloned repo). `clone-from` clones brand-new URLs to user-chosen destinations.
Splitting keeps each cloner's contract tight and lets clone-from evolve (e.g., adding `--depth`, `--single-branch`, parallel fan-out) without touching the more constrained scan/cn paths.
Index ¶
- func BuildGitArgs(r Row, dest string) []string
- func ClassifyScheme(url string) string
- func DeriveDest(url string) string
- func EffectiveCheckout(r Row) string
- func EmitInputSchema() ([]byte, error)
- func EmitReportSchema() ([]byte, error)
- func EmitSchema(kind string) ([]byte, error)
- func Render(w io.Writer, p Plan) error
- func RenderSummary(w io.Writer, results []Result, reportPath string) error
- func RenderSummaryTerminal(w io.Writer, results []Result, csvPath, jsonPath string) error
- func RenderTerminal(w io.Writer, p Plan) error
- func TransportTally(results []Result) (sshCount, httpsCount, otherCount int)
- func WriteReport(results []Result) (string, error)
- func WriteReportJSON(results []Result) (string, error)
- 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.
func ClassifyScheme ¶
ClassifyScheme picks one bucket for a URL. Exported so tests and any future per-row preview can reuse the rule without re-deriving the prefix table.
func DeriveDest ¶
DeriveDest computes the directory name `git clone <url>` would pick by default: the last path segment with a trailing `.git` stripped. Public so the executor can use the same logic when the row's Dest field is empty.
func EffectiveCheckout ¶
EffectiveCheckout resolves a row's Checkout field to one of the three concrete modes. Empty → CloneFromCheckoutDefault ("auto"). Exported so renderers + faithful-cmd verifiers agree with the executor on the resolved mode without re-importing this file.
func EmitInputSchema ¶
EmitInputSchema returns the JSON Schema for the clone-now input (top-level array of scan records). Field set is sourced from clonenow.KnownScanFields() so additions auto-propagate.
func EmitReportSchema ¶
EmitReportSchema returns the JSON Schema for the clone-from JSON report envelope. The schemaVersion `const` is wired to constants.CloneFromReportSchemaVersion so a bump there is auto- reflected here (and the writer emits a matching number).
func EmitSchema ¶
EmitSchema dispatches on kind and returns the pretty-printed JSON Schema bytes. Unknown kinds return an error wrapping the user- facing message so the CLI layer can print and exit 2 verbatim.
func Render ¶
Render writes the legacy human-readable dry-run preview to w. Returns the first write error so callers (CLI) can surface it instead of silently truncating output to a closed pipe.
func RenderSummary ¶
RenderSummary writes a human-readable summary to w. Format:
gitmap clone-from: 5 ok, 1 skipped, 2 failed (8 total) report: .gitmap/clone-from-report-1735000000.csv ok https://github.com/a/b.git (1.2s) skipped https://github.com/c/d.git dest exists failed https://github.com/e/f.git fatal: repository not found ...
func RenderSummaryTerminal ¶
RenderSummaryTerminal writes the enriched terminal-mode summary block. csvPath / jsonPath may each be empty (write skipped or failed); the renderer substitutes a single "(skipped …)" line when BOTH are empty so the report section never disappears entirely. Returns the first write error so a closed pipe surfaces immediately instead of silently truncating.
func RenderTerminal ¶
RenderTerminal writes the standardized per-repo block (one block per row) using render.RenderRepoTermBlocks. The block matches the format emitted by scan, clone-next, and probe so users learn one shape regardless of which command produced it.
func TransportTally ¶
TransportTally collapses ClassifyScheme's seven buckets into the three columns the user-facing summary reports: ssh, https, other. Returned in that order so call sites can format with a single printf without referencing field names.
func WriteReport ¶
WriteReport persists the result set as CSV under .gitmap/. The timestamp suffix (Unix seconds) lets users keep a history of runs without one overwriting another. Returns the absolute path for the caller to surface in the summary header. On directory- create failure, returns "" + the error so the caller can decide whether the failure is fatal (it isn't — clones already happened, the report is bonus).
func WriteReportJSON ¶
WriteReportJSON persists the result set as a versioned JSON envelope under .gitmap/. Mirrors WriteReport's contract: same dir, same timestamp suffix (so the CSV and JSON for one run sort adjacently), absolute path on success, ("", err) on failure so callers can decide whether to surface the failure (they should: the JSON path is shown in the terminal summary).
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 or user-supplied path the plan was
// read from. Echoed verbatim in the dry-run header.
Source string
// Format is "json" or "csv" — used by the dry-run header so the
// user can confirm we parsed the file the way they expected.
Format 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 either JSON or CSV; consumed by Render (dry-run) and Execute. The Source field carries the on-disk path so the dry-run header can echo it back to the user without the caller having to thread the original argument through.
type Result ¶
type Result struct {
Row Row
Dest string // resolved (after DeriveDest fallback)
Status string
Detail string
Duration time.Duration
}
Result is one row's outcome. Status is one of "ok" | "skipped" | "failed". Detail is human-readable context: for "ok" the empty string; for "skipped" the reason ("dest exists"); for "failed" the trimmed git stderr (capped at GitErrorTrimLimit chars to keep the summary table readable).
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 → use the current process cwd at call time.
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 {
// URL is the clone source. Required. Validated for non-empty
// and rough HTTPS/SSH/scp-style shape — we do NOT round-trip
// through net/url.Parse because git accepts forms (scp-style
// `user@host:path`) that net/url rejects.
URL string
// Dest is the target directory relative to cwd at execute
// time. Empty → derived from the last URL segment (matches
// `git clone <url>` default).
Dest string
// Branch optionally pins the initial branch with --branch.
// Empty → git uses the remote's HEAD.
Branch string
// Depth optionally enables a shallow clone with --depth=N.
// Zero → full history.
Depth int
// Checkout controls post-clone working-tree behavior. One of
// "" / "auto" / "skip" / "force" (validated at parse time).
// Empty string means "inherit the global default" (set via
// --checkout on the CLI; defaults to "auto"). Per-row value
// always wins over the global default. See
// constants.FlagDescCloneFromCheckout for the semantics of each
// mode.
Checkout string
}
Row is one git-clone target. Every field except URL is optional; zero values translate to "use git's default" (HEAD branch, full history, dest derived from URL basename).