diff --git a/Makefile b/Makefile index 60a59d42d..744bd5bf2 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,15 @@ vet: go vet + go vet -tags test_sha256 test: go test -v -cover -race + go test -tags test_sha256 -v -cover -race bench: go test -v -cover -test.bench=. -test.benchmem coverage: go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out + go test -tags test_sha256 -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/blob_test.go b/blob_test.go index cc02c0ba3..c0264b86f 100644 --- a/blob_test.go +++ b/blob_test.go @@ -31,7 +31,7 @@ This demo also includes an image with changes on a branch for examination of ima TreeEntry: &TreeEntry{ mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("adfd6da3c0a3fb038393144becbf37f14f780087"), // Blob ID of "README.txt" file + id: testrepoMarks[39], // Blob ID of "README.txt" file parent: &Tree{ repo: testrepo, }, diff --git a/commit.go b/commit.go index 0edda64ae..660a88c42 100644 --- a/commit.go +++ b/commit.go @@ -11,8 +11,8 @@ import ( // Commit contains information of a Git commit. type Commit struct { - // The SHA-1 hash of the commit. - ID *SHA1 + // The hash of the commit. + ID Oid // The author of the commit. Author *Signature // The committer of the commit. @@ -20,7 +20,7 @@ type Commit struct { // The full commit message. Message string - parents []*SHA1 + parents []Oid *Tree submodules Submodules @@ -39,9 +39,9 @@ func (c *Commit) ParentsCount() int { return len(c.parents) } -// ParentID returns the SHA-1 hash of the n-th parent (0-based) of this commit. +// ParentID returns the Oid of the n-th parent (0-based) of this commit. // It returns an ErrParentNotExist if no such parent exists. -func (c *Commit) ParentID(n int) (*SHA1, error) { +func (c *Commit) ParentID(n int) (Oid, error) { if n >= len(c.parents) { return nil, ErrParentNotExist } diff --git a/commit_archive_test.go b/commit_archive_test.go index 8e29580f5..fc49a90d4 100644 --- a/commit_archive_test.go +++ b/commit_archive_test.go @@ -22,7 +22,7 @@ func TestCommit_Archive(t *testing.T) { ArchiveTarGz, } { t.Run(string(format), func(t *testing.T) { - c, err := testrepo.CatFileCommit(ctx, "755fd577edcfd9209d0ac072eed3b022cbe4d39b") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[1].String()) if err != nil { t.Fatal(err) } diff --git a/commit_submodule_test.go b/commit_submodule_test.go index b95167964..3e670cefa 100644 --- a/commit_submodule_test.go +++ b/commit_submodule_test.go @@ -10,7 +10,7 @@ import ( func TestCommit_Submodule(t *testing.T) { ctx := context.Background() - c, err := testrepo.CatFileCommit(ctx, "4e59b72440188e7c2578299fc28ea425fbe9aece") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[29].String()) if err != nil { t.Fatal(err) } @@ -21,7 +21,7 @@ func TestCommit_Submodule(t *testing.T) { } assert.Equal(t, "gogs/docs-api", mod.Name) assert.Equal(t, "https://github.com/gogs/docs-api.git", mod.URL) - assert.Equal(t, "6b08f76a5313fa3d26859515b30aa17a5faa2807", mod.Commit) + assert.Equal(t, submoduleSHA.String(), mod.Commit) _, err = c.Submodule(ctx, "404") assert.Equal(t, ErrSubmoduleNotExist, err) diff --git a/commit_test.go b/commit_test.go index 3a752451d..87fb3dce1 100644 --- a/commit_test.go +++ b/commit_test.go @@ -9,12 +9,12 @@ import ( func TestCommit(t *testing.T) { ctx := context.Background() - c, err := testrepo.CatFileCommit(ctx, "435ffceb7ba576c937e922766e37d4f7abdcc122") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[22].String()) if err != nil { t.Fatal(err) } t.Run("ID", func(t *testing.T) { - assert.Equal(t, "435ffceb7ba576c937e922766e37d4f7abdcc122", c.ID.String()) + assert.Equal(t, testrepoMarks[22].String(), c.ID.String()) }) t.Run("Summary", func(t *testing.T) { @@ -24,7 +24,7 @@ func TestCommit(t *testing.T) { func TestCommit_Parent(t *testing.T) { ctx := context.Background() - c, err := testrepo.CatFileCommit(ctx, "435ffceb7ba576c937e922766e37d4f7abdcc122") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[22].String()) if err != nil { t.Fatal(err) } @@ -45,11 +45,11 @@ func TestCommit_Parent(t *testing.T) { }{ { n: 0, - expParentID: "a13dba1e469944772490909daa58c53ac8fa4b0d", + expParentID: testrepoMarks[20].String(), }, { n: 1, - expParentID: "7c5ee6478d137417ae602140c615e33aed91887c", + expParentID: testrepoMarks[21].String(), }, } for _, test := range tests { @@ -72,18 +72,18 @@ func TestCommit_CommitByPath(t *testing.T) { expCommitID string }{ { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), opt: CommitByRevisionOptions{ Path: "", // No path gets back to the commit itself }, - expCommitID: "2a52e96389d02209b451ae1ddf45d645b42d744c", + expCommitID: testrepoMarks[12].String(), }, { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), opt: CommitByRevisionOptions{ Path: "resources/labels.properties", }, - expCommitID: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + expCommitID: testrepoMarks[1].String(), }, } for _, test := range tests { @@ -115,7 +115,7 @@ func commitsToIDs(commits []*Commit) []string { func TestCommit_CommitsByPage(t *testing.T) { ctx := context.Background() // There are at most 5 commits can be used for pagination before this commit. - c, err := testrepo.CatFileCommit(ctx, "f5ed01959cffa4758ca0a49bf4c34b138d7eab0a") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[5].String()) if err != nil { t.Fatal(err) } @@ -130,31 +130,31 @@ func TestCommit_CommitsByPage(t *testing.T) { page: 0, size: 2, expCommitIDs: []string{ - "f5ed01959cffa4758ca0a49bf4c34b138d7eab0a", - "9cdb160ee4118035bf73c744e3bf72a1ba16484a", + testrepoMarks[5].String(), + testrepoMarks[4].String(), }, }, { page: 1, size: 2, expCommitIDs: []string{ - "f5ed01959cffa4758ca0a49bf4c34b138d7eab0a", - "9cdb160ee4118035bf73c744e3bf72a1ba16484a", + testrepoMarks[5].String(), + testrepoMarks[4].String(), }, }, { page: 2, size: 2, expCommitIDs: []string{ - "dc64fe4ab8618a5be491a9fca46f1585585ea44e", - "32c273781bab599b955ce7c59d92c39bedf35db0", + testrepoMarks[3].String(), + testrepoMarks[2].String(), }, }, { page: 3, size: 2, expCommitIDs: []string{ - "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + testrepoMarks[1].String(), }, }, { @@ -170,7 +170,7 @@ func TestCommit_CommitsByPage(t *testing.T) { Path: "src", }, expCommitIDs: []string{ - "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + testrepoMarks[1].String(), }, }, } @@ -195,79 +195,79 @@ func TestCommit_SearchCommits(t *testing.T) { expCommitIDs []string }{ { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), pattern: "", expCommitIDs: []string{ - "2a52e96389d02209b451ae1ddf45d645b42d744c", - "57d0bf61e57cdacb309ebd1075257c6bd7e1da81", - "cb2d322bee073327e058143329d200024bd6b4c6", - "818f033c4ae7f26b2b29e904942fa79a5ccaadd0", - "369adba006a1bbf25e957a8622d2b919c994d035", - "2956e1d20897bf6ed509f6429d7f64bc4823fe33", - "333fd9bc94084c3e07e092e2bc9c22bab4476439", - "f5ed01959cffa4758ca0a49bf4c34b138d7eab0a", - "9cdb160ee4118035bf73c744e3bf72a1ba16484a", - "dc64fe4ab8618a5be491a9fca46f1585585ea44e", - "32c273781bab599b955ce7c59d92c39bedf35db0", - "755fd577edcfd9209d0ac072eed3b022cbe4d39b", - }, - }, - { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + testrepoMarks[12].String(), + testrepoMarks[11].String(), + testrepoMarks[10].String(), + testrepoMarks[9].String(), + testrepoMarks[8].String(), + testrepoMarks[7].String(), + testrepoMarks[6].String(), + testrepoMarks[5].String(), + testrepoMarks[4].String(), + testrepoMarks[3].String(), + testrepoMarks[2].String(), + testrepoMarks[1].String(), + }, + }, + { + id: testrepoMarks[12].String(), pattern: "", opt: SearchCommitsOptions{ MaxCount: 3, }, expCommitIDs: []string{ - "2a52e96389d02209b451ae1ddf45d645b42d744c", - "57d0bf61e57cdacb309ebd1075257c6bd7e1da81", - "cb2d322bee073327e058143329d200024bd6b4c6", + testrepoMarks[12].String(), + testrepoMarks[11].String(), + testrepoMarks[10].String(), }, }, { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), pattern: "feature", expCommitIDs: []string{ - "2a52e96389d02209b451ae1ddf45d645b42d744c", - "cb2d322bee073327e058143329d200024bd6b4c6", + testrepoMarks[12].String(), + testrepoMarks[10].String(), }, }, { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), pattern: "feature", opt: SearchCommitsOptions{ MaxCount: 1, }, expCommitIDs: []string{ - "2a52e96389d02209b451ae1ddf45d645b42d744c", + testrepoMarks[12].String(), }, }, { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), pattern: "add.*", opt: SearchCommitsOptions{ Path: "src", }, expCommitIDs: []string{ - "cb2d322bee073327e058143329d200024bd6b4c6", - "818f033c4ae7f26b2b29e904942fa79a5ccaadd0", - "333fd9bc94084c3e07e092e2bc9c22bab4476439", - "32c273781bab599b955ce7c59d92c39bedf35db0", - "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + testrepoMarks[10].String(), + testrepoMarks[9].String(), + testrepoMarks[6].String(), + testrepoMarks[2].String(), + testrepoMarks[1].String(), }, }, { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), pattern: "add.*", opt: SearchCommitsOptions{ MaxCount: 2, Path: "src", }, expCommitIDs: []string{ - "cb2d322bee073327e058143329d200024bd6b4c6", - "818f033c4ae7f26b2b29e904942fa79a5ccaadd0", + testrepoMarks[10].String(), + testrepoMarks[9].String(), }, }, } @@ -296,7 +296,7 @@ func TestCommit_ShowNameStatus(t *testing.T) { expStatus *NameStatus }{ { - id: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + id: testrepoMarks[1].String(), expStatus: &NameStatus{ Added: []string{ "README.txt", @@ -306,7 +306,7 @@ func TestCommit_ShowNameStatus(t *testing.T) { }, }, { - id: "32c273781bab599b955ce7c59d92c39bedf35db0", + id: testrepoMarks[2].String(), expStatus: &NameStatus{ Modified: []string{ "src/Main.groovy", @@ -314,7 +314,7 @@ func TestCommit_ShowNameStatus(t *testing.T) { }, }, { - id: "dc64fe4ab8618a5be491a9fca46f1585585ea44e", + id: testrepoMarks[3].String(), expStatus: &NameStatus{ Added: []string{ "src/Square.groovy", @@ -325,7 +325,7 @@ func TestCommit_ShowNameStatus(t *testing.T) { }, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + id: testrepoMarks[27].String(), expStatus: &NameStatus{ Removed: []string{ "fix.txt", @@ -358,27 +358,27 @@ func TestCommit_CommitsCount(t *testing.T) { expCount int64 }{ { - id: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + id: testrepoMarks[1].String(), expCount: 1, }, { - id: "f5ed01959cffa4758ca0a49bf4c34b138d7eab0a", + id: testrepoMarks[5].String(), expCount: 5, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + id: testrepoMarks[27].String(), expCount: 27, }, { - id: "7c5ee6478d137417ae602140c615e33aed91887c", + id: testrepoMarks[21].String(), opt: RevListCountOptions{ Path: "README.txt", }, expCount: 3, }, { - id: "7c5ee6478d137417ae602140c615e33aed91887c", + id: testrepoMarks[21].String(), opt: RevListCountOptions{ Path: "resources", }, @@ -411,27 +411,27 @@ func TestCommit_FilesChangedAfter(t *testing.T) { expFiles []string }{ { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "ef7bebf8bdb1919d947afe46ab4b2fb4278039b3", + id: testrepoMarks[27].String(), + after: testrepoMarks[26].String(), expFiles: []string{"fix.txt"}, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "45a30ea9afa413e226ca8614179c011d545ca883", + id: testrepoMarks[27].String(), + after: testrepoMarks[24].String(), expFiles: []string{"fix.txt", "pom.xml", "src/test/java/com/github/AppTest.java"}, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "45a30ea9afa413e226ca8614179c011d545ca883", + id: testrepoMarks[27].String(), + after: testrepoMarks[24].String(), opt: DiffNameOnlyOptions{ Path: "src", }, expFiles: []string{"src/test/java/com/github/AppTest.java"}, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "45a30ea9afa413e226ca8614179c011d545ca883", + id: testrepoMarks[27].String(), + after: testrepoMarks[24].String(), opt: DiffNameOnlyOptions{ Path: "resources", }, @@ -464,22 +464,22 @@ func TestCommit_CommitsAfter(t *testing.T) { expCommitIDs []string }{ { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "45a30ea9afa413e226ca8614179c011d545ca883", + id: testrepoMarks[27].String(), + after: testrepoMarks[24].String(), expCommitIDs: []string{ - "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - "ef7bebf8bdb1919d947afe46ab4b2fb4278039b3", - "ebbbf773431ba07510251bb03f9525c7bab2b13a", + testrepoMarks[27].String(), + testrepoMarks[26].String(), + testrepoMarks[25].String(), }, }, { - id: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - after: "45a30ea9afa413e226ca8614179c011d545ca883", + id: testrepoMarks[27].String(), + after: testrepoMarks[24].String(), opt: RevListOptions{ Path: "src", }, expCommitIDs: []string{ - "ebbbf773431ba07510251bb03f9525c7bab2b13a", + testrepoMarks[25].String(), }, }, } @@ -508,18 +508,18 @@ func TestCommit_Ancestors(t *testing.T) { expCommitIDs []string }{ { - id: "2a52e96389d02209b451ae1ddf45d645b42d744c", + id: testrepoMarks[12].String(), opt: LogOptions{ MaxCount: 3, }, expCommitIDs: []string{ - "57d0bf61e57cdacb309ebd1075257c6bd7e1da81", - "cb2d322bee073327e058143329d200024bd6b4c6", - "818f033c4ae7f26b2b29e904942fa79a5ccaadd0", + testrepoMarks[11].String(), + testrepoMarks[10].String(), + testrepoMarks[9].String(), }, }, { - id: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + id: testrepoMarks[1].String(), expCommitIDs: []string{}, }, } @@ -544,7 +544,7 @@ func TestCommit_IsImageFile(t *testing.T) { ctx := context.Background() t.Run("not a blob", func(t *testing.T) { - c, err := testrepo.CatFileCommit(ctx, "4e59b72440188e7c2578299fc28ea425fbe9aece") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[29].String()) if err != nil { t.Fatal(err) } @@ -562,12 +562,12 @@ func TestCommit_IsImageFile(t *testing.T) { expVal bool }{ { - id: "4eaa8d4b05e731e950e2eaf9e8b92f522303ab41", + id: testrepoMarks[28].String(), name: "README.txt", expVal: false, }, { - id: "4eaa8d4b05e731e950e2eaf9e8b92f522303ab41", + id: testrepoMarks[28].String(), name: "img/sourcegraph.png", expVal: true, }, @@ -593,12 +593,12 @@ func TestCommit_IsImageFileByIndex(t *testing.T) { ctx := context.Background() t.Run("not a blob", func(t *testing.T) { - c, err := testrepo.CatFileCommit(ctx, "4e59b72440188e7c2578299fc28ea425fbe9aece") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[29].String()) if err != nil { t.Fatal(err) } - isImage, err := c.IsImageFileByIndex(ctx, "fcf7087e732bfe3c25328248a9bf8c3ccd85bed4") // "gogs" + isImage, err := c.IsImageFileByIndex(ctx, testrepoMarks[40].String()) // "gogs" if err != nil { t.Fatal(err) } @@ -611,13 +611,13 @@ func TestCommit_IsImageFileByIndex(t *testing.T) { expVal bool }{ { - id: "4eaa8d4b05e731e950e2eaf9e8b92f522303ab41", - index: "adfd6da3c0a3fb038393144becbf37f14f780087", // "README.txt" + id: testrepoMarks[28].String(), + index: testrepoMarks[39].String(), // "README.txt" expVal: false, }, { - id: "4eaa8d4b05e731e950e2eaf9e8b92f522303ab41", - index: "2ce918888b0fdd4736767360fc5e3e83daf47fce", // "img/sourcegraph.png" + id: testrepoMarks[28].String(), + index: testrepoMarks[49].String(), // "img/sourcegraph.png" expVal: true, }, } diff --git a/diff.go b/diff.go index 8b339c09e..657a21215 100644 --- a/diff.go +++ b/diff.go @@ -102,10 +102,10 @@ type DiffFile struct { Name string // The type of the file. Type DiffFileType - // The index (SHA1 hash) of the file. For a changed/new file, it is the new SHA, + // The index (SHA1 or SHA256 hash) of the file. For a changed/new file, it is the new SHA, // and for a deleted file it becomes "000000". Index string - // OldIndex is the old index (SHA1 hash) of the file. + // OldIndex is the old index (SHA1 or SHA256 hash) of the file. OldIndex string // The sections in the file. Sections []*DiffSection diff --git a/git_sha1_test.go b/git_sha1_test.go new file mode 100644 index 000000000..78b22d4ef --- /dev/null +++ b/git_sha1_test.go @@ -0,0 +1,94 @@ +//go:build !test_sha256 + +package git + +import ( + "context" + stdlog "log" +) + +var ( + testrepoMarks = map[int64]Oid{ + // Commits, generated by `git rev-list --all | tac` + 1: MustIDFromString("755fd577edcfd9209d0ac072eed3b022cbe4d39b"), + 2: MustIDFromString("32c273781bab599b955ce7c59d92c39bedf35db0"), + 3: MustIDFromString("dc64fe4ab8618a5be491a9fca46f1585585ea44e"), + 4: MustIDFromString("9cdb160ee4118035bf73c744e3bf72a1ba16484a"), + 5: MustIDFromString("f5ed01959cffa4758ca0a49bf4c34b138d7eab0a"), + 6: MustIDFromString("333fd9bc94084c3e07e092e2bc9c22bab4476439"), + 7: MustIDFromString("2956e1d20897bf6ed509f6429d7f64bc4823fe33"), + 8: MustIDFromString("369adba006a1bbf25e957a8622d2b919c994d035"), + 9: MustIDFromString("818f033c4ae7f26b2b29e904942fa79a5ccaadd0"), + 10: MustIDFromString("cb2d322bee073327e058143329d200024bd6b4c6"), + 11: MustIDFromString("57d0bf61e57cdacb309ebd1075257c6bd7e1da81"), + 12: MustIDFromString("2a52e96389d02209b451ae1ddf45d645b42d744c"), + 13: MustIDFromString("8d2636da55da593c421e1cb09eea502a05556a69"), + 14: MustIDFromString("e83ece763cc9d036715c30c8cb0da93b9d480d86"), + 15: MustIDFromString("bf7a9a5ee025edee0e610bd7ba23c0704b53c6db"), + 16: MustIDFromString("d2280d000c84f1e595e4dec435ae6c1e6c245367"), + 17: MustIDFromString("c59479302142d79e46f84d11438a41b39ba51a1f"), + 18: MustIDFromString("78f4771957ffcd015caf609a1721f0fb8ba18cb6"), + 19: MustIDFromString("8d80474ffc3747e3375651cc2a0032c8599befd3"), + 20: MustIDFromString("a13dba1e469944772490909daa58c53ac8fa4b0d"), + 21: MustIDFromString("7c5ee6478d137417ae602140c615e33aed91887c"), + 22: MustIDFromString("435ffceb7ba576c937e922766e37d4f7abdcc122"), + 23: MustIDFromString("9805760644754c38d10a9f1522a54a4bdc00fa8a"), + 24: MustIDFromString("45a30ea9afa413e226ca8614179c011d545ca883"), + 25: MustIDFromString("ebbbf773431ba07510251bb03f9525c7bab2b13a"), + 26: MustIDFromString("ef7bebf8bdb1919d947afe46ab4b2fb4278039b3"), + 27: MustIDFromString("978fb7f6388b49b532fbef8b856681cfa6fcaa0a"), + 28: MustIDFromString("4eaa8d4b05e731e950e2eaf9e8b92f522303ab41"), + 29: MustIDFromString("4e59b72440188e7c2578299fc28ea425fbe9aece"), + 30: MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe"), + 31: MustIDFromString("d58e3ef9f123eea6857161c79275ee22b228f659"), + 32: MustIDFromString("cfc3b2993f74726356887a5ec093de50486dc617"), + + 34: MustIDFromString("021a721a61a1de65865542c405796d1eb985f784"), // blob HEAD:.DS_Store + 35: MustIDFromString("412eeda78dc9de1186c2e0e1526764af82ab3431"), // blob HEAD:.gitattributes + 36: MustIDFromString("7c820833a9ad5fbfc96efd533d55f5edc65dc977"), // blob HEAD:.gitignore + 37: MustIDFromString("6abde17f49a6d43df40366e57d8964fee0dfda11"), // blob HEAD:.gitmodules + 38: MustIDFromString("17eccd68b7cafa718d53c8b4db666194646e2bd9"), // blob HEAD:.travis.yml + 39: MustIDFromString("adfd6da3c0a3fb038393144becbf37f14f780087"), // blob HEAD:README.txt + 40: MustIDFromString("6058be211566308428ca6dcab3f08cf270cd9568"), // blob HEAD:build.gradle + 41: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), // tree HEAD:gogs + 42: MustIDFromString("a41a5a6cfd2d5ec3c0c1101e7cc05c9dedc3e11d"), // tree HEAD:img + 43: MustIDFromString("99975710477a65b89233b2d12bf60f7c0ffc1f5c"), // blob HEAD:pom.xml + 44: MustIDFromString("aaa0af6b82db99c660b169962524e2201ac7079c"), // tree HEAD:resource + 45: MustIDFromString("fb4bd4ec9220ed4fe0d9526d1b77147490ce8842"), // blob HEAD:run.sh + 46: MustIDFromString("c53e5f83ee07637b9383b412547d0b2f9e261f8d"), // tree HEAD:sameSHAs + 47: MustIDFromString("007cb92318c7bd3b56908ea8c2e54370245562f8"), // tree HEAD:src + 48: MustIDFromString("e0e63473c2593040d7d1c67637864821b28cef4b"), // blob HEAD:symlink.run.sh + 49: MustIDFromString("2ce918888b0fdd4736767360fc5e3e83daf47fce"), // blob HEAD:img/sourcegraph.png + + 50: MustIDFromString("b39c8508bbc4b00ad2e24d358012ea123bcafd8d"), // tag v1.1.0 + + 51: MustIDFromString("1e24b564bf2298965d8037af42d3ae15ad7d225a"), // blob 755fd57:README.txt + 52: MustIDFromString("fbdcfef007c0c09061199e687087b18c3cf8e083"), // blob 755fd57:resources/labels.properties + 53: MustIDFromString("51680791956b43effdb2f16bccd2b4752d66078f"), // blob 755fd57:src/Main.groovy + 54: MustIDFromString("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"), // blob ef7bebf:fix.txt + } + submoduleSHA = MustIDFromString("6b08f76a5313fa3d26859515b30aa17a5faa2807") +) + +const ( + repoPath = "testdata/testrepo.git" + testrepoObjectFormat = ObjectFormatSHA1 + testEmptyShaID = EmptySha1ID +) + +func initTestRepo() { + ctx := context.Background() + // Set up the test repository + if !isExist(repoPath) { + if err := Clone(ctx, "https://github.com/gogs/git-module-testrepo.git", repoPath, CloneOptions{ + Bare: true, + }); err != nil { + stdlog.Fatal(err) + } + } + var err error + testrepo, err = Open(repoPath) + if err != nil { + stdlog.Fatal(err) + } +} diff --git a/git_sha256_test.go b/git_sha256_test.go new file mode 100644 index 000000000..eb009b5e7 --- /dev/null +++ b/git_sha256_test.go @@ -0,0 +1,169 @@ +//go:build test_sha256 + +package git + +import ( + "bytes" + "context" + "fmt" + stdlog "log" + "os" +) + +var ( + testrepoMarks = map[int64]Oid{ + // Commits, generated by `git rev-list --all | tac` + 1: MustIDFromString("31a3d8bb18edda3252f7242035d4695ee9b8ddbd47d7c62f656756442c2e85af"), + 2: MustIDFromString("a1a482f1f2fa00c70e892a0ecc49c0ef0295eb7f6bf96b51a7dd32e40c54e92e"), + 3: MustIDFromString("8573f82fa6f1b1f3a74bd5df5a7e68db9477911cda33dc624cfd07cecccf6fe2"), + 4: MustIDFromString("c41b25357f8e259ba78791a01a2dce80a677061d7474e7c35ff290d4527d9a49"), + 5: MustIDFromString("5402a2cd6d628b46225e4fa5be0d854711472237d121ead1581fca4b3c8d0633"), + 6: MustIDFromString("44f45f65f43901e58282d2861eb4661e1fa8f33ef156e0e340a599c306d73828"), + 7: MustIDFromString("8e892031b84c4bf15314c3f7173549e0874442db76f429568f1fa55b49a1cfc0"), + 8: MustIDFromString("a3e5aa80d28fae8260994aba69cb80ad442fdcb3b3971307b3383f92f81842a5"), + 9: MustIDFromString("f812c295641e30395a5e02b05bbd18763335bd8867f5e7bdcf5510dbd6144b75"), + 10: MustIDFromString("a0e41bd21586bc939b7d7400c2066bb627fca7a2cbbe17a167ed03db1a9182bc"), + 11: MustIDFromString("206a8d713b97b4695e4f23e5660fd37b87d33c952965111e42f077cb44dbda93"), + 12: MustIDFromString("701cdc22435b22d31974188a4ba4a3f42746f57e7564761a98a65ff4de67f9b0"), + 13: MustIDFromString("8e32744b5ec628e9397d39fef23ed89b6465042945630e352028063307813725"), + 14: MustIDFromString("74f4d668782edc5276954505f6d2a954eda5b61dde2395d387e2a025ac070e88"), + 15: MustIDFromString("6a652d215eb60f2b319da986145810246a4fb4ff903cfc66710aeb66ae9c2a79"), + 16: MustIDFromString("772c8079c93111471b91b01ac22626677d1baefdc83c9646f1f482d149316edd"), + 17: MustIDFromString("74fec01c00c1863972cb13bfa3ed2acf8d46ded93fb97ac7290df68bd0198864"), + 18: MustIDFromString("d925b2b2d0778452a00c3d1d5b94a7cc3b2c540dc87219cfe5b292ea3877ed8f"), + 19: MustIDFromString("ff7369e546af022289c553b7c825c6934a4b6aa8d44d5d2408e8bba44725527b"), + 20: MustIDFromString("7a7e4c3508b5723d61b982e049655eca96350e1df1c5efe04a8caf6a50c0ecd0"), + 21: MustIDFromString("716c81cf2828bc20c3ae95ce73bbb978c503c400939800adf432efcea221b7cb"), + 22: MustIDFromString("1eb65ce7570a6249d955c477ccdcd1e8142d3e8696f2268a65c5aafafe2d7708"), + 23: MustIDFromString("629328565e5fa5ff0e5cd6e1d62d68f068cacfdca5a1cf6d957abbcc40e68c5f"), + 24: MustIDFromString("cda497d4c0d261045789f123ec274cd662384fb847e8f0a82fe93016546045a1"), + 25: MustIDFromString("de231aea47c5095ff5257fb9af8aebf260b48d07a1e84749cf3554a4e3ebd9a9"), + 26: MustIDFromString("489afb570dc4cc091f55bcbbea564171a54563b09272ec807b886916707d1f02"), + 27: MustIDFromString("3127f6e5e4e530dde76e8e3357ae37310c6c1fc2ab07194df2622c456160594c"), + 28: MustIDFromString("e814f101e4c215abaec1b2f42496c4012079c1f2d02519a8d389e8973e34c74a"), + 29: MustIDFromString("95a36dbd75ae6c85054678688660a5849c043d1c21b39cefbc1d6f87d93a5dd2"), + 30: MustIDFromString("d4043c6c6c5b313187a7ccfc0bc8f17dbe725374aa03a81bd6b49994e33f77bd"), + 31: MustIDFromString("e8983d273da9a8236d8566fdbf83a34499b2d5e89e5e60d8b3537d6cd1946026"), + 32: MustIDFromString("949e74b2fd94b95da3492e613656fc7fda5f7a6e82184ea291a89bd2b028dd2e"), + + 34: MustIDFromString("6ee5b1e01c3084acd459c41a9aad860bda0a0a83b23e93fa3b8e67262acaed22"), // blob HEAD:.DS_Store + 35: MustIDFromString("4fe5cee2cdd0d2a7995f10ab9f7b2b09d061b62028a51653a61948adb4434dc8"), // blob HEAD:.gitattributes + 36: MustIDFromString("db1173e5dbc280c588ac18c12461db62cf09485299984c08c0b532b0d63ceab0"), // blob HEAD:.gitignore + 37: MustIDFromString("2523f972d932f186489bb4cd9746f65c72a34ff4210b80cd6c09c9865a08ad95"), // blob HEAD:.gitmodules + 38: MustIDFromString("4f015a6e9501b585b7823f588bae41ec901354bafe30a8fe9f82160099c5c584"), // blob HEAD:.travis.yml + 39: MustIDFromString("dd66873b93ef9e7f3909bb919f45bbd91540d85ea171043f21b4f0d830e404bb"), // blob HEAD:README.txt + 40: MustIDFromString("ef9d169adc6eda7180040708d8a888d2726f8429e08235a0a6f992c2737c1d17"), // blob HEAD:build.gradle + 41: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), // tree HEAD:gogs + 42: MustIDFromString("ccfb232c491a6ba1cebce68dab2a9c3f4b79018ea45442dad99c281f52227807"), // tree HEAD:img + 43: MustIDFromString("a8e75d30f8ae30c37d91c14753f723b3b232e4293d9cc446c90c11570aee410e"), // blob HEAD:pom.xml + 44: MustIDFromString("a3291603bebc8a2b8d354e2fea44a3e093ff6b9f0171333a26ce8d56b8f6652c"), // tree HEAD:resource + 45: MustIDFromString("20f59dd73b24e3dc47f2bcf20d5d827095f1cea9778023e37b5d5d7cb36b9232"), // blob HEAD:run.sh + 46: MustIDFromString("5ea265eb087b456525021721cc2d33b005c998b5c8908b1d0122f118bb53bc9a"), // tree HEAD:sameSHAs + 47: MustIDFromString("e98f5bc0b76add753e2d330fb2974e596bdf8b96111237ebc204c4fe0280bc89"), // tree HEAD:src + 48: MustIDFromString("fdd5f856ccd57ffc0dc86a02c3d55863d078bb901c2b72353a20dc399f932536"), // blob HEAD:symlink.run.sh + 49: MustIDFromString("dae65197c87793004ef9f0bc2fac54aa4f74cf57e8bb11a274e06cce3d50fd50"), // blob HEAD:img/sourcegraph.png + + 50: MustIDFromString("264607f7e6128c06d1bab93857dbaf10c1ad98cd98ade780a9adcfd388774056"), // tag v1.1.0 + + 51: MustIDFromString("6d86d830e90b4801ac5130275272cf9c047998a63a082d6afe3adead7527495a"), // blob 31a3d8b:README.txt + 52: MustIDFromString("93324ee06704d200656b2bc0ddd75c4262965a2ab2b7e151aece2cf692960678"), // blob 31a3d8b:resources/labels.properties + 53: MustIDFromString("a4de9b44e29e16ecb7fa9d1de3cc59216fdcde0fa36e193cf9e0e629e22d1815"), // blob 31a3d8b:src/Main.groovy + 54: MustIDFromString("473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"), // blob 489afb5:fix.txt + } + submoduleSHA = MustIDFromString("8fa8e7ed491f06aa84c52730587547852f91e8d1b0b9105660209f253edd2c41") +) + +const ( + repoPath = "testdata/testrepo-sha256.git" + testrepoObjectFormat = ObjectFormatSHA256 + testEmptyShaID = EmptySha256ID +) + +func initTestRepo() { + ctx := context.Background() + + // Set up the test repository + if !isExist(repoPath) { + sha1RepoPath := tempPath() + if err := Clone(ctx, "https://github.com/gogs/git-module-testrepo.git", sha1RepoPath, CloneOptions{ + Bare: true, + }); err != nil { + stdlog.Fatal(err) + } + defer os.RemoveAll(sha1RepoPath) + sha1Repo, err := Open(sha1RepoPath) + if err != nil { + stdlog.Fatal(err) + } + err = Init(ctx, repoPath, InitOptions{Bare: true, ObjectFormat: "sha256"}) + if err != nil { + stdlog.Fatal(err) + } + sha256Repo, err := Open(repoPath) + if err != nil { + stdlog.Fatal(err) + } + + data, err := fastExport(ctx, sha1Repo) + if err != nil { + stdlog.Fatal(err) + } + err = fastImport(ctx, sha256Repo, data, map[string]map[string]string{ + "gogs/docs-api": { + "6b08f76a5313fa3d26859515b30aa17a5faa2807": "8fa8e7ed491f06aa84c52730587547852f91e8d1b0b9105660209f253edd2c41", + }, + }) + + if err != nil { + os.RemoveAll(repoPath) + stdlog.Fatal(err) + } + } + var err error + testrepo, err = Open(repoPath) + if err != nil { + stdlog.Fatal(err) + } +} + +func fastExport(ctx context.Context, repo *Repository) ([]byte, error) { + return exec(ctx, repo.path, []string{"fast-export", "--all"}, nil) +} + +func fastImport(ctx context.Context, repo *Repository, data []byte, submoduleRewrite map[string]map[string]string) error { + args := []string{"fast-import"} + + for submodule, hashes := range submoduleRewrite { + frompath := tempPath() + fromfile, err := os.Create(frompath) + if err != nil { + return err + } + defer os.Remove(frompath) + topath := tempPath() + tofile, err := os.Create(topath) + if err != nil { + fromfile.Close() + return err + } + defer os.Remove(topath) + + markIndex := 0 + for from, to := range hashes { + markIndex += 1 + fmt.Fprintf(fromfile, ":%d %s\n", markIndex, from) + fmt.Fprintf(tofile, ":%d %s\n", markIndex, to) + } + fromfile.Close() + tofile.Close() + + args = append(args, + fmt.Sprintf("--rewrite-submodules-from=%s:%s", submodule, frompath), + fmt.Sprintf("--rewrite-submodules-to=%s:%s", submodule, topath)) + } + + c, cancel := cmd(ctx, repo.path, args, nil) + defer cancel() + c.Input(bytes.NewReader(data)) + return c.Run().Wait() +} diff --git a/git_test.go b/git_test.go index 165f64e81..89d6b4502 100644 --- a/git_test.go +++ b/git_test.go @@ -2,17 +2,13 @@ package git import ( "bytes" - "context" "flag" - stdlog "log" "os" "testing" "github.com/stretchr/testify/assert" ) -const repoPath = "testdata/testrepo.git" - var testrepo *Repository func TestMain(m *testing.M) { @@ -22,22 +18,7 @@ func TestMain(m *testing.M) { SetOutput(os.Stdout) } - ctx := context.Background() - - // Set up the test repository - if !isExist(repoPath) { - if err := Clone(ctx, "https://github.com/gogs/git-module-testrepo.git", repoPath, CloneOptions{ - Bare: true, - }); err != nil { - stdlog.Fatal(err) - } - } - - var err error - testrepo, err = Open(repoPath) - if err != nil { - stdlog.Fatal(err) - } + initTestRepo() os.Exit(m.Run()) } diff --git a/hook.go b/hook.go index 0c602f8b3..718380607 100644 --- a/hook.go +++ b/hook.go @@ -51,7 +51,7 @@ fi HookUpdate: `#!/bin/sh # # An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# Called by "git receive-pack" with arguments: refname oid-old oid-new # # To enable this hook, rename this file to "update". # diff --git a/oid.go b/oid.go new file mode 100644 index 000000000..8fd2cf610 --- /dev/null +++ b/oid.go @@ -0,0 +1,150 @@ +package git + +import ( + "encoding/hex" + "errors" + "strings" + "sync" +) + +const ( + // EmptySha1ID is an ID with empty SHA-1 hash. + EmptySha1ID = "0000000000000000000000000000000000000000" + // EmptySha256ID is an ID with empty SHA-256 hash. + EmptySha256ID = "0000000000000000000000000000000000000000000000000000000000000000" +) + +// Oid is the id of a Git object +type Oid interface { + Equal(interface{}) bool + String() string + Bytes() []byte +} + +// SHA1 is the SHA-1 hash of a Git object. +type SHA1 struct { + bytes [20]byte + + str string + strOnce sync.Once +} + +// Equal returns true if s2 has the same SHA1 as s. It supports +// 40-length-string, []byte, and SHA1. +func (s *SHA1) Equal(s2 interface{}) bool { + switch v := s2.(type) { + case string: + return v == s.String() + case [20]byte: + return v == s.bytes + case *SHA1: + return v.bytes == s.bytes + } + return false +} + +// String returns string (hex) representation of the SHA1. +func (s *SHA1) String() string { + s.strOnce.Do(func() { + result := make([]byte, 0, 40) + hexvalues := []byte("0123456789abcdef") + for i := 0; i < 20; i++ { + result = append(result, hexvalues[s.bytes[i]>>4]) + result = append(result, hexvalues[s.bytes[i]&0xf]) + } + s.str = string(result) + }) + return s.str +} + +// Bytes returns bytes (length 20) representation of the SHA1. +func (s *SHA1) Bytes() []byte { + return s.bytes[:] +} + +// SHA256 is the SHA-256 hash of a Git object. +type SHA256 struct { + bytes [32]byte + + str string + strOnce sync.Once +} + +// Equal returns true if s2 has the same SHA256 as s. It supports +// 64-length-string, []byte, and SHA256. +func (s *SHA256) Equal(s2 interface{}) bool { + switch v := s2.(type) { + case string: + return v == s.String() + case [32]byte: + return v == s.bytes + case *SHA256: + return v.bytes == s.bytes + } + return false + +} + +// String returns string (hex) representation of the SHA256. +func (s *SHA256) String() string { + s.strOnce.Do(func() { + result := make([]byte, 0, 64) + hexvalues := []byte("0123456789abcdef") + for i := 0; i < 32; i++ { + result = append(result, hexvalues[s.bytes[i]>>4]) + result = append(result, hexvalues[s.bytes[i]&0xf]) + } + s.str = string(result) + }) + return s.str +} + +// Bytes returns bytes (length 32) representation of the SHA256. +func (s *SHA256) Bytes() []byte { + return s.bytes[:] +} + +// MustID always returns a new Oid from a [20]byte or [32]byte array with no validation of input. +func MustID(b []byte) Oid { + if len(b) < 32 { + var id SHA1 + for i := 0; i < 20; i++ { + id.bytes[i] = b[i] + } + return &id + } else { + var id SHA256 + for i := 0; i < 32; i++ { + id.bytes[i] = b[i] + } + return &id + } +} + +// NewID returns a new Oid from a [20]byte or [32]byte array. +func NewID(b []byte) (Oid, error) { + if len(b) != 20 && len(b) != 32 { + return nil, errors.New("length must be 20 or 32") + } + return MustID(b), nil +} + +// MustIDFromString always returns a new sha from a ID with no validation of +// input. +func MustIDFromString(s string) Oid { + b, _ := hex.DecodeString(s) + return MustID(b) +} + +// NewIDFromString returns a new Oid from a ID string of length 40 or 64. +func NewIDFromString(s string) (Oid, error) { + s = strings.TrimSpace(s) + if len(s) != 40 && len(s) != 64 { + return nil, errors.New("length must be 40 or 64") + } + b, err := hex.DecodeString(s) + if err != nil { + return nil, err + } + return NewID(b) +} diff --git a/oid_test.go b/oid_test.go new file mode 100644 index 000000000..416228dd6 --- /dev/null +++ b/oid_test.go @@ -0,0 +1,107 @@ +package git + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestOid_Equal(t *testing.T) { + tests := []struct { + s1 Oid + s2 interface{} + expVal bool + }{ + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: "fcf7087e732bfe3c25328248a9bf8c3ccd85bed4", + expVal: true, + }, { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: EmptySha1ID, + expVal: false, + }, + + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4").(*SHA1).bytes, + expVal: true, + }, + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: MustIDFromString(EmptySha1ID).(*SHA1).bytes, + expVal: false, + }, + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + expVal: true, + }, + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: MustIDFromString(EmptySha1ID), + expVal: false, + }, + + { + s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + s2: []byte(EmptySha1ID), + expVal: false, + }, + + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: "ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e", + expVal: true, + }, + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: EmptySha256ID, + expVal: false, + }, + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e").(*SHA256).bytes, + expVal: true, + }, + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: MustIDFromString(EmptySha256ID).(*SHA256).bytes, + expVal: false, + }, + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + expVal: true, + }, + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: []byte(EmptySha256ID), + expVal: false, + }, + + { + s1: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7bb5581a8918b7885abb7888e"), + s2: MustIDFromString("ba2cc18e595b5f70a47cea3ed71f3568addd55e7"), + expVal: false, + }, + } + for _, test := range tests { + t.Run("", func(t *testing.T) { + assert.Equal(t, test.expVal, test.s1.Equal(test.s2)) + }) + } +} + +func TestNewID(t *testing.T) { + sha, err := NewID([]byte("000000")) + assert.Equal(t, errors.New("length must be 20 or 32"), err) + assert.Nil(t, sha) +} + +func TestNewIDFromString(t *testing.T) { + sha, err := NewIDFromString("000000") + assert.Equal(t, errors.New("length must be 40 or 64"), err) + assert.Nil(t, sha) +} diff --git a/repo.go b/repo.go index 140ece359..d060f6232 100644 --- a/repo.go +++ b/repo.go @@ -13,13 +13,26 @@ import ( "strings" ) +// ObjectFormat represent the hash algorithm of a Git repository +type ObjectFormat string + +const ( + ObjectFormatSHA1 ObjectFormat = "sha1" + ObjectFormatSHA256 ObjectFormat = "sha256" +) + +func (obf *ObjectFormat) String() string { + return string(*obf) +} + // Repository contains information of a Git repository. type Repository struct { path string - cachedCommits *objectCache - cachedTags *objectCache - cachedTrees *objectCache + cachedCommits *objectCache + cachedTags *objectCache + cachedTrees *objectCache + cachedObjectFomart ObjectFormat } // Path returns the path of the repository. @@ -53,7 +66,9 @@ func (r *Repository) parsePrettyFormatLogToList(ctx context.Context, logs []byte // Docs: https://git-scm.com/docs/git-init type InitOptions struct { // Indicates whether the repository should be initialized in bare format. - Bare bool + Bare bool + ObjectFormat ObjectFormat + CommandOptions } @@ -73,6 +88,9 @@ func Init(ctx context.Context, path string, opts ...InitOptions) error { if opt.Bare { args = append(args, "--bare") } + if opt.ObjectFormat != "" { + args = append(args, "--object-format", opt.ObjectFormat.String()) + } args = append(args, "--end-of-options") _, err = exec(ctx, path, args, opt.Envs) return err @@ -443,7 +461,7 @@ type RevParseOptions struct { CommandOptions } -// RevParse returns full length (40) commit ID by given revision in the +// RevParse returns full length (40 or 64) commit ID by given revision in the // repository. func (r *Repository) RevParse(ctx context.Context, rev string, opts ...RevParseOptions) (string, error) { var opt RevParseOptions @@ -544,4 +562,31 @@ func (r *Repository) Fsck(ctx context.Context, opts ...FsckOptions) error { args := []string{"fsck", "--end-of-options"} _, err := exec(ctx, r.path, args, opt.Envs) return err + +} + +// ObjectFomat returns hash algorithm (sha1 or sha256) of the repository +func (r *Repository) ObjectFormat(ctx context.Context) (ObjectFormat, error) { + if r.cachedObjectFomart != "" { + return r.cachedObjectFomart, nil + } + + id, err := exec(ctx, r.path, []string{"hash-object", "--stdin"}, nil) + if err != nil { + return "", fmt.Errorf("hash object: %v", err) + } + oid, err := NewIDFromString(strings.TrimSpace(string(id))) + if err != nil { + return "", fmt.Errorf("parse oid: %v", err) + } + switch oid.(type) { + case *SHA1: + r.cachedObjectFomart = ObjectFormatSHA1 + return ObjectFormatSHA1, nil + case *SHA256: + r.cachedObjectFomart = ObjectFormatSHA256 + return ObjectFormatSHA256, nil + default: + return "", fmt.Errorf("unknown object format") + } } diff --git a/repo_blame_test.go b/repo_blame_test.go index 133ea4c5e..d55bc87bc 100644 --- a/repo_blame_test.go +++ b/repo_blame_test.go @@ -16,7 +16,7 @@ func TestRepository_Blame(t *testing.T) { assert.Error(t, err) }) - blame, err := testrepo.Blame(ctx, "cfc3b2993f74726356887a5ec093de50486dc617", "README.txt") + blame, err := testrepo.Blame(ctx, testrepoMarks[32].String(), "README.txt") assert.Nil(t, err) // Assert representative commits @@ -25,10 +25,10 @@ func TestRepository_Blame(t *testing.T) { line int expID string }{ - {line: 1, expID: "755fd577edcfd9209d0ac072eed3b022cbe4d39b"}, - {line: 3, expID: "a13dba1e469944772490909daa58c53ac8fa4b0d"}, - {line: 5, expID: "755fd577edcfd9209d0ac072eed3b022cbe4d39b"}, - {line: 13, expID: "8d2636da55da593c421e1cb09eea502a05556a69"}, + {line: 1, expID: testrepoMarks[1].String()}, + {line: 3, expID: testrepoMarks[20].String()}, + {line: 5, expID: testrepoMarks[1].String()}, + {line: 13, expID: testrepoMarks[13].String()}, } for _, test := range tests { t.Run(fmt.Sprintf("Line %d", test.line), func(t *testing.T) { diff --git a/repo_blob_test.go b/repo_blob_test.go index 4818145e4..274b8a809 100644 --- a/repo_blob_test.go +++ b/repo_blob_test.go @@ -12,18 +12,18 @@ func TestRepository_CatFileBlob(t *testing.T) { ctx := context.Background() t.Run("not a blob", func(t *testing.T) { - _, err := testrepo.CatFileBlob(ctx, "007cb92318c7bd3b56908ea8c2e54370245562f8") + _, err := testrepo.CatFileBlob(ctx, testrepoMarks[47].String()) assert.Equal(t, ErrNotBlob, err) }) t.Run("get a blob, no full rev hash", func(t *testing.T) { - b, err := testrepo.CatFileBlob(ctx, "021a") + b, err := testrepo.CatFileBlob(ctx, testrepoMarks[34].String()[:4]) require.NoError(t, err) assert.True(t, b.IsBlob()) }) t.Run("get a blob", func(t *testing.T) { - b, err := testrepo.CatFileBlob(ctx, "021a721a61a1de65865542c405796d1eb985f784") + b, err := testrepo.CatFileBlob(ctx, testrepoMarks[34].String()) require.NoError(t, err) assert.True(t, b.IsBlob()) }) diff --git a/repo_commit_test.go b/repo_commit_test.go index b4ccac770..90df1d058 100644 --- a/repo_commit_test.go +++ b/repo_commit_test.go @@ -3,6 +3,7 @@ package git import ( "context" "errors" + "fmt" "testing" "time" @@ -43,12 +44,12 @@ func TestRepository_CatFileCommit(t *testing.T) { assert.Nil(t, c) }) - c, err := testrepo.CatFileCommit(ctx, "d58e3ef9f123eea6857161c79275ee22b228f659") + c, err := testrepo.CatFileCommit(ctx, testrepoMarks[31].String()) if err != nil { t.Fatal(err) } - assert.Equal(t, "d58e3ef9f123eea6857161c79275ee22b228f659", c.ID.String()) + assert.Equal(t, testrepoMarks[31].String(), c.ID.String()) assert.Equal(t, "Add a symlink\n", c.Message) } @@ -66,7 +67,7 @@ func TestRepository_BranchCommit(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", c.ID.String()) + assert.Equal(t, testrepoMarks[30].String(), c.ID.String()) assert.Equal(t, "Rename shell script\n", c.Message) } @@ -84,7 +85,7 @@ func TestRepository_TagCommit(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", c.ID.String()) + assert.Equal(t, testrepoMarks[30].String(), c.ID.String()) assert.Equal(t, "Rename shell script\n", c.Message) } @@ -96,17 +97,17 @@ func TestRepository_Log(t *testing.T) { expCommitIDs []string }{ { - rev: "0eedd79eba4394bbef888c804e899731644367fe", + rev: testrepoMarks[30].String(), opt: LogOptions{ Since: time.Unix(1581250680, 0), }, expCommitIDs: []string{ - "0eedd79eba4394bbef888c804e899731644367fe", - "4e59b72440188e7c2578299fc28ea425fbe9aece", + testrepoMarks[30].String(), + testrepoMarks[29].String(), }, }, { - rev: "0eedd79eba4394bbef888c804e899731644367fe", + rev: testrepoMarks[30].String(), opt: LogOptions{ Since: time.Now().AddDate(100, 0, 0), }, @@ -140,8 +141,8 @@ func TestRepository_CommitByRevision(t *testing.T) { expID string }{ { - rev: "4e59b72", - expID: "4e59b72440188e7c2578299fc28ea425fbe9aece", + rev: testrepoMarks[29].String()[:7], + expID: testrepoMarks[29].String(), }, } for _, test := range tests { @@ -165,15 +166,15 @@ func TestRepository_CommitsSince(t *testing.T) { expCommitIDs []string }{ { - rev: "0eedd79eba4394bbef888c804e899731644367fe", + rev: testrepoMarks[30].String(), since: time.Unix(1581250680, 0), expCommitIDs: []string{ - "0eedd79eba4394bbef888c804e899731644367fe", - "4e59b72440188e7c2578299fc28ea425fbe9aece", + testrepoMarks[30].String(), + testrepoMarks[29].String(), }, }, { - rev: "0eedd79eba4394bbef888c804e899731644367fe", + rev: testrepoMarks[30].String(), since: time.Now().AddDate(100, 0, 0), expCommitIDs: []string{}, }, @@ -199,13 +200,13 @@ func TestRepository_DiffNameOnly(t *testing.T) { expFiles []string }{ { - base: "ef7bebf8bdb1919d947afe46ab4b2fb4278039b3", - head: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + base: testrepoMarks[26].String(), + head: testrepoMarks[27].String(), expFiles: []string{"fix.txt"}, }, { - base: "45a30ea9afa413e226ca8614179c011d545ca883", - head: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + base: testrepoMarks[24].String(), + head: testrepoMarks[27].String(), opt: DiffNameOnlyOptions{ NeedsMergeBase: true, }, @@ -213,16 +214,16 @@ func TestRepository_DiffNameOnly(t *testing.T) { }, { - base: "45a30ea9afa413e226ca8614179c011d545ca883", - head: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + base: testrepoMarks[24].String(), + head: testrepoMarks[27].String(), opt: DiffNameOnlyOptions{ Path: "src", }, expFiles: []string{"src/test/java/com/github/AppTest.java"}, }, { - base: "45a30ea9afa413e226ca8614179c011d545ca883", - head: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + base: testrepoMarks[24].String(), + head: testrepoMarks[27].String(), opt: DiffNameOnlyOptions{ Path: "resources", }, @@ -256,27 +257,27 @@ func TestRepository_RevListCount(t *testing.T) { expCount int64 }{ { - refspecs: []string{"755fd577edcfd9209d0ac072eed3b022cbe4d39b"}, + refspecs: []string{testrepoMarks[1].String()}, expCount: 1, }, { - refspecs: []string{"f5ed01959cffa4758ca0a49bf4c34b138d7eab0a"}, + refspecs: []string{testrepoMarks[5].String()}, expCount: 5, }, { - refspecs: []string{"978fb7f6388b49b532fbef8b856681cfa6fcaa0a"}, + refspecs: []string{testrepoMarks[27].String()}, expCount: 27, }, { - refspecs: []string{"7c5ee6478d137417ae602140c615e33aed91887c"}, + refspecs: []string{testrepoMarks[21].String()}, opt: RevListCountOptions{ Path: "README.txt", }, expCount: 3, }, { - refspecs: []string{"7c5ee6478d137417ae602140c615e33aed91887c"}, + refspecs: []string{testrepoMarks[21].String()}, opt: RevListCountOptions{ Path: "resources", }, @@ -310,20 +311,20 @@ func TestRepository_RevList(t *testing.T) { expCommitIDs []string }{ { - refspecs: []string{"45a30ea9afa413e226ca8614179c011d545ca883...978fb7f6388b49b532fbef8b856681cfa6fcaa0a"}, + refspecs: []string{fmt.Sprintf("%s...%s", testrepoMarks[24].String(), testrepoMarks[27].String())}, expCommitIDs: []string{ - "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", - "ef7bebf8bdb1919d947afe46ab4b2fb4278039b3", - "ebbbf773431ba07510251bb03f9525c7bab2b13a", + testrepoMarks[27].String(), + testrepoMarks[26].String(), + testrepoMarks[25].String(), }, }, { - refspecs: []string{"45a30ea9afa413e226ca8614179c011d545ca883...978fb7f6388b49b532fbef8b856681cfa6fcaa0a"}, + refspecs: []string{fmt.Sprintf("%s...%s", testrepoMarks[24].String(), testrepoMarks[27].String())}, opt: RevListOptions{ Path: "src", }, expCommitIDs: []string{ - "ebbbf773431ba07510251bb03f9525c7bab2b13a", + testrepoMarks[25].String(), }, }, } diff --git a/repo_diff_test.go b/repo_diff_test.go index 4fcbd57e2..44e52e65d 100644 --- a/repo_diff_test.go +++ b/repo_diff_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "fmt" "strings" "testing" @@ -21,14 +22,14 @@ func TestRepository_Diff(t *testing.T) { expDiff *Diff }{ { - rev: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + rev: testrepoMarks[27].String(), expDiff: &Diff{ Files: []*DiffFile{ { Name: "fix.txt", Type: DiffFileDelete, - Index: "0000000000000000000000000000000000000000", - OldIndex: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + Index: testEmptyShaID, + OldIndex: testrepoMarks[54].String(), Sections: nil, numAdditions: 0, numDeletions: 0, @@ -46,14 +47,14 @@ func TestRepository_Diff(t *testing.T) { }, }, { - rev: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + rev: testrepoMarks[1].String(), expDiff: &Diff{ Files: []*DiffFile{ { Name: "README.txt", Type: DiffFileAdd, - Index: "1e24b564bf2298965d8037af42d3ae15ad7d225a", - OldIndex: "0000000000000000000000000000000000000000", + Index: testrepoMarks[51].String(), + OldIndex: testEmptyShaID, Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -143,8 +144,8 @@ func TestRepository_Diff(t *testing.T) { { Name: "resources/labels.properties", Type: DiffFileAdd, - Index: "fbdcfef007c0c09061199e687087b18c3cf8e083", - OldIndex: "0000000000000000000000000000000000000000", + Index: testrepoMarks[52].String(), + OldIndex: testEmptyShaID, Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -192,8 +193,8 @@ func TestRepository_Diff(t *testing.T) { { Name: "src/Main.groovy", Type: DiffFileAdd, - Index: "51680791956b43effdb2f16bccd2b4752d66078f", - OldIndex: "0000000000000000000000000000000000000000", + Index: testrepoMarks[53].String(), + OldIndex: testEmptyShaID, Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -257,17 +258,17 @@ func TestRepository_Diff(t *testing.T) { }, }, { - rev: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + rev: testrepoMarks[27].String(), opt: DiffOptions{ - Base: "ef7bebf8bdb1919d947afe46ab4b2fb4278039b3", + Base: testrepoMarks[26].String(), }, expDiff: &Diff{ Files: []*DiffFile{ { Name: "fix.txt", Type: DiffFileDelete, - Index: "0000000000000000000000000000000000000000", - OldIndex: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + Index: testEmptyShaID, + OldIndex: testrepoMarks[54].String(), Sections: nil, numAdditions: 0, numDeletions: 0, @@ -306,7 +307,7 @@ func TestRepository_RawDiff(t *testing.T) { }) t.Run("invalid diffType", func(t *testing.T) { - err := testrepo.RawDiff(ctx, "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", "bad_diff_type", nil) + err := testrepo.RawDiff(ctx, testrepoMarks[27].String(), "bad_diff_type", nil) assert.Equal(t, errors.New("invalid diffType: bad_diff_type"), err) }) @@ -317,17 +318,17 @@ func TestRepository_RawDiff(t *testing.T) { expOutput string }{ { - rev: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + rev: testrepoMarks[27].String(), diffType: RawDiffNormal, - expOutput: `diff --git a/fix.txt b/fix.txt + expOutput: fmt.Sprintf(`diff --git a/fix.txt b/fix.txt deleted file mode 100644 -index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 -`, +index %s..%s +`, testrepoMarks[54].String(), testEmptyShaID), }, { - rev: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + rev: testrepoMarks[27].String(), diffType: RawDiffPatch, - expOutput: `Date: Sun, 9 Feb 2020 17:22:24 +0800 + expOutput: fmt.Sprintf(`Date: Sun, 9 Feb 2020 17:22:24 +0800 Subject: [PATCH] Delete fix.txt --- @@ -337,13 +338,13 @@ Subject: [PATCH] Delete fix.txt diff --git a/fix.txt b/fix.txt deleted file mode 100644 -index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 -`, +index %s..%s +`, testrepoMarks[54].String(), testEmptyShaID), }, { - rev: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + rev: testrepoMarks[1].String(), diffType: RawDiffNormal, - expOutput: `commit 755fd577edcfd9209d0ac072eed3b022cbe4d39b + expOutput: fmt.Sprintf(`commit %[1]s Author: Matthew McCullough Date: Mon Nov 24 21:22:01 2008 -0700 @@ -355,7 +356,7 @@ Date: Mon Nov 24 21:22:01 2008 -0700 diff --git a/README.txt b/README.txt new file mode 100644 -index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15ad7d225a +index %[2]s..%[3]s --- /dev/null +++ b/README.txt @@ -0,0 +1,11 @@ @@ -373,7 +374,7 @@ index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15 \ No newline at end of file diff --git a/resources/labels.properties b/resources/labels.properties new file mode 100644 -index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c3cf8e083 +index %[2]s..%[4]s --- /dev/null +++ b/resources/labels.properties @@ -0,0 +1,4 @@ @@ -383,7 +384,7 @@ index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c +cli.usage=This application doesn't use a command line interface diff --git a/src/Main.groovy b/src/Main.groovy new file mode 100644 -index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b4752d66078f +index %[2]s..%[5]s --- /dev/null +++ b/src/Main.groovy @@ -0,0 +1,6 @@ @@ -394,12 +395,12 @@ index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b475 +int programmingPoints = 10 +println "${name} has at least ${programmingPoints} programming points." \ No newline at end of file -`, +`, testrepoMarks[1].String(), testEmptyShaID, testrepoMarks[51].String(), testrepoMarks[52].String(), testrepoMarks[53].String()), }, { - rev: "755fd577edcfd9209d0ac072eed3b022cbe4d39b", + rev: testrepoMarks[1].String(), diffType: RawDiffPatch, - expOutput: `Date: Mon, 24 Nov 2008 21:22:01 -0700 + expOutput: fmt.Sprintf(`Date: Mon, 24 Nov 2008 21:22:01 -0700 Subject: [PATCH] Addition of the README and basic Groovy source samples. - Addition of the README.txt file explaining what this repository is all about. @@ -416,7 +417,7 @@ Subject: [PATCH] Addition of the README and basic Groovy source samples. diff --git a/README.txt b/README.txt new file mode 100644 -index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15ad7d225a +index %[2]s..%[3]s --- /dev/null +++ b/README.txt @@ -0,0 +1,11 @@ @@ -434,7 +435,7 @@ index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15 \ No newline at end of file diff --git a/resources/labels.properties b/resources/labels.properties new file mode 100644 -index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c3cf8e083 +index %[2]s..%[4]s --- /dev/null +++ b/resources/labels.properties @@ -0,0 +1,4 @@ @@ -444,7 +445,7 @@ index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c +cli.usage=This application doesn't use a command line interface diff --git a/src/Main.groovy b/src/Main.groovy new file mode 100644 -index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b4752d66078f +index %[2]s..%[5]s --- /dev/null +++ b/src/Main.groovy @@ -0,0 +1,6 @@ @@ -455,7 +456,7 @@ index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b475 +int programmingPoints = 10 +println "${name} has at least ${programmingPoints} programming points." \ No newline at end of file -`, +`, testrepoMarks[1].String(), testEmptyShaID, testrepoMarks[51].String(), testrepoMarks[52].String(), testrepoMarks[53].String()), }, } for _, test := range tests { @@ -487,11 +488,11 @@ func TestRepository_DiffBinary(t *testing.T) { expOutput string }{ { - base: "4eaa8d4b05e731e950e2eaf9e8b92f522303ab41", - head: "4e59b72440188e7c2578299fc28ea425fbe9aece", - expOutput: `diff --git a/.gitmodules b/.gitmodules + base: testrepoMarks[28].String(), + head: testrepoMarks[29].String(), + expOutput: fmt.Sprintf(`diff --git a/.gitmodules b/.gitmodules new file mode 100644 -index 0000000000000000000000000000000000000000..6abde17f49a6d43df40366e57d8964fee0dfda11 +index %[1]s..%[2]s --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ @@ -500,12 +501,12 @@ index 0000000000000000000000000000000000000000..6abde17f49a6d43df40366e57d8964fe + url = https://github.com/gogs/docs-api.git diff --git a/gogs/docs-api b/gogs/docs-api new file mode 160000 -index 0000000000000000000000000000000000000000..6b08f76a5313fa3d26859515b30aa17a5faa2807 +index %[1]s..%[3]s --- /dev/null +++ b/gogs/docs-api @@ -0,0 +1 @@ -+Subproject commit 6b08f76a5313fa3d26859515b30aa17a5faa2807 -`, ++Subproject commit %[3]s +`, testEmptyShaID, testrepoMarks[37].String(), submoduleSHA.String()), }, } for _, test := range tests { diff --git a/repo_pull_test.go b/repo_pull_test.go index 082e987b6..2de31cd8c 100644 --- a/repo_pull_test.go +++ b/repo_pull_test.go @@ -14,7 +14,7 @@ func TestRepository_MergeBase(t *testing.T) { t.Run("bad revision", func(t *testing.T) { // "bad_revision" doesn't exist, so git fails with exit status 128 (fatal), // not exit status 1 (no merge base). - mb, err := testrepo.MergeBase(ctx, "0eedd79eba4394bbef888c804e899731644367fe", "bad_revision") + mb, err := testrepo.MergeBase(ctx, testrepoMarks[30].String(), "bad_revision") assert.Error(t, err) assert.Empty(t, mb) }) @@ -26,14 +26,14 @@ func TestRepository_MergeBase(t *testing.T) { wantMergeBase string }{ { - base: "4e59b72440188e7c2578299fc28ea425fbe9aece", - head: "0eedd79eba4394bbef888c804e899731644367fe", - wantMergeBase: "4e59b72440188e7c2578299fc28ea425fbe9aece", + base: testrepoMarks[29].String(), + head: testrepoMarks[30].String(), + wantMergeBase: testrepoMarks[29].String(), }, { base: "master", head: "release-1.0", - wantMergeBase: "0eedd79eba4394bbef888c804e899731644367fe", + wantMergeBase: testrepoMarks[30].String(), }, } for _, test := range tests { diff --git a/repo_reference_test.go b/repo_reference_test.go index 05a243c05..9db9f6277 100644 --- a/repo_reference_test.go +++ b/repo_reference_test.go @@ -48,7 +48,7 @@ func TestRepository_ShowRefVerify(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", rev) + assert.Equal(t, testrepoMarks[30].String(), rev) } func TestRepository_BranchCommitID(t *testing.T) { @@ -65,7 +65,7 @@ func TestRepository_BranchCommitID(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", rev) + assert.Equal(t, testrepoMarks[30].String(), rev) } func TestRepository_TagCommitID(t *testing.T) { @@ -82,7 +82,7 @@ func TestRepository_TagCommitID(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", rev) + assert.Equal(t, testrepoMarks[30].String(), rev) } func TestRepository_HasReference(t *testing.T) { @@ -205,7 +205,7 @@ func TestRepository_ShowRef(t *testing.T) { }, expRefs: []*Reference{ { - ID: "0eedd79eba4394bbef888c804e899731644367fe", + ID: testrepoMarks[30].String(), Refspec: "refs/heads/release-1.0", }, }, @@ -216,7 +216,7 @@ func TestRepository_ShowRef(t *testing.T) { }, expRefs: []*Reference{ { - ID: "0eedd79eba4394bbef888c804e899731644367fe", + ID: testrepoMarks[30].String(), Refspec: "refs/tags/v1.0.0", }, }, diff --git a/repo_remote_test.go b/repo_remote_test.go index d4e0962ac..2c9c433b3 100644 --- a/repo_remote_test.go +++ b/repo_remote_test.go @@ -23,7 +23,7 @@ func TestLsRemote(t *testing.T) { }, expRefs: []*Reference{ { - ID: "0eedd79eba4394bbef888c804e899731644367fe", + ID: testrepoMarks[30].String(), Refspec: "refs/heads/release-1.0", }, }, @@ -35,7 +35,7 @@ func TestLsRemote(t *testing.T) { }, expRefs: []*Reference{ { - ID: "0eedd79eba4394bbef888c804e899731644367fe", + ID: testrepoMarks[30].String(), Refspec: "refs/tags/v1.0.0", }, }, @@ -47,7 +47,7 @@ func TestLsRemote(t *testing.T) { }, expRefs: []*Reference{ { - ID: "0eedd79eba4394bbef888c804e899731644367fe", + ID: testrepoMarks[30].String(), Refspec: "refs/tags/v1.0.0", }, }, @@ -92,9 +92,13 @@ func TestRepository_RemoteAdd(t *testing.T) { defer func() { _ = os.RemoveAll(path) }() - - err := Init(ctx, path, InitOptions{ - Bare: true, + objfmt, err := testrepo.ObjectFormat(ctx) + if err != nil { + t.Fatal(err) + } + err = Init(ctx, path, InitOptions{ + Bare: true, + ObjectFormat: objfmt, }) if err != nil { t.Fatal(err) diff --git a/repo_tag.go b/repo_tag.go index 3d3098979..02bcf9674 100644 --- a/repo_tag.go +++ b/repo_tag.go @@ -47,8 +47,8 @@ l: return tag, nil } -// getTag returns a tag by given SHA1 hash. -func (r *Repository) getTag(ctx context.Context, id *SHA1) (*Tag, error) { +// getTag returns a tag by given object id. +func (r *Repository) getTag(ctx context.Context, id Oid) (*Tag, error) { t, ok := r.cachedTags.Get(id.String()) if ok { logf("Cached tag hit: %s", id) diff --git a/repo_tag_test.go b/repo_tag_test.go index 9905c927c..466c9a164 100644 --- a/repo_tag_test.go +++ b/repo_tag_test.go @@ -18,16 +18,16 @@ func TestRepository_Tag(t *testing.T) { name: "v1.0.0", expTag: &Tag{ typ: ObjectCommit, - id: MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe"), - commitID: MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe"), + id: MustIDFromString(testrepoMarks[30].String()), + commitID: MustIDFromString(testrepoMarks[30].String()), refspec: "refs/tags/v1.0.0", }, }, { name: "v1.1.0", expTag: &Tag{ typ: ObjectTag, - id: MustIDFromString("b39c8508bbc4b00ad2e24d358012ea123bcafd8d"), - commitID: MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe"), + id: MustIDFromString(testrepoMarks[50].String()), + commitID: MustIDFromString(testrepoMarks[30].String()), refspec: "refs/tags/v1.1.0", }, }, diff --git a/repo_test.go b/repo_test.go index 6f7e9bd85..ea486739e 100644 --- a/repo_test.go +++ b/repo_test.go @@ -276,7 +276,7 @@ func TestRepository_Reset(t *testing.T) { opt ResetOptions }{ { - rev: "978fb7f6388b49b532fbef8b856681cfa6fcaa0a", + rev: testrepoMarks[27].String(), opt: ResetOptions{ Hard: true, }, @@ -444,28 +444,28 @@ func TestRepository_RevParse(t *testing.T) { expErr error }{ { - rev: "4e59b72", - expID: "4e59b72440188e7c2578299fc28ea425fbe9aece", + rev: testrepoMarks[29].String()[:7], + expID: testrepoMarks[29].String(), expErr: nil, }, { rev: "release-1.0", - expID: "0eedd79eba4394bbef888c804e899731644367fe", + expID: testrepoMarks[30].String(), expErr: nil, }, { rev: "RELEASE_1.0", - expID: "2a52e96389d02209b451ae1ddf45d645b42d744c", + expID: testrepoMarks[12].String(), expErr: nil, }, { rev: "refs/heads/release-1.0", - expID: "0eedd79eba4394bbef888c804e899731644367fe", + expID: testrepoMarks[30].String(), expErr: nil, }, { rev: "refs/tags/RELEASE_1.0", - expID: "2a52e96389d02209b451ae1ddf45d645b42d744c", + expID: testrepoMarks[12].String(), expErr: nil, }, @@ -501,3 +501,12 @@ func TestRepository_Fsck(t *testing.T) { t.Fatal(err) } } + +func TestRepository_ObjectFormat(t *testing.T) { + ctx := context.Background() + obf, err := testrepo.ObjectFormat(ctx) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, obf, testrepoObjectFormat) +} diff --git a/repo_tree.go b/repo_tree.go index 98badf2e7..594caa19a 100644 --- a/repo_tree.go +++ b/repo_tree.go @@ -72,13 +72,14 @@ func parseTree(t *Tree, data []byte, lineTerminator byte) ([]*TreeEntry, error) } pos += step + 6 // Skip string type of entry type. - step = 40 + step = bytes.Index(data[pos:], []byte{9}) // index of \t + id, err := NewIDFromString(string(data[pos : pos+step])) if err != nil { return nil, err } entry.id = id - pos += step + 1 // Skip half of SHA1. + pos += step + 1 // Skip half of Oid. step = bytes.IndexByte(data[pos:], lineTerminator) if data[pos] == '"' { diff --git a/server_test.go b/server_test.go index 32baf1e3d..54879500a 100755 --- a/server_test.go +++ b/server_test.go @@ -2,6 +2,7 @@ package git import ( "context" + "fmt" "os" "path/filepath" "testing" @@ -23,8 +24,11 @@ func TestReceivePack(t *testing.T) { ctx := context.Background() got, err := ReceivePack(ctx, repoPath, ReceivePackOptions{HTTPBackendInfoRefs: true}) require.NoError(t, err) - const contains = "report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta object-format=sha1 agent=git/" - assert.Contains(t, string(got), contains) + var regPattern = fmt.Sprintf( + "report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta (push-options |)object-format=%s agent=git/", + testrepoObjectFormat, + ) + assert.Regexp(t, regPattern, string(got)) } func TestUploadPack(t *testing.T) { @@ -37,6 +41,6 @@ func TestUploadPack(t *testing.T) { }, ) require.NoError(t, err) - const contains = "multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master object-format=sha1 agent=git/" - assert.Contains(t, string(got), contains) + var regPattern = fmt.Sprintf("multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed (allow-tip-sha1-in-want |)(allow-reachable-sha1-in-want |)no-done symref=HEAD:refs/heads/master (filter |)object-format=%s agent=git/", testrepoObjectFormat) + assert.Regexp(t, regPattern, string(got)) } diff --git a/sha1.go b/sha1.go deleted file mode 100644 index c977166c7..000000000 --- a/sha1.go +++ /dev/null @@ -1,85 +0,0 @@ -package git - -import ( - "encoding/hex" - "errors" - "strings" - "sync" -) - -// EmptyID is an ID with empty SHA-1 hash. -const EmptyID = "0000000000000000000000000000000000000000" - -// SHA1 is the SHA-1 hash of a Git object. -type SHA1 struct { - bytes [20]byte - - str string - strOnce sync.Once -} - -// Equal returns true if s2 has the same SHA1 as s. It supports -// 40-length-string, []byte, and SHA1. -func (s *SHA1) Equal(s2 interface{}) bool { - switch v := s2.(type) { - case string: - return v == s.String() - case [20]byte: - return v == s.bytes - case *SHA1: - return v.bytes == s.bytes - } - return false -} - -// String returns string (hex) representation of the SHA1. -func (s *SHA1) String() string { - s.strOnce.Do(func() { - result := make([]byte, 0, 40) - hexvalues := []byte("0123456789abcdef") - for i := 0; i < 20; i++ { - result = append(result, hexvalues[s.bytes[i]>>4]) - result = append(result, hexvalues[s.bytes[i]&0xf]) - } - s.str = string(result) - }) - return s.str -} - -// MustID always returns a new SHA1 from a [20]byte array with no validation of -// input. -func MustID(b []byte) *SHA1 { - var id SHA1 - for i := 0; i < 20; i++ { - id.bytes[i] = b[i] - } - return &id -} - -// NewID returns a new SHA1 from a [20]byte array. -func NewID(b []byte) (*SHA1, error) { - if len(b) != 20 { - return nil, errors.New("length must be 20") - } - return MustID(b), nil -} - -// MustIDFromString always returns a new sha from a ID with no validation of -// input. -func MustIDFromString(s string) *SHA1 { - b, _ := hex.DecodeString(s) - return MustID(b) -} - -// NewIDFromString returns a new SHA1 from a ID string of length 40. -func NewIDFromString(s string) (*SHA1, error) { - s = strings.TrimSpace(s) - if len(s) != 40 { - return nil, errors.New("length must be 40") - } - b, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - return NewID(b) -} diff --git a/sha1_test.go b/sha1_test.go deleted file mode 100644 index be98b0d0f..000000000 --- a/sha1_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package git - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestSHA1_Equal(t *testing.T) { - tests := []struct { - s1 *SHA1 - s2 interface{} - expVal bool - }{ - { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: "fcf7087e732bfe3c25328248a9bf8c3ccd85bed4", - expVal: true, - }, { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: EmptyID, - expVal: false, - }, - - { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4").bytes, - expVal: true, - }, { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: MustIDFromString(EmptyID).bytes, - expVal: false, - }, - - { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - expVal: true, - }, { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: MustIDFromString(EmptyID), - expVal: false, - }, - - { - s1: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), - s2: []byte(EmptyID), - expVal: false, - }, - } - for _, test := range tests { - t.Run("", func(t *testing.T) { - assert.Equal(t, test.expVal, test.s1.Equal(test.s2)) - }) - } -} - -func TestNewID(t *testing.T) { - sha, err := NewID([]byte("000000")) - assert.Equal(t, errors.New("length must be 20"), err) - assert.Nil(t, sha) -} - -func TestNewIDFromString(t *testing.T) { - sha, err := NewIDFromString("000000") - assert.Equal(t, errors.New("length must be 40"), err) - assert.Nil(t, sha) -} diff --git a/tag.go b/tag.go index 40efd5a0b..53066b1e0 100644 --- a/tag.go +++ b/tag.go @@ -5,8 +5,8 @@ import "context" // Tag contains information of a Git tag. type Tag struct { typ ObjectType - id *SHA1 - commitID *SHA1 // The ID of the underlying commit + id Oid + commitID Oid // The ID of the underlying commit refspec string tagger *Signature message string @@ -20,12 +20,12 @@ func (t *Tag) Type() ObjectType { } // ID returns the SHA-1 hash of the tag. -func (t *Tag) ID() *SHA1 { +func (t *Tag) ID() Oid { return t.id } // CommitID returns the commit ID of the tag. -func (t *Tag) CommitID() *SHA1 { +func (t *Tag) CommitID() Oid { return t.commitID } diff --git a/tag_test.go b/tag_test.go index c43c15106..c23259fdd 100644 --- a/tag_test.go +++ b/tag_test.go @@ -15,8 +15,8 @@ func TestTag(t *testing.T) { } assert.Equal(t, ObjectTag, tag.Type()) - assert.Equal(t, "b39c8508bbc4b00ad2e24d358012ea123bcafd8d", tag.ID().String()) - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", tag.CommitID().String()) + assert.Equal(t, testrepoMarks[50].String(), tag.ID().String()) + assert.Equal(t, testrepoMarks[30].String(), tag.CommitID().String()) assert.Equal(t, "refs/tags/v1.1.0", tag.Refspec()) t.Run("Tagger", func(t *testing.T) { @@ -40,5 +40,5 @@ func TestTag_Commit(t *testing.T) { t.Fatal(err) } - assert.Equal(t, "0eedd79eba4394bbef888c804e899731644367fe", c.ID.String()) + assert.Equal(t, testrepoMarks[30].String(), c.ID.String()) } diff --git a/tree.go b/tree.go index 539027b44..8395b1bf5 100644 --- a/tree.go +++ b/tree.go @@ -8,7 +8,7 @@ import ( // Tree represents a flat directory listing in Git. type Tree struct { - id *SHA1 + id Oid parent *Tree repo *Repository diff --git a/tree_blob_test.go b/tree_blob_test.go index ed9d509ea..13714f1ab 100644 --- a/tree_blob_test.go +++ b/tree_blob_test.go @@ -26,7 +26,7 @@ func TestTree_TreeEntry(t *testing.T) { func TestTree_Blob(t *testing.T) { ctx := context.Background() - tree, err := testrepo.LsTree(ctx, "d58e3ef9f123eea6857161c79275ee22b228f659") + tree, err := testrepo.LsTree(ctx, testrepoMarks[31].String()) if err != nil { t.Fatal(err) } diff --git a/tree_entry.go b/tree_entry.go index 071d9abfa..9c3132982 100644 --- a/tree_entry.go +++ b/tree_entry.go @@ -28,7 +28,7 @@ const ( type TreeEntry struct { mode EntryMode typ ObjectType - id *SHA1 + id Oid name string parent *Tree @@ -74,7 +74,7 @@ func (e *TreeEntry) Type() ObjectType { } // ID returns the SHA-1 hash of the entry. -func (e *TreeEntry) ID() *SHA1 { +func (e *TreeEntry) ID() Oid { return e.id } diff --git a/tree_entry_test.go b/tree_entry_test.go index e8c3707d5..d4897342a 100644 --- a/tree_entry_test.go +++ b/tree_entry_test.go @@ -9,7 +9,7 @@ import ( ) func TestTreeEntry(t *testing.T) { - id := MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe") + id := MustIDFromString(testrepoMarks[12].String()) e := &TreeEntry{ mode: EntrySymlink, typ: ObjectTree, @@ -30,7 +30,7 @@ func TestTreeEntry(t *testing.T) { func TestTreeEntry_Size(t *testing.T) { ctx := context.Background() - tree, err := testrepo.LsTree(ctx, "0eedd79eba4394bbef888c804e899731644367fe") + tree, err := testrepo.LsTree(ctx, testrepoMarks[30].String()) require.NoError(t, err) es, err := tree.Entries(ctx) @@ -63,7 +63,7 @@ func TestTreeEntry_Size(t *testing.T) { func TestEntries_Sort(t *testing.T) { ctx := context.Background() - tree, err := testrepo.LsTree(ctx, "0eedd79eba4394bbef888c804e899731644367fe") + tree, err := testrepo.LsTree(ctx, testrepoMarks[30].String()) if err != nil { t.Fatal(err) } @@ -79,67 +79,67 @@ func TestEntries_Sort(t *testing.T) { { mode: EntryTree, typ: ObjectTree, - id: MustIDFromString("fcf7087e732bfe3c25328248a9bf8c3ccd85bed4"), + id: MustIDFromString(testrepoMarks[41].String()), name: "gogs", }, { mode: EntryTree, typ: ObjectTree, - id: MustIDFromString("a41a5a6cfd2d5ec3c0c1101e7cc05c9dedc3e11d"), + id: MustIDFromString(testrepoMarks[42].String()), name: "img", }, { mode: EntryTree, typ: ObjectTree, - id: MustIDFromString("aaa0af6b82db99c660b169962524e2201ac7079c"), + id: MustIDFromString(testrepoMarks[44].String()), name: "resources", }, { mode: EntryTree, typ: ObjectTree, - id: MustIDFromString("007cb92318c7bd3b56908ea8c2e54370245562f8"), + id: MustIDFromString(testrepoMarks[47].String()), name: "src", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("021a721a61a1de65865542c405796d1eb985f784"), + id: MustIDFromString(testrepoMarks[34].String()), name: ".DS_Store", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("412eeda78dc9de1186c2e0e1526764af82ab3431"), + id: MustIDFromString(testrepoMarks[35].String()), name: ".gitattributes", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("7c820833a9ad5fbfc96efd533d55f5edc65dc977"), + id: MustIDFromString(testrepoMarks[36].String()), name: ".gitignore", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("6abde17f49a6d43df40366e57d8964fee0dfda11"), + id: MustIDFromString(testrepoMarks[37].String()), name: ".gitmodules", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("17eccd68b7cafa718d53c8b4db666194646e2bd9"), + id: MustIDFromString(testrepoMarks[38].String()), name: ".travis.yml", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("adfd6da3c0a3fb038393144becbf37f14f780087"), + id: MustIDFromString(testrepoMarks[39].String()), name: "README.txt", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("6058be211566308428ca6dcab3f08cf270cd9568"), + id: MustIDFromString(testrepoMarks[40].String()), name: "build.gradle", }, { mode: EntryBlob, typ: ObjectBlob, - id: MustIDFromString("99975710477a65b89233b2d12bf60f7c0ffc1f5c"), + id: MustIDFromString(testrepoMarks[43].String()), name: "pom.xml", }, { mode: EntryExec, typ: ObjectBlob, - id: MustIDFromString("fb4bd4ec9220ed4fe0d9526d1b77147490ce8842"), + id: MustIDFromString(testrepoMarks[45].String()), name: "run.sh", }, } @@ -153,7 +153,7 @@ func TestEntries_Sort(t *testing.T) { func TestEntries_CommitsInfo(t *testing.T) { ctx := context.Background() - tree, err := testrepo.LsTree(ctx, "cfc3b2993f74726356887a5ec093de50486dc617") + tree, err := testrepo.LsTree(ctx, testrepoMarks[32].String()) if err != nil { t.Fatal(err) } @@ -180,98 +180,98 @@ func TestEntries_CommitsInfo(t *testing.T) { name: ".DS_Store", }, Commit: &Commit{ - ID: MustIDFromString("4eaa8d4b05e731e950e2eaf9e8b92f522303ab41"), + ID: MustIDFromString(testrepoMarks[28].String()), }, }, { Entry: &TreeEntry{ name: ".gitattributes", }, Commit: &Commit{ - ID: MustIDFromString("bf7a9a5ee025edee0e610bd7ba23c0704b53c6db"), + ID: MustIDFromString(testrepoMarks[15].String()), }, }, { Entry: &TreeEntry{ name: ".gitignore", }, Commit: &Commit{ - ID: MustIDFromString("d2280d000c84f1e595e4dec435ae6c1e6c245367"), + ID: MustIDFromString(testrepoMarks[16].String()), }, }, { Entry: &TreeEntry{ name: ".gitmodules", }, Commit: &Commit{ - ID: MustIDFromString("4e59b72440188e7c2578299fc28ea425fbe9aece"), + ID: MustIDFromString(testrepoMarks[29].String()), }, }, { Entry: &TreeEntry{ name: ".travis.yml", }, Commit: &Commit{ - ID: MustIDFromString("9805760644754c38d10a9f1522a54a4bdc00fa8a"), + ID: MustIDFromString(testrepoMarks[23].String()), }, }, { Entry: &TreeEntry{ name: "README.txt", }, Commit: &Commit{ - ID: MustIDFromString("a13dba1e469944772490909daa58c53ac8fa4b0d"), + ID: MustIDFromString(testrepoMarks[20].String()), }, }, { Entry: &TreeEntry{ name: "build.gradle", }, Commit: &Commit{ - ID: MustIDFromString("c59479302142d79e46f84d11438a41b39ba51a1f"), + ID: MustIDFromString(testrepoMarks[17].String()), }, }, { Entry: &TreeEntry{ name: "gogs", }, Commit: &Commit{ - ID: MustIDFromString("4e59b72440188e7c2578299fc28ea425fbe9aece"), + ID: MustIDFromString(testrepoMarks[29].String()), }, }, { Entry: &TreeEntry{ name: "img", }, Commit: &Commit{ - ID: MustIDFromString("4eaa8d4b05e731e950e2eaf9e8b92f522303ab41"), + ID: MustIDFromString(testrepoMarks[28].String()), }, }, { Entry: &TreeEntry{ name: "pom.xml", }, Commit: &Commit{ - ID: MustIDFromString("ef7bebf8bdb1919d947afe46ab4b2fb4278039b3"), + ID: MustIDFromString(testrepoMarks[26].String()), }, }, { Entry: &TreeEntry{ name: "resources", }, Commit: &Commit{ - ID: MustIDFromString("755fd577edcfd9209d0ac072eed3b022cbe4d39b"), + ID: MustIDFromString(testrepoMarks[1].String()), }, }, { Entry: &TreeEntry{ name: "run.sh", }, Commit: &Commit{ - ID: MustIDFromString("0eedd79eba4394bbef888c804e899731644367fe"), + ID: MustIDFromString(testrepoMarks[30].String()), }, }, { Entry: &TreeEntry{ name: "sameSHAs", }, Commit: &Commit{ - ID: MustIDFromString("cfc3b2993f74726356887a5ec093de50486dc617"), + ID: MustIDFromString(testrepoMarks[32].String()), }, }, { Entry: &TreeEntry{ name: "src", }, Commit: &Commit{ - ID: MustIDFromString("ebbbf773431ba07510251bb03f9525c7bab2b13a"), + ID: MustIDFromString(testrepoMarks[25].String()), }, }, } @@ -305,7 +305,7 @@ func TestEntries_CommitsInfo(t *testing.T) { name: "docs-api", }, Commit: &Commit{ - ID: MustIDFromString("4e59b72440188e7c2578299fc28ea425fbe9aece"), + ID: MustIDFromString(testrepoMarks[29].String()), }, }, } @@ -339,14 +339,14 @@ func TestEntries_CommitsInfo(t *testing.T) { name: "file1.txt", }, Commit: &Commit{ - ID: MustIDFromString("cfc3b2993f74726356887a5ec093de50486dc617"), + ID: MustIDFromString(testrepoMarks[32].String()), }, }, { Entry: &TreeEntry{ name: "file2.txt", }, Commit: &Commit{ - ID: MustIDFromString("cfc3b2993f74726356887a5ec093de50486dc617"), + ID: MustIDFromString(testrepoMarks[32].String()), }, }, }