In Git for Windows, we ran with a patch "in production" for quite a while where paths starting with a slash (i.e. looking like Unix paths, not like Windows paths) were interpreted as being relative to the runtime prefix, when expanded via expand_user_path(). This was sent to the Git mailing list as a discussion starter, and it was pointed out that this is neither portable nor unambiguous. After the dust settled, I thought about the presented ideas for a while (quite a while...), and ended up with the following: any path starting with <RUNTIME-PREFIX>/ is expanded. This is ambiguous because it could be a valid path. But then, it is unlikely, and if someone really wants to specify such a path, it is easy to slap a ./ in front and they're done. Changes since v1: * Included a test for the RUNTIME_PREFIX that I had meant to send for ages already, and based on which... * A test case was added to verify that this actually works as intended * It is no longer Windows-specific * I added some documentation Johannes Schindelin (2): tests: exercise the RUNTIME_PREFIX feature expand_user_path(): support specifying paths relative to the runtime prefix Documentation/config.txt | 10 ++++++++++ Makefile | 5 +++++ path.c | 5 +++++ t/t0060-path-utils.sh | 26 ++++++++++++++++++++++++++ 4 files changed, 46 insertions(+) base-commit: ebf3c04b262aa27fbb97f8a0156c2347fecafafb Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-66%2Fdscho%2Fmingw-expand-absolute-user-path-v2 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-66/dscho/mingw-expand-absolute-user-path-v2 Pull-Request: https://github.com/gitgitgadget/git/pull/66 Range-diff vs v1: -: ----------- > 1: cc8f09baba9 tests: exercise the RUNTIME_PREFIX feature 1: 2287dd96cf0 ! 2: 66df56f5db0 mingw: handle absolute paths in expand_user_path() @@ Metadata Author: Johannes Schindelin <Johannes.Schindelin@xxxxxx> ## Commit message ## - mingw: handle absolute paths in expand_user_path() + expand_user_path(): support specifying paths relative to the runtime prefix - On Windows, an absolute POSIX path needs to be turned into a Windows - one. + Ever since Git learned to detect its install location at runtime, there + was the slightly awkward problem that it was impossible to specify paths + relative to said location. + + For example, if a version of Git was shipped with custom SSL + certificates to use, there was no portable way to specify + `http.sslCAInfo`. + + In Git for Windows, the problem was "solved" for years by interpreting + paths starting with a slash as relative to the runtime prefix. + + However, this is not correct: such paths _are_ legal on Windows, and + they are interpreted as absolute paths in the same drive as the current + directory. + + After a lengthy discussion, and a way lengthier time to mull over the + problem and its best solution, we decided to introduce support for the + magic sequence `<RUNTIME-PREFIX>/`. If a path starts with this, the + remainder is interpreted as relative to the detected runtime prefix. + + This solves the problem, but what new problems does it stir up? Here are + the two most obvious ones: + + - What if Git was not compiled with support for a runtime prefix? + + In that case, we will simply use the compiled-in hard-coded prefix. + + - What if a user _wants_ to specify a path starting with the magic + sequence? + + In that case, the user will simply need to prefix the magic sequence + with `./` and voilà, the path won't be expanded. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> + ## Documentation/config.txt ## +@@ Documentation/config.txt: 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 `<RUNTIME-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, ++`<RUNTIME-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: ++`./<RUNTIME-PREFIX>/bin`. + + + Variables + ## path.c ## @@ - #include "path.h" #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) @@ path.c: char *expand_user_path(const char *path, int real_home) if (path == NULL) goto return_null; -+#ifdef __MINGW32__ -+ if (path[0] == '/') -+ return system_path(path + 1); -+#endif ++ ++ if (skip_prefix(path, "<RUNTIME-PREFIX>/", &path)) ++ return system_path(path); ++ if (path[0] == '~') { const char *first_slash = strchrnul(path, '/'); const char *username = path + 1; + + ## t/t0060-path-utils.sh ## +@@ t/t0060-path-utils.sh: test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' ' + 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 '<RUNTIME-PREFIX>/ works' ' ++ mkdir -p pretend/bin && ++ cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && ++ git config yes.path "<RUNTIME-PREFIX>/yes" && ++ GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual && ++ echo "$(pwd)/pretend/yes" >expect && + test_cmp expect actual + ' + -- gitgitgadget