Skip to content

Commit ecfd075

Browse files
committed
Abstract SHA1 function usage
Refactor SHA1 interfaces and centralize the hash function. This will allow easier introduction of different hash function later on.
1 parent ad9aac3 commit ecfd075

File tree

121 files changed

+915
-582
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

+915
-582
lines changed

cmd/hook.go

+5-2
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

+2-3
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ 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(),
3737
},
3838
}
3939

40-
err := git_model.UpdateBranch(db.DefaultContext, repo.ID, secondBranch.PusherID, secondBranch.Name, commit)
41-
assert.NoError(t, err)
40+
assert.NoError(t, git_model.UpdateBranch(db.DefaultContext, repo.ID, secondBranch.PusherID, secondBranch.Name, commit))
4241
}
4342

4443
func TestGetDeletedBranches(t *testing.T) {

models/git/commit_status.go

+5-8
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

@@ -423,7 +424,7 @@ 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.ObjectID
427428
CommitStatus *CommitStatus
428429
}
429430

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

441-
if _, err := git.NewIDFromString(opts.SHA); err != nil {
442-
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
443-
}
444-
445442
ctx, committer, err := db.TxContext(ctx)
446443
if err != nil {
447444
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, 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

+5-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+
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 commitID == "" || commitID == repo.ObjectFormat.Empty().String() {
317321
result = ""
318322
} else {
319323
result = repo.Link() + "/commit/" + url.PathEscape(commitID)

modules/context/api.go

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
827827
}
828828
// For legacy and API support only full commit sha
829829
parts := strings.Split(path, "/")
830-
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
830+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
831+
832+
if len(parts) > 0 && len(parts[0]) == objectFormat.FullLength() {
831833
repo.TreePath = strings.Join(parts[1:], "/")
832834
return parts[0]
833835
}
@@ -871,7 +873,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
871873
return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist)
872874
case RepoRefCommit:
873875
parts := strings.Split(path, "/")
874-
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
876+
objectFormat, _ := repo.GitRepo.GetObjectFormat()
877+
878+
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= objectFormat.FullLength() {
875879
repo.TreePath = strings.Join(parts[1:], "/")
876880
return parts[0]
877881
}
@@ -931,6 +935,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
931935
}
932936
}
933937

938+
objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat()
939+
if err != nil {
940+
log.Error("Cannot determine objectFormat for repository: %w", err)
941+
ctx.Repo.Repository.MarkAsBrokenEmpty()
942+
}
943+
934944
// Get default branch.
935945
if len(ctx.Params("*")) == 0 {
936946
refName = ctx.Repo.Repository.DefaultBranch
@@ -997,7 +1007,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
9971007
return cancel
9981008
}
9991009
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
1000-
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
1010+
} else if len(refName) >= 7 && len(refName) <= objectFormat.FullLength() {
10011011
ctx.Repo.IsViewCommit = true
10021012
ctx.Repo.CommitID = refName
10031013

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

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

+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+
objectFormat ObjectFormat
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 objectID string
63+
objectFormatLength := r.objectFormat.FullLength()
6764

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

72-
if blamePart.Sha != sha1 {
73-
r.lastSha = &sha1
73+
if blamePart.Sha != objectID {
74+
r.lastSha = &objectID
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, objectFormat ObjectFormat, 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+
objectFormat: objectFormat,
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, &Sha1ObjectFormat{}, "./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.objectFormat, "./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 ObjectID
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 ObjectID
2020

2121
gotSize bool
2222
size int64

0 commit comments

Comments
 (0)