diff options
| author | Patrick Steinhardt <ps@pks.im> | 2018-11-13 13:40:17 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-13 13:40:17 +0100 |
| commit | 20cb30b6b8e269d2ce3474523562b2739a8efea2 (patch) | |
| tree | e297534b5f126e583bd8420331001016d14bdabb /src | |
| parent | 28239be33d4f55228c9088d070c7cd7b9b6628ad (diff) | |
| parent | 666c7bd84547b8793967820339cf265664fd9a95 (diff) | |
| download | libgit2-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.c | 4 | ||||
| -rw-r--r-- | src/remote.c | 173 |
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; |
