path: Make path real "work" with nonexistent paths

This just goes back until it finds an existent path, resolves that,
and adds the normalized rest on top.

So if you try

/bin/foo/bar////../baz

and /bin exists as a symlink to /usr/bin, it would resolve that, and
normalize the rest, giving

/usr/bin/foo/baz

(note: We might want to add this to realpath as well?)
This commit is contained in:
Fabian Homborg 2022-01-25 21:08:07 +01:00
parent 4fced3ef5a
commit 479fde27d7
2 changed files with 33 additions and 1 deletions

View file

@ -631,7 +631,28 @@ static int path_real(parser_t &parser, io_streams_t &streams, int argc, const wc
auto real = wrealpath(*arg);
if (!real) {
continue;
// The path doesn't exist, so we go up until we find
// something that does.
wcstring next = *arg;
// First add $PWD if we're relative
if (!next.empty() && next[0] != L'/') {
next = wgetcwd() + L"/" + next;
}
auto rest = wbasename(next);
while(!next.empty() && next != L"/") {
next = wdirname(next);
real = wrealpath(next);
if (real) {
next.push_back(L'/');
next.append(rest);
real = normalize_path(next, false);
break;
}
rest = wbasename(next) + L'/' + rest;
}
if (!real) {
continue;
}
}
// Return 0 if we found a realpath.

View file

@ -110,3 +110,14 @@ path real bin//sh | string match -r -- 'bin/bash$'
# The "//" is squashed, and the symlink is resolved.
# sh here is bash
# CHECK: bin/bash
# `path real` with nonexistent paths
set -l path (path real foo/bar)
string match -rq "^"(string escape --style=regex -- $PWD)'/' -- $path
and echo It matches pwd!
# CHECK: It matches pwd!
string replace -r "^"(string escape --style=regex -- $PWD)'/' "" -- $path
# CHECK: foo/bar
path real /banana//terracota/terracota/booooo/../pie
# CHECK: /banana/terracota/terracota/pie