git-module

fork of https://git.lin.moe/gogs/git-module

git clone git://git.lin.moe/fork/git-module.git

  1package git
  2
  3import (
  4	"encoding/hex"
  5	"errors"
  6	"strings"
  7	"sync"
  8)
  9
 10const (
 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)
 16
 17// Oid is the id of a Git object
 18type Oid interface {
 19	Equal(interface{}) bool
 20	String() string
 21	Bytes() []byte
 22}
 23
 24// SHA1 is the SHA-1 hash of a Git object.
 25type SHA1 struct {
 26	bytes [20]byte
 27
 28	str     string
 29	strOnce sync.Once
 30}
 31
 32// Equal returns true if s2 has the same SHA1 as s. It supports
 33// 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.bytes
 40	case *SHA1:
 41		return v.bytes == s.bytes
 42	}
 43	return false
 44}
 45
 46// 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.str
 58}
 59
 60// Bytes returns bytes (length 20) representation of the SHA1.
 61func (s *SHA1) Bytes() []byte {
 62	return s.bytes[:]
 63}
 64
 65// SHA256 is the SHA-256 hash of a Git object.
 66type SHA256 struct {
 67	bytes [32]byte
 68
 69	str     string
 70	strOnce sync.Once
 71}
 72
 73// Equal returns true if s2 has the same SHA256 as s. It supports
 74// 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.bytes
 81	case *SHA256:
 82		return v.bytes == s.bytes
 83	}
 84	return false
 85
 86}
 87
 88// 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.str
100}
101
102// Bytes returns bytes (length 32) representation of the SHA256.
103func (s *SHA256) Bytes() []byte {
104	return s.bytes[:]
105}
106
107// 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 SHA1
111		for i := 0; i < 20; i++ {
112			id.bytes[i] = b[i]
113		}
114		return &id
115	} else {
116		var id SHA256
117		for i := 0; i < 32; i++ {
118			id.bytes[i] = b[i]
119		}
120		return &id
121	}
122}
123
124// 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), nil
130}
131
132// MustIDFromString always returns a new sha from a ID with no validation of
133// input.
134func MustIDFromString(s string) Oid {
135	b, _ := hex.DecodeString(s)
136	return MustID(b)
137}
138
139// 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, err
148	}
149	return NewID(b)
150}