Fast implementation of Git in pure Go codeberg.org/lindenii/furgit
git go
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

object/id: Split files

Runxi Yu 32f84b9d e4afe122

+290 -264
+1 -1
format/commitgraph/read/layer_lookup.go
··· 9 9 ) 10 10 11 11 func layerLookup(layer *layer, oid objectid.ObjectID) (uint32, bool) { 12 - hashSize := oid.Size() 12 + hashSize := oid.Algorithm().Size() 13 13 first := int(oid.RawBytes()[0]) 14 14 15 15 var lo uint32
+1 -1
object/commit/serialize.go
··· 13 13 func (commit *Commit) SerializeWithoutHeader() ([]byte, error) { 14 14 var buf bytes.Buffer 15 15 16 - if commit.Tree.Size() == 0 { 16 + if commit.Tree.Algorithm().Size() == 0 { 17 17 return nil, errors.New("object: commit: missing tree id") 18 18 } 19 19
+12
object/id/algorithm.go
··· 1 + package objectid 2 + 3 + //#nosec gosec 4 + 5 + // Algorithm identifies the hash algorithm used for Git object IDs. 6 + type Algorithm uint8 7 + 8 + const ( 9 + AlgorithmUnknown Algorithm = iota 10 + AlgorithmSHA1 11 + AlgorithmSHA256 12 + )
+16
object/id/algorithm_details.go
··· 1 + package objectid 2 + 3 + import "hash" 4 + 5 + type algorithmDetails struct { 6 + name string 7 + size int 8 + packHashID uint32 9 + sum func([]byte) ObjectID 10 + new func() hash.Hash 11 + emptyTree ObjectID 12 + } 13 + 14 + func (algo Algorithm) info() algorithmDetails { 15 + return algorithmTable[algo] 16 + }
+7
object/id/algorithm_emptytree.go
··· 1 + package objectid 2 + 3 + // EmptyTree returns the object ID of an empty tree ("tree 0\x00") for this 4 + // algorithm. 5 + func (algo Algorithm) EmptyTree() ObjectID { 6 + return algo.info().emptyTree 7 + }
+6
object/id/algorithm_hexlen.go
··· 1 + package objectid 2 + 3 + // HexLen returns the encoded hexadecimal length. 4 + func (algo Algorithm) HexLen() int { 5 + return algo.Size() * 2 6 + }
+13
object/id/algorithm_new.go
··· 1 + package objectid 2 + 3 + import "hash" 4 + 5 + // New returns a new hash.Hash for this algorithm. 6 + func (algo Algorithm) New() (hash.Hash, error) { 7 + newFn := algo.info().new 8 + if newFn == nil { 9 + return nil, ErrInvalidAlgorithm 10 + } 11 + 12 + return newFn(), nil 13 + }
+8
object/id/algorithm_packhashid.go
··· 1 + package objectid 2 + 3 + // PackHashID returns the Git pack/rev hash-id encoding for this algorithm. 4 + // 5 + // Unknown algorithms return 0. 6 + func (algo Algorithm) PackHashID() uint32 { 7 + return algo.info().packHashID 8 + }
+8
object/id/algorithm_parse.go
··· 1 + package objectid 2 + 3 + // ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256"). 4 + func ParseAlgorithm(s string) (Algorithm, bool) { 5 + algo, ok := algorithmByName[s] 6 + 7 + return algo, ok 8 + }
+6
object/id/algorithm_size.go
··· 1 + package objectid 2 + 3 + // Size returns the hash size in bytes. 4 + func (algo Algorithm) Size() int { 5 + return algo.info().size 6 + }
+11
object/id/algorithm_string.go
··· 1 + package objectid 2 + 3 + // String returns the canonical algorithm name. 4 + func (algo Algorithm) String() string { 5 + inf := algo.info() 6 + if inf.name == "" { 7 + return "unknown" 8 + } 9 + 10 + return inf.name 11 + }
+6
object/id/algorithm_sum.go
··· 1 + package objectid 2 + 3 + // Sum computes an object ID from raw data using the selected algorithm. 4 + func (algo Algorithm) Sum(data []byte) ObjectID { 5 + return algo.info().sum(data) 6 + }
+7
object/id/algorithm_supported.go
··· 1 + package objectid 2 + 3 + // SupportedAlgorithms returns all object ID algorithms supported by furgit. 4 + // Do not mutate. 5 + func SupportedAlgorithms() []Algorithm { 6 + return supportedAlgorithms 7 + }
+63
object/id/algorithm_tables.go
··· 1 + package objectid 2 + 3 + import ( 4 + "crypto/sha1" 5 + "crypto/sha256" 6 + ) 7 + 8 + //nolint:gochecknoglobals 9 + var algorithmTable = [...]algorithmDetails{ 10 + AlgorithmUnknown: {}, 11 + AlgorithmSHA1: { 12 + name: "sha1", 13 + size: sha1.Size, 14 + packHashID: 1, 15 + sum: func(data []byte) ObjectID { 16 + sum := sha1.Sum(data) //#nosec G401 17 + 18 + var id ObjectID 19 + copy(id.data[:], sum[:]) 20 + id.algo = AlgorithmSHA1 21 + 22 + return id 23 + }, 24 + new: sha1.New, 25 + }, 26 + AlgorithmSHA256: { 27 + name: "sha256", 28 + size: sha256.Size, 29 + packHashID: 2, 30 + sum: func(data []byte) ObjectID { 31 + sum := sha256.Sum256(data) 32 + 33 + var id ObjectID 34 + copy(id.data[:], sum[:]) 35 + id.algo = AlgorithmSHA256 36 + 37 + return id 38 + }, 39 + new: sha256.New, 40 + }, 41 + } 42 + 43 + var ( 44 + //nolint:gochecknoglobals 45 + algorithmByName = map[string]Algorithm{} 46 + //nolint:gochecknoglobals 47 + supportedAlgorithms []Algorithm 48 + ) 49 + 50 + func init() { //nolint:gochecknoinits 51 + emptyTreeInput := []byte("tree 0\x00") 52 + 53 + for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { 54 + info := &algorithmTable[algo] 55 + if info.name == "" { 56 + continue 57 + } 58 + 59 + info.emptyTree = info.sum(emptyTreeInput) 60 + algorithmByName[info.name] = algo 61 + supportedAlgorithms = append(supportedAlgorithms, algo) 62 + } 63 + }
-150
object/id/algorithms.go
··· 1 - package objectid 2 - 3 - import ( 4 - "crypto/sha1" //#nosec gosec 5 - "crypto/sha256" 6 - "hash" 7 - ) 8 - 9 - // maxObjectIDSize MUST be >= the largest supported algorithm size. 10 - const maxObjectIDSize = sha256.Size 11 - 12 - // Algorithm identifies the hash algorithm used for Git object IDs. 13 - type Algorithm uint8 14 - 15 - const ( 16 - AlgorithmUnknown Algorithm = iota 17 - AlgorithmSHA1 18 - AlgorithmSHA256 19 - ) 20 - 21 - type algorithmDetails struct { 22 - name string 23 - size int 24 - packHashID uint32 25 - sum func([]byte) ObjectID 26 - new func() hash.Hash 27 - emptyTree ObjectID 28 - } 29 - 30 - //nolint:gochecknoglobals 31 - var algorithmTable = [...]algorithmDetails{ 32 - AlgorithmUnknown: {}, 33 - AlgorithmSHA1: { 34 - name: "sha1", 35 - size: sha1.Size, 36 - packHashID: 1, 37 - sum: func(data []byte) ObjectID { 38 - sum := sha1.Sum(data) //#nosec G401 39 - 40 - var id ObjectID 41 - copy(id.data[:], sum[:]) 42 - id.algo = AlgorithmSHA1 43 - 44 - return id 45 - }, 46 - new: sha1.New, 47 - }, 48 - AlgorithmSHA256: { 49 - name: "sha256", 50 - size: sha256.Size, 51 - packHashID: 2, 52 - sum: func(data []byte) ObjectID { 53 - sum := sha256.Sum256(data) 54 - 55 - var id ObjectID 56 - copy(id.data[:], sum[:]) 57 - id.algo = AlgorithmSHA256 58 - 59 - return id 60 - }, 61 - new: sha256.New, 62 - }, 63 - } 64 - 65 - var ( 66 - //nolint:gochecknoglobals 67 - algorithmByName = map[string]Algorithm{} 68 - //nolint:gochecknoglobals 69 - supportedAlgorithms []Algorithm 70 - ) 71 - 72 - func init() { //nolint:gochecknoinits 73 - emptyTreeInput := []byte("tree 0\x00") 74 - 75 - for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { 76 - info := &algorithmTable[algo] 77 - if info.name == "" { 78 - continue 79 - } 80 - 81 - info.emptyTree = info.sum(emptyTreeInput) 82 - algorithmByName[info.name] = algo 83 - supportedAlgorithms = append(supportedAlgorithms, algo) 84 - } 85 - } 86 - 87 - // SupportedAlgorithms returns all object ID algorithms supported by furgit. 88 - // Do not mutate. 89 - func SupportedAlgorithms() []Algorithm { 90 - return supportedAlgorithms 91 - } 92 - 93 - // ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256"). 94 - func ParseAlgorithm(s string) (Algorithm, bool) { 95 - algo, ok := algorithmByName[s] 96 - 97 - return algo, ok 98 - } 99 - 100 - // Size returns the hash size in bytes. 101 - func (algo Algorithm) Size() int { 102 - return algo.info().size 103 - } 104 - 105 - // String returns the canonical algorithm name. 106 - func (algo Algorithm) String() string { 107 - inf := algo.info() 108 - if inf.name == "" { 109 - return "unknown" 110 - } 111 - 112 - return inf.name 113 - } 114 - 115 - // HexLen returns the encoded hexadecimal length. 116 - func (algo Algorithm) HexLen() int { 117 - return algo.Size() * 2 118 - } 119 - 120 - // PackHashID returns the Git pack/rev hash-id encoding for this algorithm. 121 - // 122 - // Unknown algorithms return 0. 123 - func (algo Algorithm) PackHashID() uint32 { 124 - return algo.info().packHashID 125 - } 126 - 127 - // Sum computes an object ID from raw data using the selected algorithm. 128 - func (algo Algorithm) Sum(data []byte) ObjectID { 129 - return algo.info().sum(data) 130 - } 131 - 132 - // New returns a new hash.Hash for this algorithm. 133 - func (algo Algorithm) New() (hash.Hash, error) { 134 - newFn := algo.info().new 135 - if newFn == nil { 136 - return nil, ErrInvalidAlgorithm 137 - } 138 - 139 - return newFn(), nil 140 - } 141 - 142 - // EmptyTree returns the object ID of an empty tree ("tree 0\x00") for this 143 - // algorithm. 144 - func (algo Algorithm) EmptyTree() ObjectID { 145 - return algo.info().emptyTree 146 - } 147 - 148 - func (algo Algorithm) info() algorithmDetails { 149 - return algorithmTable[algo] 150 - }
+6
object/id/max_size.go
··· 1 + package objectid 2 + 3 + import "crypto/sha256" 4 + 5 + // maxObjectIDSize MUST be >= the largest supported algorithm size. 6 + const maxObjectIDSize = sha256.Size
+1 -102
object/id/objectid.go
··· 1 1 package objectid 2 2 3 - import ( 4 - //#nosec G505 5 - 6 - "bytes" 7 - "encoding/hex" 8 - "fmt" 9 - ) 3 + //#nosec G505 10 4 11 5 // ObjectID represents a Git object ID. 12 6 // ··· 15 9 algo Algorithm 16 10 data [maxObjectIDSize]byte 17 11 } 18 - 19 - // Algorithm returns the object ID's hash algorithm. 20 - func (id ObjectID) Algorithm() Algorithm { 21 - return id.algo 22 - } 23 - 24 - // Size returns the object ID size in bytes. 25 - func (id ObjectID) Size() int { 26 - return id.algo.Size() 27 - } 28 - 29 - // String returns the canonical hex representation. 30 - func (id ObjectID) String() string { 31 - size := id.Size() 32 - 33 - return hex.EncodeToString(id.data[:size]) 34 - } 35 - 36 - // Bytes returns a copy of the object ID bytes. 37 - func (id ObjectID) Bytes() []byte { 38 - size := id.Size() 39 - 40 - return append([]byte(nil), id.data[:size]...) 41 - } 42 - 43 - // RawBytes returns a direct byte slice view of the object ID bytes. 44 - // 45 - // The returned slice aliases the object ID's internal storage. Callers MUST 46 - // treat it as read-only and MUST NOT modify its contents. 47 - // 48 - // Use Bytes when an independent copy is required. 49 - func (id *ObjectID) RawBytes() []byte { 50 - size := id.Size() 51 - 52 - return id.data[:size:size] 53 - } 54 - 55 - // Compare lexicographically compares two object IDs by their canonical byte 56 - // representation. 57 - func Compare(left, right ObjectID) int { 58 - return bytes.Compare(left.RawBytes(), right.RawBytes()) 59 - } 60 - 61 - // Zero returns the all-zero object ID for the specified algorithm. 62 - func Zero(algo Algorithm) ObjectID { 63 - id, err := FromBytes(algo, make([]byte, algo.Size())) 64 - if err != nil { 65 - panic(err) 66 - } 67 - 68 - return id 69 - } 70 - 71 - // ParseHex parses an object ID from hex for the specified algorithm. 72 - func ParseHex(algo Algorithm, s string) (ObjectID, error) { 73 - var id ObjectID 74 - if algo.Size() == 0 { 75 - return id, ErrInvalidAlgorithm 76 - } 77 - 78 - if len(s)%2 != 0 { 79 - return id, fmt.Errorf("%w: odd hex length %d", ErrInvalidObjectID, len(s)) 80 - } 81 - 82 - if len(s) != algo.HexLen() { 83 - return id, fmt.Errorf("%w: got %d chars, expected %d", ErrInvalidObjectID, len(s), algo.HexLen()) 84 - } 85 - 86 - decoded, err := hex.DecodeString(s) 87 - if err != nil { 88 - return id, fmt.Errorf("%w: decode: %w", ErrInvalidObjectID, err) 89 - } 90 - 91 - copy(id.data[:], decoded) 92 - id.algo = algo 93 - 94 - return id, nil 95 - } 96 - 97 - // FromBytes builds an object ID from raw bytes for the specified algorithm. 98 - func FromBytes(algo Algorithm, b []byte) (ObjectID, error) { 99 - var id ObjectID 100 - if algo.Size() == 0 { 101 - return id, ErrInvalidAlgorithm 102 - } 103 - 104 - if len(b) != algo.Size() { 105 - return id, fmt.Errorf("%w: got %d bytes, expected %d", ErrInvalidObjectID, len(b), algo.Size()) 106 - } 107 - 108 - copy(id.data[:], b) 109 - id.algo = algo 110 - 111 - return id, nil 112 - }
+6
object/id/objectid_algorithm.go
··· 1 + package objectid 2 + 3 + // Algorithm returns the object ID's hash algorithm. 4 + func (id ObjectID) Algorithm() Algorithm { 5 + return id.algo 6 + }
+20
object/id/objectid_byte.go
··· 1 + package objectid 2 + 3 + // Bytes returns a copy of the object ID bytes. 4 + func (id ObjectID) Bytes() []byte { 5 + size := id.Algorithm().Size() 6 + 7 + return append([]byte(nil), id.data[:size]...) 8 + } 9 + 10 + // RawBytes returns a direct byte slice view of the object ID bytes. 11 + // 12 + // The returned slice aliases the object ID's internal storage. Callers MUST 13 + // treat it as read-only and MUST NOT modify its contents. 14 + // 15 + // Use Bytes when an independent copy is required. 16 + func (id *ObjectID) RawBytes() []byte { 17 + size := id.Algorithm().Size() 18 + 19 + return id.data[:size:size] 20 + }
+9
object/id/objectid_compare.go
··· 1 + package objectid 2 + 3 + import "bytes" 4 + 5 + // Compare lexicographically compares two object IDs by their canonical byte 6 + // representation. 7 + func Compare(left, right ObjectID) int { 8 + return bytes.Compare(left.RawBytes(), right.RawBytes()) 9 + }
+20
object/id/objectid_frombytes.go
··· 1 + package objectid 2 + 3 + import "fmt" 4 + 5 + // FromBytes builds an object ID from raw bytes for the specified algorithm. 6 + func FromBytes(algo Algorithm, b []byte) (ObjectID, error) { 7 + var id ObjectID 8 + if algo.Size() == 0 { 9 + return id, ErrInvalidAlgorithm 10 + } 11 + 12 + if len(b) != algo.Size() { 13 + return id, fmt.Errorf("%w: got %d bytes, expected %d", ErrInvalidObjectID, len(b), algo.Size()) 14 + } 15 + 16 + copy(id.data[:], b) 17 + id.algo = algo 18 + 19 + return id, nil 20 + }
+32
object/id/objectid_parse.go
··· 1 + package objectid 2 + 3 + import ( 4 + "encoding/hex" 5 + "fmt" 6 + ) 7 + 8 + // ParseHex parses an object ID from hex for the specified algorithm. 9 + func ParseHex(algo Algorithm, s string) (ObjectID, error) { 10 + var id ObjectID 11 + if algo.Size() == 0 { 12 + return id, ErrInvalidAlgorithm 13 + } 14 + 15 + if len(s)%2 != 0 { 16 + return id, fmt.Errorf("%w: odd hex length %d", ErrInvalidObjectID, len(s)) 17 + } 18 + 19 + if len(s) != algo.HexLen() { 20 + return id, fmt.Errorf("%w: got %d chars, expected %d", ErrInvalidObjectID, len(s), algo.HexLen()) 21 + } 22 + 23 + decoded, err := hex.DecodeString(s) 24 + if err != nil { 25 + return id, fmt.Errorf("%w: decode: %w", ErrInvalidObjectID, err) 26 + } 27 + 28 + copy(id.data[:], decoded) 29 + id.algo = algo 30 + 31 + return id, nil 32 + }
+10
object/id/objectid_string.go
··· 1 + package objectid 2 + 3 + import "encoding/hex" 4 + 5 + // String returns the canonical hex representation. 6 + func (id ObjectID) String() string { 7 + size := id.Algorithm().Size() 8 + 9 + return hex.EncodeToString(id.data[:size]) 10 + }
+5 -5
object/id/objectid_test.go
··· 44 44 t.Fatalf("String() = %q, want %q", got, hex) 45 45 } 46 46 47 - if got := id.Size(); got != algo.Size() { 47 + if got := id.Algorithm().Size(); got != algo.Size() { 48 48 t.Fatalf("Size() = %d, want %d", got, algo.Size()) 49 49 } 50 50 ··· 148 148 } 149 149 150 150 b := id.RawBytes() 151 - if len(b) != id.Size() { 152 - t.Fatalf("RawBytes len = %d, want %d", len(b), id.Size()) 151 + if len(b) != id.Algorithm().Size() { 152 + t.Fatalf("RawBytes len = %d, want %d", len(b), id.Algorithm().Size()) 153 153 } 154 154 155 155 if cap(b) != len(b) { ··· 169 169 t.Parallel() 170 170 171 171 id1 := objectid.AlgorithmSHA1.Sum([]byte("hello")) 172 - if id1.Algorithm() != objectid.AlgorithmSHA1 || id1.Size() != objectid.AlgorithmSHA1.Size() { 172 + if id1.Algorithm() != objectid.AlgorithmSHA1 || id1.Algorithm().Size() != objectid.AlgorithmSHA1.Size() { 173 173 t.Fatalf("sha1 sum produced invalid object id") 174 174 } 175 175 176 176 id2 := objectid.AlgorithmSHA256.Sum([]byte("hello")) 177 - if id2.Algorithm() != objectid.AlgorithmSHA256 || id2.Size() != objectid.AlgorithmSHA256.Size() { 177 + if id2.Algorithm() != objectid.AlgorithmSHA256 || id2.Algorithm().Size() != objectid.AlgorithmSHA256.Size() { 178 178 t.Fatalf("sha256 sum produced invalid object id") 179 179 } 180 180
+11
object/id/objectid_zero.go
··· 1 + package objectid 2 + 3 + // Zero returns the all-zero object ID for the specified algorithm. 4 + func Zero(algo Algorithm) ObjectID { 5 + id, err := FromBytes(algo, make([]byte, algo.Size())) 6 + if err != nil { 7 + panic(err) 8 + } 9 + 10 + return id 11 + }
+1 -1
object/tag/serialize.go
··· 11 11 12 12 // SerializeWithoutHeader renders the raw tag body bytes. 13 13 func (tag *Tag) SerializeWithoutHeader() ([]byte, error) { 14 - if tag.Target.Size() == 0 { 14 + if tag.Target.Algorithm().Size() == 0 { 15 15 return nil, errors.New("object: tag: missing target id") 16 16 } 17 17
+1 -1
object/tree/serialize.go
··· 14 14 15 15 for _, entry := range tree.Entries { 16 16 mode := strconv.FormatUint(uint64(entry.Mode), 8) 17 - bodyLen += len(mode) + 1 + len(entry.Name) + 1 + entry.ID.Size() 17 + bodyLen += len(mode) + 1 + len(entry.Name) + 1 + entry.ID.Algorithm().Size() 18 18 } 19 19 20 20 body := make([]byte, bodyLen)
+1 -1
ref/store/files/resolve_list_test.go
··· 236 236 t.Fatalf("Resolve(tag) type = %T, want ref.Detached", tagRef) 237 237 } 238 238 239 - if tagDet.ID.Size() == 0 { 239 + if tagDet.ID.Algorithm().Size() == 0 { 240 240 t.Fatal("Resolve(tag) returned zero object id") 241 241 } 242 242 })
+2 -2
ref/store/files/update_validate.go
··· 21 21 return wrapUpdateError(op.name, &refstore.InvalidNameError{Err: err}) 22 22 } 23 23 24 - if op.newID.Size() == 0 { 24 + if op.newID.Algorithm().Size() == 0 { 25 25 return wrapUpdateError(op.name, &refstore.InvalidValueError{Err: objectid.ErrInvalidAlgorithm}) 26 26 } 27 27 case updateDelete, updateVerify: ··· 30 30 return wrapUpdateError(op.name, &refstore.InvalidNameError{Err: err}) 31 31 } 32 32 33 - if op.oldID.Size() == 0 { 33 + if op.oldID.Algorithm().Size() == 0 { 34 34 return wrapUpdateError(op.name, &refstore.InvalidValueError{Err: objectid.ErrInvalidAlgorithm}) 35 35 } 36 36 case updateCreateSymbolic, updateReplaceSymbolic: