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:
John Ericson 2024-08-26 12:24:37 -04:00
parent dbabfc92d4
commit a97a08411c
37 changed files with 258 additions and 120 deletions

View file

@ -18,6 +18,8 @@
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
fetchers::Settings fetchSettings; fetchers::Settings fetchSettings;
static GlobalConfig::Register rFetchSettings(&fetchSettings); static GlobalConfig::Register rFetchSettings(&fetchSettings);
@ -119,8 +121,8 @@ MixEvalArgs::MixEvalArgs()
.category = category, .category = category,
.labels = {"original-ref", "resolved-ref"}, .labels = {"original-ref", "resolved-ref"},
.handler = {[&](std::string _from, std::string _to) { .handler = {[&](std::string _from, std::string _to) {
auto from = parseFlakeRef(fetchSettings, _from, absPath(".")); auto from = parseFlakeRef(fetchSettings, _from, fs::current_path().string());
auto to = parseFlakeRef(fetchSettings, _to, absPath(".")); auto to = parseFlakeRef(fetchSettings, _to, fs::current_path().string());
fetchers::Attrs extraAttrs; fetchers::Attrs extraAttrs;
if (to.subdir != "") extraAttrs["dir"] = to.subdir; if (to.subdir != "") extraAttrs["dir"] = to.subdir;
fetchers::overrideRegistry(from.input, to.input, extraAttrs); fetchers::overrideRegistry(from.input, to.input, extraAttrs);

View file

@ -31,6 +31,8 @@
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
void completeFlakeInputPath( void completeFlakeInputPath(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<EvalState> evalState,
@ -341,7 +343,7 @@ void completeFlakeRefWithFragment(
auto flakeRefS = std::string(prefix.substr(0, hash)); auto flakeRefS = std::string(prefix.substr(0, hash));
// TODO: ideally this would use the command base directory instead of assuming ".". // TODO: ideally this would use the command base directory instead of assuming ".".
auto flakeRef = parseFlakeRef(fetchSettings, expandTilde(flakeRefS), absPath(".")); auto flakeRef = parseFlakeRef(fetchSettings, expandTilde(flakeRefS), fs::current_path().string());
auto evalCache = openEvalCache(*evalState, auto evalCache = openEvalCache(*evalState,
std::make_shared<flake::LockedFlake>(lockFlake( std::make_shared<flake::LockedFlake>(lockFlake(

View file

@ -622,7 +622,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
// When missing, trigger the normal exception // When missing, trigger the normal exception
// e.g. :doc builtins.foo // e.g. :doc builtins.foo
// behaves like // behaves like
// nix-repl> builtins.foo // nix-repl> builtins.foo<tab>
// error: attribute 'foo' missing // error: attribute 'foo' missing
evalString(arg, v); evalString(arg, v);
assert(false); assert(false);
@ -720,7 +720,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
if (flakeRefS.empty()) if (flakeRefS.empty())
throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)");
auto flakeRef = parseFlakeRef(fetchSettings, flakeRefS, absPath("."), true); auto flakeRef = parseFlakeRef(fetchSettings, flakeRefS, std::filesystem::current_path().string(), true);
if (evalSettings.pureEval && !flakeRef.input.isLocked()) if (evalSettings.pureEval && !flakeRef.input.isLocked())
throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS); throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS);

View file

@ -350,7 +350,7 @@ string_parts_interpolated
path_start path_start
: PATH { : PATH {
Path path(absPath({$1.p, $1.l}, state->basePath.path.abs())); Path path(absPath(std::string_view{$1.p, $1.l}, state->basePath.path.abs()));
/* add back in the trailing '/' to the first segment */ /* add back in the trailing '/' to the first segment */
if ($1.p[$1.l-1] == '/' && $1.l > 1) if ($1.p[$1.l-1] == '/' && $1.l > 1)
path += "/"; path += "/";

View file

@ -333,7 +333,7 @@ static std::string quoteRegexChars(const std::string & raw)
} }
#if __linux__ #if __linux__
static void readFileRoots(const char * path, UncheckedRoots & roots) static void readFileRoots(const std::filesystem::path & path, UncheckedRoots & roots)
{ {
try { try {
roots[readFile(path)].emplace(path); roots[readFile(path)].emplace(path);

View file

@ -31,7 +31,7 @@ LocalOverlayStore::LocalOverlayStore(std::string_view scheme, PathView path, con
if (checkMount.get()) { if (checkMount.get()) {
std::smatch match; std::smatch match;
std::string mountInfo; std::string mountInfo;
auto mounts = readFile("/proc/self/mounts"); auto mounts = readFile(std::filesystem::path{"/proc/self/mounts"});
auto regex = std::regex(R"((^|\n)overlay )" + realStoreDir.get() + R"( .*(\n|$))"); auto regex = std::regex(R"((^|\n)overlay )" + realStoreDir.get() + R"( .*(\n|$))");
// Mount points can be stacked, so there might be multiple matching entries. // Mount points can be stacked, so there might be multiple matching entries.

View file

@ -113,6 +113,16 @@ protected:
, arity(1) , 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> template<class T>
Handler(T * dest, const T & val) Handler(T * dest, const T & val)
: fun([dest, val](std::vector<std::string> ss) { *dest = 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. * Expect 0 or more arguments.
*/ */

View file

@ -10,9 +10,6 @@ namespace nix {
* *
* We use our own implementation unconditionally for consistency. * We use our own implementation unconditionally for consistency.
*/ */
int execvpe( int execvpe(const OsChar * file0, const OsChar * const argv[], const OsChar * const envp[]);
const OsString::value_type * file0,
const OsString::value_type * const argv[],
const OsString::value_type * const envp[]);
} }

View file

@ -6,7 +6,9 @@
namespace nix { namespace nix {
namespace fs = std::filesystem; namespace fs {
using namespace std::filesystem;
}
constexpr static const OsStringView path_var_separator{ constexpr static const OsStringView path_var_separator{
&ExecutablePath::separator, &ExecutablePath::separator,
@ -24,7 +26,7 @@ ExecutablePath ExecutablePath::load()
ExecutablePath ExecutablePath::parse(const OsString & path) ExecutablePath ExecutablePath::parse(const OsString & path)
{ {
auto strings = path.empty() ? (std::list<OsString>{}) 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; std::vector<fs::path> ret;
ret.reserve(strings.size()); ret.reserve(strings.size());

View file

@ -7,11 +7,15 @@ namespace nix {
MakeError(ExecutableLookupError, Error); MakeError(ExecutableLookupError, Error);
/**
* @todo rename, it is not just good for execuatable paths, but also
* other lists of paths.
*/
struct ExecutablePath struct ExecutablePath
{ {
std::vector<std::filesystem::path> directories; std::vector<std::filesystem::path> directories;
constexpr static const OsString::value_type separator = constexpr static const OsChar separator =
#ifdef WIN32 #ifdef WIN32
L';' L';'
#else #else

View file

@ -26,10 +26,10 @@
#include "strings-inline.hh" #include "strings-inline.hh"
namespace fs = std::filesystem;
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
/** /**
* Treat the string as possibly an absolute path, by inspecting the * Treat the string as possibly an absolute path, by inspecting the
* start of it. Return whether it was probably intended to be * 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); 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) Path canonPath(PathView path, bool resolveSymlinks)
{ {
@ -206,10 +210,10 @@ bool pathExists(const Path & path)
return maybeLstat(path).has_value(); return maybeLstat(path).has_value();
} }
bool pathAccessible(const Path & path) bool pathAccessible(const std::filesystem::path & path)
{ {
try { try {
return pathExists(path); return pathExists(path.string());
} catch (SysError & e) { } catch (SysError & e) {
// swallow EPERM // swallow EPERM
if (e.errNo == EPERM) return false; if (e.errNo == EPERM) return false;
@ -238,6 +242,11 @@ std::string readFile(const Path & path)
return readFile(fd.get()); 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) 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. */ /* If it's a file, just fsync and return. */
auto st = lstat(path); auto st = lstat(path);
if (S_ISREG(st.st_mode)) { 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) if (!fd)
throw SysError("opening file '%1%'", path); throw SysError("opening file '%1%'", path);
fd.fsync(); fd.fsync();
@ -344,7 +353,7 @@ void recursiveSync(const Path & path)
if (fs::is_directory(st)) { if (fs::is_directory(st)) {
dirsToEnumerate.emplace_back(entry.path()); dirsToEnumerate.emplace_back(entry.path());
} else if (fs::is_regular_file(st)) { } 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) if (!fd)
throw SysError("opening file '%1%'", entry.path()); throw SysError("opening file '%1%'", entry.path());
fd.fsync(); fd.fsync();
@ -355,7 +364,7 @@ void recursiveSync(const Path & path)
/* Fsync all the directories. */ /* Fsync all the directories. */
for (auto dir = dirsToFsync.rbegin(); dir != dirsToFsync.rend(); ++dir) { 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) if (!fd)
throw SysError("opening directory '%1%'", *dir); throw SysError("opening directory '%1%'", *dir);
fd.fsync(); fd.fsync();
@ -595,19 +604,20 @@ void createSymlink(const Path & target, const Path & link)
fs::create_symlink(target, 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++) { 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 { try {
createSymlink(target, tmp); fs::create_symlink(target, tmp);
} catch (fs::filesystem_error & e) { } catch (fs::filesystem_error & e) {
if (e.code() == std::errc::file_exists) continue; if (e.code() == std::errc::file_exists) continue;
throw; throw;
} }
std::filesystem::rename(tmp, link); fs::rename(tmp, link);
break; break;
} }

View file

@ -46,16 +46,33 @@ struct Source;
* @return An absolutized path, resolving paths relative to the * @return An absolutized path, resolving paths relative to the
* specified directory, or the current directory otherwise. The path * specified directory, or the current directory otherwise. The path
* is also canonicalised. * is also canonicalised.
*
* In the process of being deprecated for `std::filesystem::absolute`.
*/ */
Path absPath(PathView path, Path absPath(PathView path,
std::optional<PathView> dir = {}, std::optional<PathView> dir = {},
bool resolveSymlinks = false); 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 * Canonicalise a path by removing all `.` or `..` components and
* double or trailing slashes. Optionally resolves all symlink * double or trailing slashes. Optionally resolves all symlink
* components such that each component of the resulting path is *not* * components such that each component of the resulting path is *not*
* a symbolic link. * 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); 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 * everything before the final `/`. If the path is the root or an
* immediate child thereof (e.g., `/foo`), this means `/` * immediate child thereof (e.g., `/foo`), this means `/`
* is returned. * is returned.
*
* In the process of being deprecated for
* `std::filesystem::path::parent_path`.
*/ */
Path dirOf(const PathView path); Path dirOf(const PathView path);
/** /**
* @return the base name of the given canonical path, i.e., everything * @return the base name of the given canonical path, i.e., everything
* following the final `/` (trailing slashes are removed). * 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); 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. * @return true iff the given path exists.
*
* In the process of being deprecated for `fs::symlink_exists`.
*/ */
bool pathExists(const Path & path); 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. * A version of pathExists that returns false on a permission error.
* Useful for inferring default paths across directories that might not * Useful for inferring default paths across directories that might not
* be readable. * be readable.
* @return true iff the given path can be accessed and exists * @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 * Read the contents (target) of a symbolic link. The result is not
* in any way canonicalised. * in any way canonicalised.
*
* In the process of being deprecated for
* `std::filesystem::read_symlink`.
*/ */
Path readLink(const Path & path); 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. * Read the contents of a file into a string.
*/ */
std::string readFile(const Path & path); std::string readFile(const Path & path);
std::string readFile(const std::filesystem::path & path);
void readFile(const Path & path, Sink & sink); void readFile(const Path & path, Sink & sink);
/** /**
* Write a string to a file. * Write a string to a file.
*/ */
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false); 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); 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. * 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. * 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); void createDirs(const Path & path);
inline void createDirs(PathView path) inline void createDirs(PathView path)
@ -192,13 +249,21 @@ void setWriteTime(const std::filesystem::path & path, const struct stat & st);
/** /**
* Create a symlink. * Create a symlink.
*
* In the process of being deprecated for
* `std::filesystem::create_symlink`.
*/ */
void createSymlink(const Path & target, const Path & link); void createSymlink(const Path & target, const Path & link);
/** /**
* Atomically create or replace a symlink. * 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` * Similar to 'renameFile', but fallback to a copy+remove if `src` and `dst`

View file

@ -118,7 +118,7 @@ void saveMountNamespace()
void restoreMountNamespace() void restoreMountNamespace()
{ {
try { try {
auto savedCwd = absPath("."); auto savedCwd = std::filesystem::current_path();
if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1) if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1)
throw SysError("restoring parent mount namespace"); throw SysError("restoring parent mount namespace");

View file

@ -11,21 +11,30 @@ namespace nix {
* Named because it is similar to the Rust type, except it is in the * Named because it is similar to the Rust type, except it is in the
* native encoding not WTF-8. * 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. * avoid including a much more complex header.
*/ */
using OsString = std::basic_string< using OsChar =
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
wchar_t wchar_t
#else #else
char char
#endif #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`. * `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); std::string os_string_to_string(OsStringView path);

View file

@ -20,7 +20,7 @@ PosixSourceAccessor::PosixSourceAccessor()
SourcePath PosixSourceAccessor::createAtRoot(const std::filesystem::path & path) SourcePath PosixSourceAccessor::createAtRoot(const std::filesystem::path & path)
{ {
std::filesystem::path path2 = absPath(path.string()); std::filesystem::path path2 = absPath(path);
return { return {
make_ref<PosixSourceAccessor>(path2.root_path()), make_ref<PosixSourceAccessor>(path2.root_path()),
CanonPath { path2.relative_path().string() }, CanonPath { path2.relative_path().string() },

View file

@ -9,6 +9,7 @@
#ifdef _WIN32 #ifdef _WIN32
# include <fileapi.h> # include <fileapi.h>
# include <winsock2.h>
# include "windows-error.hh" # include "windows-error.hh"
#else #else
# include <poll.h> # include <poll.h>
@ -167,13 +168,14 @@ bool FdSource::hasData()
while (true) { while (true) {
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd, &fds); int fd_ = fromDescriptorReadOnly(fd);
FD_SET(fd_, &fds);
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 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 (n < 0) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
throw SysError("polling file descriptor"); throw SysError("polling file descriptor");

View file

@ -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::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::vector<std::string> splitString(std::string_view s, std::string_view separators);
template std::list<OsString> basicSplitString( template std::list<OsString>
std::basic_string_view<OsString::value_type> s, std::basic_string_view<OsString::value_type> separators); 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::list<std::string> &);
template std::string concatStringsSep(std::string_view, const std::set<std::string> &); template std::string concatStringsSep(std::string_view, const std::set<std::string> &);

View file

@ -9,6 +9,8 @@
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
std::string getUserName() std::string getUserName()
{ {
auto pw = getpwuid(geteuid()); auto pw = getpwuid(geteuid());

View file

@ -6,6 +6,8 @@
#include "local-fs-store.hh" #include "local-fs-store.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
struct CmdBundle : InstallableValueCommand struct CmdBundle : InstallableValueCommand
@ -78,7 +80,7 @@ struct CmdBundle : InstallableValueCommand
auto [bundlerFlakeRef, bundlerName, extendedOutputsSpec] = auto [bundlerFlakeRef, bundlerName, extendedOutputsSpec] =
parseFlakeRefWithFragmentAndExtendedOutputsSpec( parseFlakeRefWithFragmentAndExtendedOutputsSpec(
fetchSettings, bundler, absPath(".")); fetchSettings, bundler, fs::current_path().string());
const flake::LockFlags lockFlags{ .writeLockFile = false }; const flake::LockFlags lockFlags{ .writeLockFile = false };
InstallableFlake bundler{this, InstallableFlake bundler{this,
evalState, std::move(bundlerFlakeRef), bundlerName, std::move(extendedOutputsSpec), evalState, std::move(bundlerFlakeRef), bundlerName, std::move(extendedOutputsSpec),

View file

@ -10,6 +10,8 @@
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include "executable-path.hh" #include "executable-path.hh"
namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
namespace { namespace {
@ -40,8 +42,6 @@ void checkInfo(const std::string & msg) {
} }
namespace fs = std::filesystem;
struct CmdConfigCheck : StoreCommand struct CmdConfigCheck : StoreCommand
{ {
bool success = true; bool success = true;

View file

@ -21,6 +21,8 @@
#include "strings.hh" #include "strings.hh"
namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
struct DevelopSettings : Config struct DevelopSettings : Config
@ -341,7 +343,7 @@ struct Common : InstallableCommand, MixProfile
ref<Store> store, ref<Store> store,
const BuildEnvironment & buildEnvironment, const BuildEnvironment & buildEnvironment,
const std::filesystem::path & tmpDir, const std::filesystem::path & tmpDir,
const std::filesystem::path & outputsDir = std::filesystem::path { absPath(".") } / "outputs") const std::filesystem::path & outputsDir = fs::path { fs::current_path() } / "outputs")
{ {
// A list of colon-separated environment variables that should be // A list of colon-separated environment variables that should be
// prepended to, rather than overwritten, in order to keep the shell usable. // prepended to, rather than overwritten, in order to keep the shell usable.
@ -450,7 +452,7 @@ struct Common : InstallableCommand, MixProfile
auto targetFilePath = tmpDir / OS_STR(".attrs."); auto targetFilePath = tmpDir / OS_STR(".attrs.");
targetFilePath += ext; targetFilePath += ext;
writeFile(targetFilePath.string(), content); writeFile(targetFilePath, content);
auto fileInBuilderEnv = buildEnvironment.vars.find(envVar); auto fileInBuilderEnv = buildEnvironment.vars.find(envVar);
assert(fileInBuilderEnv != buildEnvironment.vars.end()); assert(fileInBuilderEnv != buildEnvironment.vars.end());

View file

@ -25,7 +25,7 @@
#include "strings-inline.hh" #include "strings-inline.hh"
namespace fs = std::filesystem; namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
using namespace nix::flake; using namespace nix::flake;
@ -53,7 +53,7 @@ public:
FlakeRef getFlakeRef() FlakeRef getFlakeRef()
{ {
return parseFlakeRef(fetchSettings, flakeUrl, absPath(".")); //FIXME return parseFlakeRef(fetchSettings, flakeUrl, fs::current_path().string()); //FIXME
} }
LockedFlake lockFlake() LockedFlake lockFlake()
@ -65,7 +65,7 @@ public:
{ {
return { return {
// Like getFlakeRef but with expandTilde calld first // Like getFlakeRef but with expandTilde calld first
parseFlakeRef(fetchSettings, expandTilde(flakeUrl), absPath(".")) parseFlakeRef(fetchSettings, expandTilde(flakeUrl), fs::current_path().string())
}; };
} }
}; };
@ -880,7 +880,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
auto evalState = getEvalState(); auto evalState = getEvalState();
auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment( auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(
fetchSettings, templateUrl, absPath(".")); fetchSettings, templateUrl, fs::current_path().string());
auto installable = InstallableFlake(nullptr, auto installable = InstallableFlake(nullptr,
evalState, std::move(templateFlakeRef), templateName, ExtendedOutputsSpec::Default(), evalState, std::move(templateFlakeRef), templateName, ExtendedOutputsSpec::Default(),
@ -927,7 +927,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
} }
continue; continue;
} else } else
writeFile(to2.string(), contents); writeFile(to2, contents);
} }
else if (fs::is_symlink(st)) { else if (fs::is_symlink(st)) {
auto target = fs::read_symlink(from2); auto target = fs::read_symlink(from2);

View file

@ -20,6 +20,8 @@
#include <queue> #include <queue>
namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
std::string chrootHelperName = "__run_in_chroot"; std::string chrootHelperName = "__run_in_chroot";
@ -170,25 +172,25 @@ void chrootHelper(int argc, char * * argv)
if (!pathExists(storeDir)) { if (!pathExists(storeDir)) {
// FIXME: Use overlayfs? // FIXME: Use overlayfs?
std::filesystem::path tmpDir = createTempDir(); fs::path tmpDir = createTempDir();
createDirs(tmpDir + storeDir); createDirs(tmpDir + storeDir);
if (mount(realStoreDir.c_str(), (tmpDir + storeDir).c_str(), "", MS_BIND, 0) == -1) if (mount(realStoreDir.c_str(), (tmpDir + storeDir).c_str(), "", MS_BIND, 0) == -1)
throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir); throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir);
for (auto entry : std::filesystem::directory_iterator{"/"}) { for (auto entry : fs::directory_iterator{"/"}) {
checkInterrupt(); checkInterrupt();
auto src = entry.path(); auto src = entry.path();
Path dst = tmpDir / entry.path().filename(); fs::path dst = tmpDir / entry.path().filename();
if (pathExists(dst)) continue; if (pathExists(dst)) continue;
auto st = entry.symlink_status(); auto st = entry.symlink_status();
if (std::filesystem::is_directory(st)) { if (fs::is_directory(st)) {
if (mkdir(dst.c_str(), 0700) == -1) if (mkdir(dst.c_str(), 0700) == -1)
throw SysError("creating directory '%s'", dst); throw SysError("creating directory '%s'", dst);
if (mount(src.c_str(), dst.c_str(), "", MS_BIND | MS_REC, 0) == -1) if (mount(src.c_str(), dst.c_str(), "", MS_BIND | MS_REC, 0) == -1)
throw SysError("mounting '%s' on '%s'", src, dst); throw SysError("mounting '%s' on '%s'", src, dst);
} else if (std::filesystem::is_symlink(st)) } else if (fs::is_symlink(st))
createSymlink(readLink(src), dst); createSymlink(readLink(src), dst);
} }
@ -205,9 +207,9 @@ void chrootHelper(int argc, char * * argv)
if (mount(realStoreDir.c_str(), storeDir.c_str(), "", MS_BIND, 0) == -1) if (mount(realStoreDir.c_str(), storeDir.c_str(), "", MS_BIND, 0) == -1)
throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir); throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir);
writeFile("/proc/self/setgroups", "deny"); writeFile(fs::path{"/proc/self/setgroups"}, "deny");
writeFile("/proc/self/uid_map", fmt("%d %d %d", uid, uid, 1)); writeFile(fs::path{"/proc/self/uid_map"}, fmt("%d %d %d", uid, uid, 1));
writeFile("/proc/self/gid_map", fmt("%d %d %d", gid, gid, 1)); writeFile(fs::path{"/proc/self/gid_map"}, fmt("%d %d %d", gid, gid, 1));
#if __linux__ #if __linux__
if (system != "") if (system != "")

View file

@ -5,7 +5,9 @@
namespace nix { namespace nix {
namespace fs = std::filesystem; namespace fs {
using namespace std::filesystem;
}
fs::path getNixBin(std::optional<std::string_view> binaryNameOpt) fs::path getNixBin(std::optional<std::string_view> binaryNameOpt)
{ {

View file

@ -10,11 +10,11 @@ using nlohmann::json;
class PublicKeyTest : public CharacterizationTest class PublicKeyTest : public CharacterizationTest
{ {
Path unitTestData = getUnitTestData() + "/public-key"; std::filesystem::path unitTestData = getUnitTestData() / "public-key";
public: public:
Path goldenMaster(std::string_view testStem) const override { std::filesystem::path goldenMaster(std::string_view testStem) const override {
return unitTestData + "/" + testStem; return unitTestData / testStem;
} }
}; };

View file

@ -10,7 +10,7 @@
#include <filesystem> #include <filesystem>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace fs = std::filesystem; namespace fs { using namespace std::filesystem; }
namespace nixC { namespace nixC {
class nix_api_store_test : public nix_api_util_context class nix_api_store_test : public nix_api_util_context

View file

@ -12,10 +12,10 @@ namespace nix {
template<class Proto, const char * protocolDir> template<class Proto, const char * protocolDir>
class ProtoTest : public CharacterizationTest, public LibStoreTest class ProtoTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/" + protocolDir; std::filesystem::path unitTestData = getUnitTestData() / protocolDir;
Path goldenMaster(std::string_view testStem) const override { std::filesystem::path goldenMaster(std::string_view testStem) const override {
return unitTestData + "/" + testStem + ".bin"; return unitTestData / (std::string { testStem + ".bin" });
} }
}; };

View file

@ -16,12 +16,12 @@ using nlohmann::json;
class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/derivation"; std::filesystem::path unitTestData = getUnitTestData() / "derivation";
public: public:
Path goldenMaster(std::string_view testStem) const override std::filesystem::path goldenMaster(std::string_view testStem) const override
{ {
return unitTestData + "/" + testStem; return unitTestData / testStem;
} }
}; };

View file

@ -13,11 +13,11 @@ using nlohmann::json;
class DerivationTest : public CharacterizationTest, public LibStoreTest class DerivationTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/derivation"; std::filesystem::path unitTestData = getUnitTestData() / "derivation";
public: public:
Path goldenMaster(std::string_view testStem) const override { std::filesystem::path goldenMaster(std::string_view testStem) const override {
return unitTestData + "/" + testStem; return unitTestData / testStem;
} }
/** /**

View file

@ -13,6 +13,8 @@ using testing::Eq;
using testing::Field; using testing::Field;
using testing::SizeIs; using testing::SizeIs;
namespace nix::fs { using namespace std::filesystem; }
using namespace nix; using namespace nix;
TEST(machines, getMachinesWithEmptyBuilders) { TEST(machines, getMachinesWithEmptyBuilders) {
@ -135,10 +137,10 @@ TEST(machines, getMachinesWithIncorrectFormat) {
} }
TEST(machines, getMachinesWithCorrectFileReference) { TEST(machines, getMachinesWithCorrectFileReference) {
auto path = absPath(getUnitTestData() + "/machines/valid"); auto path = fs::weakly_canonical(getUnitTestData() / "machines/valid");
ASSERT_TRUE(pathExists(path)); ASSERT_TRUE(fs::exists(path));
auto actual = Machine::parseConfig({}, "@" + path); auto actual = Machine::parseConfig({}, "@" + path.string());
ASSERT_THAT(actual, SizeIs(3)); ASSERT_THAT(actual, SizeIs(3));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl")))); EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl")))); EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
@ -146,20 +148,22 @@ TEST(machines, getMachinesWithCorrectFileReference) {
} }
TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) {
auto path = "/dev/null"; fs::path path = "/dev/null";
ASSERT_TRUE(pathExists(path)); ASSERT_TRUE(fs::exists(path));
auto actual = Machine::parseConfig({}, std::string{"@"} + path); auto actual = Machine::parseConfig({}, "@" + path.string());
ASSERT_THAT(actual, SizeIs(0)); ASSERT_THAT(actual, SizeIs(0));
} }
TEST(machines, getMachinesWithIncorrectFileReference) { TEST(machines, getMachinesWithIncorrectFileReference) {
auto actual = Machine::parseConfig({}, "@" + absPath("/not/a/file")); auto path = fs::weakly_canonical("/not/a/file");
ASSERT_TRUE(!fs::exists(path));
auto actual = Machine::parseConfig({}, "@" + path.string());
ASSERT_THAT(actual, SizeIs(0)); ASSERT_THAT(actual, SizeIs(0));
} }
TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) { TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) {
EXPECT_THROW( EXPECT_THROW(
Machine::parseConfig({}, "@" + absPath(getUnitTestData() + "/machines/bad_format")), Machine::parseConfig({}, "@" + fs::weakly_canonical(getUnitTestData() / "machines" / "bad_format").string()),
FormatError); FormatError);
} }

View file

@ -13,10 +13,10 @@ using nlohmann::json;
class NarInfoTest : public CharacterizationTest, public LibStoreTest class NarInfoTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/nar-info"; std::filesystem::path unitTestData = getUnitTestData() / "nar-info";
Path goldenMaster(PathView testStem) const override { std::filesystem::path goldenMaster(PathView testStem) const override {
return unitTestData + "/" + testStem + ".json"; return unitTestData / (testStem + ".json");
} }
}; };

View file

@ -12,10 +12,10 @@ using nlohmann::json;
class PathInfoTest : public CharacterizationTest, public LibStoreTest class PathInfoTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/path-info"; std::filesystem::path unitTestData = getUnitTestData() / "path-info";
Path goldenMaster(PathView testStem) const override { std::filesystem::path goldenMaster(PathView testStem) const override {
return unitTestData + "/" + testStem + ".json"; return unitTestData / (testStem + ".json");
} }
}; };

View file

@ -13,11 +13,11 @@ using nlohmann::json;
class StoreReferenceTest : public CharacterizationTest, public LibStoreTest class StoreReferenceTest : public CharacterizationTest, public LibStoreTest
{ {
Path unitTestData = getUnitTestData() + "/store-reference"; std::filesystem::path unitTestData = getUnitTestData() / "store-reference";
Path goldenMaster(PathView testStem) const override std::filesystem::path goldenMaster(PathView testStem) const override
{ {
return unitTestData + "/" + testStem + ".txt"; return unitTestData / (testStem + ".txt");
} }
}; };

View file

@ -13,7 +13,7 @@ namespace nix {
* The path to the unit test data directory. See the contributing guide * The path to the unit test data directory. See the contributing guide
* in the manual for further details. * in the manual for further details.
*/ */
static inline Path getUnitTestData() { static inline std::filesystem::path getUnitTestData() {
return getEnv("_NIX_TEST_UNIT_DATA").value(); return getEnv("_NIX_TEST_UNIT_DATA").value();
} }
@ -36,7 +36,7 @@ protected:
* While the "golden master" for this characterization test is * While the "golden master" for this characterization test is
* located. It should not be shared with any other test. * located. It should not be shared with any other test.
*/ */
virtual Path goldenMaster(PathView testStem) const = 0; virtual std::filesystem::path goldenMaster(PathView testStem) const = 0;
public: public:
/** /**
@ -77,7 +77,7 @@ public:
if (testAccept()) if (testAccept())
{ {
createDirs(dirOf(file)); std::filesystem::create_directories(file.parent_path());
writeFile2(file, got); writeFile2(file, got);
GTEST_SKIP() GTEST_SKIP()
<< "Updating golden master " << "Updating golden master "
@ -97,10 +97,10 @@ public:
{ {
writeTest( writeTest(
testStem, test, testStem, test,
[](const Path & f) -> std::string { [](const std::filesystem::path & f) -> std::string {
return readFile(f); return readFile(f);
}, },
[](const Path & f, const std::string & c) { [](const std::filesystem::path & f, const std::string & c) {
return writeFile(f, c); return writeFile(f, c);
}); });
} }

View file

@ -12,8 +12,8 @@
#include <numeric> #include <numeric>
#ifdef _WIN32 #ifdef _WIN32
# define FS_SEP "\\" # define FS_SEP L"\\"
# define FS_ROOT "C:" FS_SEP // Need a mounted one, C drive is likely # define FS_ROOT L"C:" FS_SEP // Need a mounted one, C drive is likely
#else #else
# define FS_SEP "/" # define FS_SEP "/"
# define FS_ROOT FS_SEP # define FS_ROOT FS_SEP
@ -23,6 +23,12 @@
# define PATH_MAX 4096 # define PATH_MAX 4096
#endif #endif
#ifdef _WIN32
# define GET_CWD _wgetcwd
#else
# define GET_CWD getcwd
#endif
namespace nix { namespace nix {
/* ----------- tests for file-system.hh -------------------------------------*/ /* ----------- tests for file-system.hh -------------------------------------*/
@ -33,34 +39,34 @@ namespace nix {
TEST(absPath, doesntChangeRoot) TEST(absPath, doesntChangeRoot)
{ {
auto p = absPath(FS_ROOT); auto p = absPath(std::filesystem::path{FS_ROOT});
ASSERT_EQ(p, FS_ROOT); ASSERT_EQ(p, FS_ROOT);
} }
TEST(absPath, turnsEmptyPathIntoCWD) TEST(absPath, turnsEmptyPathIntoCWD)
{ {
char cwd[PATH_MAX + 1]; OsChar cwd[PATH_MAX + 1];
auto p = absPath(""); auto p = absPath(std::filesystem::path{""});
ASSERT_EQ(p, getcwd((char *) &cwd, PATH_MAX)); ASSERT_EQ(p, GET_CWD((OsChar *) &cwd, PATH_MAX));
} }
TEST(absPath, usesOptionalBasePathWhenGiven) TEST(absPath, usesOptionalBasePathWhenGiven)
{ {
char _cwd[PATH_MAX + 1]; OsChar _cwd[PATH_MAX + 1];
char * cwd = getcwd((char *) &_cwd, PATH_MAX); OsChar * cwd = GET_CWD((OsChar *) &_cwd, PATH_MAX);
auto p = absPath("", cwd); auto p = absPath(std::filesystem::path{""}.string(), std::filesystem::path{cwd}.string());
ASSERT_EQ(p, cwd); ASSERT_EQ(p, std::filesystem::path{cwd}.string());
} }
TEST(absPath, isIdempotent) TEST(absPath, isIdempotent)
{ {
char _cwd[PATH_MAX + 1]; OsChar _cwd[PATH_MAX + 1];
char * cwd = getcwd((char *) &_cwd, PATH_MAX); OsChar * cwd = GET_CWD((OsChar *) &_cwd, PATH_MAX);
auto p1 = absPath(cwd); auto p1 = absPath(std::filesystem::path{cwd});
auto p2 = absPath(p1); auto p2 = absPath(p1);
ASSERT_EQ(p1, p2); ASSERT_EQ(p1, p2);
@ -68,8 +74,8 @@ TEST(absPath, isIdempotent)
TEST(absPath, pathIsCanonicalised) TEST(absPath, pathIsCanonicalised)
{ {
auto path = FS_ROOT "some/path/with/trailing/dot/."; auto path = FS_ROOT OS_STR("some/path/with/trailing/dot/.");
auto p1 = absPath(path); auto p1 = absPath(std::filesystem::path{path});
auto p2 = absPath(p1); auto p2 = absPath(p1);
ASSERT_EQ(p1, FS_ROOT "some" FS_SEP "path" FS_SEP "with" FS_SEP "trailing" FS_SEP "dot"); ASSERT_EQ(p1, FS_ROOT "some" FS_SEP "path" FS_SEP "with" FS_SEP "trailing" FS_SEP "dot");
@ -82,26 +88,26 @@ TEST(absPath, pathIsCanonicalised)
TEST(canonPath, removesTrailingSlashes) TEST(canonPath, removesTrailingSlashes)
{ {
auto path = FS_ROOT "this/is/a/path//"; std::filesystem::path path = FS_ROOT "this/is/a/path//";
auto p = canonPath(path); auto p = canonPath(path.string());
ASSERT_EQ(p, FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"); ASSERT_EQ(p, std::filesystem::path{FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"}.string());
} }
TEST(canonPath, removesDots) TEST(canonPath, removesDots)
{ {
auto path = FS_ROOT "this/./is/a/path/./"; std::filesystem::path path = FS_ROOT "this/./is/a/path/./";
auto p = canonPath(path); auto p = canonPath(path.string());
ASSERT_EQ(p, FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"); ASSERT_EQ(p, std::filesystem::path{FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"}.string());
} }
TEST(canonPath, removesDots2) TEST(canonPath, removesDots2)
{ {
auto path = FS_ROOT "this/a/../is/a////path/foo/.."; std::filesystem::path path = FS_ROOT "this/a/../is/a////path/foo/..";
auto p = canonPath(path); auto p = canonPath(path.string());
ASSERT_EQ(p, FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"); ASSERT_EQ(p, std::filesystem::path{FS_ROOT "this" FS_SEP "is" FS_SEP "a" FS_SEP "path"}.string());
} }
TEST(canonPath, requiresAbsolutePath) TEST(canonPath, requiresAbsolutePath)
@ -243,7 +249,7 @@ TEST(isDirOrInDir, DISABLED_shouldWork)
TEST(pathExists, rootExists) TEST(pathExists, rootExists)
{ {
ASSERT_TRUE(pathExists(FS_ROOT)); ASSERT_TRUE(pathExists(std::filesystem::path{FS_ROOT}.string()));
} }
TEST(pathExists, cwdExists) TEST(pathExists, cwdExists)

View file

@ -11,12 +11,12 @@ using namespace git;
class GitTest : public CharacterizationTest class GitTest : public CharacterizationTest
{ {
Path unitTestData = getUnitTestData() + "/git"; std::filesystem::path unitTestData = getUnitTestData() / "git";
public: public:
Path goldenMaster(std::string_view testStem) const override { std::filesystem::path goldenMaster(std::string_view testStem) const override {
return unitTestData + "/" + testStem; return unitTestData / std::string(testStem);
} }
/** /**

View file

@ -48,12 +48,14 @@ subdir('build-utils-meson/diagnostics')
sources = files( sources = files(
'args.cc', 'args.cc',
'canon-path.cc', 'canon-path.cc',
'checked-arithmetic.cc',
'chunked-vector.cc', 'chunked-vector.cc',
'closure.cc', 'closure.cc',
'compression.cc', 'compression.cc',
'config.cc', 'config.cc',
'executable-path.cc', 'executable-path.cc',
'file-content-address.cc', 'file-content-address.cc',
'file-system.cc',
'git.cc', 'git.cc',
'hash.cc', 'hash.cc',
'hilite.cc', 'hilite.cc',
@ -62,6 +64,7 @@ sources = files(
'lru-cache.cc', 'lru-cache.cc',
'nix_api_util.cc', 'nix_api_util.cc',
'pool.cc', 'pool.cc',
'position.cc',
'processes.cc', 'processes.cc',
'references.cc', 'references.cc',
'spawn.cc', 'spawn.cc',