* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "common.h"
+#include "submodule.h"
+
#include "git2/config.h"
#include "git2/sys/config.h"
#include "git2/types.h"
#include "buf_text.h"
#include "vector.h"
#include "posix.h"
-#include "config_file.h"
+#include "config_backend.h"
#include "config.h"
#include "repository.h"
-#include "submodule.h"
#include "tree.h"
#include "iterator.h"
#include "path.h"
#include "index.h"
+#include "worktree.h"
+#include "clone.h"
#define GIT_MODULES_FILE ".gitmodules"
-static git_cvar_map _sm_update_map[] = {
- {GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
- {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
- {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
- {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
+static git_configmap _sm_update_map[] = {
+ {GIT_CONFIGMAP_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
+ {GIT_CONFIGMAP_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
+ {GIT_CONFIGMAP_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
+ {GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
};
-static git_cvar_map _sm_ignore_map[] = {
- {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
- {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
- {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
- {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
+static git_configmap _sm_ignore_map[] = {
+ {GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
+ {GIT_CONFIGMAP_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
+ {GIT_CONFIGMAP_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
+ {GIT_CONFIGMAP_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
};
-static git_cvar_map _sm_recurse_map[] = {
- {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
+static git_configmap _sm_recurse_map[] = {
+ {GIT_CONFIGMAP_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
};
enum {
GITMODULES_CREATE = 1,
};
-static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
-{
- khint_t h;
-
- for (h = 0; *s; ++s)
- if (s[1] != '\0' || *s != '/')
- h = (h << 5) - h + *s;
-
- return h;
-}
-
-static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
-{
- size_t alen = a ? strlen(a) : 0;
- size_t blen = b ? strlen(b) : 0;
-
- if (alen > 0 && a[alen - 1] == '/')
- alen--;
- if (blen > 0 && b[blen - 1] == '/')
- blen--;
-
- return (alen == blen && strncmp(a, b, alen) == 0);
-}
-
-__KHASH_IMPL(
- str, static kh_inline, const char *, void *, 1,
- str_hash_no_trailing_slash, str_equal_no_trailing_slash)
-
static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
-static git_config *gitmodules_snapshot(git_repository *repo);
+static int gitmodules_snapshot(git_config **snap, git_repository *repo);
static int get_url_base(git_buf *url, git_repository *repo);
static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
+static int lookup_default_remote(git_remote **remote, git_repository *repo);
static int submodule_load_each(const git_config_entry *entry, void *payload);
static int submodule_read_config(git_submodule *sm, git_config *cfg);
static int submodule_load_from_wd_lite(git_submodule *);
if (!error)
return;
- giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
- "No submodule named '%s'" :
- "Submodule '%s' has not been added yet", name);
+ git_error_set(GIT_ERROR_SUBMODULE, (error == GIT_ENOTFOUND) ?
+ "no submodule named '%s'" :
+ "submodule '%s' has not been added yet", name);
}
typedef struct {
fdot = strchr(entry->name, '.');
ldot = strrchr(entry->name, '.');
data->name = git__strndup(fdot + 1, ldot - fdot - 1);
- GITERR_CHECK_ALLOC(data->name);
+ GIT_ERROR_CHECK_ALLOC(data->name);
}
return 0;
}
+/*
+ * Checks to see if the submodule shares its name with a file or directory that
+ * already exists on the index. If so, the submodule cannot be added.
+ */
+static int is_path_occupied(bool *occupied, git_repository *repo, const char *path)
+{
+ int error = 0;
+ git_index *index;
+ git_buf dir = GIT_BUF_INIT;
+ *occupied = false;
+
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0)
+ goto out;
+
+ if ((error = git_index_find(NULL, index, path)) != GIT_ENOTFOUND) {
+ if (!error) {
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "File '%s' already exists in the index", path);
+ *occupied = true;
+ }
+ goto out;
+ }
+
+ if ((error = git_buf_sets(&dir, path)) < 0)
+ goto out;
+
+ if ((error = git_path_to_dir(&dir)) < 0)
+ goto out;
+
+ if ((error = git_index_find_prefix(NULL, index, dir.ptr)) != GIT_ENOTFOUND) {
+ if (!error) {
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "Directory '%s' already exists in the index", path);
+ *occupied = true;
+ }
+ goto out;
+ }
+
+ error = 0;
+
+out:
+ git_buf_dispose(&dir);
+ return error;
+}
+
+/**
+ * Release the name map returned by 'load_submodule_names'.
+ */
+static void free_submodule_names(git_strmap *names)
+{
+ const char *key;
+ char *value;
+
+ if (names == NULL)
+ return;
+
+ git_strmap_foreach(names, key, value, {
+ git__free((char *) key);
+ git__free(value);
+ });
+ git_strmap_free(names);
+
+ return;
+}
+
/**
- * Find out the name of a submodule from its path
+ * Map submodule paths to names.
+ * TODO: for some use-cases, this might need case-folding on a
+ * case-insensitive filesystem
*/
-static int name_from_path(git_buf *out, git_config *cfg, const char *path)
+static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg)
{
const char *key = "submodule\\..*\\.path";
- git_config_iterator *iter;
+ git_config_iterator *iter = NULL;
git_config_entry *entry;
- int error;
+ git_buf buf = GIT_BUF_INIT;
+ git_strmap *names;
+ int isvalid, error;
+
+ *out = NULL;
+
+ if ((error = git_strmap_new(&names)) < 0)
+ goto out;
if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
- return error;
+ goto out;
while ((error = 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 (git_strmap_exists(names, entry->value)) {
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "duplicated submodule path '%s'", entry->value);
+ error = -1;
+ goto out;
+ }
- if (error == GIT_ITEROVER) {
- giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path);
- error = GIT_ENOTFOUND;
+ git_buf_clear(&buf);
+ git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
+ isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0);
+ if (isvalid < 0) {
+ error = isvalid;
+ goto out;
+ }
+ if (!isvalid)
+ continue;
+
+ if ((error = git_strmap_set(names, git__strdup(entry->value), git_buf_detach(&buf))) < 0) {
+ git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table");
+ error = -1;
+ goto out;
+ }
}
+ if (error == GIT_ITEROVER)
+ error = 0;
-cleanup:
+ *out = names;
+ names = NULL;
+
+out:
+ free_submodule_names(names);
+ git_buf_dispose(&buf);
git_config_iterator_free(iter);
return error;
}
assert(repo && name);
+ if (repo->is_bare) {
+ git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
+ return -1;
+ }
+
+ if (repo->submodule_cache != NULL) {
+ if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) {
+ if (out) {
+ *out = sm;
+ GIT_REFCOUNT_INC(*out);
+ }
+ return 0;
+ }
+ }
+
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
mods = open_gitmodules(repo, GITMODULES_EXISTING);
if (mods)
- error = git_config_file_foreach_match(mods, pattern, find_by_path, &data);
+ error = git_config_backend_foreach_match(mods, pattern, find_by_path, &data);
- git_config_file_free(mods);
+ git_config_backend_free(mods);
if (error < 0) {
git_submodule_free(sm);
- git_buf_free(&path);
+ git_buf_dispose(&path);
return error;
}
}
}
- git_buf_free(&path);
+ git_buf_dispose(&path);
}
if ((error = git_submodule_location(&location, sm)) < 0) {
if (git_path_exists(path.ptr))
error = GIT_EEXISTS;
- git_buf_free(&path);
+ git_buf_dispose(&path);
}
submodule_set_lookup_error(error, name);
return 0;
}
+int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags)
+{
+ git_buf buf = GIT_BUF_INIT;
+ int error, isvalid;
+
+ if (flags == 0)
+ flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS;
+
+ /* Avoid allocating a new string if we can avoid it */
+ if (strchr(name, '\\') != NULL) {
+ if ((error = git_path_normalize_slashes(&buf, name)) < 0)
+ return error;
+ } else {
+ git_buf_attach_notowned(&buf, name, strlen(name));
+ }
+
+ isvalid = git_path_isvalid(repo, buf.ptr, 0, flags);
+ git_buf_dispose(&buf);
+
+ return isvalid;
+}
+
static void submodule_free_dup(void *sm)
{
git_submodule_free(sm);
static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
{
- int error = 0;
- khiter_t pos;
git_submodule *sm = NULL;
+ int error;
- pos = git_strmap_lookup_index(map, name);
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ if ((sm = git_strmap_get(map, name)) != NULL)
goto done;
- }
/* if the submodule doesn't exist yet in the map, create it */
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
- pos = kh_put(str, map, sm->name, &error);
- /* nobody can beat us to adding it */
- assert(error != 0);
- if (error < 0) {
+ if ((error = git_strmap_set(map, sm->name, sm)) < 0) {
git_submodule_free(sm);
return error;
}
- git_strmap_set_value_at(map, pos, sm);
-
done:
GIT_REFCOUNT_INC(sm);
*out = sm;
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;
+ int error;
+ git_iterator *i = NULL;
+ const git_index_entry *entry;
+ git_strmap *names;
- if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
- return error;
+ if ((error = load_submodule_names(&names, git_index_owner(idx), cfg)))
+ goto done;
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(map, entry->path);
- git_submodule *sm;
+ if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
+ goto done;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
+ while (!(error = git_iterator_advance(&entry, i))) {
+ git_submodule *sm;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ if ((sm = git_strmap_get(map, entry->path)) != NULL) {
+ 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)) {
+ const char *name;
- 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 ((name = git_strmap_get(names, entry->path)) == NULL)
+ name = entry->path;
- if (error == GIT_ITEROVER)
- error = 0;
+ 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;
- 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;
+ int error;
+ git_iterator *i = NULL;
+ const git_index_entry *entry;
+ git_strmap *names;
- if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
- return error;
+ if ((error = load_submodule_names(&names, git_tree_owner(head), cfg)))
+ goto done;
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(map, entry->path);
- git_submodule *sm;
+ if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
+ goto done;
+
+ while (!(error = git_iterator_advance(&entry, i))) {
+ git_submodule *sm;
- git_buf_clear(&name);
- if (!name_from_path(&name, cfg, entry->path)) {
- git_strmap_lookup_index(map, name.ptr);
- }
+ if ((sm = git_strmap_get(map, entry->path)) != NULL) {
+ 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)) {
+ const char *name;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ if ((name = git_strmap_get(names, entry->path)) == NULL)
+ 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. */
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;
git_buf path = GIT_BUF_INIT;
git_submodule *sm;
git_config *mods = NULL;
- uint32_t mask;
assert(repo && map);
/* get sources that we will need to check */
if (git_repository_index(&idx, repo) < 0)
- giterr_clear();
+ git_error_clear();
if (git_repository_head_tree(&head, repo) < 0)
- giterr_clear();
+ git_error_clear();
wd = git_repository_workdir(repo);
if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
goto cleanup;
- /* clear submodule flags that are to be refreshed */
- mask = 0;
- mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
- GIT_SUBMODULE_STATUS__INDEX_FLAGS |
- GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
- GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
-
- mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
- GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
- mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
- if (mask != 0)
- mask |= GIT_SUBMODULE_STATUS_IN_WD |
- GIT_SUBMODULE_STATUS__WD_SCANNED |
- GIT_SUBMODULE_STATUS__WD_FLAGS |
- GIT_SUBMODULE_STATUS__WD_OID_VALID;
-
/* add submodule information from .gitmodules */
if (wd) {
lfc_data data = { 0 };
data.map = map;
data.repo = repo;
- if ((mods = gitmodules_snapshot(repo)) == NULL)
+ if ((error = gitmodules_snapshot(&mods, repo)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
goto cleanup;
+ }
data.mods = mods;
if ((error = git_config_foreach(
goto cleanup;
}
/* add back submodule information from index */
- if (idx) {
+ if (mods && idx) {
if ((error = submodules_from_index(map, idx, mods)) < 0)
goto cleanup;
}
/* add submodule information from HEAD */
- if (head) {
+ if (mods && head) {
if ((error = submodules_from_head(map, head, mods)) < 0)
goto cleanup;
}
/* shallow scan submodules in work tree as needed */
- if (wd && mask != 0) {
+ if (wd) {
git_strmap_foreach_value(map, sm, {
submodule_load_from_wd_lite(sm);
});
/* TODO: if we got an error, mark submodule config as invalid? */
git_index_free(idx);
git_tree_free(head);
- git_buf_free(&path);
+ git_buf_dispose(&path);
return error;
}
int error;
size_t i;
- if ((error = git_strmap_alloc(&submodules)) < 0)
+ if (repo->is_bare) {
+ git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
+ return -1;
+ }
+
+ if ((error = git_strmap_new(&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(
- &snapshot, kh_size(submodules), submodule_cmp))) {
+ &snapshot, git_strmap_size(submodules), submodule_cmp))) {
git_strmap_foreach_value(submodules, sm, {
if ((error = git_vector_insert(&snapshot, sm)) < 0)
git_vector_foreach(&snapshot, i, sm) {
if ((error = callback(sm, sm->name, payload)) != 0) {
- giterr_set_after_callback(error);
+ git_error_set_after_callback(error);
break;
}
}
* Old style: sub-repo goes directly into repo/<name>/.git/
*/
if (use_gitlink) {
- error = git_buf_join3(
- &repodir, '/', git_repository_path(parent_repo), "modules", path);
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
+ if (error < 0)
+ goto cleanup;
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
if (error < 0)
goto cleanup;
error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);
cleanup:
- git_buf_free(&workdir);
- git_buf_free(&repodir);
+ git_buf_dispose(&workdir);
+ git_buf_dispose(&repodir);
*out = subrepo;
git_submodule *sm = NULL;
git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
git_repository *subrepo = NULL;
+ bool path_occupied;
assert(repo && url && path);
/* see if there is already an entry for this submodule */
if (git_submodule_lookup(NULL, repo, path) < 0)
- giterr_clear();
+ git_error_clear();
else {
- giterr_set(GITERR_SUBMODULE,
- "Attempt to add submodule '%s' that already exists", path);
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "attempt to add submodule '%s' that already exists", path);
return GIT_EEXISTS;
}
path += strlen(git_repository_workdir(repo));
if (git_path_root(path) >= 0) {
- giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path");
+ git_error_set(GIT_ERROR_SUBMODULE, "submodule path must be a relative path");
error = -1;
goto cleanup;
}
+ if ((error = is_path_occupied(&path_occupied, repo, path)) < 0)
+ goto cleanup;
+
+ if (path_occupied) {
+ error = GIT_EEXISTS;
+ goto cleanup;
+ }
+
/* update .gitmodules */
if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
- giterr_set(GITERR_SUBMODULE,
- "Adding submodules to a bare repository is not supported");
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "adding submodules to a bare repository is not supported");
return -1;
}
if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
- (error = git_config_file_set_string(mods, name.ptr, path)) < 0)
+ (error = git_config_backend_set_string(mods, name.ptr, path)) < 0)
goto cleanup;
if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
- (error = git_config_file_set_string(mods, name.ptr, url)) < 0)
+ (error = git_config_backend_set_string(mods, name.ptr, url)) < 0)
goto cleanup;
git_buf_clear(&name);
if (out != NULL)
*out = sm;
- git_config_file_free(mods);
+ git_config_backend_free(mods);
git_repository_free(subrepo);
- git_buf_free(&real_url);
- git_buf_free(&name);
+ git_buf_dispose(&real_url);
+ git_buf_dispose(&name);
return error;
}
done:
git_config_free(cfg);
- git_buf_free(&buf);
+ git_buf_dispose(&buf);
+ return error;
+}
+
+static int clone_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
+{
+ GIT_UNUSED(url);
+ GIT_UNUSED(payload);
+ return git_remote_lookup(out, repo, name);
+}
+
+static int clone_return_repo(git_repository **out, const char *path, int bare, void *payload)
+{
+ git_submodule *sm = payload;
+
+ GIT_UNUSED(path);
+ GIT_UNUSED(bare);
+ return git_submodule_open(out, sm);
+}
+
+int git_submodule_clone(git_repository **out, git_submodule *submodule, const git_submodule_update_options *given_opts)
+{
+ int error;
+ git_repository *clone;
+ git_buf rel_path = GIT_BUF_INIT;
+ git_submodule_update_options sub_opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+
+ assert(submodule);
+
+ if (given_opts)
+ memcpy(&sub_opts, given_opts, sizeof(sub_opts));
+
+ GIT_ERROR_CHECK_VERSION(&sub_opts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
+
+ memcpy(&opts.checkout_opts, &sub_opts.checkout_opts, sizeof(sub_opts.checkout_opts));
+ memcpy(&opts.fetch_opts, &sub_opts.fetch_opts, sizeof(sub_opts.fetch_opts));
+ opts.repository_cb = clone_return_repo;
+ opts.repository_cb_payload = submodule;
+ opts.remote_cb = clone_return_origin;
+ opts.remote_cb_payload = submodule;
+
+ git_buf_puts(&rel_path, git_repository_workdir(git_submodule_owner(submodule)));
+ git_buf_joinpath(&rel_path, git_buf_cstr(&rel_path), git_submodule_path(submodule));
+
+ GIT_ERROR_CHECK_ALLOC_BUF(&rel_path);
+
+ error = git_clone__submodule(&clone, git_submodule_url(submodule), git_buf_cstr(&rel_path), &opts);
+ if (error < 0)
+ goto cleanup;
+
+ if (!out)
+ git_repository_free(clone);
+ else
+ *out = clone;
+
+cleanup:
+ git_buf_dispose(&rel_path);
+
return error;
}
/* read stat information for submodule working directory */
if (p_stat(path.ptr, &st) < 0) {
- giterr_set(GITERR_SUBMODULE,
- "Cannot add submodule without working directory");
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "cannot add submodule without working directory");
error = -1;
goto cleanup;
}
memset(&entry, 0, sizeof(entry));
entry.path = sm->path;
git_index_entry__init_from_stat(
- &entry, &st, !(git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE));
+ &entry, &st, !(git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE));
/* 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");
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "cannot add submodule without HEAD to index");
error = -1;
goto cleanup;
}
cleanup:
git_repository_free(sm_repo);
- git_buf_free(&path);
+ git_buf_dispose(&path);
return error;
}
} else if (strchr(url, ':') != NULL || url[0] == '/') {
error = git_buf_sets(out, url);
} else {
- giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid format for submodule URL");
error = -1;
}
- git_buf_free(&normalized);
+ git_buf_dispose(&normalized);
return error;
}
goto cleanup;
if (val)
- error = git_config_file_set_string(mods, key.ptr, val);
+ error = git_config_backend_set_string(mods, key.ptr, val);
else
- error = git_config_file_delete(mods, key.ptr);
+ error = git_config_backend_delete(mods, key.ptr);
- git_buf_free(&key);
+ git_buf_dispose(&key);
cleanup:
- git_config_file_free(mods);
+ git_config_backend_free(mods);
return error;
}
-static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
+static int write_mapped_var(git_repository *repo, const char *name, git_configmap *maps, size_t nmaps, const char *var, int ival)
{
- git_cvar_t type;
+ git_configmap_t type;
const char *val;
if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
- giterr_set(GITERR_SUBMODULE, "invalid value for %s", var);
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid value for %s", var);
return -1;
}
- if (type == GIT_CVAR_TRUE)
+ if (type == GIT_CONFIGMAP_TRUE)
val = "true";
return write_var(repo, name, var, val);
if (!git_submodule_open_bare(&subrepo, submodule))
git_repository_free(subrepo);
else
- giterr_clear();
+ git_error_clear();
}
if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
* <repo-dir>/modules/<name>/ with a gitlink in the
* sub-repo workdir directory to that repository.
*/
- error = git_buf_join3(
- &repodir, '/', git_repository_path(parent_repo), "modules", path);
+ error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
+ if (error < 0)
+ goto cleanup;
+ error = git_buf_joinpath(&repodir, repodir.ptr, path);
if (error < 0)
goto cleanup;
error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
cleanup:
- git_buf_free(&workdir);
- git_buf_free(&repodir);
+ git_buf_dispose(&workdir);
+ git_buf_dispose(&repodir);
*out = subrepo;
return submodule_repo_create(out, sm->repo, path);
}
-int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
+int git_submodule_update_options_init(git_submodule_update_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
return 0;
}
+int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
+{
+ return git_submodule_update_options_init(opts, version);
+}
+
int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
{
int error;
if (_update_options)
memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
- GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
+ GIT_ERROR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
/* Copy over the remote callbacks */
memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
if (error != GIT_ENOTFOUND)
goto done;
- if (error == GIT_ENOTFOUND && !init) {
- giterr_set(GITERR_SUBMODULE, "Submodule is not initialized.");
+ if (!init) {
+ git_error_set(GIT_ERROR_SUBMODULE, "submodule is not initialized");
error = GIT_ERROR;
goto done;
}
* will checkout the specific commit manually.
*/
clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
- update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy;
if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
goto done;
} else {
+ const git_oid *oid;
+
/**
* Work dir is initialized - look up the commit in the parent repository's index,
* update the workdir contents of the subrepository, and set the subrepository's
* head to the new commit.
*/
- if ((error = git_submodule_open(&sub_repo, sm)) < 0 ||
- (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0 ||
- (error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
+ if ((error = git_submodule_open(&sub_repo, sm)) < 0)
+ goto done;
+
+ if ((oid = git_submodule_index_id(sm)) == NULL) {
+ git_error_set(GIT_ERROR_SUBMODULE, "could not get ID of submodule in index");
+ error = -1;
+ goto done;
+ }
+
+ /* Look up the target commit in the submodule. */
+ if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJECT_COMMIT)) < 0) {
+ /* If it isn't found then fetch and try again. */
+ if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
+ (error = lookup_default_remote(&remote, sub_repo)) < 0 ||
+ (error = git_remote_fetch(remote, NULL, &update_options.fetch_opts, NULL)) < 0 ||
+ (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJECT_COMMIT)) < 0)
+ goto done;
+ }
+
+ if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
goto done;
}
done:
- git_buf_free(&buf);
+ git_buf_dispose(&buf);
git_config_free(config);
git_object_free(target_commit);
git_remote_free(remote);
git_config *cfg = NULL;
if (!sm->url) {
- giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", sm->name);
+ git_error_set(GIT_ERROR_SUBMODULE,
+ "no URL configured for submodule '%s'", sm->name);
return -1;
}
cleanup:
git_config_free(cfg);
- git_buf_free(&key);
- git_buf_free(&effective_submodule_url);
+ git_buf_dispose(&key);
+ git_buf_dispose(&effective_submodule_url);
return error;
}
int git_submodule_sync(git_submodule *sm)
{
- int error = 0;
- git_config *cfg = NULL;
- git_buf key = GIT_BUF_INIT;
+ git_buf key = GIT_BUF_INIT, url = GIT_BUF_INIT, remote_name = GIT_BUF_INIT;
git_repository *smrepo = NULL;
+ git_config *cfg = NULL;
+ int error = 0;
if (!sm->url) {
- giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", sm->name);
+ git_error_set(GIT_ERROR_SUBMODULE, "no URL configured for submodule '%s'", sm->name);
return -1;
}
/* copy URL over to config only if it already exists */
+ if ((error = git_repository_config__weakptr(&cfg, sm->repo)) < 0 ||
+ (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
+ (error = git_submodule_resolve_url(&url, sm->repo, sm->url)) < 0 ||
+ (error = git_config__update_entry(cfg, key.ptr, url.ptr, true, true)) < 0)
+ goto out;
- if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
- !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
- error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
+ if (!(sm->flags & GIT_SUBMODULE_STATUS_IN_WD))
+ goto out;
/* if submodule exists in the working directory, update remote url */
+ if ((error = git_submodule_open(&smrepo, sm)) < 0 ||
+ (error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
+ goto out;
- if (!error &&
- (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
- !(error = git_submodule_open(&smrepo, sm)))
- {
- git_buf remote_name = GIT_BUF_INIT;
-
- if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
- /* return error from reading submodule config */;
- else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
- giterr_clear();
- error = git_buf_sets(&key, "remote.origin.url");
- } else {
- error = git_buf_join3(
- &key, '.', "remote", remote_name.ptr, "url");
- git_buf_free(&remote_name);
- }
-
- if (!error)
- error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
-
- git_repository_free(smrepo);
+ if (lookup_head_remote_key(&remote_name, smrepo) == 0) {
+ if ((error = git_buf_join3(&key, '.', "remote", remote_name.ptr, "url")) < 0)
+ goto out;
+ } else if ((error = git_buf_sets(&key, "remote.origin.url")) < 0) {
+ goto out;
}
- git_buf_free(&key);
+ if ((error = git_config__update_entry(cfg, key.ptr, url.ptr, true, false)) < 0)
+ goto out;
+out:
+ git_repository_free(smrepo);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&key);
+ git_buf_dispose(&url);
return error;
}
if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
else
- giterr_clear();
+ git_error_clear();
} else if (git_path_exists(path.ptr)) {
sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
GIT_SUBMODULE_STATUS_IN_WD;
sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
}
- git_buf_free(&path);
+ git_buf_dispose(&path);
return error;
}
/* if we can't look up file in current head, then done */
if (git_repository_head_tree(&head, submodule->repo) < 0 ||
git_tree_entry_bypath(&te, head, submodule->path) < 0)
- giterr_clear();
+ git_error_clear();
else
- submodule_update_from_head_data(submodule, te->attr, &te->oid);
+ submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
git_tree_entry_free(te);
git_tree_free(head);
int git_submodule_reload(git_submodule *sm, int force)
{
- int error = 0;
- git_config *mods;
+ git_config *mods = NULL;
+ int error;
GIT_UNUSED(force);
assert(sm);
- if (!git_repository_is_bare(sm->repo)) {
- /* refresh config data */
- mods = gitmodules_snapshot(sm->repo);
- if (mods != NULL) {
- error = submodule_read_config(sm, mods);
- git_config_free(mods);
+ if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0)
+ /* This should come with a warning, but we've no API for that */
+ goto out;
- if (error < 0)
- return error;
- }
+ if (git_repository_is_bare(sm->repo))
+ goto out;
- /* refresh wd data */
- sm->flags &=
- ~(GIT_SUBMODULE_STATUS_IN_WD |
- GIT_SUBMODULE_STATUS__WD_OID_VALID |
- GIT_SUBMODULE_STATUS__WD_FLAGS);
+ /* refresh config data */
+ if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
+ goto out;
- error = submodule_load_from_wd_lite(sm);
- }
+ if (mods != NULL && (error = submodule_read_config(sm, mods)) < 0)
+ goto out;
- if (error == 0 && (error = submodule_update_index(sm)) == 0)
- error = submodule_update_head(sm);
+ /* refresh wd data */
+ sm->flags &=
+ ~(GIT_SUBMODULE_STATUS_IN_WD |
+ GIT_SUBMODULE_STATUS__WD_OID_VALID |
+ GIT_SUBMODULE_STATUS__WD_FLAGS);
+
+ if ((error = submodule_load_from_wd_lite(sm)) < 0 ||
+ (error = submodule_update_index(sm)) < 0 ||
+ (error = submodule_update_head(sm)) < 0)
+ goto out;
+out:
+ git_config_free(mods);
return error;
}
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) {
/* git_submodule_open_bare will load WD OID data */
if (git_submodule_open_bare(&smrepo, sm) < 0)
- giterr_clear();
+ git_error_clear();
else
git_repository_free(smrepo);
smrepo = NULL;
} else if (git_submodule_open(&smrepo, sm) < 0) {
- giterr_clear();
+ git_error_clear();
smrepo = NULL;
}
location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
}
-
/*
* INTERNAL FUNCTIONS
*/
git_submodule *sm;
if (!name || !(namelen = strlen(name))) {
- giterr_set(GITERR_SUBMODULE, "Invalid submodule name");
+ git_error_set(GIT_ERROR_SUBMODULE, "invalid submodule name");
return -1;
}
sm = git__calloc(1, sizeof(git_submodule));
- GITERR_CHECK_ALLOC(sm);
+ GIT_ERROR_CHECK_ALLOC(sm);
sm->name = sm->path = git__strdup(name);
if (!sm->name) {
static int submodule_config_error(const char *property, const char *value)
{
- giterr_set(GITERR_INVALID,
- "Invalid value for submodule '%s' property: '%s'", property, value);
+ git_error_set(GIT_ERROR_INVALID,
+ "invalid value for submodule '%s' property: '%s'", property, value);
return -1;
}
return error;
}
+static bool looks_like_command_line_option(const char *s)
+{
+ if (s && s[0] == '-')
+ return true;
+
+ return false;
+}
+
static int submodule_read_config(git_submodule *sm, git_config *cfg)
{
git_buf key = GIT_BUF_INIT;
if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
in_config = 1;
+ /* We would warn here if we had that API */
+ if (!looks_like_command_line_option(value)) {
/*
* TODO: if case insensitive filesystem, then the following strcmp
* should be strcasecmp
*/
- if (strcmp(sm->name, value) != 0) {
- if (sm->path != sm->name)
- git__free(sm->path);
- sm->path = git__strdup(value);
- GITERR_CHECK_ALLOC(sm->path);
+ if (strcmp(sm->name, value) != 0) {
+ if (sm->path != sm->name)
+ git__free(sm->path);
+ sm->path = git__strdup(value);
+ GIT_ERROR_CHECK_ALLOC(sm->path);
+ }
+
}
} else if (error != GIT_ENOTFOUND) {
goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
- in_config = 1;
- sm->url = git__strdup(value);
- GITERR_CHECK_ALLOC(sm->url);
+ /* We would warn here if we had that API */
+ if (!looks_like_command_line_option(value)) {
+ in_config = 1;
+ sm->url = git__strdup(value);
+ GIT_ERROR_CHECK_ALLOC(sm->url);
+ }
} else if (error != GIT_ENOTFOUND) {
goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
in_config = 1;
sm->branch = git__strdup(value);
- GITERR_CHECK_ALLOC(sm->branch);
+ GIT_ERROR_CHECK_ALLOC(sm->branch);
} else if (error != GIT_ENOTFOUND) {
goto cleanup;
}
error = 0;
cleanup:
- git_buf_free(&key);
+ git_buf_dispose(&key);
return error;
}
{
lfc_data *data = payload;
const char *namestart, *property;
- git_strmap_iter pos;
git_strmap *map = data->map;
git_buf name = GIT_BUF_INIT;
git_submodule *sm;
- int error;
+ int error, isvalid;
if (git__prefixcmp(entry->name, "submodule.") != 0)
return 0;
if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
return error;
+ isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
+ if (isvalid <= 0) {
+ error = isvalid;
+ goto done;
+ }
+
/*
* Now that we have the submodule's name, we can use that to
* figure out whether it's in the map. If it's not, we create
* a new submodule, load the config and insert it. If it's
* already inserted, we've already loaded it, so we skip.
*/
- pos = git_strmap_lookup_index(map, name.ptr);
- if (git_strmap_valid_index(map, pos)) {
+ if (git_strmap_exists(map, name.ptr)) {
error = 0;
goto done;
}
goto done;
}
- git_strmap_insert(map, sm->name, sm, error);
- assert(error != 0);
- if (error < 0)
+ if ((error = git_strmap_set(map, sm->name, sm)) < 0)
goto done;
error = 0;
done:
- git_buf_free(&name);
+ git_buf_dispose(&name);
return error;
}
if (git_path_contains(&path, DOT_GIT))
sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
- git_buf_free(&path);
+ git_buf_dispose(&path);
return 0;
}
/**
- * Returns a snapshot of $WORK_TREE/.gitmodules.
+ * Requests a snapshot of $WORK_TREE/.gitmodules.
*
- * We ignore any errors and just pretend the file isn't there.
+ * Returns GIT_ENOTFOUND in case no .gitmodules file exist
*/
-static git_config *gitmodules_snapshot(git_repository *repo)
+static int gitmodules_snapshot(git_config **snap, git_repository *repo)
{
const char *workdir = git_repository_workdir(repo);
- git_config *mods = NULL, *snap = NULL;
+ git_config *mods = NULL;
git_buf path = GIT_BUF_INIT;
+ int error;
- if (workdir != NULL) {
- if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
- return NULL;
+ if (!workdir)
+ return GIT_ENOTFOUND;
- if (git_config_open_ondisk(&mods, path.ptr) < 0)
- mods = NULL;
- }
+ if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
+ return error;
+
+ if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
+ goto cleanup;
+ git_buf_dispose(&path);
- git_buf_free(&path);
+ if ((error = git_config_snapshot(snap, mods)) < 0)
+ goto cleanup;
+
+ error = 0;
- if (mods) {
- git_config_snapshot(&snap, mods);
+cleanup:
+ if (mods)
git_config_free(mods);
- }
+ git_buf_dispose(&path);
- return snap;
+ return error;
}
static git_config_backend *open_gitmodules(
return NULL;
if (okay_to_create || git_path_isfile(path.ptr)) {
- /* git_config_file__ondisk should only fail if OOM */
- if (git_config_file__ondisk(&mods, path.ptr) < 0)
+ /* git_config_backend_from_file should only fail if OOM */
+ if (git_config_backend_from_file(&mods, path.ptr) < 0)
mods = NULL;
/* open should only fail here if the file is malformed */
- else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) {
- git_config_file_free(mods);
+ else if (git_config_backend_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
+ git_config_backend_free(mods);
mods = NULL;
}
}
}
- git_buf_free(&path);
+ git_buf_dispose(&path);
return mods;
}
* a remote key for the local tracking branch HEAD points to.
**/
if (!git_reference_is_branch(head)) {
- giterr_set(GITERR_INVALID,
+ git_error_set(GIT_ERROR_INVALID,
"HEAD does not refer to a branch.");
error = GIT_ENOTFOUND;
goto done;
goto done;
done:
- git_buf_free(&upstream_name);
+ git_buf_dispose(&upstream_name);
git_reference_free(head);
return error;
if (!(error = lookup_head_remote_key(&remote_name, repo)))
error = git_remote_lookup(remote, repo, remote_name.ptr);
- git_buf_free(&remote_name);
+ git_buf_dispose(&remote_name);
return error;
}
int error = lookup_head_remote(remote, repo);
/* if that failed, use 'origin' instead */
- if (error == GIT_ENOTFOUND)
+ if (error == GIT_ENOTFOUND || error == GIT_EUNBORNBRANCH)
error = git_remote_lookup(remote, repo, "origin");
if (error == GIT_ENOTFOUND)
- giterr_set(
- GITERR_SUBMODULE,
- "Cannot get default remote for submodule - no local tracking "
+ git_error_set(
+ GIT_ERROR_SUBMODULE,
+ "cannot get default remote for submodule - no local tracking "
"branch for HEAD and origin does not exist");
return error;
static int get_url_base(git_buf *url, git_repository *repo)
{
int error;
+ git_worktree *wt = NULL;
git_remote *remote = NULL;
- if (!(error = lookup_default_remote(&remote, repo))) {
+ if ((error = lookup_default_remote(&remote, repo)) == 0) {
error = git_buf_sets(url, git_remote_url(remote));
- git_remote_free(remote);
- }
- else if (error == GIT_ENOTFOUND) {
- /* if repository does not have a default remote, use workdir instead */
- giterr_clear();
+ goto out;
+ } else if (error != GIT_ENOTFOUND)
+ goto out;
+ else
+ git_error_clear();
+
+ /* if repository does not have a default remote, use workdir instead */
+ if (git_repository_is_worktree(repo)) {
+ if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
+ goto out;
+ error = git_buf_sets(url, wt->parent_path);
+ } else
error = git_buf_sets(url, git_repository_workdir(repo));
- }
+
+out:
+ git_remote_free(remote);
+ git_worktree_free(wt);
return error;
}
/* if we don't have an unborn head, check diff with index */
if (git_repository_head_tree(&sm_head, sm_repo) < 0)
- giterr_clear();
+ git_error_clear();
else {
/* perform head to index diff on submodule */
if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
- giterr_clear();
+ git_error_clear();
else {
if (git_diff_num_deltas(diff) > 0)
*status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
/* perform index-to-workdir diff on submodule */
if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
- giterr_clear();
+ git_error_clear();
else {
size_t untracked =
git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);