diff options
| author | 2026-03-04 08:26:56 +0800 | |
|---|---|---|
| committer | 2026-03-04 08:59:53 +0800 | |
| commit | ab7501be34032fb9e5c48726a68ae90a917af9eb (patch) | |
| tree | 20d005647569befea8133e953c3270e8fd2a2a5b /refstore/packed | |
| parent | *: gofumpt (diff) | |
| signature | No signature | |
*: Lint
Diffstat (limited to 'refstore/packed')
| -rw-r--r-- | refstore/packed/packed_test.go | 45 | ||||
| -rw-r--r-- | refstore/packed/parse.go | 12 | ||||
| -rw-r--r-- | refstore/packed/store.go | 12 |
3 files changed, 62 insertions, 7 deletions
diff --git a/refstore/packed/packed_test.go b/refstore/packed/packed_test.go index dffed2a8..0ddceabf 100644 --- a/refstore/packed/packed_test.go +++ b/refstore/packed/packed_test.go @@ -16,30 +16,39 @@ import ( func openPackedRefStoreFromRepo(t *testing.T, repoPath string, algo objectid.Algorithm) *packed.Store { t.Helper() + root, err := os.OpenRoot(repoPath) if err != nil { t.Fatalf("OpenRoot(repo): %v", err) } + defer func() { _ = root.Close() }() store, err := packed.New(root, algo) if err != nil { t.Fatalf("packed.New: %v", err) } + return store } func openPackedRefStoreFromContent(t *testing.T, content string, algo objectid.Algorithm) (*packed.Store, error) { t.Helper() + dir := t.TempDir() - if err := os.WriteFile(dir+"/packed-refs", []byte(content), 0o644); err != nil { + + err := os.WriteFile(dir+"/packed-refs", []byte(content), 0o644) + if err != nil { t.Fatalf("WriteFile(packed-refs): %v", err) } + root, err := os.OpenRoot(dir) if err != nil { t.Fatalf("OpenRoot(temp): %v", err) } + defer func() { _ = root.Close() }() + return packed.New(root, algo) } @@ -58,10 +67,12 @@ func TestPackedResolveAndPeeled(t *testing.T) { if err != nil { t.Fatalf("Resolve(main): %v", err) } + mainDet, ok := resolvedMain.(ref.Detached) if !ok { t.Fatalf("Resolve(main) type = %T, want ref.Detached", resolvedMain) } + if mainDet.ID != commitID { t.Fatalf("Resolve(main) id = %s, want %s", mainDet.ID, commitID) } @@ -70,16 +81,20 @@ func TestPackedResolveAndPeeled(t *testing.T) { if err != nil { t.Fatalf("Resolve(tag): %v", err) } + tagDet, ok := resolvedTag.(ref.Detached) if !ok { t.Fatalf("Resolve(tag) type = %T, want ref.Detached", resolvedTag) } + if tagDet.ID != tagID { t.Fatalf("Resolve(tag) id = %s, want %s", tagDet.ID, tagID) } + if tagDet.Peeled == nil { t.Fatalf("Resolve(tag) peeled = nil, want commit") } + if *tagDet.Peeled != commitID { t.Fatalf("Resolve(tag) peeled = %s, want %s", *tagDet.Peeled, commitID) } @@ -88,11 +103,13 @@ func TestPackedResolveAndPeeled(t *testing.T) { if err != nil { t.Fatalf("ResolveFully(tag): %v", err) } + if fullTag.ID != tagDet.ID { t.Fatalf("ResolveFully(tag) id = %s, want %s", fullTag.ID, tagDet.ID) } - if _, err := store.Resolve("refs/heads/does-not-exist"); !errors.Is(err, refstore.ErrReferenceNotFound) { + _, err = store.Resolve("refs/heads/does-not-exist") + if !errors.Is(err, refstore.ErrReferenceNotFound) { t.Fatalf("Resolve(not-found) error = %v", err) } }) @@ -114,11 +131,14 @@ func TestPackedListAndShorten(t *testing.T) { if err != nil { t.Fatalf("List(all): %v", err) } + allNames := make([]string, 0, len(all)) for _, entry := range all { allNames = append(allNames, entry.Name()) } + slices.Sort(allNames) + wantAll := []string{"refs/heads/main", "refs/remotes/origin/main", "refs/tags/main"} if !slices.Equal(allNames, wantAll) { t.Fatalf("List(all) names = %v, want %v", allNames, wantAll) @@ -128,6 +148,7 @@ func TestPackedListAndShorten(t *testing.T) { if err != nil { t.Fatalf("List(pattern): %v", err) } + if len(filtered) != 1 || filtered[0].Name() != "refs/heads/main" { t.Fatalf("List(refs/heads/*) = %v, want refs/heads/main only", filtered) } @@ -136,11 +157,13 @@ func TestPackedListAndShorten(t *testing.T) { if err != nil { t.Fatalf("Shorten(main): %v", err) } + if short != "heads/main" { t.Fatalf("Shorten(main) = %q, want %q", short, "heads/main") } - if _, err := store.Shorten("refs/heads/does-not-exist"); !errors.Is(err, refstore.ErrReferenceNotFound) { + _, err = store.Shorten("refs/heads/does-not-exist") + if !errors.Is(err, refstore.ErrReferenceNotFound) { t.Fatalf("Shorten(not-found) error = %v", err) } }) @@ -195,10 +218,13 @@ func TestPackedListPatternMatrix(t *testing.T) { if err != nil { t.Fatalf("List(%q): %v", tt.pattern, err) } + gotNames := refNames(got) slices.Sort(gotNames) + wantNames := append([]string(nil), tt.want...) slices.Sort(wantNames) + if !slices.Equal(gotNames, wantNames) { t.Fatalf("List(%q) names = %v, want %v", tt.pattern, gotNames, wantNames) } @@ -231,7 +257,8 @@ func TestPackedParseErrors(t *testing.T) { for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - if _, err := openPackedRefStoreFromContent(t, tt.data, algo); err == nil { + _, err := openPackedRefStoreFromContent(t, tt.data, algo) + if err == nil { t.Fatalf("packed.New expected parse error") } }) @@ -242,16 +269,21 @@ func TestPackedParseErrors(t *testing.T) { func TestPackedNewValidation(t *testing.T) { t.Parallel() dir := t.TempDir() + root, err := os.OpenRoot(dir) if err != nil { t.Fatalf("OpenRoot(temp): %v", err) } + defer func() { _ = root.Close() }() - if _, err := packed.New(root, objectid.AlgorithmUnknown); !errors.Is(err, objectid.ErrInvalidAlgorithm) { + _, err = packed.New(root, objectid.AlgorithmUnknown) + if !errors.Is(err, objectid.ErrInvalidAlgorithm) { t.Fatalf("packed.New invalid algorithm error = %v", err) } - if _, err := packed.New(root, objectid.AlgorithmSHA256); !errors.Is(err, os.ErrNotExist) { + + _, err = packed.New(root, objectid.AlgorithmSHA256) + if !errors.Is(err, os.ErrNotExist) { t.Fatalf("packed.New missing packed-refs error = %v", err) } } @@ -261,6 +293,7 @@ func refNames(refs []ref.Ref) []string { for _, entry := range refs { names = append(names, entry.Name()) } + return names } diff --git a/refstore/packed/parse.go b/refstore/packed/parse.go index 6fe88061..4846d258 100644 --- a/refstore/packed/parse.go +++ b/refstore/packed/parse.go @@ -24,24 +24,30 @@ func parsePackedRefs(r io.Reader, algo objectid.Algorithm) (map[string]ref.Detac if err != nil && err != io.EOF { return nil, nil, err } + if line == "" && err == io.EOF { break } + lineNum++ line = strings.TrimSuffix(line, "\n") line = strings.TrimSuffix(line, "\r") + line = strings.TrimSpace(line) if line == "" { if err == io.EOF { break } + continue } + if strings.HasPrefix(line, "#") { if err == io.EOF { break } + continue } @@ -49,19 +55,24 @@ func parsePackedRefs(r io.Reader, algo objectid.Algorithm) (map[string]ref.Detac if prev < 0 { return nil, nil, fmt.Errorf("refstore/packed: line %d: peeled line without preceding ref", lineNum) } + peeledHex := strings.TrimSpace(strings.TrimPrefix(line, "^")) + peeled, parseErr := objectid.ParseHex(algo, peeledHex) if parseErr != nil { return nil, nil, fmt.Errorf("refstore/packed: line %d: invalid peeled oid: %w", lineNum, parseErr) } + peeledCopy := peeled cur := ordered[prev] cur.Peeled = &peeledCopy ordered[prev] = cur byName[cur.Name()] = cur + if err == io.EOF { break } + continue } @@ -79,6 +90,7 @@ func parsePackedRefs(r io.Reader, algo objectid.Algorithm) (map[string]ref.Detac if name == "" { return nil, nil, fmt.Errorf("refstore/packed: line %d: empty ref name", lineNum) } + if _, exists := byName[name]; exists { return nil, nil, fmt.Errorf("refstore/packed: line %d: duplicate ref %q", lineNum, name) } diff --git a/refstore/packed/store.go b/refstore/packed/store.go index 7705dacb..5ab9d602 100644 --- a/refstore/packed/store.go +++ b/refstore/packed/store.go @@ -25,16 +25,19 @@ func New(root *os.Root, algo objectid.Algorithm) (*Store, error) { if algo.Size() == 0 { return nil, objectid.ErrInvalidAlgorithm } + packedRefs, err := root.Open("packed-refs") if err != nil { return nil, fmt.Errorf("refstore/packed: open packed-refs: %w", err) } + defer func() { _ = packedRefs.Close() }() byName, ordered, err := parsePackedRefs(packedRefs, algo) if err != nil { return nil, err } + return &Store{ byName: byName, ordered: ordered, @@ -47,6 +50,7 @@ func (store *Store) Resolve(name string) (ref.Ref, error) { if !ok { return nil, refstore.ErrReferenceNotFound } + return detached, nil } @@ -58,6 +62,7 @@ func (store *Store) ResolveFully(name string) (ref.Detached, error) { if !ok { return ref.Detached{}, refstore.ErrReferenceNotFound } + return detached, nil } @@ -68,7 +73,8 @@ func (store *Store) ResolveFully(name string) (ref.Detached, error) { func (store *Store) List(pattern string) ([]ref.Ref, error) { matchAll := pattern == "" if !matchAll { - if _, err := path.Match(pattern, "refs/heads/main"); err != nil { + _, err := path.Match(pattern, "refs/heads/main") + if err != nil { return nil, err } } @@ -80,12 +86,15 @@ func (store *Store) List(pattern string) ([]ref.Ref, error) { if err != nil { return nil, err } + if !matched { continue } } + refs = append(refs, entry) } + return refs, nil } @@ -100,6 +109,7 @@ func (store *Store) Shorten(name string) (string, error) { for _, entry := range store.ordered { names = append(names, entry.Name()) } + return refstore.ShortenName(name, names), nil } |
