summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt9
-rw-r--r--Makefile5
-rw-r--r--builtin/credential-cache.c2
-rw-r--r--builtin/credential-store.c2
-rw-r--r--builtin/gc.c2
-rw-r--r--cache.h4
-rw-r--r--config.c8
-rw-r--r--path.c19
-rw-r--r--sequencer.c2
-rwxr-xr-xt/t0060-path-utils.sh26
10 files changed, 64 insertions, 15 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index bf82766a6a..0c0e6b859f 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -298,6 +298,15 @@ pathname::
tilde expansion happens to such a string: `~/`
is expanded to the value of `$HOME`, and `~user/` to the
specified user's home directory.
++
+If a path starts with `%(prefix)/`, the remainder is interpreted as a
+path relative to Git's "runtime prefix", i.e. relative to the location
+where Git itself was installed. For example, `%(prefix)/bin/` refers to
+the directory in which the Git executable itself lives. If Git was
+compiled without runtime prefix support, the compiled-in prefix will be
+subsituted instead. In the unlikely event that a literal path needs to
+be specified that should _not_ be expanded, it needs to be prefixed by
+`./`, like so: `./%(prefix)/bin`.
Variables
diff --git a/Makefile b/Makefile
index 9573190f1d..3452aaab14 100644
--- a/Makefile
+++ b/Makefile
@@ -2849,6 +2849,11 @@ endif
ifdef GIT_TEST_PERL_FATAL_WARNINGS
@echo GIT_TEST_PERL_FATAL_WARNINGS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_PERL_FATAL_WARNINGS)))'\' >>$@+
endif
+ifdef RUNTIME_PREFIX
+ @echo RUNTIME_PREFIX=\'true\' >>$@+
+else
+ @echo RUNTIME_PREFIX=\'false\' >>$@+
+endif
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
### Detect Python interpreter path changes
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 76a6ba3722..e8a7415747 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -90,7 +90,7 @@ static char *get_socket_path(void)
{
struct stat sb;
char *old_dir, *socket;
- old_dir = expand_user_path("~/.git-credential-cache", 0);
+ old_dir = interpolate_path("~/.git-credential-cache", 0);
if (old_dir && !stat(old_dir, &sb) && S_ISDIR(sb.st_mode))
socket = xstrfmt("%s/socket", old_dir);
else
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index ae3c1ba75f..62a4f3c265 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -173,7 +173,7 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix)
if (file) {
string_list_append(&fns, file);
} else {
- if ((file = expand_user_path("~/.git-credentials", 0)))
+ if ((file = interpolate_path("~/.git-credentials", 0)))
string_list_append_nodup(&fns, file);
file = xdg_config_home("credentials");
if (file)
diff --git a/builtin/gc.c b/builtin/gc.c
index f05d2f0a1a..6ce5ca4512 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1542,7 +1542,7 @@ static char *launchctl_service_filename(const char *name)
struct strbuf filename = STRBUF_INIT;
strbuf_addf(&filename, "~/Library/LaunchAgents/%s.plist", name);
- expanded = expand_user_path(filename.buf, 1);
+ expanded = interpolate_path(filename.buf, 1);
if (!expanded)
die(_("failed to expand path '%s'"), filename.buf);
diff --git a/cache.h b/cache.h
index bd4869beee..d23de69368 100644
--- a/cache.h
+++ b/cache.h
@@ -1255,7 +1255,9 @@ typedef int create_file_fn(const char *path, void *cb);
int raceproof_create_file(const char *path, create_file_fn fn, void *cb);
int mkdir_in_gitdir(const char *path);
-char *expand_user_path(const char *path, int real_home);
+char *interpolate_path(const char *path, int real_home);
+/* NEEDSWORK: remove this synonym once in-flight topics have migrated */
+#define expand_user_path interpolate_path
const char *enter_repo(const char *path, int strict);
static inline int is_absolute_path(const char *path)
{
diff --git a/config.c b/config.c
index f33abeab85..cb4a8058bf 100644
--- a/config.c
+++ b/config.c
@@ -137,7 +137,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
if (!path)
return config_error_nonbool("include.path");
- expanded = expand_user_path(path, 0);
+ expanded = interpolate_path(path, 0);
if (!expanded)
return error(_("could not expand include path '%s'"), path);
path = expanded;
@@ -185,7 +185,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
char *expanded;
int prefix = 0;
- expanded = expand_user_path(pat->buf, 1);
+ expanded = interpolate_path(pat->buf, 1);
if (expanded) {
strbuf_reset(pat);
strbuf_addstr(pat, expanded);
@@ -1270,7 +1270,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
- *dest = expand_user_path(value, 0);
+ *dest = interpolate_path(value, 0);
if (!*dest)
die(_("failed to expand user dir in: '%s'"), value);
return 0;
@@ -1845,7 +1845,7 @@ void git_global_config(char **user_out, char **xdg_out)
char *xdg_config = NULL;
if (!user_config) {
- user_config = expand_user_path("~/.gitconfig", 0);
+ user_config = interpolate_path("~/.gitconfig", 0);
xdg_config = xdg_config_home("config");
}
diff --git a/path.c b/path.c
index 7bccd830e9..0bc788ea40 100644
--- a/path.c
+++ b/path.c
@@ -12,6 +12,7 @@
#include "packfile.h"
#include "object-store.h"
#include "lockfile.h"
+#include "exec-cmd.h"
static int get_st_mode_bits(const char *path, int *mode)
{
@@ -719,19 +720,25 @@ static struct passwd *getpw_str(const char *username, size_t len)
}
/*
- * Return a string with ~ and ~user expanded via getpw*. If buf != NULL,
- * then it is a newly allocated string. Returns NULL on getpw failure or
- * if path is NULL.
+ * Return a string with ~ and ~user expanded via getpw*. Returns NULL on getpw
+ * failure or if path is NULL.
*
- * If real_home is true, strbuf_realpath($HOME) is used in the expansion.
+ * If real_home is true, strbuf_realpath($HOME) is used in the `~/` expansion.
+ *
+ * If the path starts with `%(prefix)/`, the remainder is interpreted as
+ * relative to where Git is installed, and expanded to the absolute path.
*/
-char *expand_user_path(const char *path, int real_home)
+char *interpolate_path(const char *path, int real_home)
{
struct strbuf user_path = STRBUF_INIT;
const char *to_copy = path;
if (path == NULL)
goto return_null;
+
+ if (skip_prefix(path, "%(prefix)/", &path))
+ return system_path(path);
+
if (path[0] == '~') {
const char *first_slash = strchrnul(path, '/');
const char *username = path + 1;
@@ -812,7 +819,7 @@ const char *enter_repo(const char *path, int strict)
strbuf_add(&validated_path, path, len);
if (used_path.buf[0] == '~') {
- char *newpath = expand_user_path(used_path.buf, 0);
+ char *newpath = interpolate_path(used_path.buf, 0);
if (!newpath)
return NULL;
strbuf_attach(&used_path, newpath, strlen(newpath),
diff --git a/sequencer.c b/sequencer.c
index 7f07cd00f3..7483ee3a76 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1241,7 +1241,7 @@ N_("Your name and email address were configured automatically based\n"
static const char *implicit_ident_advice(void)
{
- char *user_config = expand_user_path("~/.gitconfig", 0);
+ char *user_config = interpolate_path("~/.gitconfig", 0);
char *xdg_config = xdg_config_home("config");
int config_exists = file_exists(user_config) || file_exists(xdg_config);
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index de4960783f..34d1061f32 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -525,4 +525,30 @@ test_expect_success MINGW 'is_valid_path() on Windows' '
"PRN./abc"
'
+test_lazy_prereq RUNTIME_PREFIX '
+ test true = "$RUNTIME_PREFIX"
+'
+
+test_lazy_prereq CAN_EXEC_IN_PWD '
+ cp "$GIT_EXEC_PATH"/git$X ./ &&
+ ./git rev-parse
+'
+
+test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' '
+ mkdir -p pretend/bin pretend/libexec/git-core &&
+ echo "echo HERE" | write_script pretend/libexec/git-core/git-here &&
+ cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
+ GIT_EXEC_PATH= ./pretend/bin/git here >actual &&
+ echo HERE >expect &&
+ test_cmp expect actual'
+
+test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' '
+ mkdir -p pretend/bin &&
+ cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
+ git config yes.path "%(prefix)/yes" &&
+ GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual &&
+ echo "$(pwd)/pretend/yes" >expect &&
+ test_cmp expect actual
+'
+
test_done