mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-21 16:13:13 +00:00
Repository: Added the git_repository_discover function that finds by itself the git directory that manage a given directory path.
This commit is contained in:
parent
222cf1d459
commit
fd0574e5ad
@ -132,6 +132,34 @@ GIT_EXTERN(int) git_repository_open3(git_repository **repository,
|
||||
const char *git_index_file,
|
||||
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
|
||||
*
|
||||
|
134
src/repository.c
134
src/repository.c
@ -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(¤t_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);
|
||||
|
Loading…
Reference in New Issue
Block a user