diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2021-12-02 10:00:16 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2021-12-02 10:19:27 +0200 |
commit | d3568852ca0506666fbd1b613439a3916c76ed88 (patch) | |
tree | f10e01e52a283e24bdbf2ca932a261b345870ce2 | |
parent | adb93716f41a3325f6d590cbfe6ecc8fa27d637e (diff) |
Add $relative(<path>,<dir-path>) function
-rw-r--r-- | libbuild2/functions-path.cxx | 67 | ||||
-rw-r--r-- | tests/function/path/testscript | 6 |
2 files changed, 72 insertions, 1 deletions
diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx index c23a8a8..2953067 100644 --- a/libbuild2/functions-path.cxx +++ b/libbuild2/functions-path.cxx @@ -99,6 +99,20 @@ namespace build2 } } + template <typename P> + static inline P + relative (const P& p, const dir_path& d) + { + try + { + return p.relative (d); // Note: cannot move due to diagnostics. + } + catch (const invalid_path&) + { + fail << "'" << p << "' cannot be made relative to '" << d << "'" << endf; + } + } + using butl::path_match; // Return true if a path matches the pattern. See path_match() overloads @@ -332,10 +346,18 @@ namespace build2 return ns; }; - // leaf + + // $leaf(<path>) // f["leaf"] += &path::leaf; + // $leaf(<path>, <dir-path>) + // $leaf(<paths>, <dir-path>) + // + // Return the path without the specified directory part. Return empty path + // if the paths are the same. Issue diagnostics and fail if the directory + // is not a prefix of the path. Note: expects both paths to be normalized. + // f["leaf"] += [](path p, dir_path d) { return leaf (p, move (d)); @@ -371,6 +393,49 @@ namespace build2 return ns; }; + // $relative(<path>, <dir-path>) + // $relative(<paths>, <dir-path>) + // + // Return a path relative to the specified directory that is equivalent to + // the specified path. Issue diagnostics and fail if a relative path + // cannot be derived (for example, paths are on different drives on + // Windows). + // + f["relative"] += [](path p, dir_path d) + { + return relative (p, d); + }; + + f["relative"] += [](paths v, dir_path d) + { + for (path& p: v) + p = relative (p, d); + return v; + }; + + f["relative"] += [](dir_paths v, dir_path d) + { + for (dir_path& p: v) + p = relative (p, d); + return v; + }; + + f[".relative"] += [](names ns, dir_path d) + { + // For each path decide based on the presence of a trailing slash + // whether it is a directory. Return as untyped list of (potentially + // mixed) paths. + // + for (name& n: ns) + { + if (n.directory ()) + n.dir = relative (n.dir, d); + else + n.value = relative (convert<path> (move (n)), d).string (); + } + return ns; + }; + // base // f["base"] += &path::base; diff --git a/tests/function/path/testscript b/tests/function/path/testscript index 55d727f..b0c97c9 100644 --- a/tests/function/path/testscript +++ b/tests/function/path/testscript @@ -79,6 +79,12 @@ if! $posix EOE } +: relative +: +{ + $* <'print $relative([path] a/b/c, [dir_path] a/x/y)' >"../../b/c" : basics +} + : extension : { |