diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2023-12-17 19:56:08 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-17 11:56:08 +0000 |
commit | 408a4842240e7dd906e682196bd4254d6c76fcb9 (patch) | |
tree | ec3962d5769a5891a24b4d79f725673fc1e46e35 /modules/git | |
parent | 7fb6b5147038649bfaa26147a6173cf99b322a30 (diff) | |
download | gitea-408a4842240e7dd906e682196bd4254d6c76fcb9.tar.gz gitea-408a4842240e7dd906e682196bd4254d6c76fcb9.zip |
Adjust object format interface (#28469)
- Remove `ObjectFormatID`
- Remove function `ObjectFormatFromID`.
- Use `Sha1ObjectFormat` directly but not a pointer because it's an
empty struct.
- Store `ObjectFormatName` in `repository` struct
Diffstat (limited to 'modules/git')
-rw-r--r-- | modules/git/blame_test.go | 2 | ||||
-rw-r--r-- | modules/git/commit.go | 2 | ||||
-rw-r--r-- | modules/git/object_format.go | 79 | ||||
-rw-r--r-- | modules/git/object_id.go | 33 | ||||
-rw-r--r-- | modules/git/object_id_gogit.go | 2 | ||||
-rw-r--r-- | modules/git/object_id_test.go | 2 | ||||
-rw-r--r-- | modules/git/parse_gogit_test.go | 14 | ||||
-rw-r--r-- | modules/git/parse_nogogit_test.go | 6 | ||||
-rw-r--r-- | modules/git/ref.go | 2 | ||||
-rw-r--r-- | modules/git/repo.go | 10 | ||||
-rw-r--r-- | modules/git/repo_commit_gogit.go | 4 | ||||
-rw-r--r-- | modules/git/repo_compare.go | 2 | ||||
-rw-r--r-- | modules/git/repo_compare_test.go | 4 | ||||
-rw-r--r-- | modules/git/repo_index.go | 2 | ||||
-rw-r--r-- | modules/git/repo_tag_test.go | 2 | ||||
-rw-r--r-- | modules/git/tag.go | 4 | ||||
-rw-r--r-- | modules/git/tag_test.go | 6 |
17 files changed, 85 insertions, 91 deletions
diff --git a/modules/git/blame_test.go b/modules/git/blame_test.go index 0afc6d2a1f..327edab767 100644 --- a/modules/git/blame_test.go +++ b/modules/git/blame_test.go @@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T) { } for _, bypass := range []bool{false, true} { - blameReader, err := CreateBlameReader(ctx, &Sha1ObjectFormat{}, "./tests/repos/repo5_pulls", commit, "README.md", bypass) + blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass) assert.NoError(t, err) assert.NotNil(t, blameReader) defer blameReader.Close() diff --git a/modules/git/commit.go b/modules/git/commit.go index a8b6c0e8f7..5d960e92f3 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -236,7 +236,7 @@ func (c *Commit) IsForcePush(oldCommitID string) (bool, error) { if err != nil { return false, err } - if oldCommitID == objectFormat.Empty().String() { + if oldCommitID == objectFormat.EmptyObjectID().String() { return false, nil } diff --git a/modules/git/object_format.go b/modules/git/object_format.go index 3c52de772b..ee7e659ed0 100644 --- a/modules/git/object_format.go +++ b/modules/git/object_format.go @@ -5,26 +5,17 @@ package git import ( "crypto/sha1" - "fmt" "regexp" - "strings" -) - -type ObjectFormatID int - -const ( - Sha1 ObjectFormatID = iota ) // sha1Pattern can be used to determine if a string is an valid sha var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) type ObjectFormat interface { - ID() ObjectFormatID - String() string - - // Empty is the hash of empty git - Empty() ObjectID + // Name returns the name of the object format + Name() string + // EmptyObjectID creates a new empty ObjectID from an object format hash name + EmptyObjectID() ObjectID // EmptyTree is the hash of an empty tree EmptyTree() ObjectID // FullLength is the length of the hash's hex string @@ -35,67 +26,71 @@ type ObjectFormat interface { MustIDFromString(s string) ObjectID NewID(b []byte) (ObjectID, error) NewIDFromString(s string) (ObjectID, error) - NewEmptyID() ObjectID NewHasher() HasherInterface } -type Sha1ObjectFormat struct{} +type Sha1ObjectFormatImpl struct{} -func (*Sha1ObjectFormat) ID() ObjectFormatID { return Sha1 } -func (*Sha1ObjectFormat) String() string { return "sha1" } -func (*Sha1ObjectFormat) Empty() ObjectID { return &Sha1Hash{} } -func (*Sha1ObjectFormat) EmptyTree() ObjectID { - return &Sha1Hash{ +var ( + emptyObjectID = &Sha1Hash{} + emptyTree = &Sha1Hash{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04, } +) + +func (Sha1ObjectFormatImpl) Name() string { return "sha1" } +func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID { + return emptyObjectID +} + +func (Sha1ObjectFormatImpl) EmptyTree() ObjectID { + return emptyTree } -func (*Sha1ObjectFormat) FullLength() int { return 40 } -func (*Sha1ObjectFormat) IsValid(input string) bool { +func (Sha1ObjectFormatImpl) FullLength() int { return 40 } +func (Sha1ObjectFormatImpl) IsValid(input string) bool { return sha1Pattern.MatchString(input) } -func (*Sha1ObjectFormat) MustID(b []byte) ObjectID { +func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID { var id Sha1Hash copy(id[0:20], b) return &id } -func (h *Sha1ObjectFormat) MustIDFromString(s string) ObjectID { +func (h Sha1ObjectFormatImpl) MustIDFromString(s string) ObjectID { return MustIDFromString(h, s) } -func (h *Sha1ObjectFormat) NewID(b []byte) (ObjectID, error) { +func (h Sha1ObjectFormatImpl) NewID(b []byte) (ObjectID, error) { return IDFromRaw(h, b) } -func (h *Sha1ObjectFormat) NewIDFromString(s string) (ObjectID, error) { +func (h Sha1ObjectFormatImpl) NewIDFromString(s string) (ObjectID, error) { return genericIDFromString(h, s) } -func (*Sha1ObjectFormat) NewEmptyID() ObjectID { - return NewSha1() -} - -func (h *Sha1ObjectFormat) NewHasher() HasherInterface { +func (h Sha1ObjectFormatImpl) NewHasher() HasherInterface { return &Sha1Hasher{sha1.New()} } -func ObjectFormatFromID(id ObjectFormatID) ObjectFormat { - switch id { - case Sha1: - return &Sha1ObjectFormat{} - } +var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{} - return nil +var SupportedObjectFormats = []ObjectFormat{ + Sha1ObjectFormat, + // TODO: add sha256 } -func ObjectFormatFromString(hash string) (ObjectFormat, error) { - switch strings.ToLower(hash) { - case "sha1": - return &Sha1ObjectFormat{}, nil +func ObjectFormatFromName(name string) ObjectFormat { + for _, objectFormat := range SupportedObjectFormats { + if name == objectFormat.Name() { + return objectFormat + } } + return nil +} - return nil, fmt.Errorf("unknown hash type: %s", hash) +func IsValidObjectFormat(name string) bool { + return ObjectFormatFromName(name) != nil } diff --git a/modules/git/object_id.go b/modules/git/object_id.go index 21e1c67c64..a90683678a 100644 --- a/modules/git/object_id.go +++ b/modules/git/object_id.go @@ -31,18 +31,15 @@ func (h *Sha1Hash) IsZero() bool { return bytes.Equal(empty[:], h[:]) } func (h *Sha1Hash) RawValue() []byte { return h[:] } -func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} } +func (*Sha1Hash) Type() ObjectFormat { return Sha1ObjectFormat } -func NewSha1() *Sha1Hash { - return &Sha1Hash{} -} +var _ ObjectID = &Sha1Hash{} -// NewHash is for generic implementations -func NewHash(hash string) (ObjectID, error) { - hash = strings.ToLower(hash) - switch hash { - case "sha1": - return &Sha1Hash{}, nil +// EmptyObjectID creates a new ObjectID from an object format hash name +func EmptyObjectID(objectFormatName string) (ObjectID, error) { + objectFormat := ObjectFormatFromName(objectFormatName) + if objectFormat != nil { + return objectFormat.EmptyObjectID(), nil } return nil, errors.New("unsupported hash type") @@ -50,7 +47,7 @@ func NewHash(hash string) (ObjectID, error) { func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) { if len(b) != h.FullLength()/2 { - return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b) + return h.EmptyObjectID(), fmt.Errorf("length must be %d: %v", h.FullLength(), b) } return h.MustID(b), nil } @@ -63,24 +60,20 @@ func MustIDFromString(h ObjectFormat, s string) ObjectID { func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) { s = strings.TrimSpace(s) if len(s) != h.FullLength() { - return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s) + return h.EmptyObjectID(), fmt.Errorf("length must be %d: %s", h.FullLength(), s) } b, err := hex.DecodeString(s) if err != nil { - return h.Empty(), err + return h.EmptyObjectID(), err } return h.NewID(b) } func IDFromString(hexHash string) (ObjectID, error) { - switch len(hexHash) { - case 40: - hashType := Sha1ObjectFormat{} - h, err := hashType.NewIDFromString(hexHash) - if err != nil { - return nil, err + for _, objectFormat := range SupportedObjectFormats { + if len(hexHash) == objectFormat.FullLength() { + return objectFormat.NewIDFromString(hexHash) } - return h, nil } return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash)) diff --git a/modules/git/object_id_gogit.go b/modules/git/object_id_gogit.go index 50917f0552..0cebb0d50b 100644 --- a/modules/git/object_id_gogit.go +++ b/modules/git/object_id_gogit.go @@ -12,7 +12,7 @@ import ( func ParseGogitHash(h plumbing.Hash) ObjectID { switch hash.Size { case 20: - return ObjectFormatFromID(Sha1).MustID(h[:]) + return Sha1ObjectFormat.MustID(h[:]) } return nil diff --git a/modules/git/object_id_test.go b/modules/git/object_id_test.go index c78a215755..1ad40096a0 100644 --- a/modules/git/object_id_test.go +++ b/modules/git/object_id_test.go @@ -10,7 +10,7 @@ import ( ) func TestIsValidSHAPattern(t *testing.T) { - h := NewSha1().Type() + h := Sha1ObjectFormat assert.True(t, h.IsValid("fee1")) assert.True(t, h.IsValid("abc000")) assert.True(t, h.IsValid("9023902390239023902390239023902390239023")) diff --git a/modules/git/parse_gogit_test.go b/modules/git/parse_gogit_test.go index 7ba50cbff9..9755f81cce 100644 --- a/modules/git/parse_gogit_test.go +++ b/modules/git/parse_gogit_test.go @@ -28,9 +28,9 @@ func TestParseTreeEntries(t *testing.T) { Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n", Expected: []*TreeEntry{ { - ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), + ID: Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), gogitTreeEntry: &object.TreeEntry{ - Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), + Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Name: "example/file2.txt", Mode: filemode.Regular, }, @@ -44,9 +44,9 @@ func TestParseTreeEntries(t *testing.T) { "040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n", Expected: []*TreeEntry{ { - ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), + ID: Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), gogitTreeEntry: &object.TreeEntry{ - Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), + Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Name: "example/\n.txt", Mode: filemode.Symlink, }, @@ -54,10 +54,10 @@ func TestParseTreeEntries(t *testing.T) { sized: true, }, { - ID: ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), + ID: Sha1ObjectFormat.MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), sized: true, gogitTreeEntry: &object.TreeEntry{ - Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()), + Hash: plumbing.Hash(Sha1ObjectFormat.MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()), Name: "example", Mode: filemode.Dir, }, @@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) { } for _, testCase := range testCases { - entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte(testCase.Input)) + entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input)) assert.NoError(t, err) if len(entries) > 1 { fmt.Println(testCase.Expected[0].ID) diff --git a/modules/git/parse_nogogit_test.go b/modules/git/parse_nogogit_test.go index 0b78c081cd..36313e00f3 100644 --- a/modules/git/parse_nogogit_test.go +++ b/modules/git/parse_nogogit_test.go @@ -12,7 +12,7 @@ import ( ) func TestParseTreeEntriesLong(t *testing.T) { - objectFormat := ObjectFormatFromID(Sha1) + objectFormat := Sha1ObjectFormat testCases := []struct { Input string @@ -66,7 +66,7 @@ func TestParseTreeEntriesLong(t *testing.T) { } func TestParseTreeEntriesShort(t *testing.T) { - objectFormat := ObjectFormatFromID(Sha1) + objectFormat := Sha1ObjectFormat testCases := []struct { Input string @@ -102,7 +102,7 @@ func TestParseTreeEntriesShort(t *testing.T) { func TestParseTreeEntriesInvalid(t *testing.T) { // there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315 - entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) + entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) assert.Error(t, err) assert.Len(t, entries, 0) } diff --git a/modules/git/ref.go b/modules/git/ref.go index b96b4ababb..ed801f20d5 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -205,7 +205,7 @@ func RefURL(repoURL, ref string) string { return repoURL + "/src/branch/" + refName case refFullName.IsTag(): return repoURL + "/src/tag/" + refName - case !ObjectFormatFromID(Sha1).IsValid(ref): + case !Sha1ObjectFormat.IsValid(ref): // assume they mean a branch return repoURL + "/src/branch/" + refName default: diff --git a/modules/git/repo.go b/modules/git/repo.go index c036a217eb..52e54715d6 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -90,7 +90,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat, } // InitRepository initializes a new Git repository. -func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormat ObjectFormat) error { +func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error { err := os.MkdirAll(repoPath, os.ModePerm) if err != nil { return err @@ -98,7 +98,13 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma cmd := NewCommand(ctx, "init") if SupportHashSha256 { - cmd.AddOptionValues("--object-format", objectFormat.String()) + if objectFormatName == "" { + objectFormatName = Sha1ObjectFormat.Name() + } + if !IsValidObjectFormat(objectFormatName) { + return fmt.Errorf("invalid object format: %s", objectFormatName) + } + cmd.AddOptionValues("--object-format", objectFormatName) } if bare { cmd.AddArguments("--bare") diff --git a/modules/git/repo_commit_gogit.go b/modules/git/repo_commit_gogit.go index 893055bccd..d0992fd385 100644 --- a/modules/git/repo_commit_gogit.go +++ b/modules/git/repo_commit_gogit.go @@ -54,9 +54,9 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { if err != nil { if strings.Contains(err.Error(), "unknown revision or path") || strings.Contains(err.Error(), "fatal: Needed a single revision") { - return objectFormat.Empty(), ErrNotExist{commitID, ""} + return objectFormat.EmptyObjectID(), ErrNotExist{commitID, ""} } - return objectFormat.Empty(), err + return objectFormat.EmptyObjectID(), err } return objectFormat.NewIDFromString(actualCommitID) diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 8885df4f70..0e9a0c70d7 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -284,7 +284,7 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error { // If base is the SHA of an empty tree (EmptyTreeSHA), it returns the files changes from the initial commit to the head commit func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) { cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z") - if base == repo.objectFormat.Empty().String() { + if base == repo.objectFormat.EmptyObjectID().String() { cmd.AddDynamicArguments(head) } else { cmd.AddDynamicArguments(base, head) diff --git a/modules/git/repo_compare_test.go b/modules/git/repo_compare_test.go index 9bfaa5c02a..526b213550 100644 --- a/modules/git/repo_compare_test.go +++ b/modules/git/repo_compare_test.go @@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testing.T) { files []string }{ { - repo.objectFormat.Empty().String(), + repo.objectFormat.EmptyObjectID().String(), "95bb4d39648ee7e325106df01a621c530863a653", []string{"file1.txt"}, }, { - repo.objectFormat.Empty().String(), + repo.objectFormat.EmptyObjectID().String(), "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", []string{"file2.txt"}, }, diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go index 6f43734655..e3b19bf036 100644 --- a/modules/git/repo_index.go +++ b/modules/git/repo_index.go @@ -101,7 +101,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error { for _, file := range filenames { if file != "" { buffer.WriteString("0 ") - buffer.WriteString(repo.objectFormat.Empty().String()) + buffer.WriteString(repo.objectFormat.EmptyObjectID().String()) buffer.WriteByte('\t') buffer.WriteString(file) buffer.WriteByte('\000') diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index c7699f4a7d..48c1bc41c2 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -194,7 +194,7 @@ func TestRepository_GetAnnotatedTag(t *testing.T) { } func TestRepository_parseTagRef(t *testing.T) { - sha1 := ObjectFormatFromID(Sha1) + sha1 := Sha1ObjectFormat tests := []struct { name string diff --git a/modules/git/tag.go b/modules/git/tag.go index 27358d74f8..c7d0d8aef9 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -35,8 +35,8 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) { // \n\n separate headers from message func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { tag := new(Tag) - tag.ID = objectFormat.NewEmptyID() - tag.Object = objectFormat.NewEmptyID() + tag.ID = objectFormat.EmptyObjectID() + tag.Object = objectFormat.EmptyObjectID() tag.Tagger = &Signature{} // we now have the contents of the commit object. Let's investigate... nextline := 0 diff --git a/modules/git/tag_test.go b/modules/git/tag_test.go index 129c1e3a02..f980b0c560 100644 --- a/modules/git/tag_test.go +++ b/modules/git/tag_test.go @@ -22,7 +22,7 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100 `), tag: Tag{ Name: "", - ID: NewSha1(), + ID: Sha1ObjectFormat.EmptyObjectID(), Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, Type: "commit", Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, @@ -39,7 +39,7 @@ o ono`), tag: Tag{ Name: "", - ID: NewSha1(), + ID: Sha1ObjectFormat.EmptyObjectID(), Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, Type: "commit", Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, @@ -49,7 +49,7 @@ ono`), tag: Tag{ } for _, test := range testData { - tag, err := parseTagData(ObjectFormatFromID(Sha1), test.data) + tag, err := parseTagData(Sha1ObjectFormat, test.data) assert.NoError(t, err) assert.EqualValues(t, test.tag.ID, tag.ID) assert.EqualValues(t, test.tag.Object, tag.Object) |