commit 85f51bbadd426ab2f3f7fc70e879ac6763354479 from: Stefan Sperling date: Mon Jul 16 06:03:36 2018 UTC scan upwards for git repositories commit - 2550e4c30a9f21b56451804f10fada6b4be29233 commit + 85f51bbadd426ab2f3f7fc70e879ac6763354479 blob - 4cda42e4375329eac05ec2c3dd673bd79dd9661f blob + ed9663ebba15d6ad33dcc70aa70b8c8af92d0086 --- lib/repository.c +++ lib/repository.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "got_error.h" #include "got_reference.h" @@ -296,12 +298,97 @@ got_repo_get_cached_commit(struct got_repository *repo } const struct got_error * -got_repo_open(struct got_repository **ret, const char *path) +open_repo(struct got_repository *repo, const char *path) { + const struct got_error *err = NULL; + struct got_worktree *worktree = NULL; + + /* bare git repository? */ + repo->path_git_dir = strdup(path); + if (repo->path_git_dir == NULL) { + err = got_error_from_errno(); + goto done; + } + if (is_git_repo(repo)) { + repo->path = strdup(repo->path_git_dir); + if (repo->path == NULL) { + err = got_error_from_errno(); + goto done; + } + return NULL; + } + + /* git repository with working tree? */ + free(repo->path_git_dir); + if (asprintf(&repo->path_git_dir, "%s/%s", path, GOT_GIT_DIR) == -1) { + err = got_error_from_errno(); + goto done; + } + if (is_git_repo(repo)) { + repo->path = strdup(path); + if (repo->path == NULL) { + err = got_error_from_errno(); + goto done; + } + return NULL; + } + + /* got work tree checked out from bare git repository? */ + free(repo->path_git_dir); + repo->path_git_dir = NULL; + err = got_worktree_open(&worktree, path); + if (err) { + if (err->code == GOT_ERR_ERRNO && errno == ENOENT) + err = got_error(GOT_ERR_NOT_GIT_REPO); + goto done; + } + repo->path_git_dir = strdup(worktree->repo_path); + if (repo->path_git_dir == NULL) { + err = got_error_from_errno(); + goto done; + } + + /* got work tree checked out from git repository with working tree? */ + if (!is_git_repo(repo)) { + free(repo->path_git_dir); + if (asprintf(&repo->path_git_dir, "%s/%s", worktree->repo_path, + GOT_GIT_DIR) == -1) { + err = got_error_from_errno(); + repo->path_git_dir = NULL; + goto done; + } + if (!is_git_repo(repo)) { + err = got_error(GOT_ERR_NOT_GIT_REPO); + goto done; + } + repo->path = strdup(worktree->repo_path); + if (repo->path == NULL) { + err = got_error_from_errno(); + goto done; + } + } else { + repo->path = strdup(repo->path_git_dir); + if (repo->path == NULL) { + err = got_error_from_errno(); + goto done; + } + } +done: + if (worktree) + got_worktree_close(worktree); + return err; +} + +const struct got_error * +got_repo_open(struct got_repository **repop, const char *path) +{ struct got_repository *repo = NULL; const struct got_error *err = NULL; - char *abspath; + char *abspath, *normpath = NULL; + int tried_root = 0; + *repop = NULL; + if (got_path_is_absolute(path)) abspath = strdup(path); else @@ -341,57 +428,37 @@ got_repo_open(struct got_repository **ret, const char goto done; } - repo->path = got_path_normalize(abspath); - if (repo->path == NULL) { + normpath = got_path_normalize(abspath); + if (normpath == NULL) { err = got_error(GOT_ERR_BAD_PATH); goto done; } - repo->path_git_dir = strdup(repo->path); - if (repo->path_git_dir == NULL) { - err = got_error_from_errno(); - goto done; - } - if (!is_git_repo(repo)) { - free(repo->path_git_dir); - if (asprintf(&repo->path_git_dir, "%s/%s", repo->path, - GOT_GIT_DIR) == -1) { - err = got_error_from_errno(); - goto done; - } - if (!is_git_repo(repo)) { - struct got_worktree *worktree; - if (got_worktree_open(&worktree, repo->path) == NULL) { - free(repo->path_git_dir); - repo->path_git_dir = - strdup(worktree->repo_path); - if (repo->path_git_dir == NULL) { - err = got_error_from_errno(); - goto done; - } - if (!is_git_repo(repo)) { - free(repo->path_git_dir); - if (asprintf(&repo->path_git_dir, - "%s/%s", worktree->repo_path, - GOT_GIT_DIR) == -1) { - err = got_error_from_errno(); - goto done; - } - } - got_worktree_close(worktree); + path = normpath; + do { + err = open_repo(repo, path); + if (err == NULL) + break; + if (err->code != GOT_ERR_NOT_GIT_REPO) + break; + if (path[0] == '/' && path[1] == '\0') { + if (tried_root) { + err = got_error(GOT_ERR_NOT_GIT_REPO); + break; } + tried_root = 1; } - if (!is_git_repo(repo)) { - err = got_error(GOT_ERR_NOT_GIT_REPO); - goto done; - } - } - - *ret = repo; + path = dirname(path); + if (path == NULL) + err = got_error_from_errno(); + } while (path); done: if (err) got_repo_close(repo); + else + *repop = repo; free(abspath); + free(normpath); return err; }