Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Vosmaer (GitLab) <jacob@gitlab.com>2017-07-03 14:32:11 +0300
committerJacob Vosmaer (GitLab) <jacob@gitlab.com>2017-07-03 14:32:11 +0300
commit57f976e4e7f92c39869af37ec5fbd1c2dbf2d3fb (patch)
tree0ccf1d71f5f307782600fa888ec449c4dffdf7b0
parent2a702cf905656e7fd2a0a02f04af1ea7eecb2bcf (diff)
parentfd220a3c953f767f0ce4b6d2eed2f3f0e7366c9f (diff)
Merge branch 'zj-repo-exists' into 'master'
Repo exists implemenation Closes #335 See merge request !200
-rw-r--r--CHANGELOG.md2
-rw-r--r--internal/helper/repo.go40
-rw-r--r--internal/service/repository/repository.go21
-rw-r--r--internal/service/repository/repository_test.go91
-rw-r--r--internal/service/repository/server.go12
-rw-r--r--internal/service/repository/testhelper_test.go64
6 files changed, 224 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 873fff428..7eded313c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@ v0.14.0
- Override gRPC code to Canceled/DeadlineExceeded on requests with
canceled contexts
https://gitlab.com/gitlab-org/gitaly/merge_requests/199
+- Add RepositoryExists Implementation
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/200
v0.13.0
diff --git a/internal/helper/repo.go b/internal/helper/repo.go
index a3cd3363c..2c3a1f51c 100644
--- a/internal/helper/repo.go
+++ b/internal/helper/repo.go
@@ -18,6 +18,26 @@ import (
// relevant error codes and should be passed back to gRPC without further
// decoration.
func GetRepoPath(repo *pb.Repository) (string, error) {
+ repoPath, err := GetPath(repo)
+ if err != nil {
+ return "", err
+ }
+
+ if repoPath == "" {
+ return "", grpc.Errorf(codes.InvalidArgument, "GetRepoPath: empty repo")
+ }
+
+ if IsGitDirectory(repoPath) {
+ return repoPath, nil
+ }
+
+ return "", grpc.Errorf(codes.NotFound, "GetRepoPath: not a git repository '%s'", repoPath)
+}
+
+// GetPath returns the path of the repo passed as first argument. An error is
+// returned when either the storage can't be found or the path includes
+// constructs trying to perform directory traversal.
+func GetPath(repo *pb.Repository) (string, error) {
storagePath, ok := config.StoragePath(repo.GetStorageName())
if !ok {
return "", grpc.Errorf(codes.InvalidArgument, "GetRepoPath: invalid storage name '%s'", repo.GetStorageName())
@@ -33,15 +53,23 @@ func GetRepoPath(repo *pb.Repository) (string, error) {
return "", grpc.Errorf(codes.InvalidArgument, "GetRepoPath: relative path can't contain directory traversal")
}
- repoPath := path.Join(storagePath, relativePath)
+ return path.Join(storagePath, relativePath), nil
+}
- if repoPath == "" {
- return "", grpc.Errorf(codes.InvalidArgument, "GetRepoPath: empty repo")
+// IsGitDirectory checks if the directory passed as first argument looks like
+// a valid git directory.
+func IsGitDirectory(dir string) bool {
+ if dir == "" {
+ return false
+ }
+
+ if _, err := os.Stat(path.Join(dir, "objects")); err != nil {
+ return false
}
- if _, err := os.Stat(path.Join(repoPath, "objects")); err != nil {
- return "", grpc.Errorf(codes.NotFound, "GetRepoPath: not a git repository '%s'", repoPath)
+ if _, err := os.Stat(path.Join(dir, "HEAD")); err != nil {
+ return false
}
- return repoPath, nil
+ return true
}
diff --git a/internal/service/repository/repository.go b/internal/service/repository/repository.go
new file mode 100644
index 000000000..61ff2040d
--- /dev/null
+++ b/internal/service/repository/repository.go
@@ -0,0 +1,21 @@
+package repository
+
+import (
+ "golang.org/x/net/context"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
+)
+
+func (s *server) Exists(ctx context.Context, in *pb.RepositoryExistsRequest) (*pb.RepositoryExistsResponse, error) {
+ path, err := helper.GetPath(in.Repository)
+ if err != nil {
+ return nil, err
+ }
+
+ if helper.IsGitDirectory(path) {
+ return &pb.RepositoryExistsResponse{Exists: true}, nil
+ }
+
+ return &pb.RepositoryExistsResponse{Exists: false}, nil
+}
diff --git a/internal/service/repository/repository_test.go b/internal/service/repository/repository_test.go
new file mode 100644
index 000000000..01ef5cbf5
--- /dev/null
+++ b/internal/service/repository/repository_test.go
@@ -0,0 +1,91 @@
+package repository
+
+import (
+ "testing"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+ "gitlab.com/gitlab-org/gitaly/internal/config"
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
+
+ "github.com/stretchr/testify/require"
+ "golang.org/x/net/context"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+func TestRepositoryExists(t *testing.T) {
+ server := runRepoServer(t)
+ defer server.Stop()
+
+ client := newRepositoryClient(t)
+
+ // Setup storage paths
+ testStorages := []config.Storage{
+ {Name: "default", Path: testhelper.GitlabTestStoragePath()},
+ {Name: "other", Path: "/home/git/repositories2"},
+ }
+
+ defer func(oldStorages []config.Storage) {
+ config.Config.Storages = oldStorages
+ }(config.Config.Storages)
+ config.Config.Storages = testStorages
+
+ queries := []struct {
+ Request *pb.RepositoryExistsRequest
+ ErrorCode codes.Code
+ Exists bool
+ }{
+ {
+ Request: &pb.RepositoryExistsRequest{
+ Repository: nil,
+ },
+ ErrorCode: codes.InvalidArgument,
+ },
+ {
+ Request: &pb.RepositoryExistsRequest{
+ Repository: &pb.Repository{
+ StorageName: "",
+ RelativePath: testhelper.TestRelativePath,
+ },
+ },
+ ErrorCode: codes.InvalidArgument,
+ },
+ {
+ Request: &pb.RepositoryExistsRequest{
+ Repository: &pb.Repository{
+ StorageName: "default",
+ RelativePath: "",
+ },
+ },
+ ErrorCode: codes.InvalidArgument,
+ },
+ {
+ Request: &pb.RepositoryExistsRequest{
+ Repository: &pb.Repository{
+ StorageName: "default",
+ RelativePath: testhelper.TestRelativePath,
+ },
+ },
+ Exists: true,
+ },
+ {
+ Request: &pb.RepositoryExistsRequest{
+ Repository: &pb.Repository{
+ StorageName: "other",
+ RelativePath: testhelper.TestRelativePath,
+ },
+ },
+ Exists: false,
+ },
+ }
+
+ for _, tc := range queries {
+ response, err := client.Exists(context.Background(), tc.Request)
+ if err != nil {
+ require.Equal(t, tc.ErrorCode, grpc.Code(err))
+ continue
+ }
+
+ require.Equal(t, tc.Exists, response.Exists)
+ }
+}
diff --git a/internal/service/repository/server.go b/internal/service/repository/server.go
new file mode 100644
index 000000000..d47c1a9b8
--- /dev/null
+++ b/internal/service/repository/server.go
@@ -0,0 +1,12 @@
+package repository
+
+import (
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+)
+
+type server struct{}
+
+// NewServer creates a new instance of a gRPC repo server
+func NewServer() pb.RepositoryServiceServer {
+ return &server{}
+}
diff --git a/internal/service/repository/testhelper_test.go b/internal/service/repository/testhelper_test.go
new file mode 100644
index 000000000..0972baa75
--- /dev/null
+++ b/internal/service/repository/testhelper_test.go
@@ -0,0 +1,64 @@
+package repository
+
+import (
+ "net"
+ "os"
+ "path"
+ "testing"
+ "time"
+
+ log "github.com/Sirupsen/logrus"
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/reflection"
+)
+
+const scratchDir = "testdata/scratch"
+
+var (
+ serverSocketPath = path.Join(scratchDir, "gitaly.sock")
+ testRepo *pb.Repository
+)
+
+func TestMain(m *testing.M) {
+ testRepo = testhelper.TestRepository()
+
+ if err := os.MkdirAll(scratchDir, 0755); err != nil {
+ log.WithError(err).Fatal("mkdirall failed")
+ }
+
+ os.Exit(func() int {
+ return m.Run()
+ }())
+}
+
+func newRepositoryClient(t *testing.T) pb.RepositoryServiceClient {
+ connOpts := []grpc.DialOption{
+ grpc.WithInsecure(),
+ grpc.WithDialer(func(addr string, _ time.Duration) (net.Conn, error) {
+ return net.Dial("unix", addr)
+ }),
+ }
+ conn, err := grpc.Dial(serverSocketPath, connOpts...)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return pb.NewRepositoryServiceClient(conn)
+}
+
+func runRepoServer(t *testing.T) *grpc.Server {
+ server := grpc.NewServer()
+ listener, err := net.Listen("unix", serverSocketPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pb.RegisterRepositoryServiceServer(server, NewServer())
+ reflection.Register(server)
+
+ go server.Serve(listener)
+
+ return server
+}