summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2018-11-13 13:40:17 +0100
committerGitHub <noreply@github.com>2018-11-13 13:40:17 +0100
commit20cb30b6b8e269d2ce3474523562b2739a8efea2 (patch)
treee297534b5f126e583bd8420331001016d14bdabb /src
parent28239be33d4f55228c9088d070c7cd7b9b6628ad (diff)
parent666c7bd84547b8793967820339cf265664fd9a95 (diff)
downloadlibgit2-20cb30b6b8e269d2ce3474523562b2739a8efea2.tar.gz
Merge pull request #4667 from tiennou/feature/remote-create-api
Remote creation API
Diffstat (limited to 'src')
-rw-r--r--src/config.c4
-rw-r--r--src/remote.c173
2 files changed, 113 insertions, 64 deletions
diff --git a/src/config.c b/src/config.c
index 0837500f5..042805e95 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1182,6 +1182,8 @@ int git_config_lock(git_transaction **out, git_config *cfg)
git_config_backend *backend;
backend_internal *internal;
+ assert(cfg);
+
internal = git_vector_get(&cfg->backends, 0);
if (!internal || !internal->backend) {
giterr_set(GITERR_CONFIG, "cannot lock; the config has no backends");
@@ -1200,6 +1202,8 @@ int git_config_unlock(git_config *cfg, int commit)
git_config_backend *backend;
backend_internal *internal;
+ assert(cfg);
+
internal = git_vector_get(&cfg->backends, 0);
if (!internal || !internal->backend) {
giterr_set(GITERR_CONFIG, "cannot lock; the config has no backends");
diff --git a/src/remote.c b/src/remote.c
index 7a07c0138..393068b31 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -189,58 +189,119 @@ static int canonicalize_url(git_buf *out, const char *in)
return git_buf_puts(out, in);
}
-static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
+static int default_fetchspec_for_name(git_buf *buf, const char *name)
{
+ if (git_buf_printf(buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
+{
+ int error;
git_remote *remote;
+
+ error = git_remote_lookup(&remote, repo, name);
+
+ if (error == GIT_ENOTFOUND)
+ return 0;
+
+ if (error < 0)
+ return error;
+
+ git_remote_free(remote);
+
+ giterr_set(GITERR_CONFIG, "remote '%s' already exists", name);
+
+ return GIT_EEXISTS;
+}
+
+int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+ opts, version, git_remote_create_options, GIT_REMOTE_CREATE_OPTIONS_INIT);
+ return 0;
+}
+
+int git_remote_create_with_opts(git_remote **out, const char *url, const git_remote_create_options *opts)
+{
+ git_remote *remote = NULL;
git_config *config_ro = NULL, *config_rw;
git_buf canonical_url = GIT_BUF_INIT;
git_buf var = GIT_BUF_INIT;
+ git_buf specbuf = GIT_BUF_INIT;
+ const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
int error = -1;
- /* repo, name, and fetch are optional */
assert(out && url);
- if (repo && (error = git_repository_config_snapshot(&config_ro, repo)) < 0)
- return error;
+ if (!opts) {
+ opts = &dummy_opts;
+ }
+
+ GITERR_CHECK_VERSION(opts, GIT_REMOTE_CREATE_OPTIONS_VERSION, "git_remote_create_options");
+
+ if (opts->name != NULL) {
+ if ((error = ensure_remote_name_is_valid(opts->name)) < 0)
+ return error;
+
+ if (opts->repository &&
+ (error = ensure_remote_doesnot_exist(opts->repository, opts->name)) < 0)
+ return error;
+ }
+
+ if (opts->repository) {
+ if ((error = git_repository_config_snapshot(&config_ro, opts->repository)) < 0)
+ goto on_error;
+ }
remote = git__calloc(1, sizeof(git_remote));
GITERR_CHECK_ALLOC(remote);
- remote->repo = repo;
+ remote->repo = opts->repository;
- if ((error = git_vector_init(&remote->refs, 32, NULL)) < 0 ||
+ if ((error = git_vector_init(&remote->refs, 8, NULL)) < 0 ||
(error = canonicalize_url(&canonical_url, url)) < 0)
goto on_error;
- if (repo) {
+ if (opts->repository && !(opts->flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF)) {
remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
} else {
remote->url = git__strdup(canonical_url.ptr);
}
GITERR_CHECK_ALLOC(remote->url);
- if (name != NULL) {
- remote->name = git__strdup(name);
+ if (opts->name != NULL) {
+ remote->name = git__strdup(opts->name);
GITERR_CHECK_ALLOC(remote->name);
- if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
- goto on_error;
-
- if (repo &&
- ((error = git_repository_config__weakptr(&config_rw, repo)) < 0 ||
- (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
+ if (opts->repository &&
+ ((error = git_buf_printf(&var, CONFIG_URL_FMT, opts->name)) < 0 ||
+ (error = git_repository_config__weakptr(&config_rw, opts->repository)) < 0 ||
+ (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
goto on_error;
}
- if (fetch != NULL) {
- if ((error = add_refspec(remote, fetch, true)) < 0)
- goto on_error;
+ if (opts->fetchspec != NULL ||
+ (opts->name && !(opts->flags & GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC))) {
+ const char *fetch = NULL;
+ if (opts->fetchspec) {
+ fetch = opts->fetchspec;
+ } else {
+ if ((error = default_fetchspec_for_name(&specbuf, opts->name)) < 0)
+ goto on_error;
+
+ fetch = git_buf_cstr(&specbuf);
+ }
- /* only write for non-anonymous remotes */
- if (repo && name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
+ if ((error = add_refspec(remote, fetch, true)) < 0)
goto on_error;
- if (repo && (error = lookup_remote_prune_config(remote, config_ro, name)) < 0)
+ /* only write for named remotes with a repository */
+ if (opts->repository && opts->name &&
+ ((error = write_add_refspec(opts->repository, opts->name, fetch, true)) < 0 ||
+ (error = lookup_remote_prune_config(remote, config_ro, opts->name)) < 0))
goto on_error;
/* Move the data over to where the matching functions can find them */
@@ -249,7 +310,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
}
/* A remote without a name doesn't download tags */
- if (!name)
+ if (!opts->name)
remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
else
remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
@@ -265,43 +326,32 @@ on_error:
git_remote_free(remote);
git_config_free(config_ro);
+ git_buf_dispose(&specbuf);
git_buf_dispose(&canonical_url);
git_buf_dispose(&var);
return error;
}
-static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
+int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
{
+ git_buf buf = GIT_BUF_INIT;
int error;
- git_remote *remote;
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
- error = git_remote_lookup(&remote, repo, name);
-
- if (error == GIT_ENOTFOUND)
- return 0;
-
- if (error < 0)
+ /* Those 2 tests are duplicated here because of backward-compatibility */
+ if ((error = ensure_remote_name_is_valid(name)) < 0)
return error;
- git_remote_free(remote);
-
- giterr_set(
- GITERR_CONFIG,
- "remote '%s' already exists", name);
-
- return GIT_EEXISTS;
-}
+ if (canonicalize_url(&buf, url) < 0)
+ return GIT_ERROR;
+ git_buf_clear(&buf);
-int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
-{
- git_buf buf = GIT_BUF_INIT;
- int error;
+ opts.repository = repo;
+ opts.name = name;
- if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
- return -1;
+ error = git_remote_create_with_opts(out, url, &opts);
- error = git_remote_create_with_fetchspec(out, repo, name, url, git_buf_cstr(&buf));
git_buf_dispose(&buf);
return error;
@@ -309,35 +359,32 @@ int git_remote_create(git_remote **out, git_repository *repo, const char *name,
int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
{
- git_remote *remote = NULL;
int error;
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
if ((error = ensure_remote_name_is_valid(name)) < 0)
return error;
- if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
- return error;
+ opts.repository = repo;
+ opts.name = name;
+ opts.fetchspec = fetch;
+ opts.flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC;
- if (create_internal(&remote, repo, name, url, fetch) < 0)
- goto on_error;
-
- *out = remote;
-
- return 0;
-
-on_error:
- git_remote_free(remote);
- return -1;
+ return git_remote_create_with_opts(out, url, &opts);
}
int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
{
- return create_internal(out, repo, NULL, url, NULL);
+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
+
+ opts.repository = repo;
+
+ return git_remote_create_with_opts(out, url, &opts);
}
int git_remote_create_detached(git_remote **out, const char *url)
{
- return create_internal(out, NULL, NULL, url, NULL);
+ return git_remote_create_with_opts(out, url, NULL);
}
int git_remote_dup(git_remote **dest, git_remote *source)
@@ -1946,8 +1993,7 @@ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const
if ((error = git_vector_init(problems, 1, NULL)) < 0)
return error;
- if ((error = git_buf_printf(
- &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
+ if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
return error;
git_vector_foreach(&remote->refspecs, i, spec) {
@@ -1972,8 +2018,7 @@ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const
git_buf_clear(&val);
git_buf_clear(&var);
- if (git_buf_printf(
- &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
+ if (default_fetchspec_for_name(&val, new_name) < 0 ||
git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
{
error = -1;