mirror of
https://github.com/NixOS/nix
synced 2025-07-05 16:31:47 +02:00
More support for std::filepath
in libnixutil
We're not replacing `Path` in exposed definitions in many cases, but just adding alternatives. This will allow us to "top down" change `Path` to `std::fileysystem::path`, and then we can remove the `Path`-using utilities which will become unused. Also add some test files which we forgot to include in the libutil unit tests `meson.build`. Co-Authored-By: siddhantCodes <siddhantk232@gmail.com>
This commit is contained in:
parent
dbabfc92d4
commit
a97a08411c
37 changed files with 258 additions and 120 deletions
|
@ -113,6 +113,16 @@ protected:
|
|||
, arity(1)
|
||||
{ }
|
||||
|
||||
Handler(std::filesystem::path * dest)
|
||||
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
|
||||
, arity(1)
|
||||
{ }
|
||||
|
||||
Handler(std::optional<std::filesystem::path> * dest)
|
||||
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
|
||||
, arity(1)
|
||||
{ }
|
||||
|
||||
template<class T>
|
||||
Handler(T * dest, const T & val)
|
||||
: fun([dest, val](std::vector<std::string> ss) { *dest = val; })
|
||||
|
@ -283,6 +293,18 @@ public:
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a path argument.
|
||||
*/
|
||||
void expectArg(const std::string & label, std::filesystem::path * dest, bool optional = false)
|
||||
{
|
||||
expectArgs({
|
||||
.label = label,
|
||||
.optional = optional,
|
||||
.handler = {dest}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect 0 or more arguments.
|
||||
*/
|
||||
|
|
|
@ -10,9 +10,6 @@ namespace nix {
|
|||
*
|
||||
* We use our own implementation unconditionally for consistency.
|
||||
*/
|
||||
int execvpe(
|
||||
const OsString::value_type * file0,
|
||||
const OsString::value_type * const argv[],
|
||||
const OsString::value_type * const envp[]);
|
||||
int execvpe(const OsChar * file0, const OsChar * const argv[], const OsChar * const envp[]);
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace fs {
|
||||
using namespace std::filesystem;
|
||||
}
|
||||
|
||||
constexpr static const OsStringView path_var_separator{
|
||||
&ExecutablePath::separator,
|
||||
|
@ -24,7 +26,7 @@ ExecutablePath ExecutablePath::load()
|
|||
ExecutablePath ExecutablePath::parse(const OsString & path)
|
||||
{
|
||||
auto strings = path.empty() ? (std::list<OsString>{})
|
||||
: basicSplitString<std::list<OsString>, OsString::value_type>(path, path_var_separator);
|
||||
: basicSplitString<std::list<OsString>, OsChar>(path, path_var_separator);
|
||||
|
||||
std::vector<fs::path> ret;
|
||||
ret.reserve(strings.size());
|
||||
|
|
|
@ -7,11 +7,15 @@ namespace nix {
|
|||
|
||||
MakeError(ExecutableLookupError, Error);
|
||||
|
||||
/**
|
||||
* @todo rename, it is not just good for execuatable paths, but also
|
||||
* other lists of paths.
|
||||
*/
|
||||
struct ExecutablePath
|
||||
{
|
||||
std::vector<std::filesystem::path> directories;
|
||||
|
||||
constexpr static const OsString::value_type separator =
|
||||
constexpr static const OsChar separator =
|
||||
#ifdef WIN32
|
||||
L';'
|
||||
#else
|
||||
|
|
|
@ -26,10 +26,10 @@
|
|||
|
||||
#include "strings-inline.hh"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace nix {
|
||||
|
||||
namespace fs { using namespace std::filesystem; }
|
||||
|
||||
/**
|
||||
* Treat the string as possibly an absolute path, by inspecting the
|
||||
* start of it. Return whether it was probably intended to be
|
||||
|
@ -73,6 +73,10 @@ Path absPath(PathView path, std::optional<PathView> dir, bool resolveSymlinks)
|
|||
return canonPath(path, resolveSymlinks);
|
||||
}
|
||||
|
||||
std::filesystem::path absPath(const std::filesystem::path & path, bool resolveSymlinks)
|
||||
{
|
||||
return absPath(path.string(), std::nullopt, resolveSymlinks);
|
||||
}
|
||||
|
||||
Path canonPath(PathView path, bool resolveSymlinks)
|
||||
{
|
||||
|
@ -206,10 +210,10 @@ bool pathExists(const Path & path)
|
|||
return maybeLstat(path).has_value();
|
||||
}
|
||||
|
||||
bool pathAccessible(const Path & path)
|
||||
bool pathAccessible(const std::filesystem::path & path)
|
||||
{
|
||||
try {
|
||||
return pathExists(path);
|
||||
return pathExists(path.string());
|
||||
} catch (SysError & e) {
|
||||
// swallow EPERM
|
||||
if (e.errNo == EPERM) return false;
|
||||
|
@ -238,6 +242,11 @@ std::string readFile(const Path & path)
|
|||
return readFile(fd.get());
|
||||
}
|
||||
|
||||
std::string readFile(const std::filesystem::path & path)
|
||||
{
|
||||
return readFile(os_string_to_string(PathViewNG { path }));
|
||||
}
|
||||
|
||||
|
||||
void readFile(const Path & path, Sink & sink)
|
||||
{
|
||||
|
@ -324,7 +333,7 @@ void recursiveSync(const Path & path)
|
|||
/* If it's a file, just fsync and return. */
|
||||
auto st = lstat(path);
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
AutoCloseFD fd = open(path.c_str(), O_RDONLY, 0);
|
||||
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY, 0));
|
||||
if (!fd)
|
||||
throw SysError("opening file '%1%'", path);
|
||||
fd.fsync();
|
||||
|
@ -344,7 +353,7 @@ void recursiveSync(const Path & path)
|
|||
if (fs::is_directory(st)) {
|
||||
dirsToEnumerate.emplace_back(entry.path());
|
||||
} else if (fs::is_regular_file(st)) {
|
||||
AutoCloseFD fd = open(entry.path().c_str(), O_RDONLY, 0);
|
||||
AutoCloseFD fd = toDescriptor(open(entry.path().string().c_str(), O_RDONLY, 0));
|
||||
if (!fd)
|
||||
throw SysError("opening file '%1%'", entry.path());
|
||||
fd.fsync();
|
||||
|
@ -355,7 +364,7 @@ void recursiveSync(const Path & path)
|
|||
|
||||
/* Fsync all the directories. */
|
||||
for (auto dir = dirsToFsync.rbegin(); dir != dirsToFsync.rend(); ++dir) {
|
||||
AutoCloseFD fd = open(dir->c_str(), O_RDONLY, 0);
|
||||
AutoCloseFD fd = toDescriptor(open(dir->string().c_str(), O_RDONLY, 0));
|
||||
if (!fd)
|
||||
throw SysError("opening directory '%1%'", *dir);
|
||||
fd.fsync();
|
||||
|
@ -595,19 +604,20 @@ void createSymlink(const Path & target, const Path & link)
|
|||
fs::create_symlink(target, link);
|
||||
}
|
||||
|
||||
void replaceSymlink(const Path & target, const Path & link)
|
||||
void replaceSymlink(const fs::path & target, const fs::path & link)
|
||||
{
|
||||
for (unsigned int n = 0; true; n++) {
|
||||
Path tmp = canonPath(fmt("%s/.%d_%s", dirOf(link), n, baseNameOf(link)));
|
||||
auto tmp = link.parent_path() / fs::path{fmt(".%d_%s", n, link.filename().string())};
|
||||
tmp = tmp.lexically_normal();
|
||||
|
||||
try {
|
||||
createSymlink(target, tmp);
|
||||
fs::create_symlink(target, tmp);
|
||||
} catch (fs::filesystem_error & e) {
|
||||
if (e.code() == std::errc::file_exists) continue;
|
||||
throw;
|
||||
}
|
||||
|
||||
std::filesystem::rename(tmp, link);
|
||||
fs::rename(tmp, link);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -46,16 +46,33 @@ struct Source;
|
|||
* @return An absolutized path, resolving paths relative to the
|
||||
* specified directory, or the current directory otherwise. The path
|
||||
* is also canonicalised.
|
||||
*
|
||||
* In the process of being deprecated for `std::filesystem::absolute`.
|
||||
*/
|
||||
Path absPath(PathView path,
|
||||
std::optional<PathView> dir = {},
|
||||
bool resolveSymlinks = false);
|
||||
|
||||
inline Path absPath(const Path & path,
|
||||
std::optional<PathView> dir = {},
|
||||
bool resolveSymlinks = false)
|
||||
{
|
||||
return absPath(PathView{path}, dir, resolveSymlinks);
|
||||
}
|
||||
|
||||
std::filesystem::path absPath(const std::filesystem::path & path,
|
||||
bool resolveSymlinks = false);
|
||||
|
||||
/**
|
||||
* Canonicalise a path by removing all `.` or `..` components and
|
||||
* double or trailing slashes. Optionally resolves all symlink
|
||||
* components such that each component of the resulting path is *not*
|
||||
* a symbolic link.
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::path::lexically_normal` (for the `resolveSymlinks =
|
||||
* false` case), and `std::filesystem::weakly_canonical` (for the
|
||||
* `resolveSymlinks = true` case).
|
||||
*/
|
||||
Path canonPath(PathView path, bool resolveSymlinks = false);
|
||||
|
||||
|
@ -64,12 +81,18 @@ Path canonPath(PathView path, bool resolveSymlinks = false);
|
|||
* everything before the final `/`. If the path is the root or an
|
||||
* immediate child thereof (e.g., `/foo`), this means `/`
|
||||
* is returned.
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::path::parent_path`.
|
||||
*/
|
||||
Path dirOf(const PathView path);
|
||||
|
||||
/**
|
||||
* @return the base name of the given canonical path, i.e., everything
|
||||
* following the final `/` (trailing slashes are removed).
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::path::filename`.
|
||||
*/
|
||||
std::string_view baseNameOf(std::string_view path);
|
||||
|
||||
|
@ -98,20 +121,42 @@ std::optional<struct stat> maybeLstat(const Path & path);
|
|||
|
||||
/**
|
||||
* @return true iff the given path exists.
|
||||
*
|
||||
* In the process of being deprecated for `fs::symlink_exists`.
|
||||
*/
|
||||
bool pathExists(const Path & path);
|
||||
|
||||
namespace fs {
|
||||
|
||||
/**
|
||||
* ```
|
||||
* symlink_exists(p) = std::filesystem::exists(std::filesystem::symlink_status(p))
|
||||
* ```
|
||||
* Missing convenience analogous to
|
||||
* ```
|
||||
* std::filesystem::exists(p) = std::filesystem::exists(std::filesystem::status(p))
|
||||
* ```
|
||||
*/
|
||||
inline bool symlink_exists(const std::filesystem::path & path) {
|
||||
return std::filesystem::exists(std::filesystem::symlink_status(path));
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
|
||||
/**
|
||||
* A version of pathExists that returns false on a permission error.
|
||||
* Useful for inferring default paths across directories that might not
|
||||
* be readable.
|
||||
* @return true iff the given path can be accessed and exists
|
||||
*/
|
||||
bool pathAccessible(const Path & path);
|
||||
bool pathAccessible(const std::filesystem::path & path);
|
||||
|
||||
/**
|
||||
* Read the contents (target) of a symbolic link. The result is not
|
||||
* in any way canonicalised.
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::read_symlink`.
|
||||
*/
|
||||
Path readLink(const Path & path);
|
||||
|
||||
|
@ -124,14 +169,23 @@ Descriptor openDirectory(const std::filesystem::path & path);
|
|||
* Read the contents of a file into a string.
|
||||
*/
|
||||
std::string readFile(const Path & path);
|
||||
std::string readFile(const std::filesystem::path & path);
|
||||
void readFile(const Path & path, Sink & sink);
|
||||
|
||||
/**
|
||||
* Write a string to a file.
|
||||
*/
|
||||
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
|
||||
static inline void writeFile(const std::filesystem::path & path, std::string_view s, mode_t mode = 0666, bool sync = false)
|
||||
{
|
||||
return writeFile(path.string(), s, mode, sync);
|
||||
}
|
||||
|
||||
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
|
||||
static inline void writeFile(const std::filesystem::path & path, Source & source, mode_t mode = 0666, bool sync = false)
|
||||
{
|
||||
return writeFile(path.string(), source, mode, sync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush a path's parent directory to disk.
|
||||
|
@ -154,6 +208,9 @@ void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed);
|
|||
|
||||
/**
|
||||
* Create a directory and all its parents, if necessary.
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::create_directories`.
|
||||
*/
|
||||
void createDirs(const Path & path);
|
||||
inline void createDirs(PathView path)
|
||||
|
@ -192,13 +249,21 @@ void setWriteTime(const std::filesystem::path & path, const struct stat & st);
|
|||
|
||||
/**
|
||||
* Create a symlink.
|
||||
*
|
||||
* In the process of being deprecated for
|
||||
* `std::filesystem::create_symlink`.
|
||||
*/
|
||||
void createSymlink(const Path & target, const Path & link);
|
||||
|
||||
/**
|
||||
* Atomically create or replace a symlink.
|
||||
*/
|
||||
void replaceSymlink(const Path & target, const Path & link);
|
||||
void replaceSymlink(const std::filesystem::path & target, const std::filesystem::path & link);
|
||||
|
||||
inline void replaceSymlink(const Path & target, const Path & link)
|
||||
{
|
||||
return replaceSymlink(std::filesystem::path{target}, std::filesystem::path{link});
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to 'renameFile', but fallback to a copy+remove if `src` and `dst`
|
||||
|
|
|
@ -118,7 +118,7 @@ void saveMountNamespace()
|
|||
void restoreMountNamespace()
|
||||
{
|
||||
try {
|
||||
auto savedCwd = absPath(".");
|
||||
auto savedCwd = std::filesystem::current_path();
|
||||
|
||||
if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1)
|
||||
throw SysError("restoring parent mount namespace");
|
||||
|
|
|
@ -11,21 +11,30 @@ namespace nix {
|
|||
* Named because it is similar to the Rust type, except it is in the
|
||||
* native encoding not WTF-8.
|
||||
*
|
||||
* Same as `std::filesystem::path::string_type`, but manually defined to
|
||||
* Same as `std::filesystem::path::value_type`, but manually defined to
|
||||
* avoid including a much more complex header.
|
||||
*/
|
||||
using OsString = std::basic_string<
|
||||
using OsChar =
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
wchar_t
|
||||
#else
|
||||
char
|
||||
#endif
|
||||
>;
|
||||
;
|
||||
|
||||
/**
|
||||
* Named because it is similar to the Rust type, except it is in the
|
||||
* native encoding not WTF-8.
|
||||
*
|
||||
* Same as `std::filesystem::path::string_type`, but manually defined
|
||||
* for the same reason as `OsChar`.
|
||||
*/
|
||||
using OsString = std::basic_string<OsChar>;
|
||||
|
||||
/**
|
||||
* `std::string_view` counterpart for `OsString`.
|
||||
*/
|
||||
using OsStringView = std::basic_string_view<OsString::value_type>;
|
||||
using OsStringView = std::basic_string_view<OsChar>;
|
||||
|
||||
std::string os_string_to_string(OsStringView path);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ PosixSourceAccessor::PosixSourceAccessor()
|
|||
|
||||
SourcePath PosixSourceAccessor::createAtRoot(const std::filesystem::path & path)
|
||||
{
|
||||
std::filesystem::path path2 = absPath(path.string());
|
||||
std::filesystem::path path2 = absPath(path);
|
||||
return {
|
||||
make_ref<PosixSourceAccessor>(path2.root_path()),
|
||||
CanonPath { path2.relative_path().string() },
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
# include <fileapi.h>
|
||||
# include <winsock2.h>
|
||||
# include "windows-error.hh"
|
||||
#else
|
||||
# include <poll.h>
|
||||
|
@ -167,13 +168,14 @@ bool FdSource::hasData()
|
|||
while (true) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
int fd_ = fromDescriptorReadOnly(fd);
|
||||
FD_SET(fd_, &fds);
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
auto n = select(fd + 1, &fds, nullptr, nullptr, &timeout);
|
||||
auto n = select(fd_ + 1, &fds, nullptr, nullptr, &timeout);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
throw SysError("polling file descriptor");
|
||||
|
|
|
@ -14,8 +14,8 @@ template std::list<std::string> splitString(std::string_view s, std::string_view
|
|||
template std::set<std::string> splitString(std::string_view s, std::string_view separators);
|
||||
template std::vector<std::string> splitString(std::string_view s, std::string_view separators);
|
||||
|
||||
template std::list<OsString> basicSplitString(
|
||||
std::basic_string_view<OsString::value_type> s, std::basic_string_view<OsString::value_type> separators);
|
||||
template std::list<OsString>
|
||||
basicSplitString(std::basic_string_view<OsChar> s, std::basic_string_view<OsChar> separators);
|
||||
|
||||
template std::string concatStringsSep(std::string_view, const std::list<std::string> &);
|
||||
template std::string concatStringsSep(std::string_view, const std::set<std::string> &);
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
namespace fs { using namespace std::filesystem; }
|
||||
|
||||
std::string getUserName()
|
||||
{
|
||||
auto pw = getpwuid(geteuid());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue