diff options
author | Yuang Li <yuangli88@hotmail.com> | 2022-07-29 09:36:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-29 09:36:14 +0100 |
commit | a491917f8e37108b6180590736d833095626b1ec (patch) | |
tree | 2802cfbafd3e7d94e6a3153848ed0edf3ac1aebc /src | |
parent | 7f46bfac14f0502711f8441348fd361175953fd5 (diff) | |
parent | 09acf6986513381316c8797c4529323bff8525a5 (diff) | |
download | libgit2-a491917f8e37108b6180590736d833095626b1ec.tar.gz |
Merge pull request #5 from mathworks/shallow-clone-local
Shallow clone local
Diffstat (limited to 'src')
-rw-r--r-- | src/libgit2/commit.c | 43 | ||||
-rw-r--r-- | src/libgit2/grafts.c | 246 | ||||
-rw-r--r-- | src/libgit2/grafts.h | 37 | ||||
-rw-r--r-- | src/libgit2/libgit2.c | 5 | ||||
-rw-r--r-- | src/libgit2/repository.c | 41 | ||||
-rw-r--r-- | src/libgit2/repository.h | 6 |
6 files changed, 370 insertions, 8 deletions
diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 114ae6fc9..75cc8837c 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -22,6 +22,7 @@ #include "object.h" #include "array.h" #include "oidarray.h" +#include "grafts.h" void git_commit__free(void *_commit) { @@ -421,13 +422,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig buffer += tree_len; } - /* - * TODO: commit grafts! - */ - - while (git_object__parse_oid_header(&parent_id, - &buffer, buffer_end, "parent ", - GIT_OID_SHA1) == 0) { + while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GIT_ERROR_CHECK_ALLOC(new_id); @@ -508,9 +503,41 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size) return commit_parse(commit, data, size, 0); } +static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) { + size_t idx; + git_oid *oid; + + git_array_clear(commit->parent_ids); + git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents)); + git_array_foreach(graft->parents, idx, oid) { + git_oid *id = git_array_alloc(commit->parent_ids); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, oid); + } + + return 0; +} + int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) { - return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags); + git_repository *repo = git_object_owner((git_object *)commit); + git_commit_graft *graft; + int error; + + if ((error = commit_parse(commit, git_odb_object_data(odb_obj), + git_odb_object_size(odb_obj), flags)) < 0) + return error; + + if (!git_shallow__enabled) + return 0; + + /* Perform necessary grafts */ + if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 && + git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0) + return 0; + + return assign_commit_parents_from_graft(commit, graft); } int git_commit__parse(void *_commit, git_odb_object *odb_obj) diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c new file mode 100644 index 000000000..82be2a680 --- /dev/null +++ b/src/libgit2/grafts.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "grafts.h" + +#include "futils.h" +#include "oidarray.h" +#include "parse.h" + +bool git_shallow__enabled = false; + +struct git_grafts { + /* Map of `git_commit_graft`s */ + git_oidmap *commits; + + /* File backing the graft. NULL if it's an in-memory graft */ + char *path; + git_oid path_checksum; +}; + +int git_grafts_new(git_grafts **out) +{ + git_grafts *grafts; + + grafts = git__calloc(1, sizeof(*grafts)); + GIT_ERROR_CHECK_ALLOC(grafts); + + if ((git_oidmap_new(&grafts->commits)) < 0) { + git__free(grafts); + return -1; + } + + *out = grafts; + return 0; +} + +int git_grafts_from_file(git_grafts **out, const char *path) +{ + git_grafts *grafts = NULL; + int error; + + if ((error = git_grafts_new(&grafts)) < 0) + goto error; + + grafts->path = git__strdup(path); + GIT_ERROR_CHECK_ALLOC(grafts->path); + + if ((error = git_grafts_refresh(grafts)) < 0) + goto error; + + *out = grafts; +error: + if (error < 0) + git_grafts_free(grafts); + return error; +} + +void git_grafts_free(git_grafts *grafts) +{ + if (!grafts) + return; + git__free(grafts->path); + git_grafts_clear(grafts); + git_oidmap_free(grafts->commits); + git__free(grafts); +} + +void git_grafts_clear(git_grafts *grafts) +{ + git_commit_graft *graft; + + assert(grafts); + + git_oidmap_foreach_value(grafts->commits, graft, { + git__free(graft->parents.ptr); + git__free(graft); + }); + + git_oidmap_clear(grafts->commits); +} + +int git_grafts_refresh(git_grafts *grafts) +{ + git_str contents = GIT_STR_INIT; + int error, updated = 0; + + assert(grafts); + + if (!grafts->path) + return 0; + + if ((error = git_futils_readbuffer_updated(&contents, grafts->path, + (grafts->path_checksum).id, &updated)) < 0) { + if (error == GIT_ENOTFOUND) { + git_grafts_clear(grafts); + error = 0; + } + + goto cleanup; + } + + if (!updated) { + goto cleanup; + } + + if ((error = git_grafts_parse(grafts, contents.ptr, contents.size)) < 0) + goto cleanup; + +cleanup: + git_str_dispose(&contents); + return error; +} + +int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen) +{ + git_array_oid_t parents = GIT_ARRAY_INIT; + git_parse_ctx parser; + int error; + + git_grafts_clear(grafts); + + if ((error = git_parse_ctx_init(&parser, content, contentlen)) < 0) + goto error; + + for (; parser.remain_len; git_parse_advance_line(&parser)) { + const char *line_start = parser.line, *line_end = parser.line + parser.line_len; + git_oid graft_oid; + + if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num); + goto error; + } + line_start += GIT_OID_HEXSZ; + + while (line_start < line_end && *line_start == ' ') { + git_oid *id = git_array_alloc(parents); + GIT_ERROR_CHECK_ALLOC(id); + + if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ)) < 0) { + git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num); + goto error; + } + + line_start += GIT_OID_HEXSZ; + } + + if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0) + goto error; + + git_array_clear(parents); + } + +error: + git_array_clear(parents); + return error; +} + +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents) +{ + git_commit_graft *graft; + git_oid *parent_oid; + int error; + size_t i; + + assert(grafts && oid); + + graft = git__calloc(1, sizeof(*graft)); + GIT_ERROR_CHECK_ALLOC(graft); + + git_array_init_to_size(graft->parents, git_array_size(parents)); + git_array_foreach(parents, i, parent_oid) { + git_oid *id = git_array_alloc(graft->parents); + GIT_ERROR_CHECK_ALLOC(id); + + git_oid_cpy(id, parent_oid); + } + git_oid_cpy(&graft->oid, oid); + + if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND) + goto cleanup; + if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0) + goto cleanup; + + return 0; + +cleanup: + git_array_clear(graft->parents); + git__free(graft); + return error; +} + +int git_grafts_remove(git_grafts *grafts, const git_oid *oid) +{ + git_commit_graft *graft; + int error; + + assert(grafts && oid); + + if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + + if ((error = git_oidmap_delete(grafts->commits, oid)) < 0) + return error; + + git__free(graft->parents.ptr); + git__free(graft); + + return 0; +} + +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid) +{ + assert(out && grafts && oid); + if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL) + return GIT_ENOTFOUND; + return 0; +} + +int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts) +{ + git_array_oid_t oids = GIT_ARRAY_INIT; + const git_oid *oid; + size_t i = 0; + int error; + + assert(out && grafts); + + while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) { + git_oid *cpy = git_array_alloc(oids); + GIT_ERROR_CHECK_ALLOC(cpy); + git_oid_cpy(cpy, oid); + } + + git_oidarray__from_array(out, &oids); + + return 0; +} + +size_t git_grafts_size(git_grafts *grafts) +{ + return git_oidmap_size(grafts->commits); +} diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h new file mode 100644 index 000000000..fd9ef6736 --- /dev/null +++ b/src/libgit2/grafts.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_graft_h__ +#define INCLUDE_graft_h__ + +#include "common.h" +#include "oidarray.h" +#include "oidmap.h" + +/** graft commit */ +typedef struct { + git_oid oid; + git_array_oid_t parents; +} git_commit_graft; + +typedef struct git_grafts git_grafts; + +extern bool git_shallow__enabled; + +int git_grafts_new(git_grafts **out); +int git_grafts_from_file(git_grafts **out, const char *path); +void git_grafts_free(git_grafts *grafts); +void git_grafts_clear(git_grafts *grafts); + +int git_grafts_refresh(git_grafts *grafts); +int git_grafts_parse(git_grafts *grafts, const char *content, size_t contentlen); +int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents); +int git_grafts_remove(git_grafts *grafts, const git_oid *oid); +int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid); +int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts); +size_t git_grafts_size(git_grafts *grafts); + +#endif diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c index 2fda0722e..2537730cf 100644 --- a/src/libgit2/libgit2.c +++ b/src/libgit2/libgit2.c @@ -13,6 +13,7 @@ #include "cache.h" #include "common.h" #include "filter.h" +#include "grafts.h" #include "hash.h" #include "index.h" #include "merge_driver.h" @@ -414,6 +415,10 @@ int git_libgit2_opts(int key, ...) git_repository__validate_ownership = (va_arg(ap, int) != 0); break; + case GIT_OPT_ENABLE_SHALLOW: + git_shallow__enabled = (va_arg(ap, int) != 0); + break; + default: git_error_set(GIT_ERROR_INVALID, "invalid option key"); error = -1; diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 90ac91db9..761772d55 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -15,6 +15,7 @@ #include "buf.h" #include "common.h" #include "commit.h" +#include "grafts.h" #include "tag.h" #include "blob.h" #include "futils.h" @@ -150,6 +151,8 @@ int git_repository__cleanup(git_repository *repo) git_repository_submodule_cache_clear(repo); git_cache_clear(&repo->objects); git_attr_cache_flush(repo); + git_grafts_free(repo->grafts); + git_grafts_free(repo->shallow_grafts); set_config(repo, NULL); set_index(repo, NULL); @@ -727,6 +730,27 @@ out: return error; } +static int load_grafts(git_repository *repo) +{ + git_str path = GIT_STR_INIT; + int error; + + if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || + (error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 || + (error = git_grafts_from_file(&repo->grafts, path.ptr)) < 0) + goto error; + + git_str_clear(&path); + + if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 || + (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0) + goto error; + +error: + git_str_dispose(&path); + return error; +} + int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) @@ -1016,6 +1040,9 @@ int git_repository_open_ext( if ((error = check_extensions(config, version)) < 0) goto cleanup; + if (git_shallow__enabled && (error = load_grafts(repo)) < 0) + goto cleanup; + if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) { repo->is_bare = 1; } else { @@ -1402,6 +1429,20 @@ int git_repository_set_index(git_repository *repo, git_index *index) return 0; } +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + assert(out && repo && repo->grafts); + *out = repo->grafts; + return 0; +} + +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo) +{ + assert(out && repo && repo->shallow_grafts); + *out = repo->shallow_grafts; + return 0; +} + int git_repository_set_namespace(git_repository *repo, const char *namespace) { git__free(repo->namespace); diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h index a488f2bf2..3cca53b3e 100644 --- a/src/libgit2/repository.h +++ b/src/libgit2/repository.h @@ -24,6 +24,7 @@ #include "attrcache.h" #include "submodule.h" #include "diff_driver.h" +#include "grafts.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" @@ -156,6 +157,9 @@ struct git_repository { unsigned int lru_counter; + git_grafts *grafts; + git_grafts *shallow_grafts; + git_atomic32 attr_session_key; intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX]; @@ -187,6 +191,8 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo); int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); +int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo); +int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo); /* * Configuration map cache |