From: Aniket Gupta <aniketgupta3001@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>, Derrick Stolee <stolee@gmail.com>
Subject: [PATCH] bundle-uri: do not die on unresolvable relative URIs
Date: Wed, 28 Oct 2026 11:58:18 +0000 [thread overview]
Message-ID: <20261028115818.410-1-aniketgupta3001@gmail.com> (raw)
relative_url() calls die() when the relative URL has more "../"
components than the remote URL can absorb. bundle_list_update() calls
it on URIs taken from a bundle list and a single bad entry takes down
the whole command.
Add relative_url_gently() which returns NULL and records the reason in
a strbuf instead of dying. This will keep relative_url() as a wrapper
that dies so the submodule callers are unchanged. Use the new function
in bundle_list_update() and report the problem as an error like the
other malformed lines in a bundle list.
Update the test in t5750 accordingly and drop its TODO.
Signed-off-by: Aniket Gupta <aniketgupta3001@gmail.com>
---
bundle-uri.c | 10 +++++++++-
remote.c | 39 +++++++++++++++++++++++++++++--------
remote.h | 8 ++++++++
t/t5750-bundle-uri-parse.sh | 15 +++++++-------
4 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/bundle-uri.c b/bundle-uri.c
index 2bb2eb99e4..1f198ef9a9 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -210,9 +210,17 @@ static int bundle_list_update(const char *key, const char *value,
strbuf_release(&id);
if (!strcmp(subkey, "uri")) {
+ struct strbuf err = STRBUF_INIT;
+
if (bundle->uri)
return -1;
- bundle->uri = relative_url(list->baseURI, value, NULL);
+ bundle->uri = relative_url_gently(list->baseURI, value, NULL,
+ &err);
+ if (!bundle->uri) {
+ error("%s", err.buf);
+ strbuf_release(&err);
+ return -1;
+ }
return 0;
}
diff --git a/remote.c b/remote.c
index 49ee2ea318..7472c426aa 100644
--- a/remote.c
+++ b/remote.c
@@ -3005,9 +3005,11 @@ void remote_state_clear(struct remote_state *remote_state)
}
/*
- * Returns 1 if it was the last chop before ':'.
+ * Returns 1 if it was the last chop before ':', or -1 (and records the
+ * reason in `err`) if there is nothing left to chop.
*/
-static int chop_last_dir(char **remoteurl, int is_relative)
+static int chop_last_dir(char **remoteurl, int is_relative,
+ struct strbuf *err)
{
char *rfind = find_last_dir_sep(*remoteurl);
if (rfind) {
@@ -3021,17 +3023,19 @@ static int chop_last_dir(char **remoteurl, int is_relative)
return 1;
}
- if (is_relative || !strcmp(".", *remoteurl))
- die(_("cannot strip one component off url '%s'"),
- *remoteurl);
+ if (is_relative || !strcmp(".", *remoteurl)) {
+ strbuf_addf(err, _("cannot strip one component off url '%s'"),
+ *remoteurl);
+ return -1;
+ }
free(*remoteurl);
*remoteurl = xstrdup(".");
return 0;
}
-char *relative_url(const char *remote_url, const char *url,
- const char *up_path)
+char *relative_url_gently(const char *remote_url, const char *url,
+ const char *up_path, struct strbuf *err)
{
int is_relative = 0;
int colonsep = 0;
@@ -3073,8 +3077,16 @@ char *relative_url(const char *remote_url, const char *url,
*/
while (*url) {
if (starts_with_dot_dot_slash_native(url)) {
+ int chopped;
+
url += 3;
- colonsep |= chop_last_dir(&remoteurl, is_relative);
+ chopped = chop_last_dir(&remoteurl, is_relative, err);
+ if (chopped < 0) {
+ free(remoteurl);
+ strbuf_release(&sb);
+ return NULL;
+ }
+ colonsep |= chopped;
} else if (starts_with_dot_slash_native(url))
url += 2;
else
@@ -3102,6 +3114,17 @@ char *relative_url(const char *remote_url, const char *url,
return strbuf_detach(&sb, NULL);
}
+char *relative_url(const char *remote_url, const char *url,
+ const char *up_path)
+{
+ struct strbuf err = STRBUF_INIT;
+ char *out = relative_url_gently(remote_url, url, up_path, &err);
+
+ if (!out)
+ die("%s", err.buf);
+ return out;
+}
+
int valid_remote_name(const char *name)
{
int result;
diff --git a/remote.h b/remote.h
index cca02033b9..940474fa71 100644
--- a/remote.h
+++ b/remote.h
@@ -478,6 +478,14 @@ void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
char *relative_url(const char *remote_url, const char *url,
const char *up_path);
+/*
+ * Like relative_url(), but if `url` cannot be resolved against
+ * `remote_url`, return NULL and add the reason to `err` instead of
+ * dying. `err` must not be NULL.
+ */
+char *relative_url_gently(const char *remote_url, const char *url,
+ const char *up_path, struct strbuf *err);
+
int valid_remote_name(const char *name);
#endif
diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh
index 70ae94c4d0..0f0ac29565 100755
--- a/t/t5750-bundle-uri-parse.sh
+++ b/t/t5750-bundle-uri-parse.sh
@@ -68,17 +68,16 @@ test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' '
uri = <uri>/bundle.bdl
[bundle "two"]
uri = bundle.bdl
- [bundle "three"]
- uri = <uri>/../bundle.bdl
EOF
- # TODO: We would prefer if parsing a bundle list would not cause
- # a die() and instead would give a warning and allow the rest of
- # a Git command to continue. This test_must_fail is necessary for
- # now until the interface for relative_url() allows for reporting
- # an error instead of die()ing.
+ cat >err.expect <<-\EOF &&
+ error: cannot strip one component off url '\''.'\''
+ error: bad line: '\''bundle.three.uri=../../bundle.bdl'\''
+ EOF
+
test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err &&
- test_grep "fatal: cannot strip one component off url" err
+ test_cmp err.expect err &&
+ test_cmp_config_output expect actual
'
test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' '
base-commit: 37b3475fb530c14109211faca33716a173db61ed
--
2.43.0
reply other threads:[~2026-10-28 11:58 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261028115818.410-1-aniketgupta3001@gmail.com \
--to=aniketgupta3001@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=stolee@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox