aboutsummaryrefslogtreecommitdiff
path: root/internal/testgit/packobjects.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/testgit/packobjects.go')
-rw-r--r--internal/testgit/packobjects.go124
1 files changed, 111 insertions, 13 deletions
diff --git a/internal/testgit/packobjects.go b/internal/testgit/packobjects.go
index 9f56eef0..62f86963 100644
--- a/internal/testgit/packobjects.go
+++ b/internal/testgit/packobjects.go
@@ -2,7 +2,8 @@ package testgit
import (
"bytes"
- "iter"
+ "errors"
+ "fmt"
"path/filepath"
"strings"
"testing"
@@ -10,38 +11,135 @@ import (
"lindenii.org/go/furgit/object/id"
)
-// PackObjectsOptions controls one pack-objects invocation.
+// ErrInvalidPackObjectsOptions reports an inconsistent
+// combination of pack-objects options.
+var ErrInvalidPackObjectsOptions = errors.New("internal/testgit: invalid pack-objects options")
+
+// PackObjectsOptions controls one on-disk pack-objects invocation.
type PackObjectsOptions struct {
// RevIndex requests writing a .rev reverse index alongside the pack.
RevIndex bool
+
+ // Revs changes how the input is interpreted.
+ //
+ // When false, each include is one object name,
+ // and exactly those objects are packed.
+ //
+ // When true, each include is a revision argument,
+ // and pack-objects packs the closure of objects
+ // reachable from the includes but not from the excludes,
+ // the same walk git rev-list --objects performs.
+ Revs bool
+
+ // Exclude lists objects to omit by reachability,
+ // fed as "^<oid>" revision arguments.
+ // A non-nil Exclude requires Revs.
+ Exclude []id.ObjectID
}
-// PackObjects packs the supplied objects with git pack-objects
+// PackObjects packs the include objects with git pack-objects
// into a temporary directory,
// and returns the artifact path prefix "<dir>/pack-<hash>",
// to which ".pack", ".idx", and ".rev" suffixes apply.
-func (repo *Repo) PackObjects(tb testing.TB, oids iter.Seq[id.ObjectID], opts PackObjectsOptions) (string, error) {
+func (repo *Repo) PackObjects(tb testing.TB, include []id.ObjectID, opts PackObjectsOptions) (string, error) {
tb.Helper()
- dir := tb.TempDir()
-
- var stdin bytes.Buffer
- for oid := range oids {
- stdin.WriteString(oid.String())
- stdin.WriteByte('\n')
+ if opts.Exclude != nil && !opts.Revs {
+ return "", fmt.Errorf("%w: Exclude requires Revs", ErrInvalidPackObjectsOptions)
}
+ dir := tb.TempDir()
+
revIndex := "false"
if opts.RevIndex {
revIndex = "true"
}
- out, err := repo.run(tb, &stdin,
- "git", "-c", "pack.writeReverseIndex="+revIndex,
- "pack-objects", "--end-of-options", filepath.Join(dir, "pack"))
+ args := []string{"-c", "pack.writeReverseIndex=" + revIndex, "pack-objects"}
+ if opts.Revs {
+ args = append(args, "--revs")
+ }
+
+ args = append(args, "--end-of-options", filepath.Join(dir, "pack"))
+
+ out, err := repo.run(tb, packObjectsStdin(include, opts.Exclude), "git", args...)
if err != nil {
return "", err
}
return filepath.Join(dir, "pack-"+strings.TrimSpace(string(out))), nil
}
+
+// PackObjectsStdoutOptions controls one streamed pack-objects invocation.
+type PackObjectsStdoutOptions struct {
+ // Revs changes how the input is interpreted.
+ //
+ // When false, each include is one object name,
+ // and exactly those objects are packed.
+ //
+ // When true, each include is a revision argument,
+ // and pack-objects packs the closure of objects
+ // reachable from the includes but not from the excludes,
+ // the same walk git rev-list --objects performs.
+ Revs bool
+
+ // Thin omits excluded base objects from the pack,
+ // producing a thin pack that must be completed before use.
+ // Thin requires Revs.
+ Thin bool
+
+ // Exclude lists objects to omit by reachability,
+ // fed as "^<oid>" revision arguments.
+ // A non-nil Exclude requires Revs.
+ Exclude []id.ObjectID
+}
+
+// PackObjectsStdout packs the include objects with git pack-objects
+// and returns the pack stream written to standard output.
+func (repo *Repo) PackObjectsStdout(tb testing.TB, include []id.ObjectID, opts PackObjectsStdoutOptions) ([]byte, error) {
+ tb.Helper()
+
+ if opts.Exclude != nil && !opts.Revs {
+ return nil, fmt.Errorf("%w: Exclude requires Revs", ErrInvalidPackObjectsOptions)
+ }
+
+ if opts.Thin && !opts.Revs {
+ return nil, fmt.Errorf("%w: Thin requires Revs", ErrInvalidPackObjectsOptions)
+ }
+
+ args := []string{"pack-objects", "--stdout"}
+ if opts.Revs {
+ args = append(args, "--revs")
+ }
+
+ if opts.Thin {
+ args = append(args, "--thin")
+ }
+
+ out, err := repo.run(tb, packObjectsStdin(include, opts.Exclude), "git", args...)
+ if err != nil {
+ return nil, err
+ }
+
+ return out, nil
+}
+
+// packObjectsStdin builds the pack-objects standard input:
+// the include object IDs,
+// followed by the exclude object IDs as "^<oid>" lines.
+func packObjectsStdin(include, exclude []id.ObjectID) *bytes.Buffer {
+ var stdin bytes.Buffer
+
+ for _, oid := range include {
+ stdin.WriteString(oid.String())
+ stdin.WriteByte('\n')
+ }
+
+ for _, oid := range exclude {
+ stdin.WriteByte('^')
+ stdin.WriteString(oid.String())
+ stdin.WriteByte('\n')
+ }
+
+ return &stdin
+}