Skip to content

Commit fd090c8

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 ff5106d commit fd090c8

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

+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

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

+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

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

+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 git.IsEmptyCommitID(commitID) {
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
@@ -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

+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

+20-19
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

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

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