aboutsummaryrefslogtreecommitdiff
path: root/cmd/index-pack
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-05 18:24:40 +0800
committerGravatar Runxi Yu2026-03-05 19:05:47 +0800
commit57f1818d547f2f1dca38033b4e29f62d89ef80f9 (patch)
tree88d55ac38e2427860bf380c8cce42fcb3bb1e9ee /cmd/index-pack
parentinternal/compress/zlib: Use flate's compression consumed counter (diff)
signatureNo signature
format/pack/ingest: Init
Diffstat (limited to 'cmd/index-pack')
-rw-r--r--cmd/index-pack/main.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/cmd/index-pack/main.go b/cmd/index-pack/main.go
new file mode 100644
index 00000000..12d01ed8
--- /dev/null
+++ b/cmd/index-pack/main.go
@@ -0,0 +1,107 @@
+// Command index-pack ingests one pack stream from stdin and writes .pack/.idx/.rev.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ "codeberg.org/lindenii/furgit/format/pack/ingest"
+ "codeberg.org/lindenii/furgit/objectid"
+ "codeberg.org/lindenii/furgit/objectstore"
+ "codeberg.org/lindenii/furgit/repository"
+)
+
+func main() {
+ repoPath := flag.String("r", "", "path to git dir (.git or bare repo root)")
+ destinationPath := flag.String("destination", "", "path to destination objects/pack directory")
+ objectFormat := flag.String("object-format", "", "object format (sha1 or sha256)")
+ fixThin := flag.Bool("fix-thin", false, "fix thin packs using repository object store")
+ writeRev := flag.Bool("rev-index", true, "write reverse index (.rev)")
+
+ flag.Parse()
+
+ if *destinationPath == "" {
+ log.Fatal("must provide -destination <objects/pack>")
+ }
+
+ err := run(*repoPath, *destinationPath, *objectFormat, *fixThin, *writeRev)
+ if err != nil {
+ log.Fatalf("run: %v", err)
+ }
+}
+
+func run(repoPath, destinationPath, objectFormat string, fixThin, writeRev bool) error {
+ var (
+ algo objectid.Algorithm
+ base objectstore.Store
+ repo *repository.Repository
+ )
+ if repoPath != "" {
+ repoRoot, err := os.OpenRoot(repoPath)
+ if err != nil {
+ return fmt.Errorf("open repo root: %w", err)
+ }
+ defer func() { _ = repoRoot.Close() }()
+
+ repo, err = repository.Open(repoRoot)
+ if err != nil {
+ return fmt.Errorf("open repository: %w", err)
+ }
+ defer func() { _ = repo.Close() }()
+ }
+
+ algo, err := resolveAlgorithm(repo, objectFormat)
+ if err != nil {
+ return err
+ }
+
+ if fixThin {
+ if repo == nil {
+ return fmt.Errorf("fix-thin requires -r <repo>")
+ }
+ if repo.Algorithm() != algo {
+ return fmt.Errorf("algorithm mismatch: repo=%s flag=%s", repo.Algorithm(), algo)
+ }
+ base = repo.Objects()
+ }
+
+ absDestination, err := filepath.Abs(destinationPath)
+ if err != nil {
+ return fmt.Errorf("absolute destination path: %w", err)
+ }
+
+ destinationRoot, err := os.OpenRoot(absDestination)
+ if err != nil {
+ return fmt.Errorf("open destination root: %w", err)
+ }
+ defer func() { _ = destinationRoot.Close() }()
+
+ result, err := ingest.Ingest(os.Stdin, destinationRoot, algo, fixThin, writeRev, base)
+ if err != nil {
+ return err
+ }
+
+ _, _ = fmt.Fprintf(os.Stdout, "pack\t%s\n", result.PackHash.String())
+
+ return nil
+}
+
+func resolveAlgorithm(repo *repository.Repository, objectFormat string) (objectid.Algorithm, error) {
+ if objectFormat != "" {
+ algo, ok := objectid.ParseAlgorithm(objectFormat)
+ if !ok {
+ return objectid.AlgorithmUnknown, fmt.Errorf("invalid object format %q", objectFormat)
+ }
+
+ return algo, nil
+ }
+
+ if repo != nil {
+ return repo.Algorithm(), nil
+ }
+
+ return objectid.AlgorithmSHA1, nil
+}