summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/log.c6
-rw-r--r--include/git2/config.h11
-rw-r--r--include/git2/remote.h15
-rw-r--r--include/git2/sys/config.h1
-rw-r--r--src/config.c13
-rw-r--r--src/config_file.c89
-rw-r--r--src/merge.c2
-rw-r--r--src/netops.c7
-rw-r--r--src/pack-objects.c7
-rw-r--r--src/remote.c9
-rw-r--r--src/transports/git.c4
-rw-r--r--src/transports/smart.h4
-rw-r--r--src/transports/smart_pkt.c30
-rw-r--r--src/transports/smart_protocol.c53
-rw-r--r--src/transports/ssh.c11
-rw-r--r--tests-clar/clone/nonetwork.c9
-rw-r--r--tests-clar/config/multivar.c65
-rw-r--r--tests-clar/network/remote/remotes.c25
-rw-r--r--tests-clar/network/urlparse.c7
19 files changed, 293 insertions, 75 deletions
diff --git a/examples/log.c b/examples/log.c
index 4c2df07c9..81b056cc5 100644
--- a/examples/log.c
+++ b/examples/log.c
@@ -125,7 +125,7 @@ static int add_revision(struct log_state *s, const char *revstr)
static void print_time(const git_time *intime, const char *prefix)
{
char sign, out[32];
- struct tm intm;
+ struct tm *intm;
int offset, hours, minutes;
time_t t;
@@ -142,8 +142,8 @@ static void print_time(const git_time *intime, const char *prefix)
t = (time_t)intime->time + (intime->offset * 60);
- gmtime_r(&t, &intm);
- strftime(out, sizeof(out), "%a %b %e %T %Y", &intm);
+ intm = gmtime(&t);
+ strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
printf("%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes);
}
diff --git a/include/git2/config.h b/include/git2/config.h
index f14415148..95da4bc03 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -435,6 +435,17 @@ GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const
GIT_EXTERN(int) git_config_delete_entry(git_config *cfg, const char *name);
/**
+ * Deletes one or several entries from a multivar in the local config file.
+ *
+ * @param cfg where to look for the variables
+ * @param name the variable's name
+ * @param regexp a regular expression to indicate which values to delete
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp);
+
+/**
* Perform an operation on each config variable.
*
* The callback receives the normalized name and value of each variable
diff --git a/include/git2/remote.h b/include/git2/remote.h
index f4cd1cbfa..b9cf86ef1 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -357,21 +357,6 @@ GIT_EXTERN(int) git_remote_list(git_strarray *out, git_repository *repo);
GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check);
/**
- * Set a credentials acquisition callback for this remote. If the remote is
- * not available for anonymous access, then you must set this callback in order
- * to provide credentials to the transport at the time of authentication
- * failure so that retry can be performed.
- *
- * @param remote the remote to configure
- * @param cred_acquire_cb The credentials acquisition callback to use (defaults
- * to NULL)
- */
-GIT_EXTERN(void) git_remote_set_cred_acquire_cb(
- git_remote *remote,
- git_cred_acquire_cb cred_acquire_cb,
- void *payload);
-
-/**
* Sets a custom transport for the remote. The caller can use this function
* to bypass the automatic discovery of a transport by URL scheme (i.e.
* http://, https://, git://) and supply their own transport to be used
diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index 7572ace51..419ad7ea7 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -61,6 +61,7 @@ struct git_config_backend {
int (*set)(struct git_config_backend *, const char *key, const char *value);
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
int (*del)(struct git_config_backend *, const char *key);
+ int (*del_multivar)(struct git_config_backend *, const char *key, const char *regexp);
int (*iterator)(git_config_iterator **, struct git_config_backend *);
int (*refresh)(struct git_config_backend *);
void (*free)(struct git_config_backend *);
diff --git a/src/config.c b/src/config.c
index c98d6a52d..0d9471383 100644
--- a/src/config.c
+++ b/src/config.c
@@ -862,6 +862,19 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
return file->set_multivar(file, name, regexp, value);
}
+int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp)
+{
+ git_config_backend *file;
+ file_internal *internal;
+
+ internal = git_vector_get(&cfg->files, 0);
+ if (!internal || !internal->file)
+ return config_error_nofiles(name);
+ file = internal->file;
+
+ return file->del_multivar(file, name, regexp);
+}
+
int git_config_next(git_config_entry **entry, git_config_iterator *iter)
{
return iter->next(entry, iter);
diff --git a/src/config_file.c b/src/config_file.c
index 8fb43b990..6abf60621 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -120,6 +120,18 @@ static void cvar_free(cvar_t *var)
git__free(var);
}
+static int cvar_length(cvar_t *var)
+{
+ int length = 0;
+
+ while (var) {
+ length++;
+ var = var->next;
+ }
+
+ return length;
+}
+
int git_config_file_normalize_section(char *start, char *end)
{
char *scan;
@@ -531,6 +543,80 @@ static int config_delete(git_config_backend *cfg, const char *name)
return result;
}
+static int config_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp)
+{
+ cvar_t *var, *prev = NULL, *new_head = NULL;
+ cvar_t **to_delete;
+ int to_delete_idx;
+ diskfile_backend *b = (diskfile_backend *)cfg;
+ char *key;
+ regex_t preg;
+ int result;
+ khiter_t pos;
+
+ if ((result = git_config__normalize_name(name, &key)) < 0)
+ return result;
+
+ pos = git_strmap_lookup_index(b->values, key);
+
+ if (!git_strmap_valid_index(b->values, pos)) {
+ giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name);
+ git__free(key);
+ return GIT_ENOTFOUND;
+ }
+
+ var = git_strmap_value_at(b->values, pos);
+
+ result = regcomp(&preg, regexp, REG_EXTENDED);
+ if (result < 0) {
+ git__free(key);
+ giterr_set_regex(&preg, result);
+ regfree(&preg);
+ return -1;
+ }
+
+ to_delete = git__calloc(cvar_length(var), sizeof(cvar_t *));
+ GITERR_CHECK_ALLOC(to_delete);
+ to_delete_idx = 0;
+
+ while (var != NULL) {
+ cvar_t *next = var->next;
+
+ if (regexec(&preg, var->entry->value, 0, NULL, 0) == 0) {
+ // If we are past the head, reattach previous node to next one,
+ // otherwise set the new head for the strmap.
+ if (prev != NULL) {
+ prev->next = next;
+ } else {
+ new_head = next;
+ }
+
+ to_delete[to_delete_idx++] = var;
+ } else {
+ prev = var;
+ }
+
+ var = next;
+ }
+
+ if (new_head != NULL) {
+ git_strmap_set_value_at(b->values, pos, new_head);
+ } else {
+ git_strmap_delete_at(b->values, pos);
+ }
+
+ if (to_delete_idx > 0)
+ result = config_write(b, key, &preg, NULL);
+
+ while (to_delete_idx-- > 0)
+ cvar_free(to_delete[to_delete_idx]);
+
+ git__free(key);
+ git__free(to_delete);
+ regfree(&preg);
+ return result;
+}
+
int git_config_file__ondisk(git_config_backend **out, const char *path)
{
diskfile_backend *backend;
@@ -548,6 +634,7 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend->parent.set = config_set;
backend->parent.set_multivar = config_set_multivar;
backend->parent.del = config_delete;
+ backend->parent.del_multivar = config_delete_multivar;
backend->parent.iterator = config_iterator_new;
backend->parent.refresh = config_refresh;
backend->parent.free = backend_free;
@@ -1214,7 +1301,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
}
/* multiline variable? we need to keep reading lines to match */
- if (preg != NULL) {
+ if (preg != NULL && section_matches) {
data_start = post_start;
continue;
}
diff --git a/src/merge.c b/src/merge.c
index b07e8c52f..a22801e48 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -285,7 +285,7 @@ int git_repository_mergehead_foreach(git_repository *repo,
if ((error = git_oid_fromstr(&oid, line)) < 0)
goto cleanup;
- if (cb(&oid, payload) < 0) {
+ if (cb(&oid, payload) != 0) {
error = GIT_EUSER;
goto cleanup;
}
diff --git a/src/netops.c b/src/netops.c
index 7a61ef820..7e13f12e7 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -679,9 +679,10 @@ int gitno_extract_url_parts(
slash = strchr(url, '/');
at = strchr(url, '@');
- if (slash == NULL) {
- giterr_set(GITERR_NET, "Malformed URL: missing /");
- return -1;
+ if (!slash ||
+ (colon && (slash < colon))) {
+ giterr_set(GITERR_NET, "Malformed URL");
+ return GIT_EINVALIDSPEC;
}
start = url;
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 938b28fde..2d0f564d1 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -824,7 +824,7 @@ static unsigned long free_unpacked(struct unpacked *n)
static int find_deltas(git_packbuilder *pb, git_pobject **list,
unsigned int *list_size, unsigned int window,
- unsigned int depth)
+ int depth)
{
git_pobject *po;
git_buf zbuf = GIT_BUF_INIT;
@@ -839,8 +839,7 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
for (;;) {
struct unpacked *n = array + idx;
- unsigned int max_depth;
- int j, best_base = -1;
+ int max_depth, j, best_base = -1;
git_packbuilder__progress_lock(pb);
if (!*list_size) {
@@ -1033,7 +1032,7 @@ static void *threaded_find_deltas(void *arg)
static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
unsigned int list_size, unsigned int window,
- unsigned int depth)
+ int depth)
{
struct thread_params *p;
int i, ret, active_threads = 0;
diff --git a/src/remote.c b/src/remote.c
index bdfa08642..3528b1c46 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -365,16 +365,18 @@ static int update_config_refspec(const git_remote *remote, git_config *config, i
const char *dir;
size_t i;
int error = 0;
+ const char *cname;
push = direction == GIT_DIRECTION_PUSH;
dir = push ? "push" : "fetch";
if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
return -1;
+ cname = git_buf_cstr(&name);
/* Clear out the existing config */
while (!error)
- error = git_config_delete_entry(config, git_buf_cstr(&name));
+ error = git_config_delete_multivar(config, cname, ".*");
if (error != GIT_ENOTFOUND)
return error;
@@ -385,8 +387,11 @@ static int update_config_refspec(const git_remote *remote, git_config *config, i
if (spec->push != push)
continue;
+ // "$^" is a unmatcheable regexp: it will not match anything at all, so
+ // all values will be considered new and we will not replace any
+ // present value.
if ((error = git_config_set_multivar(
- config, git_buf_cstr(&name), "", spec->string)) < 0) {
+ config, cname, "$^", spec->string)) < 0) {
goto cleanup;
}
}
diff --git a/src/transports/git.c b/src/transports/git.c
index 3a0b86345..79a9e7dd4 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -179,7 +179,7 @@ static int _git_uploadpack_ls(
const char *url,
git_smart_subtransport_stream **stream)
{
- char *host, *port, *user=NULL, *pass=NULL;
+ char *host=NULL, *port=NULL, *user=NULL, *pass=NULL;
git_stream *s;
*stream = NULL;
@@ -235,7 +235,7 @@ static int _git_receivepack_ls(
const char *url,
git_smart_subtransport_stream **stream)
{
- char *host, *port, *user=NULL, *pass=NULL;
+ char *host=NULL, *port=NULL, *user=NULL, *pass=NULL;
git_stream *s;
*stream = NULL;
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 7fda27d4e..5232e54de 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -16,6 +16,7 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
+#define GIT_CAP_MULTI_ACK_DETAILED "multi_ack_detailed"
#define GIT_CAP_SIDE_BAND "side-band"
#define GIT_CAP_SIDE_BAND_64K "side-band-64k"
#define GIT_CAP_INCLUDE_TAG "include-tag"
@@ -40,7 +41,7 @@ enum git_pkt_type {
GIT_PKT_UNPACK,
};
-/* Used for multi-ack */
+/* Used for multi_ack and mutli_ack_detailed */
enum git_ack_status {
GIT_ACK_NONE,
GIT_ACK_CONTINUE,
@@ -113,6 +114,7 @@ typedef struct transport_smart_caps {
int common:1,
ofs_delta:1,
multi_ack: 1,
+ multi_ack_detailed: 1,
side_band:1,
side_band_64k:1,
include_tag:1,
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index a1f623c78..2bb09c750 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -39,7 +39,7 @@ static int flush_pkt(git_pkt **out)
return 0;
}
-/* the rest of the line will be useful for multi_ack */
+/* the rest of the line will be useful for multi_ack and multi_ack_detailed */
static int ack_pkt(git_pkt **out, const char *line, size_t len)
{
git_pkt_ack *pkt;
@@ -62,6 +62,10 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
if (len >= 7) {
if (!git__prefixcmp(line + 1, "continue"))
pkt->status = GIT_ACK_CONTINUE;
+ if (!git__prefixcmp(line + 1, "common"))
+ pkt->status = GIT_ACK_COMMON;
+ if (!git__prefixcmp(line + 1, "ready"))
+ pkt->status = GIT_ACK_READY;
}
*out = (git_pkt *) pkt;
@@ -456,25 +460,27 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
- /* Prefer side-band-64k if the server supports both */
- if (caps->side_band) {
- if (caps->side_band_64k)
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
- else
- git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
- }
- if (caps->ofs_delta)
- git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
-
- if (caps->multi_ack)
+ /* Prefer multi_ack_detailed */
+ if (caps->multi_ack_detailed)
+ git_buf_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " ");
+ else if (caps->multi_ack)
git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
+ /* Prefer side-band-64k if the server supports both */
+ if (caps->side_band_64k)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
+ else if (caps->side_band)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
+
if (caps->include_tag)
git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " ");
if (caps->thin_pack)
git_buf_puts(&str, GIT_CAP_THIN_PACK " ");
+ if (caps->ofs_delta)
+ git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
+
if (git_buf_oom(&str))
return -1;
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 8833b2816..651901b1b 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -97,6 +97,13 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps)
continue;
}
+ /* Keep multi_ack_detailed before multi_ack */
+ if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK_DETAILED)) {
+ caps->common = caps->multi_ack_detailed = 1;
+ ptr += strlen(GIT_CAP_MULTI_ACK_DETAILED);
+ continue;
+ }
+
if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
caps->common = caps->multi_ack = 1;
ptr += strlen(GIT_CAP_MULTI_ACK);
@@ -236,6 +243,32 @@ on_error:
return -1;
}
+static int wait_while_ack(gitno_buffer *buf)
+{
+ int error;
+ git_pkt_ack *pkt = NULL;
+
+ while (1) {
+ git__free(pkt);
+
+ if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
+ return error;
+
+ if (pkt->type == GIT_PKT_NAK)
+ break;
+
+ if (pkt->type == GIT_PKT_ACK &&
+ (pkt->status != GIT_ACK_CONTINUE ||
+ pkt->status != GIT_ACK_COMMON)) {
+ git__free(pkt);
+ break;
+ }
+ }
+
+ git__free(pkt);
+ return 0;
+}
+
int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count)
{
transport_smart *t = (transport_smart *)transport;
@@ -287,7 +320,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
goto on_error;
git_buf_clear(&data);
- if (t->caps.multi_ack) {
+ if (t->caps.multi_ack || t->caps.multi_ack_detailed) {
if ((error = store_common(t)) < 0)
goto on_error;
} else {
@@ -365,7 +398,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_revwalk_free(walk);
/* Now let's eat up whatever the server gives us */
- if (!t->caps.multi_ack) {
+ if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
pkt_type = recv_pkt(NULL, buf);
if (pkt_type < 0) {
@@ -375,22 +408,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
return -1;
}
} else {
- git_pkt_ack *pkt;
- do {
- if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
- return error;
-
- if (pkt->type == GIT_PKT_NAK ||
- (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) {
- git__free(pkt);
- break;
- }
-
- git__free(pkt);
- } while (1);
+ error = wait_while_ack(buf);
}
- return 0;
+ return error;
on_error:
git_revwalk_free(walk);
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 6ce673d5e..4e2834b49 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -213,10 +213,6 @@ static int git_ssh_extract_url_parts(
colon = strchr(url, ':');
- if (colon == NULL) {
- giterr_set(GITERR_NET, "Malformed URL: missing :");
- return -1;
- }
at = strchr(url, '@');
if (at) {
@@ -228,6 +224,11 @@ static int git_ssh_extract_url_parts(
*username = NULL;
}
+ if (colon == NULL || (colon < start)) {
+ giterr_set(GITERR_NET, "Malformed URL");
+ return -1;
+ }
+
*host = git__substrdup(start, colon - start);
GITERR_CHECK_ALLOC(*host);
@@ -316,7 +317,7 @@ static int _git_ssh_setup_conn(
const char *cmd,
git_smart_subtransport_stream **stream)
{
- char *host, *port=NULL, *user=NULL, *pass=NULL;
+ char *host=NULL, *port=NULL, *user=NULL, *pass=NULL;
const char *default_port="22";
ssh_stream *s;
LIBSSH2_SESSION* session=NULL;
diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c
index 071e3d09f..a286e2a8f 100644
--- a/tests-clar/clone/nonetwork.c
+++ b/tests-clar/clone/nonetwork.c
@@ -46,7 +46,7 @@ void test_clone_nonetwork__cleanup(void)
cl_fixture_cleanup("./foo");
}
-void test_clone_nonetwork__bad_url(void)
+void test_clone_nonetwork__bad_urls(void)
{
/* Clone should clean up the mess if the URL isn't a git repository */
cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options));
@@ -54,6 +54,13 @@ void test_clone_nonetwork__bad_url(void)
g_options.bare = true;
cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options));
cl_assert(!git_path_exists("./foo"));
+
+ cl_git_fail(git_clone(&g_repo, "git://example.com:asdf", "./foo", &g_options));
+ cl_git_fail(git_clone(&g_repo, "https://example.com:asdf/foo", "./foo", &g_options));
+ cl_git_fail(git_clone(&g_repo, "git://github.com/git://github.com/foo/bar.git.git",
+ "./foo", &g_options));
+ cl_git_fail(git_clone(&g_repo, "arrbee:my/bad:password@github.com:1111/strange:words.git",
+ "./foo", &g_options));
}
void test_clone_nonetwork__do_not_clean_existing_directory(void)
diff --git a/tests-clar/config/multivar.c b/tests-clar/config/multivar.c
index 0d552d65e..afdb1e5f4 100644
--- a/tests-clar/config/multivar.c
+++ b/tests-clar/config/multivar.c
@@ -221,3 +221,68 @@ void test_config_multivar__replace_multiple(void)
git_config_free(cfg);
}
+
+void test_config_multivar__delete(void)
+{
+ git_config *cfg;
+ int n;
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
+
+ n = 0;
+ cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
+ cl_assert(n == 2);
+
+ cl_git_pass(git_config_delete_multivar(cfg, _name, "github"));
+
+ n = 0;
+ cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
+ cl_assert(n == 1);
+
+ git_config_free(cfg);
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
+
+ n = 0;
+ cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
+ cl_assert(n == 1);
+
+ git_config_free(cfg);
+}
+
+void test_config_multivar__delete_multiple(void)
+{
+ git_config *cfg;
+ int n;
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
+
+ n = 0;
+ cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
+ cl_assert(n == 2);
+
+ cl_git_pass(git_config_delete_multivar(cfg, _name, "git"));
+
+ n = 0;
+ cl_git_fail_with(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n), GIT_ENOTFOUND);
+
+ git_config_free(cfg);
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
+
+ n = 0;
+ cl_git_fail_with(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n), GIT_ENOTFOUND);
+
+ git_config_free(cfg);
+}
+
+void test_config_multivar__delete_notfound(void)
+{
+ git_config *cfg;
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
+
+ cl_git_fail_with(git_config_delete_multivar(cfg, "remote.ab.noturl", "git"), GIT_ENOTFOUND);
+
+ git_config_free(cfg);
+}
diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c
index 6e0eeeb05..7c79b8318 100644
--- a/tests-clar/network/remote/remotes.c
+++ b/tests-clar/network/remote/remotes.c
@@ -150,8 +150,10 @@ void test_network_remote_remotes__add_pushspec(void)
void test_network_remote_remotes__save(void)
{
git_strarray array;
- const char *fetch_refspec = "refs/heads/*:refs/remotes/upstream/*";
- const char *push_refspec = "refs/heads/*:refs/heads/*";
+ const char *fetch_refspec1 = "refs/heads/ns1/*:refs/remotes/upstream/ns1/*";
+ const char *fetch_refspec2 = "refs/heads/ns2/*:refs/remotes/upstream/ns2/*";
+ const char *push_refspec1 = "refs/heads/ns1/*:refs/heads/ns1/*";
+ const char *push_refspec2 = "refs/heads/ns2/*:refs/heads/ns2/*";
git_remote_free(_remote);
_remote = NULL;
@@ -160,8 +162,10 @@ void test_network_remote_remotes__save(void)
cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2"));
git_remote_clear_refspecs(_remote);
- cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec));
- cl_git_pass(git_remote_add_push(_remote, push_refspec));
+ cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec1));
+ cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec2));
+ cl_git_pass(git_remote_add_push(_remote, push_refspec1));
+ cl_git_pass(git_remote_add_push(_remote, push_refspec2));
cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push"));
cl_git_pass(git_remote_save(_remote));
git_remote_free(_remote);
@@ -171,16 +175,19 @@ void test_network_remote_remotes__save(void)
cl_git_pass(git_remote_load(&_remote, _repo, "upstream"));
cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote));
- cl_assert_equal_i(1, (int)array.count);
- cl_assert_equal_s(fetch_refspec, array.strings[0]);
+ cl_assert_equal_i(2, (int)array.count);
+ cl_assert_equal_s(fetch_refspec1, array.strings[0]);
+ cl_assert_equal_s(fetch_refspec2, array.strings[1]);
git_strarray_free(&array);
cl_git_pass(git_remote_get_push_refspecs(&array, _remote));
- cl_assert_equal_i(1, (int)array.count);
- cl_assert_equal_s(push_refspec, array.strings[0]);
+ cl_assert_equal_i(2, (int)array.count);
+ cl_assert_equal_s(push_refspec1, array.strings[0]);
+ cl_assert_equal_s(push_refspec2, array.strings[1]);
+ git_strarray_free(&array);
+
cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push");
- git_strarray_free(&array);
/* remove the pushurl again and see if we can save that too */
cl_git_pass(git_remote_set_pushurl(_remote, NULL));
diff --git a/tests-clar/network/urlparse.c b/tests-clar/network/urlparse.c
index 274d7e900..15e841b35 100644
--- a/tests-clar/network/urlparse.c
+++ b/tests-clar/network/urlparse.c
@@ -31,6 +31,13 @@ void test_network_urlparse__trivial(void)
cl_assert_equal_p(pass, NULL);
}
+void test_network_urlparse__bad_url(void)
+{
+ cl_git_fail_with(gitno_extract_url_parts(&host, &port, &user, &pass,
+ "github.com/git://github.com/foo/bar.git.git", "443"),
+ GIT_EINVALIDSPEC);
+}
+
void test_network_urlparse__user(void)
{
cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass,