Skip to content

Commit 38807ae

Browse files
committed
Abstract hash function usage
Refactor Hash interfaces and centralize hash function. This will allow easier introduction of different hash function later on.
1 parent 0c72256 commit 38807ae

File tree

121 files changed

+838
-557
lines changed

Some content is hidden

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

121 files changed

+838
-557
lines changed

cmd/hook.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,12 @@ 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+
hash, err := git.HashFromString(newCommitIDs[count])
381+
if err != nil {
382+
return err
383+
}
384+
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != hash.Type().Empty().String() && count == total {
380385
masterPushed = true
381386
}
382387
count++
@@ -669,7 +674,11 @@ Gitea or set your environment appropriately.`, "")
669674
if err != nil {
670675
return err
671676
}
672-
if rs.OldOID != git.EmptySHA {
677+
hash, err := git.HashFromString(rs.OldOID)
678+
if err != nil {
679+
return err
680+
}
681+
if rs.OldOID != hash.Type().Empty().String() {
673682
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
674683
if err != nil {
675684
return err

models/git/branch_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ func TestAddDeletedBranch(t *testing.T) {
2121
assert.NoError(t, unittest.PrepareTestDatabase())
2222
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
2323
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
24+
hash, err := git.HashTypeFromString(repo.HashType)
2425

26+
assert.NoError(t, err)
2527
assert.True(t, firstBranch.IsDeleted)
2628
assert.NoError(t, git_model.AddDeletedBranch(db.DefaultContext, repo.ID, firstBranch.Name, firstBranch.DeletedByID))
2729
assert.NoError(t, git_model.AddDeletedBranch(db.DefaultContext, repo.ID, "branch2", int64(1)))
@@ -30,14 +32,14 @@ func TestAddDeletedBranch(t *testing.T) {
3032
assert.True(t, secondBranch.IsDeleted)
3133

3234
commit := &git.Commit{
33-
ID: git.MustIDFromString(secondBranch.CommitID),
35+
ID: hash.MustIDFromString(secondBranch.CommitID),
3436
CommitMessage: secondBranch.CommitMessage,
3537
Committer: &git.Signature{
3638
When: secondBranch.CommitTime.AsLocalTime(),
3739
},
3840
}
3941

40-
err := git_model.UpdateBranch(db.DefaultContext, repo.ID, secondBranch.PusherID, secondBranch.Name, commit)
42+
err = git_model.UpdateBranch(db.DefaultContext, repo.ID, secondBranch.PusherID, secondBranch.Name, commit)
4143
assert.NoError(t, err)
4244
}
4345

models/git/commit_status.go

+8-11
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.HashFromString(sha)
118+
if err != nil {
118119
return 0, git.ErrInvalidSHA{SHA: sha}
119120
}
120121

@@ -423,41 +424,37 @@ func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, befor
423424
type NewCommitStatusOptions struct {
424425
Repo *repo_model.Repository
425426
Creator *user_model.User
426-
SHA string
427+
SHA git.Hash
427428
CommitStatus *CommitStatus
428429
}
429430

430431
// NewCommitStatus save commit statuses into database
431432
func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error {
432433
if opts.Repo == nil {
433-
return fmt.Errorf("NewCommitStatus[nil, %s]: no repository specified", opts.SHA)
434+
return fmt.Errorf("NewCommitStatus[nil, %s]: no repository specified", opts.SHA.String())
434435
}
435436

436437
repoPath := opts.Repo.RepoPath()
437438
if opts.Creator == nil {
438-
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
439-
}
440-
441-
if _, err := git.NewIDFromString(opts.SHA); err != nil {
442-
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
439+
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA.String())
443440
}
444441

445442
ctx, committer, err := db.TxContext(ctx)
446443
if err != nil {
447-
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
444+
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA.String(), err)
448445
}
449446
defer committer.Close()
450447

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

457454
opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
458455
opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
459456
opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
460-
opts.CommitStatus.SHA = opts.SHA
457+
opts.CommitStatus.SHA = opts.SHA.String()
461458
opts.CommitStatus.CreatorID = opts.Creator.ID
462459
opts.CommitStatus.RepoID = opts.Repo.ID
463460
opts.CommitStatus.Index = idx

models/repo/repo.go

+6-1
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+
HashType string
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.HashType = "sha1"
277281
}
278282

279283
// LoadAttributes loads attributes of the repository.
@@ -313,7 +317,8 @@ 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+
hash, _ := git.HashTypeFromString(repo.HashType)
321+
if commitID == "" || commitID == hash.Empty().String() {
317322
result = ""
318323
} else {
319324
result = repo.Link() + "/commit/" + url.PathEscape(commitID)

modules/context/api.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
342342
return
343343
}
344344
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
345-
} else if len(refName) == git.SHAFullLength {
345+
} else if len(refName) == ctx.Repo.GitRepo.Hash.FullLength() {
346346
ctx.Repo.CommitID = refName
347347
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
348348
if err != nil {

modules/context/repo.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
826826
}
827827
// For legacy and API support only full commit sha
828828
parts := strings.Split(path, "/")
829-
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
829+
if len(parts) > 0 && len(parts[0]) == repo.GitRepo.Hash.FullLength() {
830830
repo.TreePath = strings.Join(parts[1:], "/")
831831
return parts[0]
832832
}
@@ -870,7 +870,7 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
870870
return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
871871
case RepoRefCommit:
872872
parts := strings.Split(path, "/")
873-
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
873+
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= repo.GitRepo.Hash.FullLength() {
874874
repo.TreePath = strings.Join(parts[1:], "/")
875875
return parts[0]
876876
}
@@ -996,7 +996,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
996996
return cancel
997997
}
998998
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
999-
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
999+
} else if len(refName) >= 7 && len(refName) <= ctx.Repo.GitRepo.Hash.FullLength() {
10001000
ctx.Repo.IsViewCommit = true
10011001
ctx.Repo.CommitID = refName
10021002

@@ -1006,7 +1006,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
10061006
return cancel
10071007
}
10081008
// If short commit ID add canonical link header
1009-
if len(refName) < git.SHAFullLength {
1009+
if len(refName) < ctx.Repo.GitRepo.Hash.FullLength() {
10101010
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
10111011
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
10121012
}

modules/git/batch_reader.go

+15-15
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 BinToHexHash(hash HashType, sha, out []byte) []byte {
266+
for i := hash.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(hash HashType, 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+
hashLen := hash.FullLength() / 2
329+
for idx < hashLen {
330330
var read int
331-
read, err = rd.Read(shaBuf[idx:20])
331+
read, err = rd.Read(shaBuf[idx:hashLen])
332332
n += read
333333
if err != nil {
334334
return mode, fname, sha, n, err

modules/git/blame.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"fmt"
1111
"io"
1212
"os"
13-
"regexp"
1413

1514
"code.gitea.io/gitea/modules/log"
1615
"code.gitea.io/gitea/modules/util"
@@ -30,14 +29,13 @@ type BlameReader struct {
3029
done chan error
3130
lastSha *string
3231
ignoreRevsFile *string
32+
hash HashType
3333
}
3434

3535
func (r *BlameReader) UsesIgnoreRevs() bool {
3636
return r.ignoreRevsFile != nil
3737
}
3838

39-
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
40-
4139
// NextPart returns next part of blame (sequential code lines with the same commit)
4240
func (r *BlameReader) NextPart() (*BlamePart, error) {
4341
var blamePart *BlamePart
@@ -61,16 +59,19 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
6159
continue
6260
}
6361

64-
lines := shaLineRegex.FindSubmatch(line)
65-
if lines != nil {
66-
sha1 := string(lines[1])
62+
var hash string
63+
hashLen := r.hash.FullLength()
6764

65+
if len(line) > hashLen && line[hashLen] == ' ' && r.hash.IsValid(string(line[0:hashLen])) {
66+
hash = string(line[0:hashLen])
67+
}
68+
if len(hash) > 0 {
6869
if blamePart == nil {
69-
blamePart = &BlamePart{sha1, make([]string, 0)}
70+
blamePart = &BlamePart{hash, make([]string, 0)}
7071
}
7172

72-
if blamePart.Sha != sha1 {
73-
r.lastSha = &sha1
73+
if blamePart.Sha != hash {
74+
r.lastSha = &hash
7475
// need to munch to end of line...
7576
for isPrefix {
7677
_, isPrefix, err = r.bufferedReader.ReadLine()
@@ -113,7 +114,7 @@ func (r *BlameReader) Close() error {
113114
}
114115

115116
// CreateBlameReader creates reader for given repository, commit and file
116-
func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
117+
func CreateBlameReader(ctx context.Context, hash HashType, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
117118
var ignoreRevsFile *string
118119
if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore {
119120
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
@@ -162,6 +163,7 @@ func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, fil
162163
bufferedReader: bufferedReader,
163164
done: done,
164165
ignoreRevsFile: ignoreRevsFile,
166+
hash: hash,
165167
}, nil
166168
}
167169

modules/git/blame_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestReadingBlameOutput(t *testing.T) {
3737
}
3838

3939
for _, bypass := range []bool{false, true} {
40-
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
40+
blameReader, err := CreateBlameReader(ctx, &Sha1HashType{}, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
4141
assert.NoError(t, err)
4242
assert.NotNil(t, blameReader)
4343
defer blameReader.Close()
@@ -118,7 +118,7 @@ func TestReadingBlameOutput(t *testing.T) {
118118
commit, err := repo.GetCommit(c.CommitID)
119119
assert.NoError(t, err)
120120

121-
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
121+
blameReader, err := CreateBlameReader(ctx, repo.Hash, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
122122
assert.NoError(t, err)
123123
assert.NotNil(t, blameReader)
124124
defer blameReader.Close()

modules/git/blob_gogit.go

+1-1
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 Hash
1818

1919
gogitEncodedObj plumbing.EncodedObject
2020
name string

modules/git/blob_nogogit.go

+1-1
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 Hash
2020

2121
gotSize bool
2222
size int64

0 commit comments

Comments
 (0)