Skip to content

Commit

Permalink
Introduced sha256 support for git-sizer
Browse files Browse the repository at this point in the history
  • Loading branch information
fcharlie committed Apr 17, 2023
1 parent 0b6d3a2 commit e8687bb
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 54 deletions.
23 changes: 20 additions & 3 deletions git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type Repository struct {

// gitBin is the path of the `git` executable that should be used
// when running commands in this repository.
gitBin string
gitBin string
hashAlgo HashAlgo
}

// smartJoin returns the path that can be described as `relPath`
Expand Down Expand Up @@ -77,10 +78,18 @@ func NewRepository(path string) (*Repository, error) {
if err == nil {
return nil, errors.New("this appears to be a shallow clone; full clone required")
}
hashAlgo := HashSHA1
cmd = exec.Command(gitBin, "rev-parse", "--show-object-format")
if out, err = cmd.Output(); err == nil {
if string(bytes.TrimSpace(out)) == "sha256" {
hashAlgo = HashSHA256
}
}

return &Repository{
path: gitDir,
gitBin: gitBin,
path: gitDir,
gitBin: gitBin,
hashAlgo: hashAlgo,
}, nil
}

Expand Down Expand Up @@ -115,3 +124,11 @@ func (repo *Repository) GitCommand(callerArgs ...string) *exec.Cmd {
func (repo *Repository) Path() string {
return repo.path
}

func (repo *Repository) HashAlgo() HashAlgo {
return repo.hashAlgo
}

func (repo *Repository) HashSize() int {
return repo.hashAlgo.HashSize()
}
6 changes: 3 additions & 3 deletions git/obj_iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (repo *Repository) NewObjectIter(ctx context.Context) (*ObjectIter, error)
errCh: make(chan error),
headerCh: make(chan BatchHeader),
}

