Commit fd0574e5 by Romain Geissler

Repository: Added the git_repository_discover function that finds by itself the…

Repository: Added the git_repository_discover function that finds by itself the git directory that manage a given directory path.
parent 222cf1d4
......@@ -133,6 +133,34 @@ GIT_EXTERN(int) git_repository_open3(git_repository **repository,
const char *git_work_tree);
/**
* Look for a git repository and copy its path in the given buffer. The lookup start
* from base_path and walk across parent directories if nothing has been found. The
* lookup ends when the first repository is found, or when reaching a directory
* referenced in ceiling_dirs or when the filesystem changes (in case across_fs
* is true).
*
* The method will automatically detect if the repository is bare (if there is
* a repository).
*
* @param repository_path The user allocated buffer which will contain the found path.
*
* @param size repository_path size
*
* @param start_path The base path where the lookup starts.
*
* @param across_fs If true, then the lookup will not stop when a filesystem device change
* is detected while exploring parent directories.
*
* @param ceiling_dirs A colon separated of absolute symbolic link free paths. The lookup will
* stop when any of this paths is reached. Note that the lookup always performs on start_path
* no matter start_path appears in ceiling_dirs
* ceiling_dirs might be NULL (which is equivalent to an empty string)
*
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs);
/**
* Get the object database behind a Git repository
*
* @param repo a repository object
......
......@@ -271,6 +271,21 @@ cleanup:
return git__rethrow(error, "Failed to open repository");
}
static int discover_repository_dirs(git_repository *repo, const char *path)
{
int error;
error = guess_repository_dirs(repo, path);
if (error < GIT_SUCCESS)
return error;
error = check_repository_dirs(repo);
if (error < GIT_SUCCESS)
return error;
return GIT_SUCCESS;
}
int git_repository_open(git_repository **repo_out, const char *path)
{
git_repository *repo;
......@@ -282,11 +297,7 @@ int git_repository_open(git_repository **repo_out, const char *path)
if (repo == NULL)
return GIT_ENOMEM;
error = guess_repository_dirs(repo, path);
if (error < GIT_SUCCESS)
goto cleanup;
error = check_repository_dirs(repo);
error = discover_repository_dirs(repo, path);
if (error < GIT_SUCCESS)
goto cleanup;
......@@ -440,6 +451,119 @@ void git_repository_free(git_repository *repo)
free(repo);
}
int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
{
git_repository repo;
int error, ceiling_offset;
char bare_path[GIT_PATH_MAX];
char normal_path[GIT_PATH_MAX];
char *found_path;
dev_t current_device;
assert(start_path && repository_path);
memset(&repo, 0x0, sizeof(git_repository));
error = abspath(bare_path, sizeof(bare_path), start_path);
if (error < GIT_SUCCESS)
goto cleanup;
if (!across_fs) {
error = retrieve_device(&current_device, bare_path);
if (error < GIT_SUCCESS)
goto cleanup;
}
ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
git__joinpath(normal_path, bare_path, DOT_GIT);
while(1){
//look for .git file
if (gitfo_isfile(normal_path) == GIT_SUCCESS) {
error = read_gitfile(repository_path, size, normal_path, bare_path);
if (error < GIT_SUCCESS) {
git__rethrow(error, "Unable to read git file `%s`", normal_path);
goto cleanup;
}
error = discover_repository_dirs(&repo, repository_path);
if (error < GIT_SUCCESS)
goto cleanup;
git_repository__free_dirs(&repo);
return GIT_SUCCESS;
}
//look for .git repository
error = discover_repository_dirs(&repo, normal_path);
if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
goto cleanup;
if (error == GIT_SUCCESS) {
found_path = normal_path;
break;
}
git_repository__free_dirs(&repo);
//look for bare repository in current directory
error = discover_repository_dirs(&repo, bare_path);
if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
goto cleanup;
if (error == GIT_SUCCESS) {
found_path = bare_path;
break;
}
git_repository__free_dirs(&repo);
//nothing has been found, lets try the parent directory
if (bare_path[ceiling_offset] == '\0') {
error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
goto cleanup;
}
if (git__dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
goto cleanup;
if (!across_fs) {
dev_t new_device;
error = retrieve_device(&new_device, normal_path);
if (error < GIT_SUCCESS)
goto cleanup;
if (current_device != new_device) {
error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM_ENVIRONMENT not set).", bare_path);
goto cleanup;
}
current_device = new_device;
}
strcpy(bare_path, normal_path);
git__joinpath(normal_path, bare_path, DOT_GIT);
}
if (size < (strlen(found_path) + 1) * sizeof(char)) {
error = git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
goto cleanup;
}
strcpy(repository_path, found_path);
git_repository__free_dirs(&repo);
return GIT_SUCCESS;
cleanup:
git_repository__free_dirs(&repo);
return git__rethrow(error, "Failed to discover repository");
}
git_odb *git_repository_database(git_repository *repo)
{
assert(repo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment