Skip to content

Commit 817c3a6

Browse files
committed
Abstract hash function usage (go-gitea#28138)
Refactor Hash interfaces and centralize hash function. This will allow easier introduction of different hash function later on. This forms the "no-op" part of the SHA256 enablement patch.
1 parent f492385 commit 817c3a6

File tree

122 files changed

+946
-592
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+946
-592
lines changed

cmd/hook.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ Gitea or set your environment appropriately.`, "")
376376
oldCommitIDs[count] = string(fields[0])
377377
newCommitIDs[count] = string(fields[1])
378378
refFullNames[count] = git.RefName(fields[2])
379-
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
379+
380+
commitID, _ := git.IDFromString(newCommitIDs[count])
381+
if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total {
380382
masterPushed = true
381383
}
382384
count++
@@ -669,7 +671,8 @@ Gitea or set your environment appropriately.`, "")
669671
if err != nil {
670672
return err
671673
}
672-
if rs.OldOID != git.EmptySHA {
674+
commitID, _ := git.IDFromString(rs.OldOID)
675+
if !commitID.IsZero() {
673676
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
674677
if err != nil {
675678
return err

models/git/branch_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestAddDeletedBranch(t *testing.T) {
3131
assert.True(t, secondBranch.IsDeleted)
3232

3333
commit := &git.Commit{
34-
ID: git.MustIDFromString(secondBranch.CommitID),
34+
ID: repo.ObjectFormat.MustIDFromString(secondBranch.CommitID),
3535
CommitMessage: secondBranch.CommitMessage,
3636
Committer: &git.Signature{
3737
When: secondBranch.CommitTime.AsLocalTime(),

models/git/commit_status.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ WHEN NOT MATCHED
113113

114114
// GetNextCommitStatusIndex retried 3 times to generate a resource index
115115
func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) {
116-
if !git.IsValidSHAPattern(sha) {
116+
_, err := git.IDFromString(sha)
117+
if err != nil {
117118
return 0, git.ErrInvalidSHA{SHA: sha}
118119
}
119120

@@ -420,7 +421,7 @@ func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, befor
420421
type NewCommitStatusOptions struct {
421422
Repo *repo_model.Repository
422423
Creator *user_model.User
423-
SHA string
424+
SHA git.ObjectID
424425
CommitStatus *CommitStatus
425426
}
426427

@@ -435,26 +436,22 @@ func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error {
435436
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
436437
}
437438

438-
if _, err := git.NewIDFromString(opts.SHA); err != nil {
439-
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
440-
}
441-
442439
ctx, committer, err := db.TxContext(ctx)
443440
if err != nil {
444441
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
445442
}
446443
defer committer.Close()
447444

448445
// Get the next Status Index
449-
idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA)
446+
idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA.String())
450447
if err != nil {
451448
return fmt.Errorf("generate commit status index failed: %w", err)
452449
}
453450

454451
opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
455452
opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
456453
opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
457-
opts.CommitStatus.SHA = opts.SHA
454+
opts.CommitStatus.SHA = opts.SHA.String()
458455
opts.CommitStatus.CreatorID = opts.Creator.ID
459456
opts.CommitStatus.RepoID = opts.Repo.ID
460457
opts.CommitStatus.Index = idx

models/repo/repo.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"code.gitea.io/gitea/models/unit"
1818
user_model "code.gitea.io/gitea/models/user"
1919
"code.gitea.io/gitea/modules/base"
20+
"code.gitea.io/gitea/modules/git"
2021
"code.gitea.io/gitea/modules/log"
2122
"code.gitea.io/gitea/modules/markup"
2223
"code.gitea.io/gitea/modules/setting"
@@ -179,6 +180,7 @@ type Repository struct {
179180
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
180181
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
181182
Topics []string `xorm:"TEXT JSON"`
183+
ObjectFormat git.ObjectFormat `xorm:"-"`
182184

183185
TrustModel TrustModelType
184186

@@ -274,6 +276,8 @@ func (repo *Repository) AfterLoad() {
274276
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
275277
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
276278
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
279+
280+
repo.ObjectFormat = git.ObjectFormatFromID(git.Sha1)
277281
}
278282

279283
// LoadAttributes loads attributes of the repository.
@@ -313,7 +317,7 @@ func (repo *Repository) HTMLURL() string {
313317
// CommitLink make link to by commit full ID
314318
// note: won't check whether it's an right id
315319
func (repo *Repository) CommitLink(commitID string) (result string) {
316-
if commitID == "" || commitID == "0000000000000000000000000000000000000000" {
320+
if git.IsEmptyCommitID(commitID) {
317321
result = ""
318322
} else {
319323
result = repo.Link() + "/commit/" + url.PathEscape(commitID)

modules/context/api.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ func RepoRefForAPI(next http.Handler) http.Handler {
302302
return
303303
}
304304

305+
objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat()
306+
if err != nil {
307+
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
308+
return
309+
}
310+
305311
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
306312
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
307313
if err != nil {
@@ -319,7 +325,6 @@ func RepoRefForAPI(next http.Handler) http.Handler {
319325
return
320326
}
321327

322-
var err error
323328
refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
324329

325330
if ctx.Repo.GitRepo.IsBranchExist(refName) {
@@ -336,7 +341,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
336341
return
337342
}
338343
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
339-
} else if len(refName) == git.SHAFullLength {
344+
} else if len(refName) == objectFormat.FullLength() {
340345
ctx.Repo.CommitID = refName
341346
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
342347
if err != nil {

modules/context/repo.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
824824
}
825825
// For legacy and API support only full commit sha
826826
parts := strings.Split(path, "/")
827-
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
827+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
828+
829+
if len(parts) > 0 && len(parts[0]) == objectFormat.FullLength() {
828830
repo.TreePath = strings.Join(parts[1:], "/")
829831
return parts[0]
830832
}
@@ -868,7 +870,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
868870
return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
869871
case RepoRefCommit:
870872
parts := strings.Split(path, "/")
871-
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
873+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
874+
875+
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= objectFormat.FullLength() {
872876
repo.TreePath = strings.Join(parts[1:], "/")
873877
return parts[0]
874878
}
@@ -928,6 +932,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
928932
}
929933
}
930934

935+
objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat()
936+
if err != nil {
937+
log.Error("Cannot determine objectFormat for repository: %w", err)
938+
ctx.Repo.Repository.MarkAsBrokenEmpty()
939+
}
940+
931941
// Get default branch.
932942
if len(ctx.Params("*")) == 0 {
933943
refName = ctx.Repo.Repository.DefaultBranch
@@ -994,7 +1004,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
9941004
return cancel
9951005
}
9961006
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
997-
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
1007+
} else if len(refName) >= 7 && len(refName) <= objectFormat.FullLength() {
9981008
ctx.Repo.IsViewCommit = true
9991009
ctx.Repo.CommitID = refName
10001010

@@ -1004,7 +1014,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
10041014
return cancel
10051015
}
10061016
// If short commit ID add canonical link header
1007-
if len(refName) < git.SHAFullLength {
1017+
if len(refName) < objectFormat.FullLength() {
10081018
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
10091019
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
10101020
}

modules/git/batch_reader.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
148148
// ReadBatchLine reads the header line from cat-file --batch
149149
// We expect:
150150
// <sha> SP <type> SP <size> LF
151-
// sha is a 40byte not 20byte here
151+
// sha is a hex encoded here
152152
func ReadBatchLine(rd *bufio.Reader) (sha []byte, typ string, size int64, err error) {
153153
typ, err = rd.ReadString('\n')
154154
if err != nil {
@@ -251,20 +251,19 @@ headerLoop:
251251
}
252252

253253
// git tree files are a list:
254-
// <mode-in-ascii> SP <fname> NUL <20-byte SHA>
254+
// <mode-in-ascii> SP <fname> NUL <binary Hash>
255255
//
256256
// Unfortunately this 20-byte notation is somewhat in conflict to all other git tools
257-
// Therefore we need some method to convert these 20-byte SHAs to a 40-byte SHA
257+
// Therefore we need some method to convert these binary hashes to hex hashes
258258

259-
// constant hextable to help quickly convert between 20byte and 40byte hashes
259+
// constant hextable to help quickly convert between binary and hex representation
260260
const hextable = "0123456789abcdef"
261261

262-
// To40ByteSHA converts a 20-byte SHA into a 40-byte sha. Input and output can be the
263-
// same 40 byte slice to support in place conversion without allocations.
262+
// BinToHexHeash converts a binary Hash into a hex encoded one. Input and output can be the
263+
// same byte slice to support in place conversion without allocations.
264264
// This is at least 100x quicker that hex.EncodeToString
265-
// NB This requires that out is a 40-byte slice
266-
func To40ByteSHA(sha, out []byte) []byte {
267-
for i := 19; i >= 0; i-- {
265+
func BinToHex(objectFormat ObjectFormat, sha, out []byte) []byte {
266+
for i := objectFormat.FullLength()/2 - 1; i >= 0; i-- {
268267
v := sha[i]
269268
vhi, vlo := v>>4, v&0x0f
270269
shi, slo := hextable[vhi], hextable[vlo]
@@ -278,10 +277,10 @@ func To40ByteSHA(sha, out []byte) []byte {
278277
// It is recommended therefore to pass in an fnameBuf large enough to avoid almost all allocations
279278
//
280279
// Each line is composed of:
281-
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <20-byte SHA>
280+
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH>
282281
//
283-
// We don't attempt to convert the 20-byte SHA to 40-byte SHA to save a lot of time
284-
func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
282+
// We don't attempt to convert the raw HASH to save a lot of time
283+
func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
285284
var readBytes []byte
286285

287286
// Read the Mode & fname
@@ -324,11 +323,12 @@ func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fn
324323
fnameBuf = fnameBuf[:len(fnameBuf)-1]
325324
fname = fnameBuf
326325

327-
// Deal with the 20-byte SHA
326+
// Deal with the binary hash
328327
idx = 0
329-
for idx < 20 {
328+
len := objectFormat.FullLength() / 2
329+
for idx < len {
330330
var read int
331-
read, err = rd.Read(shaBuf[idx:20])
331+
read, err = rd.Read(shaBuf[idx:len])
332332
n += read
333333
if err != nil {
334334
return mode, fname, sha, n, err

modules/git/blame.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010
"fmt"
1111
"io"
1212
"os"
13-
"regexp"
14-
"strings"
1513

1614
"code.gitea.io/gitea/modules/log"
1715
"code.gitea.io/gitea/modules/util"
@@ -33,14 +31,13 @@ type BlameReader struct {
3331
done chan error
3432
lastSha *string
3533
ignoreRevsFile *string
34+
objectFormat ObjectFormat
3635
}
3736

3837
func (r *BlameReader) UsesIgnoreRevs() bool {
3938
return r.ignoreRevsFile != nil
4039
}
4140

42-
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
43-
4441
// NextPart returns next part of blame (sequential code lines with the same commit)
4542
func (r *BlameReader) NextPart() (*BlamePart, error) {
4643
var blamePart *BlamePart
@@ -52,6 +49,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
5249
}
5350
}
5451

52+
const previousHeader = "previous "
5553
var lineBytes []byte
5654
var isPrefix bool
5755
var err error
@@ -67,21 +65,22 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
6765
continue
6866
}
6967

70-
line := string(lineBytes)
71-
72-
lines := shaLineRegex.FindStringSubmatch(line)
73-
if lines != nil {
74-
sha1 := lines[1]
68+
var objectID string
69+
objectFormatLength := r.objectFormat.FullLength()
7570

71+
if len(lineBytes) > objectFormatLength && lineBytes[objectFormatLength] == ' ' && r.objectFormat.IsValid(string(lineBytes[0:objectFormatLength])) {
72+
objectID = string(lineBytes[0:objectFormatLength])
73+
}
74+
if len(objectID) > 0 {
7675
if blamePart == nil {
7776
blamePart = &BlamePart{
78-
Sha: sha1,
77+
Sha: objectID,
7978
Lines: make([]string, 0),
8079
}
8180
}
8281

83-
if blamePart.Sha != sha1 {
84-
r.lastSha = &sha1
82+
if blamePart.Sha != objectID {
83+
r.lastSha = &objectID
8584
// need to munch to end of line...
8685
for isPrefix {
8786
_, isPrefix, err = r.bufferedReader.ReadLine()
@@ -91,12 +90,13 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
9190
}
9291
return blamePart, nil
9392
}
94-
} else if line[0] == '\t' {
95-
blamePart.Lines = append(blamePart.Lines, line[1:])
96-
} else if strings.HasPrefix(line, "previous ") {
97-
parts := strings.SplitN(line[len("previous "):], " ", 2)
98-
blamePart.PreviousSha = parts[0]
99-
blamePart.PreviousPath = parts[1]
93+
} else if lineBytes[0] == '\t' {
94+
blamePart.Lines = append(blamePart.Lines, string(lineBytes[1:]))
95+
} else if bytes.HasPrefix(lineBytes, []byte(previousHeader)) {
96+
offset := len(previousHeader) // already includes a space
97+
blamePart.PreviousSha = string(lineBytes[offset : offset+objectFormatLength])
98+
offset += objectFormatLength + 1 // +1 for space
99+
blamePart.PreviousPath = string(lineBytes[offset:])
100100
}
101101

102102
// need to munch to end of line...
@@ -126,7 +126,7 @@ func (r *BlameReader) Close() error {
126126
}
127127

128128
// CreateBlameReader creates reader for given repository, commit and file
129-
func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
129+
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
130130
var ignoreRevsFile *string
131131
if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore {
132132
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
@@ -175,6 +175,7 @@ func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, fil
175175
bufferedReader: bufferedReader,
176176
done: done,
177177
ignoreRevsFile: ignoreRevsFile,
178+
objectFormat: objectFormat,
178179
}, nil
179180
}
180181

modules/git/blame_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T) {
3939
}
4040

4141
for _, bypass := range []bool{false, true} {
42-
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
42+
blameReader, err := CreateBlameReader(ctx, &Sha1ObjectFormat{}, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
4343
assert.NoError(t, err)
4444
assert.NotNil(t, blameReader)
4545
defer blameReader.Close()
@@ -122,7 +122,7 @@ func TestReadingBlameOutput(t *testing.T) {
122122
commit, err := repo.GetCommit(c.CommitID)
123123
assert.NoError(t, err)
124124

125-
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
125+
blameReader, err := CreateBlameReader(ctx, repo.objectFormat, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
126126
assert.NoError(t, err)
127127
assert.NotNil(t, blameReader)
128128
defer blameReader.Close()

modules/git/blob_gogit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
// Blob represents a Git object.
1616
type Blob struct {
17-
ID SHA1
17+
ID ObjectID
1818

1919
gogitEncodedObj plumbing.EncodedObject
2020
name string

modules/git/blob_nogogit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
// Blob represents a Git object.
1818
type Blob struct {
19-
ID SHA1
19+
ID ObjectID
2020

2121
gotSize bool
2222
size int64

0 commit comments

Comments
 (0)