hashSize := repo.HashSize()
iter.p.Add(
// Read OIDs from `iter.oidCh` and write them to `git
// rev-list`:
Expand Down Expand Up @@ -68,10 +68,10 @@ func (repo *Repository) NewObjectIter(ctx context.Context) (*ObjectIter, error)
pipe.LinewiseFunction(
"copy-oids",
func(_ context.Context, _ pipe.Env, line []byte, stdout *bufio.Writer) error {
if len(line) < 40 {
if len(line) < hashSize {
return fmt.Errorf("line too short: '%s'", line)
}
if _, err := stdout.Write(line[:40]); err != nil {
if _, err := stdout.Write(line[:hashSize]); err != nil {
return fmt.Errorf("writing OID to 'git cat-file': %w", err)
}
if err := stdout.WriteByte('\n'); err != nil {
Expand Down
62 changes: 53 additions & 9 deletions git/oid.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,75 @@
package git

import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"errors"
)

const (
HashSizeSHA256 = sha256.Size
HashSizeSHA1 = sha1.Size
HashSizeMax = HashSizeSHA256
)

type HashAlgo int

const (
HashUnknown HashAlgo = iota
HashSHA1
HashSHA256
)

// OID represents the SHA-1 object ID of a Git object, in binary
// format.
type OID struct {
v [20]byte
v [HashSizeMax]byte
hashSize int
}

// NullOID is the null object ID; i.e., all zeros.
var NullOID OID
func (h HashAlgo) NullOID() OID {
switch h {
case HashSHA1:
return OID{hashSize: HashSizeSHA1}
case HashSHA256:
return OID{hashSize: HashSizeSHA256}
}
return OID{}
}

func (h HashAlgo) HashSize() int {
switch h {
case HashSHA1:
return HashSizeSHA1
case HashSHA256:
return HashSizeSHA256
}
return 0
}

// defaultNullOID is the null object ID; i.e., all zeros.
var defaultNullOID OID

func IsNullOID(o OID) bool {
return bytes.Equal(o.v[:], defaultNullOID.v[:])
}

// OIDFromBytes converts a byte slice containing an object ID in
// binary format into an `OID`.
func OIDFromBytes(oidBytes []byte) (OID, error) {
var oid OID
if len(oidBytes) != len(oid.v) {
oidSize := len(oidBytes)
if oidSize != HashSizeSHA1 && oidSize != HashSizeSHA256 {
return OID{}, errors.New("bytes oid has the wrong length")
}
copy(oid.v[0:20], oidBytes)
oid.hashSize = oidSize
copy(oid.v[0:oidSize], oidBytes)
return oid, nil
}

// NewOID converts an object ID in hex format (i.e., `[0-9a-f]{40}`)
// NewOID converts an object ID in hex format (i.e., `[0-9a-f]{40,32}`)
// into an `OID`.
func NewOID(s string) (OID, error) {
oidBytes, err := hex.DecodeString(s)
Expand All @@ -37,18 +81,18 @@ func NewOID(s string) (OID, error) {

// String formats `oid` as a string in hex format.
func (oid OID) String() string {
return hex.EncodeToString(oid.v[:])
return hex.EncodeToString(oid.v[:oid.hashSize])
}

// Bytes returns a byte slice view of `oid`, in binary format.
func (oid OID) Bytes() []byte {
return oid.v[:]
return oid.v[:oid.hashSize]
}

// MarshalJSON expresses `oid` as a JSON string with its enclosing
// quotation marks.
func (oid OID) MarshalJSON() ([]byte, error) {
src := oid.v[:]
src := oid.v[:oid.hashSize]
dst := make([]byte, hex.EncodedLen(len(src))+2)
dst[0] = '"'
dst[len(dst)-1] = '"'
Expand Down
18 changes: 9 additions & 9 deletions git/ref_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ func (f intersection) Filter(refname string) bool {
// If `f1` is `nil`, it is treated as including nothing.
type include struct{}

func (_ include) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
func (include) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
if f1 == nil {
return f2
}
return union{f1, f2}
}

func (_ include) Inverted() Combiner {
func (include) Inverted() Combiner {
return Exclude
}

Expand All @@ -61,23 +61,23 @@ func (f union) Filter(refname string) bool {
// If `f1` is `nil`, it is treated as including everything.
type exclude struct{}

func (_ exclude) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
func (exclude) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
if f1 == nil {
return inverse{f2}
}
return intersection{f1, inverse{f2}}

}

func (_ exclude) Inverted() Combiner {
func (exclude) Inverted() Combiner {
return include{}
}

var Exclude exclude

type allReferencesFilter struct{}

func (_ allReferencesFilter) Filter(_ string) bool {
func (allReferencesFilter) Filter(_ string) bool {
return true
}

Expand All @@ -87,11 +87,11 @@ var AllReferencesFilter allReferencesFilter
// whose names start with the specified `prefix`, which must match at
// a component boundary. For example,
//
// * Prefix "refs/foo" matches "refs/foo" and "refs/foo/bar" but not
// "refs/foobar".
// - Prefix "refs/foo" matches "refs/foo" and "refs/foo/bar" but not
// "refs/foobar".
//
// * Prefix "refs/foo/" matches "refs/foo/bar" but not "refs/foo" or
// "refs/foobar".
// - Prefix "refs/foo/" matches "refs/foo/bar" but not "refs/foo" or
// "refs/foobar".
func PrefixFilter(prefix string) ReferenceFilter {
if prefix == "" {
return AllReferencesFilter
Expand Down
19 changes: 11 additions & 8 deletions git/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import (

// Tree represents a Git tree object.
type Tree struct {
data string
data string
hashSize int
}

// ParseTree parses the tree object whose contents are contained in
// `data`. `oid` is currently unused.
func ParseTree(oid OID, data []byte) (*Tree, error) {
return &Tree{string(data)}, nil
return &Tree{string(data), oid.hashSize}, nil
}

// Size returns the size of the tree object.
Expand All @@ -36,13 +37,15 @@ type TreeEntry struct {
// TreeIter is an iterator over the entries in a Git tree object.
type TreeIter struct {
// The as-yet-unread part of the tree's data.
data string
data string
hashSize int
}

// Iter returns an iterator over the entries in `tree`.
func (tree *Tree) Iter() *TreeIter {
return &TreeIter{
data: tree.data,
data: tree.data,
hashSize: tree.hashSize,
}
}

Expand Down Expand Up @@ -74,12 +77,12 @@ func (iter *TreeIter) NextEntry() (TreeEntry, bool, error) {
entry.Name = iter.data[:nulAt]

iter.data = iter.data[nulAt+1:]
if len(iter.data) < 20 {
if len(iter.data) < iter.hashSize {
return TreeEntry{}, false, errors.New("tree entry ends unexpectedly")
}

copy(entry.OID.v[0:20], iter.data[0:20])
iter.data = iter.data[20:]
entry.OID.hashSize = iter.hashSize
copy(entry.OID.v[0:iter.hashSize], iter.data[0:iter.hashSize])
iter.data = iter.data[iter.hashSize:]

return entry, true, nil
}
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ module github.com/github/git-sizer
go 1.17

require (
github.com/cli/safeexec v1.0.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/cli/safeexec v1.0.1
github.com/github/go-pipe v1.0.2
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.1
golang.org/x/sync v0.1.0 // indirect
github.com/stretchr/testify v1.8.2
)

require github.com/github/go-pipe v1.0.2

require (
github.com/kr/pretty v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
golang.org/x/sync v0.1.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
17 changes: 12 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00=
github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/github/go-pipe v1.0.2 h1:befTXflsc6ir/h9f6Q7QCDmfojoBswD1MfQrPhmmSoA=
github.com/github/go-pipe v1.0.2/go.mod h1:/GvNLA516QlfGGMtfv4PC/5/CdzL9X4af/AJYhmLD54=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
Expand Down Expand Up @@ -54,8 +60,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2 changes: 1 addition & 1 deletion internal/testutils/repoutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (repo *TestRepo) UpdateRef(t *testing.T, refname string, oid git.OID) {

var cmd *exec.Cmd

if oid == git.NullOID {
if git.IsNullOID(oid) {
cmd = repo.GitCommand(t, "update-ref", "-d", refname)
} else {
cmd = repo.GitCommand(t, "update-ref", refname, oid.String())
Expand Down
4 changes: 2 additions & 2 deletions sizes/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func ScanRepositoryUsingGraph(
) (HistorySize, error) {
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()

nullOID := repo.HashAlgo().NullOID()
graph := NewGraph(rg, nameStyle)

refIter, err := repo.NewReferenceIter(ctx)
Expand Down Expand Up @@ -190,7 +190,7 @@ func ScanRepositoryUsingGraph(
case "tree":
trees = append(trees, ObjectHeader{obj.OID, obj.ObjectSize})
case "commit":
commits = append(commits, CommitHeader{ObjectHeader{obj.OID, obj.ObjectSize}, git.NullOID})
commits = append(commits, CommitHeader{ObjectHeader{obj.OID, obj.ObjectSize}, nullOID})
case "tag":
tags = append(tags, ObjectHeader{obj.OID, obj.ObjectSize})
default:
Expand Down
Loading

0 comments on commit e8687bb

Please sign in to comment.