diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-07-18 14:57:25 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-07-18 15:20:40 +0300 |
commit | 0df249b77e79dca793021edd273b6ef080a99f9b (patch) | |
tree | e6c8ff5ede05b8b5df63afc8b112c53908094a34 | |
parent | d8c2902881d174d6ebf79da2dff6a05f1b7721f0 (diff) |
git: Add logic to detect object hash for a repositorypks-git-objectids-sha256
Add a new funciton `DetectObjectHash()` that, given a repository, can
detect the object hash that's used by the repository by inspecting the
`extensions.objectFormat` config entry.
-rw-r--r-- | internal/git/gittest/repo.go | 5 | ||||
-rw-r--r-- | internal/git/object_id.go | 31 | ||||
-rw-r--r-- | internal/git/object_id_test.go | 91 |
3 files changed, 127 insertions, 0 deletions
diff --git a/internal/git/gittest/repo.go b/internal/git/gittest/repo.go index a9ff1e75e..1b4b08bb3 100644 --- a/internal/git/gittest/repo.go +++ b/internal/git/gittest/repo.go @@ -239,6 +239,8 @@ func RewrittenRepository(ctx context.Context, t testing.TB, cfg config.Cfg, repo type InitRepoOpts struct { // WithRelativePath determines the relative path of this repository. WithRelativePath string + // ObjectFormat overrides the object format used by the repository. + ObjectFormat string } // InitRepo creates a new empty repository in the given storage. You can either pass no or exactly @@ -260,6 +262,9 @@ func InitRepo(t testing.TB, cfg config.Cfg, storage config.Storage, opts ...Init args := []string{"init", "--bare"} args = append(args, initRepoExtraArgs...) args = append(args, repoPath) + if opt.ObjectFormat != "" { + args = append(args, "--object-format", opt.ObjectFormat) + } Exec(t, cfg, args...) diff --git a/internal/git/object_id.go b/internal/git/object_id.go index fcaf7225c..4d6083a12 100644 --- a/internal/git/object_id.go +++ b/internal/git/object_id.go @@ -1,10 +1,15 @@ package git import ( + "bytes" + "context" "encoding/hex" "errors" "fmt" "regexp" + + "gitlab.com/gitlab-org/gitaly/v15/internal/command" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper/text" ) var ( @@ -36,6 +41,32 @@ type ObjectHash struct { ZeroOID ObjectID } +// DetectObjectHash detects the object-hash used by the given repository. +func DetectObjectHash(ctx context.Context, repoExecutor RepositoryExecutor) (ObjectHash, error) { + var stdout bytes.Buffer + + if err := repoExecutor.ExecAndWait(ctx, SubCmd{ + Name: "config", + Args: []string{"extensions.objectFormat"}, + }, WithStdout(&stdout)); err != nil { + if status, ok := command.ExitStatus(err); ok && status == 1 { + return ObjectHashSHA1, nil + } + + return ObjectHash{}, fmt.Errorf("reading object format: %w", err) + } + + objectFormat := text.ChompBytes(stdout.Bytes()) + switch objectFormat { + case "sha1": + return ObjectHashSHA1, nil + case "sha256": + return ObjectHashSHA256, nil + default: + return ObjectHash{}, fmt.Errorf("unknown object format: %q", objectFormat) + } +} + // FromHex constructs a new ObjectID from the given hex representation of the object ID. Returns // ErrInvalidObjectID if the given object ID is not valid. func (h ObjectHash) FromHex(hex string) (ObjectID, error) { diff --git a/internal/git/object_id_test.go b/internal/git/object_id_test.go index f637fec3e..a6b62ffdc 100644 --- a/internal/git/object_id_test.go +++ b/internal/git/object_id_test.go @@ -6,13 +6,104 @@ import ( "bytes" "encoding/hex" "fmt" + "path/filepath" "strings" "testing" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v15/internal/git" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/localrepo" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper/text" + "gitlab.com/gitlab-org/gitaly/v15/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/v15/internal/testhelper/testcfg" + "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" ) +func TestDetectObjectHash(t *testing.T) { + cfg := testcfg.Build(t) + ctx := testhelper.Context(t) + + for _, tc := range []struct { + desc string + setup func(t *testing.T) *gitalypb.Repository + expectedErr error + expectedHash git.ObjectHash + }{ + { + desc: "defaults to SHA1", + setup: func(t *testing.T) *gitalypb.Repository { + repo, repoPath := gittest.InitRepo(t, cfg, cfg.Storages[0], gittest.InitRepoOpts{ + ObjectFormat: "sha1", + }) + + // Verify that the repo doesn't explicitly mention it's using SHA1 + // as object hash. + content := testhelper.MustReadFile(t, filepath.Join(repoPath, "config")) + require.NotContains(t, text.ChompBytes(content), "sha1") + + return repo + }, + expectedHash: git.ObjectHashSHA1, + }, + { + desc: "explicitly set to SHA1", + setup: func(t *testing.T) *gitalypb.Repository { + repo, repoPath := gittest.InitRepo(t, cfg, cfg.Storages[0], gittest.InitRepoOpts{ + ObjectFormat: "sha1", + }) + + // Explicitly set the object format to SHA1. + gittest.Exec(t, cfg, "-C", repoPath, "config", "extensions.objectFormat", "sha1") + + return repo + }, + expectedHash: git.ObjectHashSHA1, + }, + { + desc: "explicitly set to SHA256", + setup: func(t *testing.T) *gitalypb.Repository { + repo, repoPath := gittest.InitRepo(t, cfg, cfg.Storages[0], gittest.InitRepoOpts{ + ObjectFormat: "sha256", + }) + + require.Equal(t, + "sha256", + text.ChompBytes(gittest.Exec(t, cfg, "-C", repoPath, "config", "extensions.objectFormat")), + ) + + return repo + }, + expectedHash: git.ObjectHashSHA256, + }, + { + desc: "unknown hash", + setup: func(t *testing.T) *gitalypb.Repository { + repo, repoPath := gittest.InitRepo(t, cfg, cfg.Storages[0]) + + // Explicitly set the object format to something unknown. + gittest.Exec(t, cfg, "-C", repoPath, "config", "extensions.objectFormat", "blake2") + + return repo + }, + expectedErr: fmt.Errorf("reading object format: exit status 128"), + }, + } { + t.Run(tc.desc, func(t *testing.T) { + repoProto := tc.setup(t) + repo := localrepo.NewTestRepo(t, cfg, repoProto) + + hash, err := git.DetectObjectHash(ctx, repo) + if tc.expectedErr != nil { + require.EqualError(t, err, tc.expectedErr.Error()) + } else { + require.NoError(t, err) + } + require.Equal(t, tc.expectedHash, hash) + }) + } +} + func TestObjectHash_ValidateHex(t *testing.T) { for _, hash := range []struct { desc string |