1package git23import (4 "encoding/hex"5 "errors"6 "strings"7 "sync"8)910const (11 // EmptySha1ID is an ID with empty SHA-1 hash.12 EmptySha1ID = "0000000000000000000000000000000000000000"13 // EmptySha256ID is an ID with empty SHA-256 hash.14 EmptySha256ID = "0000000000000000000000000000000000000000000000000000000000000000"15)1617// Oid is the id of a Git object18type Oid interface {19 Equal(interface{}) bool20 String() string21 Bytes() []byte22}2324// SHA1 is the SHA-1 hash of a Git object.25type SHA1 struct {26 bytes [20]byte2728 str string29 strOnce sync.Once30}3132// Equal returns true if s2 has the same SHA1 as s. It supports33// 40-length-string, []byte, and SHA1.34func (s *SHA1) Equal(s2 interface{}) bool {35 switch v := s2.(type) {36 case string:37 return v == s.String()38 case [20]byte:39 return v == s.bytes40 case *SHA1:41 return v.bytes == s.bytes42 }43 return false44}4546// String returns string (hex) representation of the SHA1.47func (s *SHA1) String() string {48 s.strOnce.Do(func() {49 result := make([]byte, 0, 40)50 hexvalues := []byte("0123456789abcdef")51 for i := 0; i < 20; i++ {52 result = append(result, hexvalues[s.bytes[i]>>4])53 result = append(result, hexvalues[s.bytes[i]&0xf])54 }55 s.str = string(result)56 })57 return s.str58}5960// Bytes returns bytes (length 20) representation of the SHA1.61func (s *SHA1) Bytes() []byte {62 return s.bytes[:]63}6465// SHA256 is the SHA-256 hash of a Git object.66type SHA256 struct {67 bytes [32]byte6869 str string70 strOnce sync.Once71}7273// Equal returns true if s2 has the same SHA256 as s. It supports74// 64-length-string, []byte, and SHA256.75func (s *SHA256) Equal(s2 interface{}) bool {76 switch v := s2.(type) {77 case string:78 return v == s.String()79 case [32]byte:80 return v == s.bytes81 case *SHA256:82 return v.bytes == s.bytes83 }84 return false8586}8788// String returns string (hex) representation of the SHA256.89func (s *SHA256) String() string {90 s.strOnce.Do(func() {91 result := make([]byte, 0, 64)92 hexvalues := []byte("0123456789abcdef")93 for i := 0; i < 32; i++ {94 result = append(result, hexvalues[s.bytes[i]>>4])95 result = append(result, hexvalues[s.bytes[i]&0xf])96 }97 s.str = string(result)98 })99 return s.str100}101102// Bytes returns bytes (length 32) representation of the SHA256.103func (s *SHA256) Bytes() []byte {104 return s.bytes[:]105}106107// MustID always returns a new Oid from a [20]byte or [32]byte array with no validation of input.108func MustID(b []byte) Oid {109 if len(b) < 32 {110 var id SHA1111 for i := 0; i < 20; i++ {112 id.bytes[i] = b[i]113 }114 return &id115 } else {116 var id SHA256117 for i := 0; i < 32; i++ {118 id.bytes[i] = b[i]119 }120 return &id121 }122}123124// NewID returns a new Oid from a [20]byte or [32]byte array.125func NewID(b []byte) (Oid, error) {126 if len(b) != 20 && len(b) != 32 {127 return nil, errors.New("length must be 20 or 32")128 }129 return MustID(b), nil130}131132// MustIDFromString always returns a new sha from a ID with no validation of133// input.134func MustIDFromString(s string) Oid {135 b, _ := hex.DecodeString(s)136 return MustID(b)137}138139// NewIDFromString returns a new Oid from a ID string of length 40 or 64.140func NewIDFromString(s string) (Oid, error) {141 s = strings.TrimSpace(s)142 if len(s) != 40 && len(s) != 64 {143 return nil, errors.New("length must be 40 or 64")144 }145 b, err := hex.DecodeString(s)146 if err != nil {147 return nil, err148 }149 return NewID(b)150}