aboutsummaryrefslogtreecommitdiff
path: root/object
diff options
context:
space:
mode:
Diffstat (limited to 'object')
-rw-r--r--object/id/algorithm.go8
-rw-r--r--object/id/algorithm_details.go68
-rw-r--r--object/id/algorithm_ops.go60
-rw-r--r--object/id/algorithm_parse.go8
-rw-r--r--object/id/errors.go12
-rw-r--r--object/id/object_id.go9
6 files changed, 164 insertions, 1 deletions
diff --git a/object/id/algorithm.go b/object/id/algorithm.go
index 47a1b02a..1b02cbc4 100644
--- a/object/id/algorithm.go
+++ b/object/id/algorithm.go
@@ -5,7 +5,7 @@ type Algorithm uint8
const (
// AlgorithmUnknown identifies an unknown object ID hash algorithm.
- AlgorithmUknown Algorithm = iota
+ AlgorithmUnknown Algorithm = iota
// AlgorithmSHA1 identifies the SHA-1 object ID hash algorithm.
// This is the default for all versions of Git until Git 3.0.
@@ -15,3 +15,9 @@ const (
// This is the default for Git 3.0 and beyond.
AlgorithmSHA256
)
+
+// SupportedAlgorithms returns all object ID algorithms supported by furgit.
+// Labels: Mut-No.
+func SupportedAlgorithms() []Algorithm {
+ return supportedAlgorithms
+}
diff --git a/object/id/algorithm_details.go b/object/id/algorithm_details.go
new file mode 100644
index 00000000..d3fd665d
--- /dev/null
+++ b/object/id/algorithm_details.go
@@ -0,0 +1,68 @@
+package id
+
+import (
+ "crypto/sha1" //#nosec:G505
+ "crypto/sha256"
+ "hash"
+)
+
+type algorithmDetails struct {
+ name string
+ size int
+ packHashID uint32
+ signatureHeaderName string
+ sum func([]byte) ObjectID
+ new func() hash.Hash
+ emptyTree ObjectID
+}
+
+func (algo Algorithm) info() algorithmDetails {
+ return algorithmTable[algo]
+}
+
+//nolint:gochecknoglobals
+var algorithmTable = [...]algorithmDetails{
+ AlgorithmUnknown: {},
+ AlgorithmSHA1: {
+ name: "sha1",
+ size: sha1.Size,
+ packHashID: 1,
+ signatureHeaderName: "gpgsig",
+ new: sha1.New,
+ },
+ AlgorithmSHA256: {
+ name: "sha256",
+ size: sha256.Size,
+ packHashID: 2,
+ signatureHeaderName: "gpgsig-sha256",
+ new: sha256.New,
+ },
+}
+
+// maxObjectIDSize MUST be >= the largest supported algorithm size.
+const maxObjectIDSize = sha256.Size
+
+var (
+ //nolint:gochecknoglobals
+ algorithmByName = map[string]Algorithm{}
+ //nolint:gochecknoglobals
+ algorithmBySignatureHeaderName = map[string]Algorithm{}
+ //nolint:gochecknoglobals
+ supportedAlgorithms []Algorithm
+)
+
+func init() { //nolint:gochecknoinits
+ // Skip over AlgorithmUnknown.
+ for algo := Algorithm(1); int(algo) < len(algorithmTable); algo++ {
+ info := &algorithmTable[algo]
+
+ info.emptyTree = info.sum([]byte("tree 0\x00"))
+
+ algorithmByName[info.name] = algo
+ if info.signatureHeaderName != "" {
+ algorithmBySignatureHeaderName[info.signatureHeaderName] = algo
+ }
+
+ supportedAlgorithms = append(supportedAlgorithms, algo)
+ }
+}
diff --git a/object/id/algorithm_ops.go b/object/id/algorithm_ops.go
new file mode 100644
index 00000000..b746dc5f
--- /dev/null
+++ b/object/id/algorithm_ops.go
@@ -0,0 +1,60 @@
+package id
+
+import "hash"
+
+// EmptyTree returns the object ID of
+// an empty tree ("tree 0\x00")
+// for this algorithm.
+func (algo Algorithm) EmptyTree() ObjectID {
+ return algo.info().emptyTree
+}
+
+// HexLen returns the encoded hexadecimal length.
+func (algo Algorithm) HexLen() int {
+ return algo.Size() * 2
+}
+
+// Size returns the hash size in bytes.
+func (algo Algorithm) Size() int {
+ return algo.info().size
+}
+
+// New returns a new hash.Hash for this algorithm.
+func (algo Algorithm) New() (hash.Hash, error) {
+ newFn := algo.info().new
+ if newFn == nil {
+ return nil, ErrInvalidAlgorithm
+ }
+
+ return newFn(), nil
+}
+
+// PackHashID returns the Git pack/rev hash-id encoding for this algorithm.
+//
+// Unknown algorithms return 0.
+func (algo Algorithm) PackHashID() uint32 {
+ return algo.info().packHashID
+}
+
+// SignatureHeaderName returns the signature header name for this algorithm.
+func (algo Algorithm) SignatureHeaderName() string {
+ return algo.info().signatureHeaderName
+}
+
+// String returns the canonical algorithm name.
+func (algo Algorithm) String() string {
+ return algo.info().name
+}
+
+// Sum computes an object ID from raw data using the selected algorithm.
+func (algo Algorithm) Sum(data []byte) ObjectID {
+ return algo.info().sum(data)
+}
+
+// Zero returns the all-zero object ID for this algorithm.
+func (algo Algorithm) Zero() ObjectID {
+ return ObjectID{
+ algo: algo,
+ data: [maxObjectIDSize]byte{},
+ }
+}
diff --git a/object/id/algorithm_parse.go b/object/id/algorithm_parse.go
new file mode 100644
index 00000000..7349288f
--- /dev/null
+++ b/object/id/algorithm_parse.go
@@ -0,0 +1,8 @@
+package id
+
+// ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256").
+func ParseAlgorithm(s string) (Algorithm, bool) {
+ algo, ok := algorithmByName[s]
+
+ return algo, ok
+}
diff --git a/object/id/errors.go b/object/id/errors.go
new file mode 100644
index 00000000..11c471ed
--- /dev/null
+++ b/object/id/errors.go
@@ -0,0 +1,12 @@
+package id
+
+import "errors"
+
+var (
+ // ErrInvalidAlgorithm indicates an unsupported object ID algorithm.
+ ErrInvalidAlgorithm = errors.New("objectid: invalid algorithm")
+
+ // ErrInvalidObjectID indicates malformed object ID data.
+ // ErrInvalidObjectID = errors.New("objectid: invalid object id")
+ // TODO
+)
diff --git a/object/id/object_id.go b/object/id/object_id.go
new file mode 100644
index 00000000..4cf562fa
--- /dev/null
+++ b/object/id/object_id.go
@@ -0,0 +1,9 @@
+package id
+
+// ObjectID represents a Git object ID.
+//
+//nolint:recvcheck
+type ObjectID struct {
+ algo Algorithm
+ data [maxObjectIDSize]byte
+}