diff options
author | Edward Thomson <ethomson@github.com> | 2017-01-22 01:39:59 +0300 |
---|---|---|
committer | Edward Thomson <ethomson@github.com> | 2017-01-22 01:39:59 +0300 |
commit | 9e78b7279de4bcf22a354c02ae25a6a0849dbb7d (patch) | |
tree | d1685f02dd139a9414d8940df129039beb23b518 /src/submodule.c | |
parent | ba3a8304ab53e9711cce5aec4ffa5668300034b1 (diff) | |
parent | 176f55527d00160ec9ef4816fec3a045c37890d8 (diff) |
Merge branch 'master' into pr/3938
Diffstat (limited to 'src/submodule.c')
-rw-r--r-- | src/submodule.c | 266 |
1 files changed, 158 insertions, 108 deletions
diff --git a/src/submodule.c b/src/submodule.c index ac6998603..21e3d45e4 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -124,8 +124,8 @@ static void submodule_set_lookup_error(int error, const char *name) return; giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ? - "No submodule named '%s'" : - "Submodule '%s' has not been added yet", name); + "no submodule named '%s'" : + "submodule '%s' has not been added yet", name); } typedef struct { @@ -149,40 +149,53 @@ static int find_by_path(const git_config_entry *entry, void *payload) } /** - * Find out the name of a submodule from its path + * Release the name map returned by 'load_submodule_names'. */ -static int name_from_path(git_buf *out, git_config *cfg, const char *path) +static void free_submodule_names(git_strmap *names) +{ + git_buf *name = 0; + if (names == NULL) + return; + git_strmap_foreach_value(names, name, { + git__free(name); + }); + git_strmap_free(names); + return; +} + +/** + * Map submodule paths to names. + * TODO: for some use-cases, this might need case-folding on a + * case-insensitive filesystem + */ +static int load_submodule_names(git_strmap *out, git_config *cfg) { const char *key = "submodule\\..*\\.path"; git_config_iterator *iter; git_config_entry *entry; - int error; + git_buf buf = GIT_BUF_INIT; + int rval; + int error = 0; if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) return error; - while ((error = git_config_next(&entry, iter)) == 0) { + while (git_config_next(&entry, iter) == 0) { const char *fdot, *ldot; - /* TODO: this should maybe be strcasecmp on a case-insensitive fs */ - if (strcmp(path, entry->value) != 0) - continue; - fdot = strchr(entry->name, '.'); ldot = strrchr(entry->name, '.'); - git_buf_clear(out); - git_buf_put(out, fdot + 1, ldot - fdot - 1); - goto cleanup; - } - - if (error == GIT_ITEROVER) { - giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path); - error = GIT_ENOTFOUND; + git_buf_put(&buf, fdot + 1, ldot - fdot - 1); + git_strmap_insert(out, entry->value, git_buf_detach(&buf), rval); + if (rval < 0) { + giterr_set(GITERR_NOMEMORY, "Error inserting submodule into hash table"); + free_submodule_names(out); + return -1; + } } -cleanup: git_config_iterator_free(iter); - return error; + return 0; } int git_submodule_lookup( @@ -196,6 +209,17 @@ int git_submodule_lookup( assert(repo && name); + if (repo->submodule_cache != NULL) { + khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name); + if (git_strmap_valid_index(repo->submodule_cache, pos)) { + if (out) { + *out = git_strmap_value_at(repo->submodule_cache, pos); + GIT_REFCOUNT_INC(*out); + } + return 0; + } + } + if ((error = submodule_alloc(&sm, repo, name)) < 0) return error; @@ -324,89 +348,107 @@ done: static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg) { - int error; - git_iterator *i; - const git_index_entry *entry; - git_buf name = GIT_BUF_INIT; - - if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) - return error; - - while (!(error = git_iterator_advance(&entry, i))) { - khiter_t pos = git_strmap_lookup_index(map, entry->path); - git_submodule *sm; + int error; + git_iterator *i; + const git_index_entry *entry; + git_strmap *names = 0; + git_strmap_alloc(&names); + if ((error = load_submodule_names(names, cfg))) + goto done; - git_buf_clear(&name); - if (!name_from_path(&name, cfg, entry->path)) { - git_strmap_lookup_index(map, name.ptr); - } + if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) + goto done; - if (git_strmap_valid_index(map, pos)) { - sm = git_strmap_value_at(map, pos); + while (!(error = git_iterator_advance(&entry, i))) { + khiter_t pos = git_strmap_lookup_index(map, entry->path); + git_submodule *sm; + + if (git_strmap_valid_index(map, pos)) { + sm = git_strmap_value_at(map, pos); + + if (S_ISGITLINK(entry->mode)) + submodule_update_from_index_entry(sm, entry); + else + sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE; + } else if (S_ISGITLINK(entry->mode)) { + khiter_t name_pos; + const char *name; + + name_pos = git_strmap_lookup_index(names, entry->path); + if (git_strmap_valid_index(names, name_pos)) { + name = git_strmap_value_at(names, name_pos); + } else { + name = entry->path; + } - if (S_ISGITLINK(entry->mode)) - submodule_update_from_index_entry(sm, entry); - else - sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE; - } else if (S_ISGITLINK(entry->mode)) { - if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name.ptr ? name.ptr : entry->path)) { - submodule_update_from_index_entry(sm, entry); - git_submodule_free(sm); - } - } - } + if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) { + submodule_update_from_index_entry(sm, entry); + git_submodule_free(sm); + } + } + } - if (error == GIT_ITEROVER) - error = 0; + if (error == GIT_ITEROVER) + error = 0; - git_buf_free(&name); - git_iterator_free(i); +done: + git_iterator_free(i); + free_submodule_names(names); - return error; + return error; } static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg) { - int error; - git_iterator *i; - const git_index_entry *entry; - git_buf name = GIT_BUF_INIT; - - if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) - return error; - - while (!(error = git_iterator_advance(&entry, i))) { - khiter_t pos = git_strmap_lookup_index(map, entry->path); - git_submodule *sm; + int error; + git_iterator *i; + const git_index_entry *entry; + git_strmap *names = 0; + git_strmap_alloc(&names); + if ((error = load_submodule_names(names, cfg))) + goto done; - git_buf_clear(&name); - if (!name_from_path(&name, cfg, entry->path)) { - git_strmap_lookup_index(map, name.ptr); - } + if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) + goto done; - if (git_strmap_valid_index(map, pos)) { - sm = git_strmap_value_at(map, pos); + while (!(error = git_iterator_advance(&entry, i))) { + khiter_t pos = git_strmap_lookup_index(map, entry->path); + git_submodule *sm; + + if (git_strmap_valid_index(map, pos)) { + sm = git_strmap_value_at(map, pos); + + if (S_ISGITLINK(entry->mode)) + submodule_update_from_head_data(sm, entry->mode, &entry->id); + else + sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE; + } else if (S_ISGITLINK(entry->mode)) { + khiter_t name_pos; + const char *name; + + name_pos = git_strmap_lookup_index(names, entry->path); + if (git_strmap_valid_index(names, name_pos)) { + name = git_strmap_value_at(names, name_pos); + } else { + name = entry->path; + } - if (S_ISGITLINK(entry->mode)) - submodule_update_from_head_data(sm, entry->mode, &entry->id); - else - sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE; - } else if (S_ISGITLINK(entry->mode)) { - if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name.ptr ? name.ptr : entry->path)) { - submodule_update_from_head_data( - sm, entry->mode, &entry->id); - git_submodule_free(sm); - } - } - } + if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) { + submodule_update_from_head_data( + sm, entry->mode, &entry->id); + git_submodule_free(sm); + } + } + } - if (error == GIT_ITEROVER) - error = 0; + if (error == GIT_ITEROVER) + error = 0; - git_buf_free(&name); - git_iterator_free(i); +done: + git_iterator_free(i); + free_submodule_names(names); - return error; + return error; } /* If have_sm is true, sm is populated, otherwise map an repo are. */ @@ -416,7 +458,7 @@ typedef struct { git_repository *repo; } lfc_data; -static int all_submodules(git_repository *repo, git_strmap *map) +int git_submodule__map(git_repository *repo, git_strmap *map) { int error = 0; git_index *idx = NULL; @@ -509,7 +551,7 @@ int git_submodule_foreach( if ((error = git_strmap_alloc(&submodules)) < 0) return error; - if ((error = all_submodules(repo, submodules)) < 0) + if ((error = git_submodule__map(repo, submodules)) < 0) goto done; if (!(error = git_vector_init( @@ -618,7 +660,7 @@ int git_submodule_add_setup( giterr_clear(); else { giterr_set(GITERR_SUBMODULE, - "Attempt to add submodule '%s' that already exists", path); + "attempt to add submodule '%s' that already exists", path); return GIT_EEXISTS; } @@ -628,7 +670,7 @@ int git_submodule_add_setup( path += strlen(git_repository_workdir(repo)); if (git_path_root(path) >= 0) { - giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path"); + giterr_set(GITERR_SUBMODULE, "submodule path must be a relative path"); error = -1; goto cleanup; } @@ -637,7 +679,7 @@ int git_submodule_add_setup( if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) { giterr_set(GITERR_SUBMODULE, - "Adding submodules to a bare repository is not supported"); + "adding submodules to a bare repository is not supported"); return -1; } @@ -758,7 +800,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index) /* read stat information for submodule working directory */ if (p_stat(path.ptr, &st) < 0) { giterr_set(GITERR_SUBMODULE, - "Cannot add submodule without working directory"); + "cannot add submodule without working directory"); error = -1; goto cleanup; } @@ -771,7 +813,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index) /* calling git_submodule_open will have set sm->wd_oid if possible */ if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) { giterr_set(GITERR_SUBMODULE, - "Cannot add submodule without HEAD to index"); + "cannot add submodule without HEAD to index"); error = -1; goto cleanup; } @@ -861,7 +903,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur } else if (strchr(url, ':') != NULL || url[0] == '/') { error = git_buf_sets(out, url); } else { - giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL"); + giterr_set(GITERR_SUBMODULE, "invalid format for submodule URL"); error = -1; } @@ -1133,7 +1175,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio goto done; if (!init) { - giterr_set(GITERR_SUBMODULE, "Submodule is not initialized."); + giterr_set(GITERR_SUBMODULE, "submodule is not initialized"); error = GIT_ERROR; goto done; } @@ -1214,7 +1256,7 @@ int git_submodule_init(git_submodule *sm, int overwrite) if (!sm->url) { giterr_set(GITERR_SUBMODULE, - "No URL configured for submodule '%s'", sm->name); + "no URL configured for submodule '%s'", sm->name); return -1; } @@ -1258,7 +1300,7 @@ int git_submodule_sync(git_submodule *sm) if (!sm->url) { giterr_set(GITERR_SUBMODULE, - "No URL configured for submodule '%s'", sm->name); + "no URL configured for submodule '%s'", sm->name); return -1; } @@ -1501,13 +1543,22 @@ int git_submodule__status( return 0; } - /* refresh the index OID */ - if (submodule_update_index(sm) < 0) - return -1; + /* If the user has requested caching submodule state, performing these + * expensive operations (especially `submodule_update_head`, which is + * bottlenecked on `git_repository_head_tree`) eliminates much of the + * advantage. We will, therefore, interpret the request for caching to + * apply here to and skip them. + */ - /* refresh the HEAD OID */ - if (submodule_update_head(sm) < 0) - return -1; + if (sm->repo->submodule_cache == NULL) { + /* refresh the index OID */ + if (submodule_update_index(sm) < 0) + return -1; + + /* refresh the HEAD OID */ + if (submodule_update_head(sm) < 0) + return -1; + } /* for ignore == dirty, don't scan the working directory */ if (ign == GIT_SUBMODULE_IGNORE_DIRTY) { @@ -1565,7 +1616,6 @@ int git_submodule_location(unsigned int *location, git_submodule *sm) location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL); } - /* * INTERNAL FUNCTIONS */ @@ -1577,7 +1627,7 @@ static int submodule_alloc( git_submodule *sm; if (!name || !(namelen = strlen(name))) { - giterr_set(GITERR_SUBMODULE, "Invalid submodule name"); + giterr_set(GITERR_SUBMODULE, "invalid submodule name"); return -1; } @@ -1629,7 +1679,7 @@ void git_submodule_free(git_submodule *sm) static int submodule_config_error(const char *property, const char *value) { giterr_set(GITERR_INVALID, - "Invalid value for submodule '%s' property: '%s'", property, value); + "invalid value for submodule '%s' property: '%s'", property, value); return -1; } @@ -1967,7 +2017,7 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo) if (error == GIT_ENOTFOUND) giterr_set( GITERR_SUBMODULE, - "Cannot get default remote for submodule - no local tracking " + "cannot get default remote for submodule - no local tracking " "branch for HEAD and origin does not exist"); return error; |