Commit 372dc9ff6ada409204b7c3de882e5dad16f30b36

Patrick Steinhardt 2015-10-21T13:49:55

worktree: implement `git_worktree_validate` Add a new function that checks wether a given `struct git_worktree` is valid. The validation includes checking if the gitdir, parent directory and common directory are present.

diff --git a/include/git2/errors.h b/include/git2/errors.h
index e959ffd..1d27136 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -100,6 +100,7 @@ typedef enum {
 	GITERR_REBASE,
 	GITERR_FILESYSTEM,
 	GITERR_PATCH,
+	GITERR_WORKTREE
 } git_error_t;
 
 /**
diff --git a/include/git2/worktree.h b/include/git2/worktree.h
index 8313265..c6ca30b 100644
--- a/include/git2/worktree.h
+++ b/include/git2/worktree.h
@@ -49,6 +49,18 @@ GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, co
  */
 GIT_EXTERN(void) git_worktree_free(git_worktree *wt);
 
+/**
+ * Check if worktree is valid
+ *
+ * A valid worktree requires both the git data structures inside
+ * the linked parent repository and the linked working copy to be
+ * present.
+ *
+ * @param wt Worktree to check
+ * @return 0 when worktree is valid, error-code otherwise
+ */
+GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/src/worktree.c b/src/worktree.c
index a0e5d93..2852c18 100644
--- a/src/worktree.c
+++ b/src/worktree.c
@@ -145,3 +145,41 @@ void git_worktree_free(git_worktree *wt)
 	git__free(wt->name);
 	git__free(wt);
 }
+
+int git_worktree_validate(const git_worktree *wt)
+{
+	git_buf buf = GIT_BUF_INIT;
+	int err = 0;
+
+	assert(wt);
+
+	git_buf_puts(&buf, wt->gitdir_path);
+	if (!is_worktree_dir(&buf)) {
+		giterr_set(GITERR_WORKTREE,
+			"Worktree gitdir ('%s') is not valid",
+			wt->gitlink_path);
+		err = -1;
+		goto out;
+	}
+
+	if (!git_path_exists(wt->parent_path)) {
+		giterr_set(GITERR_WORKTREE,
+			"Worktree parent directory ('%s') does not exist ",
+			wt->parent_path);
+		err = -2;
+		goto out;
+	}
+
+	if (!git_path_exists(wt->commondir_path)) {
+		giterr_set(GITERR_WORKTREE,
+			"Worktree common directory ('%s') does not exist ",
+			wt->commondir_path);
+		err = -3;
+		goto out;
+	}
+
+out:
+	git_buf_free(&buf);
+
+	return err;
+}
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
index d891d6f..7e9cd25 100644
--- a/tests/worktree/worktree.c
+++ b/tests/worktree/worktree.c
@@ -203,3 +203,53 @@ void test_worktree_worktree__open_invalid_parent(void)
 	git_buf_free(&buf);
 	git_worktree_free(wt);
 }
+
+void test_worktree_worktree__validate(void)
+{
+	git_worktree *wt;
+
+	cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+	cl_git_pass(git_worktree_validate(wt));
+
+	git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_commondir(void)
+{
+	git_worktree *wt;
+
+	cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+	git__free(wt->commondir_path);
+	wt->commondir_path = "/path/to/invalid/commondir";
+
+	cl_git_fail(git_worktree_validate(wt));
+
+	wt->commondir_path = NULL;
+	git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_gitdir(void)
+{
+	git_worktree *wt;
+
+	cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+	git__free(wt->gitdir_path);
+	wt->gitdir_path = "/path/to/invalid/gitdir";
+	cl_git_fail(git_worktree_validate(wt));
+
+	wt->gitdir_path = NULL;
+	git_worktree_free(wt);
+}
+
+void test_worktree_worktree__validate_invalid_parent(void)
+{
+	git_worktree *wt;
+
+	cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
+	git__free(wt->parent_path);
+	wt->parent_path = "/path/to/invalid/parent";
+	cl_git_fail(git_worktree_validate(wt));
+
+	wt->parent_path = NULL;
+	git_worktree_free(wt);
+}