Skip to content

Commit cbf923e

Browse files
authored
Abstract hash function usage (#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 064f052 commit cbf923e

File tree

122 files changed

+945
-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

+945
-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
@@ -30,7 +30,7 @@ func TestAddDeletedBranch(t *testing.T) {
3030
assert.True(t, secondBranch.IsDeleted)
3131

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

models/git/commit_status.go

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

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

@@ -425,7 +426,7 @@ func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, befor
425426
type NewCommitStatusOptions struct {
426427
Repo *repo_model.Repository
427428
Creator *user_model.User
428-
SHA string
429+
SHA git.ObjectID
429430
CommitStatus *CommitStatus
430431
}
431432

@@ -440,26 +441,22 @@ func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error {
440441
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
441442
}
442443

443-
if _, err := git.NewIDFromString(opts.SHA); err != nil {
444-
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
445-
}
446-
447444
ctx, committer, err := db.TxContext(ctx)
448445
if err != nil {
449446
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
450447
}
451448
defer committer.Close()
452449

453450
// Get the next Status Index
454-
idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA)
451+
idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA.String())
455452
if err != nil {
456453
return fmt.Errorf("generate commit status index failed: %w", err)
457454
}
458455

459456
opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
460457
opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
461458
opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
462-
opts.CommitStatus.SHA = opts.SHA
459+
opts.CommitStatus.SHA = opts.SHA.String()
463460
opts.CommitStatus.CreatorID = opts.Creator.ID
464461
opts.CommitStatus.RepoID = opts.Repo.ID
465462
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
@@ -308,6 +308,12 @@ func RepoRefForAPI(next http.Handler) http.Handler {
308308
return
309309
}
310310

311+
objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat()
312+
if err != nil {
313+
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
314+
return
315+
}
316+
311317
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
312318
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
313319
if err != nil {
@@ -325,7 +331,6 @@ func RepoRefForAPI(next http.Handler) http.Handler {
325331
return
326332
}
327333

328-
var err error
329334
refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
330335

331336
if ctx.Repo.GitRepo.IsBranchExist(refName) {
@@ -342,7 +347,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
342347
return
343348
}
344349
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
345-
} else if len(refName) == git.SHAFullLength {
350+
} else if len(refName) == objectFormat.FullLength() {
346351
ctx.Repo.CommitID = refName
347352
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
348353
if err != nil {

modules/context/repo.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
825825
}
826826
// For legacy and API support only full commit sha
827827
parts := strings.Split(path, "/")
828-
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
828+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
829+
830+
if len(parts) > 0 && len(parts[0]) == objectFormat.FullLength() {
829831
repo.TreePath = strings.Join(parts[1:], "/")
830832
return parts[0]
831833
}
@@ -869,7 +871,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
869871
return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
870872
case RepoRefCommit:
871873
parts := strings.Split(path, "/")
872-
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
874+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
875+
876+
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= objectFormat.FullLength() {
873877
repo.TreePath = strings.Join(parts[1:], "/")
874878
return parts[0]
875879
}
@@ -929,6 +933,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
929933
}
930934
}
931935

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

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

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)