diff options
Diffstat (limited to 'refstore/packed/parse.go')
| -rw-r--r-- | refstore/packed/parse.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/refstore/packed/parse.go b/refstore/packed/parse.go new file mode 100644 index 00000000..6fe88061 --- /dev/null +++ b/refstore/packed/parse.go @@ -0,0 +1,100 @@ +package packed + +import ( + "bufio" + "fmt" + "io" + "strings" + + "codeberg.org/lindenii/furgit/objectid" + "codeberg.org/lindenii/furgit/ref" +) + +// parsePackedRefs parses packed-refs content into detached refs. +func parsePackedRefs(r io.Reader, algo objectid.Algorithm) (map[string]ref.Detached, []ref.Detached, error) { + byName := make(map[string]ref.Detached) + ordered := make([]ref.Detached, 0, 32) + + br := bufio.NewReader(r) + prev := -1 + lineNum := 0 + + for { + line, err := br.ReadString('\n') + 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 + } + + if strings.HasPrefix(line, "^") { + 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 + } + + fields := strings.Fields(line) + if len(fields) != 2 { + return nil, nil, fmt.Errorf("refstore/packed: line %d: malformed entry", lineNum) + } + + id, parseErr := objectid.ParseHex(algo, fields[0]) + if parseErr != nil { + return nil, nil, fmt.Errorf("refstore/packed: line %d: invalid oid: %w", lineNum, parseErr) + } + + name := fields[1] + 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) + } + + detached := ref.Detached{ + RefName: name, + ID: id, + } + ordered = append(ordered, detached) + prev = len(ordered) - 1 + byName[name] = detached + + if err == io.EOF { + break + } + } + + return byName, ordered, nil +} |
