From c1c1774d7809e957b59b11c33a38621edf917071 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 7 May 2024 00:20:30 -0400 Subject: [PATCH] Make `Path` `std::filesystem::path` not `std::string` --- src/build-remote/build-remote.cc | 6 +- src/libcmd/common-eval-args.cc | 2 +- src/libcmd/common-eval-args.hh | 2 +- src/libexpr/eval-error.hh | 1 + src/libexpr/eval-settings.cc | 2 +- src/libfetchers/git-utils.cc | 2 +- src/libstore/globals.cc | 6 +- src/libstore/globals.hh | 2 +- src/libstore/http-binary-cache-store.cc | 4 +- src/libstore/local-binary-cache-store.cc | 2 +- src/libstore/local-fs-store.hh | 8 +- src/libstore/nar-accessor.cc | 18 ++- src/libstore/nar-info-disk-cache.cc | 5 +- src/libstore/path.cc | 2 +- src/libstore/pathlocks.hh | 1 + src/libstore/profiles.cc | 20 +-- src/libstore/sqlite.cc | 2 +- src/libstore/sqlite.hh | 1 + src/libstore/ssh.cc | 2 +- src/libstore/store-api.hh | 4 +- src/libstore/store-dir-config.hh | 2 +- src/libstore/uds-remote-store.cc | 2 +- src/libstore/uds-remote-store.hh | 2 +- src/libstore/unix/local-overlay-store.md | 2 +- src/libstore/unix/lock.cc | 6 +- src/libstore/unix/posix-fs-canonicalise.hh | 1 + src/libutil/archive.cc | 21 +-- src/libutil/archive.hh | 5 +- src/libutil/args.hh | 17 +++ src/libutil/config-impl.hh | 14 ++ src/libutil/config.hh | 3 +- src/libutil/current-process.hh | 2 +- src/libutil/file-path-impl.hh | 2 +- src/libutil/file-path.hh | 30 ++--- src/libutil/file-system.cc | 123 +++++++----------- src/libutil/file-system.hh | 16 +-- src/libutil/fs-sink.cc | 30 ++--- src/libutil/fs-sink.hh | 28 ++-- src/libutil/git.cc | 10 +- src/libutil/git.hh | 8 +- src/libutil/json-utils.hh | 5 + src/libutil/linux/cgroup.hh | 2 +- src/libutil/memory-source-accessor.cc | 6 +- src/libutil/memory-source-accessor.hh | 6 +- src/libutil/tarfile.cc | 7 +- src/libutil/types.hh | 8 -- src/libutil/unix/file-path.cc | 12 +- src/libutil/users.cc | 2 +- src/libutil/users.hh | 2 +- src/libutil/windows/file-path.cc | 18 +-- src/nix-build/nix-build.cc | 5 +- src/nix-channel/nix-channel.cc | 6 +- src/nix/eval.cc | 2 +- .../libstore-support/tests/nix_api_store.hh | 7 +- tests/unit/libstore/machines.cc | 2 +- .../libutil-support/tests/characterization.hh | 8 +- 56 files changed, 255 insertions(+), 259 deletions(-) diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index 18eee830b9e0..baad3bc7317d 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -81,11 +81,11 @@ static int main_build_remote(int argc, char * * argv) /* It would be more appropriate to use $XDG_RUNTIME_DIR, since that gets cleared on reboot, but it wouldn't work on macOS. */ - auto currentLoadName = "/current-load"; + PathView currentLoadName = "current-load"; if (auto localStore = store.dynamic_pointer_cast()) - currentLoad = std::string { localStore->stateDir } + currentLoadName; + currentLoad = localStore->stateDir / currentLoadName; else - currentLoad = settings.nixStateDir + currentLoadName; + currentLoad = settings.nixStateDir / currentLoadName.native(); std::shared_ptr sshStore; AutoCloseFD bestSlotLock; diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 155b43b700b2..071fecefd90d 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -192,7 +192,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state) return res.finish(); } -SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * baseDir) +SourcePath lookupFileArg(EvalState & state, PathView s, const Path * baseDir) { if (EvalSettings::isPseudoUrl(s)) { auto accessor = fetchers::downloadTarball( diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh index 75cb19334fe8..11d081728df2 100644 --- a/src/libcmd/common-eval-args.hh +++ b/src/libcmd/common-eval-args.hh @@ -41,6 +41,6 @@ private: /** * @param baseDir Optional [base directory](https://nixos.org/manual/nix/unstable/glossary#gloss-base-directory) */ -SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * baseDir = nullptr); +SourcePath lookupFileArg(EvalState & state, PathView s, const Path * baseDir = nullptr); } diff --git a/src/libexpr/eval-error.hh b/src/libexpr/eval-error.hh index 7e0cbe982ec5..ae9f37c7200f 100644 --- a/src/libexpr/eval-error.hh +++ b/src/libexpr/eval-error.hh @@ -4,6 +4,7 @@ #include "error.hh" #include "pos-idx.hh" +#include "file-path.hh" namespace nix { diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc index 2ccbe327fad1..e7e92c1a2379 100644 --- a/src/libexpr/eval-settings.cc +++ b/src/libexpr/eval-settings.cc @@ -58,7 +58,7 @@ Strings EvalSettings::getDefaultNixPath() if (s.empty()) { res.push_back(p); } else { - res.push_back(s + "=" + p); + res.push_back(s + "=" + p.native()); } } }; diff --git a/src/libfetchers/git-utils.cc b/src/libfetchers/git-utils.cc index 2ea1e15ed8b8..3ff69c33b12d 100644 --- a/src/libfetchers/git-utils.cc +++ b/src/libfetchers/git-utils.cc @@ -421,7 +421,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this .program = "git", .args = { "-c", - "gpg.ssh.allowedSignersFile=" + allowedSignersFile, + "gpg.ssh.allowedSignersFile=" + allowedSignersFile.string(), "-C", path.string(), "verify-commit", rev.gitRev() diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index f0096b98120f..462a556d0837 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -84,7 +84,9 @@ Settings::Settings() } #if defined(__linux__) && defined(SANDBOX_SHELL) - sandboxPaths = tokenizeString("/bin/sh=" SANDBOX_SHELL); + sandboxPaths = std::set { + Path { "/bin/sh=" SANDBOX_SHELL } + }; #endif /* chroot-like behavior from Apple's sandbox */ @@ -154,7 +156,7 @@ std::vector getUserConfigFiles() // Use the paths specified in NIX_USER_CONF_FILES if it has been defined auto nixConfFiles = getEnv("NIX_USER_CONF_FILES"); if (nixConfFiles.has_value()) { - return tokenizeString>(nixConfFiles.value(), ":"); + return tokenizeString>(nixConfFiles.value(), ":"); } // Use the paths specified by the XDG spec diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 0c71a7515536..4b9d6a26e1ea 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -276,7 +276,7 @@ public: )"}; Setting builders{ - this, "@" + nixConfDir + "/machines", "builders", + this, "@" + (nixConfDir / "machines").native(), "builders", R"( A semicolon- or newline-separated list of build machines. diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc index 5da87e935db6..eebe6344fd46 100644 --- a/src/libstore/http-binary-cache-store.cc +++ b/src/libstore/http-binary-cache-store.cc @@ -26,7 +26,7 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v { private: - Path cacheUri; + std::string cacheUri; struct State { @@ -40,7 +40,7 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v HttpBinaryCacheStore( const std::string & scheme, - const Path & _cacheUri, + const std::string & _cacheUri, const Params & params) : StoreConfig(params) , BinaryCacheStoreConfig(params) diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc index 5481dd762e27..5e8684548034 100644 --- a/src/libstore/local-binary-cache-store.cc +++ b/src/libstore/local-binary-cache-store.cc @@ -45,7 +45,7 @@ class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public std::string getUri() override { - return "file://" + binaryCacheDir; + return "file://" + binaryCacheDir.native(); } static std::set uriSchemes(); diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh index 8fb08120012d..2ce59618bea6 100644 --- a/src/libstore/local-fs-store.hh +++ b/src/libstore/local-fs-store.hh @@ -16,17 +16,17 @@ struct LocalFSStoreConfig : virtual StoreConfig "Directory prefixed to all other paths."}; const PathSetting stateDir{this, - rootDir.get() ? *rootDir.get() + "/nix/var/nix" : settings.nixStateDir, + rootDir.get() ? *rootDir.get() / "nix/var/nix" : settings.nixStateDir, "state", "Directory where Nix will store state."}; const PathSetting logDir{this, - rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : settings.nixLogDir, + rootDir.get() ? *rootDir.get() / "nix/var/log/nix" : settings.nixLogDir, "log", "directory where Nix will store log files."}; const PathSetting realStoreDir{this, - rootDir.get() ? *rootDir.get() + "/nix/store" : storeDir, "real", + rootDir.get() ? *rootDir.get() / "nix/store" : storeDir, "real", "Physical path of the Nix store."}; }; @@ -66,7 +66,7 @@ public: Path toRealPath(const Path & storePath) override { assert(isInStore(storePath)); - return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1); + return getRealStoreDir() / Path::string_type { storePath, storeDir.native().size() + 1 }; } std::optional getBuildLogExact(const StorePath & path) override; diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc index cecf8148f455..83115d24ff00 100644 --- a/src/libstore/nar-accessor.cc +++ b/src/libstore/nar-accessor.cc @@ -15,7 +15,9 @@ struct NarMember std::string target; - /* If this is a directory, all the children of the directory. */ + /** + * If this is a directory, all the children of the directory. + */ std::map children; }; @@ -71,9 +73,11 @@ struct NarAccessor : public SourceAccessor : acc(acc), source(source) { } - NarMember & createMember(const Path & path, NarMember member) + NarMember & createMember(const CanonPath & path, NarMember member) { - size_t level = std::count(path.begin(), path.end(), '/'); + size_t level = 0; + for (auto _ : path) ++level; + while (parents.size() > level) parents.pop(); if (parents.empty()) { @@ -83,14 +87,14 @@ struct NarAccessor : public SourceAccessor } else { if (parents.top()->stat.type != Type::tDirectory) throw Error("NAR file missing parent directory of path '%s'", path); - auto result = parents.top()->children.emplace(baseNameOf(path), std::move(member)); + auto result = parents.top()->children.emplace(*path.baseName(), std::move(member)); auto & ref = result.first->second; parents.push(&ref); return ref; } } - void createDirectory(const Path & path) override + void createDirectory(const CanonPath & path) override { createMember(path, NarMember{ .stat = { .type = Type::tDirectory, @@ -100,7 +104,7 @@ struct NarAccessor : public SourceAccessor } }); } - void createRegularFile(const Path & path, std::function func) override + void createRegularFile(const CanonPath & path, std::function func) override { auto & nm = createMember(path, NarMember{ .stat = { .type = Type::tRegular, @@ -112,7 +116,7 @@ struct NarAccessor : public SourceAccessor func(nmc); } - void createSymlink(const Path & path, const std::string & target) override + void createSymlink(const CanonPath & path, const std::string & target) override { createMember(path, NarMember{ diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index 07beb8acb0b3..3d6c11f383dd 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -208,7 +208,10 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache }; { - auto r(state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority)); + auto r { + state->insertCache.use() + (uri)(time(0))(storeDir.native())(wantMassQuery)(priority) + }; if (!r.next()) { abort(); } ret.id = (int) r.getInt(0); } diff --git a/src/libstore/path.cc b/src/libstore/path.cc index 4b806e4084e6..729056be0176 100644 --- a/src/libstore/path.cc +++ b/src/libstore/path.cc @@ -89,7 +89,7 @@ std::optional StoreDirConfig::maybeParseStorePath(std::string_view pa } } -bool StoreDirConfig::isStorePath(std::string_view path) const +bool StoreDirConfig::isStorePath(PathView path) const { return (bool) maybeParseStorePath(path); } diff --git a/src/libstore/pathlocks.hh b/src/libstore/pathlocks.hh index 42a84a1a37bb..09ad123bf30a 100644 --- a/src/libstore/pathlocks.hh +++ b/src/libstore/pathlocks.hh @@ -2,6 +2,7 @@ ///@file #include "file-descriptor.hh" +#include "file-path.hh" namespace nix { diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index a0bb604104a8..2a5ab47018dd 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -39,7 +39,7 @@ std::pair> findGenerations(Path pro for (auto & i : readDirectory(profileDir)) { if (auto n = parseName(profileName, i.name)) { - auto path = profileDir + "/" + i.name; + auto path = profileDir / i.name; gens.push_back({ .number = *n, .path = path, @@ -255,7 +255,7 @@ time_t parseOlderThanTimeSpec(std::string_view timeSpec) void switchLink(Path link, Path target) { /* Hacky. */ - if (dirOf(target) == dirOf(link)) target = baseNameOf(target); + if (dirOf(target) == dirOf(link)) target = baseNameOf(target).native(); replaceSymlink(target, link); } @@ -310,28 +310,30 @@ Path profilesDir() auto profileRoot = isRootUser() ? rootProfilesDir() - : createNixStateDir() + "/profiles"; + : createNixStateDir() / "profiles"; createDirs(profileRoot); return profileRoot; } Path rootProfilesDir() { - return settings.nixStateDir + "/profiles/per-user/root"; + return settings.nixStateDir / "profiles/per-user/root"; } Path getDefaultProfile() { - Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile"; + Path profileLink = settings.useXDGBaseDirectories + ? createNixStateDir() / "profile" + : getHome() / ".nix-profile"; try { - auto profile = profilesDir() + "/profile"; + auto profile = profilesDir() / "profile"; if (!pathExists(profileLink)) { replaceSymlink(profile, profileLink); } // Backwards compatibiliy measure: Make root's profile available as // `.../default` as it's what NixOS and most of the init scripts expect - Path globalProfileLink = settings.nixStateDir + "/profiles/default"; + Path globalProfileLink = settings.nixStateDir / "profiles/default"; if (isRootUser() && !pathExists(globalProfileLink)) { replaceSymlink(profile, globalProfileLink); } @@ -345,12 +347,12 @@ Path getDefaultProfile() Path defaultChannelsDir() { - return profilesDir() + "/channels"; + return profilesDir() / "channels"; } Path rootChannelsDir() { - return rootProfilesDir() + "/channels"; + return rootProfilesDir() / "channels"; } } diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index 3175c197870a..d281d481cc97 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -62,7 +62,7 @@ SQLite::SQLite(const Path & path, SQLiteOpenMode mode) bool immutable = mode == SQLiteOpenMode::Immutable; int flags = immutable ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; if (mode == SQLiteOpenMode::Normal) flags |= SQLITE_OPEN_CREATE; - auto uri = "file:" + percentEncode(path) + "?immutable=" + (immutable ? "1" : "0"); + auto uri = "file:" + percentEncode(path.native()) + "?immutable=" + (immutable ? "1" : "0"); int ret = sqlite3_open_v2(uri.c_str(), &db, SQLITE_OPEN_URI | flags, vfs); if (ret != SQLITE_OK) { const char * err = sqlite3_errstr(ret); diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh index 003e4d1013dc..a9a0055ecf23 100644 --- a/src/libstore/sqlite.hh +++ b/src/libstore/sqlite.hh @@ -5,6 +5,7 @@ #include #include "error.hh" +#include "file-path.hh" struct sqlite3; struct sqlite3_stmt; diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 04f45827943c..e634841ff354 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -35,7 +35,7 @@ void SSHMaster::addCommonSSHOpts(Strings & args) auto p = host.rfind("@"); std::string thost = p != std::string::npos ? std::string(host, p + 1) : host; writeFile(fileName, thost + " " + base64Decode(sshPublicHostKey) + "\n"); - args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName}); + args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName.native()}); } if (compress) args.push_back("-C"); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index ae8c224374fa..8d2e2c5e61c5 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -224,13 +224,13 @@ public: /** * Follow symlinks until we end up with a path in the Nix store. */ - Path followLinksToStore(std::string_view path) const; + Path followLinksToStore(PathView path) const; /** * Same as followLinksToStore(), but apply toStorePath() to the * result. */ - StorePath followLinksToStorePath(std::string_view path) const; + StorePath followLinksToStorePath(PathView path) const; /** * Check whether a path is valid. diff --git a/src/libstore/store-dir-config.hh b/src/libstore/store-dir-config.hh index 643f8854dd03..d2b63c57bdf5 100644 --- a/src/libstore/store-dir-config.hh +++ b/src/libstore/store-dir-config.hh @@ -67,7 +67,7 @@ struct StoreDirConfig : public Config * @return true if ‘path’ is a store path, i.e. a direct child of the * Nix store. */ - bool isStorePath(std::string_view path) const; + bool isStorePath(PathView path) const; /** * Split a path like /nix/store/-/ into diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc index 649644146bf0..e8da5af38d14 100644 --- a/src/libstore/uds-remote-store.cc +++ b/src/libstore/uds-remote-store.cc @@ -52,7 +52,7 @@ UDSRemoteStore::UDSRemoteStore( std::string UDSRemoteStore::getUri() { if (path) { - return std::string("unix://") + *path; + return std::string { "unix://" } + path->native(); } else { return "daemon"; } diff --git a/src/libstore/uds-remote-store.hh b/src/libstore/uds-remote-store.hh index 8bce8994a3a4..988a6404ad94 100644 --- a/src/libstore/uds-remote-store.hh +++ b/src/libstore/uds-remote-store.hh @@ -60,7 +60,7 @@ private: }; ref openConnection() override; - std::optional path; + std::optional path; }; } diff --git a/src/libstore/unix/local-overlay-store.md b/src/libstore/unix/local-overlay-store.md index 1e1a3d26c7ba..d86b9953b1ab 100644 --- a/src/libstore/unix/local-overlay-store.md +++ b/src/libstore/unix/local-overlay-store.md @@ -4,7 +4,7 @@ R"( This store type is a variation of the [local store] designed to leverage Linux's [Overlay Filesystem](https://docs.kernel.org/filesystems/overlayfs.html) (OverlayFS for short). Just as OverlayFS combines a lower and upper filesystem by treating the upper one as a patch against the lower, the local overlay store combines a lower store with an upper almost-[local store]. -("almost" because while the upper fileystems for OverlayFS is valid on its own, the upper almost-store is not a valid local store on its own because some references will dangle.) +("almost" because while the upper filesystems for OverlayFS is valid on its own, the upper almost-store is not a valid local store on its own because some references will dangle.) To use this store, you will first need to configure an OverlayFS mountpoint [appropriately](#example-filesystem-layout) as Nix will not do this for you (though it will verify the mountpoint is configured correctly). ### Conceptual parts of a local overlay store diff --git a/src/libstore/unix/lock.cc b/src/libstore/unix/lock.cc index 023c74e349bf..bc1881d87a00 100644 --- a/src/libstore/unix/lock.cc +++ b/src/libstore/unix/lock.cc @@ -50,7 +50,7 @@ struct SimpleUserLock : UserLock static std::unique_ptr acquire() { assert(settings.buildUsersGroup != ""); - createDirs(settings.nixStateDir + "/userpool"); + createDirs(settings.nixStateDir / "userpool"); /* Get the members of the build-users-group. */ struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); @@ -139,14 +139,14 @@ struct AutoUserLock : UserLock assert((uint64_t) settings.startId + (uint64_t) settings.uidCount <= std::numeric_limits::max()); assert(nrIds <= maxIdsPerBuild); - createDirs(settings.nixStateDir + "/userpool2"); + createDirs(settings.nixStateDir / "userpool2"); size_t nrSlots = settings.uidCount / maxIdsPerBuild; for (size_t i = 0; i < nrSlots; i++) { debug("trying user slot '%d'", i); - createDirs(settings.nixStateDir + "/userpool2"); + createDirs(settings.nixStateDir / "userpool2"); auto fnUserLock = fmt("%s/userpool2/slot-%d", settings.nixStateDir, i); diff --git a/src/libstore/unix/posix-fs-canonicalise.hh b/src/libstore/unix/posix-fs-canonicalise.hh index 35644af125fb..8162493ae4f5 100644 --- a/src/libstore/unix/posix-fs-canonicalise.hh +++ b/src/libstore/unix/posix-fs-canonicalise.hh @@ -6,6 +6,7 @@ #include "types.hh" #include "error.hh" +#include "file-path.hh" namespace nix { diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index 04f777d00f1e..fc05d52ab1cc 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -30,7 +30,7 @@ static ArchiveSettings archiveSettings; static GlobalConfig::Register rArchiveSettings(&archiveSettings); -PathFilter defaultPathFilter = [](const Path &) { return true; }; +PathFilter defaultPathFilter = [](PathView) { return true; }; void SourceAccessor::dumpPath( @@ -165,14 +165,14 @@ struct CaseInsensitiveCompare }; -static void parse(FileSystemObjectSink & sink, Source & source, const Path & path) +static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath & path) { std::string s; s = readString(source); if (s != "(") throw badArchive("expected open tag"); - std::map names; + std::map names; auto getString = [&]() { checkInterrupt(); @@ -246,7 +246,7 @@ static void parse(FileSystemObjectSink & sink, Source & source, const Path & pat } } else if (s == "node") { if (name.empty()) throw badArchive("entry name missing"); - parse(sink, source, path + "/" + name); + parse(sink, source, path / name); } else throw badArchive("unknown field " + s); } @@ -290,11 +290,11 @@ void parseDump(FileSystemObjectSink & sink, Source & source) } if (version != narVersionMagic1) throw badArchive("input doesn't look like a Nix archive"); - parse(sink, source, ""); + parse(sink, source, CanonPath::root); } -void restorePath(const Path & path, Source & source) +void restorePath(const std::filesystem::path & path, Source & source) { RestoreSink sink; sink.dstPath = path; @@ -315,13 +315,4 @@ void copyNAR(Source & source, Sink & sink) } -void copyPath(const Path & from, const Path & to) -{ - auto source = sinkToSource([&](Sink & sink) { - dumpPath(from, sink); - }); - restorePath(to, *source); -} - - } diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh index 28c63bb85506..57821109686e 100644 --- a/src/libutil/archive.hh +++ b/src/libutil/archive.hh @@ -8,7 +8,6 @@ namespace nix { - /** * dumpPath creates a Nix archive of the specified path. * @@ -75,15 +74,13 @@ void dumpString(std::string_view s, Sink & sink); void parseDump(FileSystemObjectSink & sink, Source & source); -void restorePath(const Path & path, Source & source); +void restorePath(const std::filesystem::path & path, Source & source); /** * Read a NAR from 'source' and write it to 'sink'. */ void copyNAR(Source & source, Sink & sink); -void copyPath(const Path & from, const Path & to); - inline constexpr std::string_view narVersionMagic1 = "nix-archive-1"; diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 7759b74a93cc..658183dcfa5f 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -113,6 +113,11 @@ protected: , arity(1) { } + Handler(std::filesystem::path * dest) + : fun([=](std::vector ss) { *dest = std::filesystem::path { ss[0] }; }) + , arity(1) + { } + template Handler(T * dest, const T & val) : fun([dest, val](std::vector ss) { *dest = val; }) @@ -283,6 +288,18 @@ public: }); } + /** + * Expect a path argument. + */ + void expectArg(const std::string & label, Path * dest, bool optional = false) + { + expectArgs({ + .label = label, + .optional = optional, + .handler = {dest} + }); + } + /** * Expect 0 or more arguments. */ diff --git a/src/libutil/config-impl.hh b/src/libutil/config-impl.hh index 1da0cb6389ed..3ab645694f58 100644 --- a/src/libutil/config-impl.hh +++ b/src/libutil/config-impl.hh @@ -28,6 +28,14 @@ template<> struct BaseSetting::trait { static constexpr bool appendable = true; }; +template<> struct BaseSetting::trait +{ + static constexpr bool appendable = true; +}; +template<> struct BaseSetting::trait +{ + static constexpr bool appendable = true; +}; template<> struct BaseSetting>::trait { static constexpr bool appendable = true; @@ -48,6 +56,8 @@ bool BaseSetting::isAppendable() template<> void BaseSetting::appendOrSet(Strings newValue, bool append); template<> void BaseSetting::appendOrSet(StringSet newValue, bool append); template<> void BaseSetting::appendOrSet(StringMap newValue, bool append); +template<> void BaseSetting::appendOrSet(Paths newValue, bool append); +template<> void BaseSetting::appendOrSet(PathSet newValue, bool append); template<> void BaseSetting>::appendOrSet(std::set newValue, bool append); template @@ -109,6 +119,10 @@ DECLARE_CONFIG_SERIALISER(bool) DECLARE_CONFIG_SERIALISER(Strings) DECLARE_CONFIG_SERIALISER(StringSet) DECLARE_CONFIG_SERIALISER(StringMap) +DECLARE_CONFIG_SERIALISER(Path) +DECLARE_CONFIG_SERIALISER(std::optional) +DECLARE_CONFIG_SERIALISER(Paths) +DECLARE_CONFIG_SERIALISER(PathSet) DECLARE_CONFIG_SERIALISER(std::set) template diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 07322b60d7a0..76b40887adc5 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -8,6 +8,7 @@ #include #include "types.hh" +#include "file-path.hh" #include "experimental-features.hh" namespace nix { @@ -350,7 +351,7 @@ public: Path parse(const std::string & str) const override; - Path operator +(const char * p) const { return value + p; } + Path operator /(PathView p) const { return value / p.native(); } void operator =(const Path & v) { this->assign(v); } }; diff --git a/src/libutil/current-process.hh b/src/libutil/current-process.hh index a5adb70cfd5b..a8423095e4b6 100644 --- a/src/libutil/current-process.hh +++ b/src/libutil/current-process.hh @@ -7,7 +7,7 @@ # include #endif -#include "types.hh" +#include "file-path.hh" namespace nix { diff --git a/src/libutil/file-path-impl.hh b/src/libutil/file-path-impl.hh index 4c90150fdc9f..011bf1089031 100644 --- a/src/libutil/file-path-impl.hh +++ b/src/libutil/file-path-impl.hh @@ -97,7 +97,7 @@ struct WindowsPathTrait */ using NativePathTrait = #ifdef _WIN32 - WindowsPathTrait + WindowsPathTrait #else UnixPathTrait #endif diff --git a/src/libutil/file-path.hh b/src/libutil/file-path.hh index 6fb1001250b2..5c614596467a 100644 --- a/src/libutil/file-path.hh +++ b/src/libutil/file-path.hh @@ -10,43 +10,41 @@ namespace nix { /** * Paths are just `std::filesystem::path`s. - * - * @todo drop `NG` suffix and replace the ones in `types.hh`. */ -typedef std::filesystem::path PathNG; -typedef std::list PathsNG; -typedef std::set PathSetNG; +typedef std::filesystem::path Path; +typedef std::list Paths; +typedef std::set PathSet; /** * Stop gap until `std::filesystem::path_view` from P1030R6 exists in a * future C++ standard. * - * @todo drop `NG` suffix and replace the one in `types.hh`. + * @todo drop `` suffix and replace the one in `types.hh`. */ -struct PathViewNG : std::basic_string_view +struct PathView : std::basic_string_view { - using string_view = std::basic_string_view; + using string_view = std::basic_string_view; using string_view::string_view; - PathViewNG(const PathNG & path) - : std::basic_string_view(path.native()) + PathView(const Path & path) + : std::basic_string_view(path.native()) { } - PathViewNG(const PathNG::string_type & path) - : std::basic_string_view(path) + PathView(const Path::string_type & path) + : std::basic_string_view(path) { } const string_view & native() const { return *this; } string_view & native() { return *this; } }; -std::string os_string_to_string(PathViewNG::string_view path); +std::string os_string_to_string(PathView::string_view path); -PathNG::string_type string_to_os_string(std::string_view s); +Path::string_type string_to_os_string(std::string_view s); -std::optional maybePathNG(PathView path); +std::optional maybePath(PathView path); -PathNG pathNG(PathView path); +Path path(PathView path); } diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 0e68241fce39..7aa5edfeaee0 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -27,22 +27,13 @@ namespace fs = std::filesystem; namespace nix { -/** - * Treat the string as possibly an absolute path, by inspecting the - * start of it. Return whether it was probably intended to be - * absolute. - */ -static bool isAbsolute(PathView path) +fs::path absPath(PathView path, std::optional dir, bool resolveSymlinks) { - return fs::path { path }.is_absolute(); -} - + fs::path scratch; -Path absPath(PathView path, std::optional dir, bool resolveSymlinks) -{ - std::string scratch; + fs::path path2 { fs::path::string_type { path } }; - if (!isAbsolute(path)) { + if (!path2.is_absolute()) { // In this case we need to call `canonPath` on a newly-created // string. We set `scratch` to that string first, and then set // `path` to `scratch`. This ensures the newly-created string @@ -59,13 +50,12 @@ Path absPath(PathView path, std::optional dir, bool resolveSymlinks) if (!getcwd(buf, sizeof(buf))) #endif throw SysError("cannot get cwd"); - scratch = concatStrings(buf, "/", path); + scratch = fs::path{fs::path::string_type{buf}} / path2; #ifdef __GNU__ free(buf); #endif } else - scratch = concatStrings(*dir, "/", path); - path = scratch; + scratch = fs::path{fs::path::string_type{*dir}} / path2; } return canonPath(path, resolveSymlinks); } @@ -75,59 +65,40 @@ Path canonPath(PathView path, bool resolveSymlinks) { assert(path != ""); - if (!isAbsolute(path)) + fs::path path2 { fs::path::string_type { path } }; + + if (resolveSymlinks) + return fs::weakly_canonical(path2); + + // `std::filesystem` does not provide an canonicalisation function + // that doesn't folllow symlinks, so we implement ourselves. + + if (!path2.is_absolute()) throw Error("not an absolute path: '%1%'", path); // For Windows - auto rootName = fs::path { path }.root_name(); - - /* This just exists because we cannot set the target of `remaining` - (the callback parameter) directly to a newly-constructed string, - since it is `std::string_view`. */ - std::string temp; - - /* Count the number of times we follow a symlink and stop at some - arbitrary (but high) limit to prevent infinite loops. */ - unsigned int followCount = 0, maxFollow = 1024; - - auto ret = canonPathInner( - path, - [&followCount, &temp, maxFollow, resolveSymlinks] - (std::string & result, std::string_view & remaining) { - if (resolveSymlinks && isLink(result)) { - if (++followCount >= maxFollow) - throw Error("infinite symlink recursion in path '%0%'", remaining); - remaining = (temp = concatStrings(readLink(result), remaining)); - if (isAbsolute(remaining)) { - /* restart for symlinks pointing to absolute path */ - result.clear(); - } else { - result = dirOf(result); - if (result == "/") { - /* we don’t want trailing slashes here, which `dirOf` - only produces if `result = /` */ - result.clear(); - } - } - } - }); + auto rootName = path2.root_name(); + + fs::path::string_type ret = canonPathInner( + path2.root_directory().native() + path2.relative_path().native(), + [](auto && result, auto && remaining) {}); if (!rootName.empty()) - ret = rootName.string() + std::move(ret); + ret = rootName / std::move(ret); return ret; } Path dirOf(const PathView path) { - Path::size_type pos = NativePathTrait::rfindPathSep(path); + PathView::size_type pos = NativePathTrait::rfindPathSep(path); if (pos == path.npos) return "."; - return fs::path{path}.parent_path().string(); + return fs::path{path}.parent_path(); } -std::string_view baseNameOf(std::string_view path) +PathView baseNameOf(PathView path) { if (path.empty()) return ""; @@ -142,11 +113,11 @@ std::string_view baseNameOf(std::string_view path) else pos += 1; - return path.substr(pos, last - pos + 1); + return PathView { path.substr(pos, last - pos + 1) }; } -bool isInDir(std::string_view path, std::string_view dir) +bool isInDir(PathView path, PathView dir) { return path.substr(0, 1) == "/" && path.substr(0, dir.size()) == dir @@ -155,7 +126,7 @@ bool isInDir(std::string_view path, std::string_view dir) } -bool isDirOrInDir(std::string_view path, std::string_view dir) +bool isDirOrInDir(PathView path, PathView dir) { return path == dir || isInDir(path, dir); } @@ -444,25 +415,23 @@ void deletePath(const Path & path) Paths createDirs(const Path & path) { Paths created; +#ifndef _WIN32 if (path == "/") return created; +#endif - struct stat st; - if (STAT(path.c_str(), &st) == -1) { + auto type = fs::symlink_status(path).type(); + if (type == fs::file_type::not_found) { created = createDirs(dirOf(path)); - if (mkdir(path.c_str() -#ifndef _WIN32 // TODO abstract mkdir perms for Windows - , 0777 -#endif - ) == -1 && errno != EEXIST) - throw SysError("creating directory '%1%'", path); - st = STAT(path); + fs::create_directory(path); + type = fs::symlink_status(path).type(); created.push_back(path); } - if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1) - throw SysError("statting symlink '%1%'", path); + if (type == fs::file_type::symlink) + type = fs::status(path).type(); - if (!S_ISDIR(st.st_mode)) throw Error("'%1%' is not a directory", path); + if (type != fs::file_type::directory) + throw Error("'%1%' is not a directory", path); return created; } @@ -480,7 +449,7 @@ void deletePath(const Path & path, uint64_t & bytesFreed) AutoDelete::AutoDelete() : del{false} {} -AutoDelete::AutoDelete(const std::string & p, bool recursive) : path(p) +AutoDelete::AutoDelete(PathView p, bool recursive) : path(Path { p.native() }) { del = true; this->recursive = recursive; @@ -507,8 +476,8 @@ void AutoDelete::cancel() del = false; } -void AutoDelete::reset(const Path & p, bool recursive) { - path = p; +void AutoDelete::reset(PathView p, bool recursive) { + path = Path { p.native() }; this->recursive = recursive; del = true; } @@ -517,7 +486,7 @@ void AutoDelete::reset(const Path & p, bool recursive) { ////////////////////////////////////////////////////////////////////// -std::string defaultTempDir() { +Path defaultTempDir() { return getEnvNonEmpty("TMPDIR").value_or("/tmp"); } @@ -568,7 +537,7 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix, std::pair createTempFile(const Path & prefix) { - Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX"); + Path tmpl(defaultTempDir() / prefix + ".XXXXXX"); // Strictly speaking, this is UB, but who cares... // FIXME: use O_TMPFILE. AutoCloseFD fd = toDescriptor(mkstemp((char *) tmpl.c_str())); @@ -624,7 +593,7 @@ void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete) { #ifndef _WIN32 // TODO: Rewrite the `is_*` to use `symlink_status()` - auto statOfFrom = lstat(from.path().c_str()); + auto statOfFrom = lstat(from.path()); #endif auto fromStatus = from.symlink_status(); @@ -675,7 +644,7 @@ void moveFile(const Path & oldName, const Path & newName) // For the move to be as atomic as possible, copy to a temporary // directory fs::path temp = createTempDir( - os_string_to_string(PathViewNG { newPath.parent_path() }), + os_string_to_string(PathView { newPath.parent_path() }), "rename-tmp"); Finally removeTemp = [&]() { fs::remove(temp); }; auto tempCopyTarget = temp / "copy-target"; @@ -684,8 +653,8 @@ void moveFile(const Path & oldName, const Path & newName) warn("Can’t rename %s as %s, copying instead", oldName, newName); copy(fs::directory_entry(oldPath), tempCopyTarget, true); renameFile( - os_string_to_string(PathViewNG { tempCopyTarget }), - os_string_to_string(PathViewNG { newPath })); + os_string_to_string(PathView { tempCopyTarget }), + os_string_to_string(PathView { newPath })); } } } diff --git a/src/libutil/file-system.hh b/src/libutil/file-system.hh index 2ecf2881c2fd..9a0971d94c0d 100644 --- a/src/libutil/file-system.hh +++ b/src/libutil/file-system.hh @@ -66,25 +66,25 @@ Path canonPath(PathView path, bool resolveSymlinks = false); * immediate child thereof (e.g., `/foo`), this means `/` * is returned. */ -Path dirOf(const PathView path); +Path dirOf(PathView path); /** * @return the base name of the given canonical path, i.e., everything * following the final `/` (trailing slashes are removed). */ -std::string_view baseNameOf(std::string_view path); +PathView baseNameOf(PathView path); /** * Check whether 'path' is a descendant of 'dir'. Both paths must be * canonicalized. */ -bool isInDir(std::string_view path, std::string_view dir); +bool isInDir(PathView path, PathView dir); /** * Check whether 'path' is equal to 'dir' or a descendant of * 'dir'. Both paths must be canonicalized. */ -bool isDirOrInDir(std::string_view path, std::string_view dir); +bool isDirOrInDir(PathView path, PathView dir); /** * Get status of `path`. @@ -170,7 +170,7 @@ void deletePath(const Path & path, uint64_t & bytesFreed); Paths createDirs(const Path & path); inline Paths createDirs(PathView path) { - return createDirs(Path(path)); + return createDirs(Path{Path::string_type{path}}); } /** @@ -212,10 +212,10 @@ class AutoDelete bool recursive; public: AutoDelete(); - AutoDelete(const Path & p, bool recursive = true); + AutoDelete(PathView p, bool recursive = true); ~AutoDelete(); void cancel(); - void reset(const Path & p, bool recursive = true); + void reset(PathView p, bool recursive = true); operator Path() const { return path; } operator PathView() const { return path; } }; @@ -250,7 +250,7 @@ Path defaultTempDir(); /** * Used in various places. */ -typedef std::function PathFilter; +typedef std::function PathFilter; extern PathFilter defaultPathFilter; diff --git a/src/libutil/fs-sink.cc b/src/libutil/fs-sink.cc index 91070ea89a9a..a7e7d4c28c26 100644 --- a/src/libutil/fs-sink.cc +++ b/src/libutil/fs-sink.cc @@ -14,7 +14,7 @@ namespace nix { void copyRecursive( SourceAccessor & accessor, const CanonPath & from, - FileSystemObjectSink & sink, const Path & to) + FileSystemObjectSink & sink, const CanonPath & to) { auto stat = accessor.lstat(from); @@ -43,7 +43,7 @@ void copyRecursive( for (auto & [name, _] : accessor.readDirectory(from)) { copyRecursive( accessor, from / name, - sink, to + "/" + name); + sink, to / name); break; } break; @@ -69,17 +69,9 @@ static RestoreSinkSettings restoreSinkSettings; static GlobalConfig::Register r1(&restoreSinkSettings); -void RestoreSink::createDirectory(const Path & path) +void RestoreSink::createDirectory(const CanonPath & path) { - Path p = dstPath + path; - if ( -#ifndef _WIN32 // TODO abstract mkdir perms for Windows - mkdir(p.c_str(), 0777) == -1 -#else - !CreateDirectoryW(pathNG(p).c_str(), NULL) -#endif - ) - throw NativeSysError("creating directory '%1%'", p); + std::filesystem::create_directory(dstPath / path.rel()); }; struct RestoreRegularFile : CreateRegularFileSink { @@ -90,13 +82,13 @@ struct RestoreRegularFile : CreateRegularFileSink { void preallocateContents(uint64_t size) override; }; -void RestoreSink::createRegularFile(const Path & path, std::function func) +void RestoreSink::createRegularFile(const CanonPath & path, std::function func) { - Path p = dstPath + path; + std::filesystem::path p = dstPath / path.rel(); RestoreRegularFile crf; crf.fd = #ifdef _WIN32 - CreateFileW(pathNG(path).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) + CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) #else open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666) #endif @@ -141,14 +133,14 @@ void RestoreRegularFile::operator () (std::string_view data) writeFull(fd.get(), data); } -void RestoreSink::createSymlink(const Path & path, const std::string & target) +void RestoreSink::createSymlink(const CanonPath & path, const std::string & target) { - Path p = dstPath + path; + std::filesystem::path p = dstPath / path.rel(); nix::createSymlink(target, p); } -void RegularFileSink::createRegularFile(const Path & path, std::function func) +void RegularFileSink::createRegularFile(const CanonPath & path, std::function func) { struct CRF : CreateRegularFileSink { RegularFileSink & back; @@ -163,7 +155,7 @@ void RegularFileSink::createRegularFile(const Path & path, std::function func) +void NullFileSystemObjectSink::createRegularFile(const CanonPath & path, std::function func) { struct : CreateRegularFileSink { void operator () (std::string_view data) override {} diff --git a/src/libutil/fs-sink.hh b/src/libutil/fs-sink.hh index ae577819a256..cf7d34d22733 100644 --- a/src/libutil/fs-sink.hh +++ b/src/libutil/fs-sink.hh @@ -28,17 +28,17 @@ struct FileSystemObjectSink { virtual ~FileSystemObjectSink() = default; - virtual void createDirectory(const Path & path) = 0; + virtual void createDirectory(const CanonPath & path) = 0; /** * This function in general is no re-entrant. Only one file can be * written at a time. */ virtual void createRegularFile( - const Path & path, + const CanonPath & path, std::function) = 0; - virtual void createSymlink(const Path & path, const std::string & target) = 0; + virtual void createSymlink(const CanonPath & path, const std::string & target) = 0; }; /** @@ -46,17 +46,17 @@ struct FileSystemObjectSink */ void copyRecursive( SourceAccessor & accessor, const CanonPath & sourcePath, - FileSystemObjectSink & sink, const Path & destPath); + FileSystemObjectSink & sink, const CanonPath & destPath); /** * Ignore everything and do nothing */ struct NullFileSystemObjectSink : FileSystemObjectSink { - void createDirectory(const Path & path) override { } - void createSymlink(const Path & path, const std::string & target) override { } + void createDirectory(const CanonPath & path) override { } + void createSymlink(const CanonPath & path, const std::string & target) override { } void createRegularFile( - const Path & path, + const CanonPath & path, std::function) override; }; @@ -65,15 +65,15 @@ struct NullFileSystemObjectSink : FileSystemObjectSink */ struct RestoreSink : FileSystemObjectSink { - Path dstPath; + std::filesystem::path dstPath; - void createDirectory(const Path & path) override; + void createDirectory(const CanonPath & path) override; void createRegularFile( - const Path & path, + const CanonPath & path, std::function) override; - void createSymlink(const Path & path, const std::string & target) override; + void createSymlink(const CanonPath & path, const std::string & target) override; }; /** @@ -88,18 +88,18 @@ struct RegularFileSink : FileSystemObjectSink RegularFileSink(Sink & sink) : sink(sink) { } - void createDirectory(const Path & path) override + void createDirectory(const CanonPath & path) override { regular = false; } - void createSymlink(const Path & path, const std::string & target) override + void createSymlink(const CanonPath & path, const std::string & target) override { regular = false; } void createRegularFile( - const Path & path, + const CanonPath & path, std::function) override; }; diff --git a/src/libutil/git.cc b/src/libutil/git.cc index 8c538c98820c..461a8ab5515d 100644 --- a/src/libutil/git.cc +++ b/src/libutil/git.cc @@ -53,7 +53,7 @@ static std::string getString(Source & source, int n) void parseBlob( FileSystemObjectSink & sink, - const Path & sinkPath, + const CanonPath & sinkPath, Source & source, BlobMode blobMode, const ExperimentalFeatureSettings & xpSettings) @@ -116,7 +116,7 @@ void parseBlob( void parseTree( FileSystemObjectSink & sink, - const Path & sinkPath, + const CanonPath & sinkPath, Source & source, std::function hook, const ExperimentalFeatureSettings & xpSettings) @@ -171,7 +171,7 @@ ObjectType parseObjectType( void parse( FileSystemObjectSink & sink, - const Path & sinkPath, + const CanonPath & sinkPath, Source & source, BlobMode rootModeIfBlob, std::function hook, @@ -208,7 +208,7 @@ std::optional convertMode(SourceAccessor::Type type) void restore(FileSystemObjectSink & sink, Source & source, std::function hook) { - parse(sink, "", source, BlobMode::Regular, [&](Path name, TreeEntry entry) { + parse(sink, CanonPath::root, source, BlobMode::Regular, [&](const std::string & name, TreeEntry entry) { auto [accessor, from] = hook(entry.hash); auto stat = accessor->lstat(from); auto gotOpt = convertMode(stat.type); @@ -225,7 +225,7 @@ void restore(FileSystemObjectSink & sink, Source & source, std::function; * Implementations may seek to memoize resources (bandwidth, storage, * etc.) for the same Git hash. */ -using SinkHook = void(const Path & name, TreeEntry entry); +using SinkHook = void(const std::string & name, TreeEntry entry); /** * Parse the "blob " or "tree " prefix. @@ -89,13 +89,13 @@ enum struct BlobMode : RawMode }; void parseBlob( - FileSystemObjectSink & sink, const Path & sinkPath, + FileSystemObjectSink & sink, const CanonPath & sinkPath, Source & source, BlobMode blobMode, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); void parseTree( - FileSystemObjectSink & sink, const Path & sinkPath, + FileSystemObjectSink & sink, const CanonPath & sinkPath, Source & source, std::function hook, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); @@ -108,7 +108,7 @@ void parseTree( * a blob, this is ignored. */ void parse( - FileSystemObjectSink & sink, const Path & sinkPath, + FileSystemObjectSink & sink, const CanonPath & sinkPath, Source & source, BlobMode rootModeIfBlob, std::function hook, diff --git a/src/libutil/json-utils.hh b/src/libutil/json-utils.hh index 08c98cc8c0d4..302db5ce4036 100644 --- a/src/libutil/json-utils.hh +++ b/src/libutil/json-utils.hh @@ -7,6 +7,8 @@ #include "types.hh" +#include "file-path.hh" + namespace nix { const nlohmann::json * get(const nlohmann::json & map, const std::string & key); @@ -62,6 +64,9 @@ struct json_avoids_null : std::true_type {}; template<> struct json_avoids_null : std::true_type {}; +template<> +struct json_avoids_null : std::true_type {}; + template struct json_avoids_null> : std::true_type {}; diff --git a/src/libutil/linux/cgroup.hh b/src/libutil/linux/cgroup.hh index 783a0ab87422..4124b098188f 100644 --- a/src/libutil/linux/cgroup.hh +++ b/src/libutil/linux/cgroup.hh @@ -4,7 +4,7 @@ #include #include -#include "types.hh" +#include "file-path.hh" namespace nix { diff --git a/src/libutil/memory-source-accessor.cc b/src/libutil/memory-source-accessor.cc index b7207cffb9bb..98445705a6e5 100644 --- a/src/libutil/memory-source-accessor.cc +++ b/src/libutil/memory-source-accessor.cc @@ -124,7 +124,7 @@ SourcePath MemorySourceAccessor::addFile(CanonPath path, std::string && contents using File = MemorySourceAccessor::File; -void MemorySink::createDirectory(const Path & path) +void MemorySink::createDirectory(const CanonPath & path) { auto * f = dst.open(CanonPath{path}, File { File::Directory { } }); if (!f) @@ -146,7 +146,7 @@ struct CreateMemoryRegularFile : CreateRegularFileSink { void preallocateContents(uint64_t size) override; }; -void MemorySink::createRegularFile(const Path & path, std::function func) +void MemorySink::createRegularFile(const CanonPath & path, std::function func) { auto * f = dst.open(CanonPath{path}, File { File::Regular {} }); if (!f) @@ -173,7 +173,7 @@ void CreateMemoryRegularFile::operator () (std::string_view data) regularFile.contents += data; } -void MemorySink::createSymlink(const Path & path, const std::string & target) +void MemorySink::createSymlink(const CanonPath & path, const std::string & target) { auto * f = dst.open(CanonPath{path}, File { File::Symlink { } }); if (!f) diff --git a/src/libutil/memory-source-accessor.hh b/src/libutil/memory-source-accessor.hh index c8f793922d68..cd5146c89139 100644 --- a/src/libutil/memory-source-accessor.hh +++ b/src/libutil/memory-source-accessor.hh @@ -81,13 +81,13 @@ struct MemorySink : FileSystemObjectSink MemorySink(MemorySourceAccessor & dst) : dst(dst) { } - void createDirectory(const Path & path) override; + void createDirectory(const CanonPath & path) override; void createRegularFile( - const Path & path, + const CanonPath & path, std::function) override; - void createSymlink(const Path & path, const std::string & target) override; + void createSymlink(const CanonPath & path, const std::string & target) override; }; } diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index 6bb2bd2f32b9..43e13eee7de9 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -173,9 +173,12 @@ time_t unpackTarfileToSink(TarArchive & archive, FileSystemObjectSink & parseSin int r = archive_read_next_header(archive.archive, &entry); if (r == ARCHIVE_EOF) break; - auto path = archive_entry_pathname(entry); - if (!path) + + auto * path_raw = archive_entry_pathname(entry); + if (!path_raw) throw Error("cannot get archive member name: %s", archive_error_string(archive.archive)); + CanonPath path { std::string_view { path_raw } }; + if (r == ARCHIVE_WARN) warn(archive_error_string(archive.archive)); else diff --git a/src/libutil/types.hh b/src/libutil/types.hh index c86f52175d52..c6f821024125 100644 --- a/src/libutil/types.hh +++ b/src/libutil/types.hh @@ -18,14 +18,6 @@ typedef std::set StringSet; typedef std::map StringMap; typedef std::map StringPairs; -/** - * Paths are just strings. - */ -typedef std::string Path; -typedef std::string_view PathView; -typedef std::list Paths; -typedef std::set PathSet; - typedef std::vector> Headers; /** diff --git a/src/libutil/unix/file-path.cc b/src/libutil/unix/file-path.cc index 54a1cc278d43..3df327160420 100644 --- a/src/libutil/unix/file-path.cc +++ b/src/libutil/unix/file-path.cc @@ -8,24 +8,24 @@ namespace nix { -std::string os_string_to_string(PathViewNG::string_view path) +std::string os_string_to_string(PathView::string_view path) { return std::string { path }; } -PathNG::string_type string_to_os_string(std::string_view s) +Path::string_type string_to_os_string(std::string_view s) { return std::string { s }; } -std::optional maybePathNG(PathView path) +std::optional maybePath(PathView path) { - return { path }; + return Path { Path::string_type { path } }; } -PathNG pathNG(PathView path) +Path path(PathView path) { - return path; + return Path::string_type { path }; } } diff --git a/src/libutil/users.cc b/src/libutil/users.cc index d546e364f508..c6b93eb88c09 100644 --- a/src/libutil/users.cc +++ b/src/libutil/users.cc @@ -22,7 +22,7 @@ std::vector getConfigDirs() { Path configHome = getConfigDir(); auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg"); - std::vector result = tokenizeString>(configDirs, ":"); + std::vector result = tokenizeString>(configDirs, ":"); result.insert(result.begin(), configHome); return result; } diff --git a/src/libutil/users.hh b/src/libutil/users.hh index 153cc73fdae4..f778167dce24 100644 --- a/src/libutil/users.hh +++ b/src/libutil/users.hh @@ -1,7 +1,7 @@ #pragma once ///@file -#include "types.hh" +#include "file-path.hh" #ifndef _WIN32 # include diff --git a/src/libutil/windows/file-path.cc b/src/libutil/windows/file-path.cc index d2f385f50d0c..14e6fac93751 100644 --- a/src/libutil/windows/file-path.cc +++ b/src/libutil/windows/file-path.cc @@ -9,38 +9,38 @@ namespace nix { -std::string os_string_to_string(PathViewNG::string_view path) +std::string os_string_to_string(PathView::string_view path) { std::wstring_convert> converter; - return converter.to_bytes(PathNG::string_type { path }); + return converter.to_bytes(Path::string_type { path }); } -PathNG::string_type string_to_os_string(std::string_view s) +Path::string_type string_to_os_string(std::string_view s) { std::wstring_convert> converter; return converter.from_bytes(std::string { s }); } -std::optional maybePathNG(PathView path) +std::optional maybePath(PathView path) { if (path.length() >= 3 && (('A' <= path[0] && path[0] <= 'Z') || ('a' <= path[0] && path[0] <= 'z')) && path[1] == ':' && WindowsPathTrait::isPathSep(path[2])) { - PathNG::string_type sw = string_to_os_string( + Path::string_type sw = string_to_os_string( std::string { "\\\\?\\" } + path); std::replace(sw.begin(), sw.end(), '/', '\\'); return sw; } if (path.length() >= 7 && path[0] == '\\' && path[1] == '\\' && (path[2] == '.' || path[2] == '?') && path[3] == '\\' && ('A' <= path[4] && path[4] <= 'Z') && path[5] == ':' && WindowsPathTrait::isPathSep(path[6])) { - PathNG::string_type sw = string_to_os_string(path); + Path::string_type sw = string_to_os_string(path); std::replace(sw.begin(), sw.end(), '/', '\\'); return sw; } - return std::optional(); + return std::optional(); } -PathNG pathNG(PathView path) +Path path(PathView path) { - std::optional sw = maybePathNG(path); + std::optional sw = maybePath(path); if (!sw) { // FIXME why are we not using the regular error handling? std::cerr << "invalid path for WinAPI call ["<isStorePath(path) && hasSuffix(path, ".drv")) + if (evalStore->isStorePath(PathView { path }) + && hasSuffix(path, ".drv")) drvs.push_back(PackageInfo(*state, evalStore, absolute)); else /* If we're in a #! script, interpret filenames @@ -317,7 +318,7 @@ static void main_nix_build(int argc, char * * argv) state->parseExprFromFile( resolveExprPath( lookupFileArg(*state, - inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))); + inShebang && !packages ? absPath(i, absPath(dirOf(script))) : Path { i })))); } } diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc index 9f7f557b59db..d2561a6f8f8d 100644 --- a/src/nix-channel/nix-channel.cc +++ b/src/nix-channel/nix-channel.cc @@ -107,7 +107,7 @@ static void update(const StringSet & channelNames) // no need to update this channel, reuse the existing store path Path symlink = profile + "/" + name; Path storepath = dirOf(readLink(symlink)); - exprs.push_back("f: rec { name = \"" + cname + "\"; type = \"derivation\"; outputs = [\"out\"]; system = \"builtin\"; outPath = builtins.storePath \"" + storepath + "\"; out = { inherit outPath; };}"); + exprs.push_back("f: rec { name = \"" + cname + "\"; type = \"derivation\"; outputs = [\"out\"]; system = \"builtin\"; outPath = builtins.storePath \"" + storepath.native() + "\"; out = { inherit outPath; };}"); } else { // We want to download the url to a file to see if it's a tarball while also checking if we // got redirected in the process, so that we can grab the various parts of a nix channel @@ -118,7 +118,7 @@ static void update(const StringSet & channelNames) bool unpacked = false; if (std::regex_search(filename, std::regex("\\.tar\\.(gz|bz2|xz)$"))) { - runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath + + runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath.string() + "{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" }); unpacked = true; } @@ -139,7 +139,7 @@ static void update(const StringSet & channelNames) // Unpack the channel tarballs into the Nix store and install them // into the channels profile. std::cerr << "unpacking " << exprs.size() << " channels...\n"; - Strings envArgs{ "--profile", profile, "--file", unpackChannelPath, "--install", "--remove-all", "--from-expression" }; + Strings envArgs{ "--profile", profile, "--file", unpackChannelPath.string(), "--install", "--remove-all", "--from-expression" }; for (auto & expr : exprs) envArgs.push_back(std::move(expr)); envArgs.push_back("--quiet"); diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 494735516f8b..ebbcceecbc6b 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -98,7 +98,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption try { if (name == "." || name == "..") throw Error("invalid file name '%s'", name); - recurse(*attr.value, attr.pos, concatStrings(path, "/", name)); + recurse(*attr.value, attr.pos, path / name); } catch (Error & e) { e.addTrace( state->positions[attr.pos], diff --git a/tests/unit/libstore-support/tests/nix_api_store.hh b/tests/unit/libstore-support/tests/nix_api_store.hh index a2d35d083d48..801d3dbd76b8 100644 --- a/tests/unit/libstore-support/tests/nix_api_store.hh +++ b/tests/unit/libstore-support/tests/nix_api_store.hh @@ -41,13 +41,14 @@ protected: { #ifdef _WIN32 // no `mkdtemp` with MinGW - auto tmpl = nix::defaultTempDir() + "/tests_nix-store."; + auto tmpl = nix::defaultTempDir() / "tests_nix-store."; for (size_t i = 0; true; ++i) { - nixDir = tmpl + std::string { i }; + auto nixDir = tmpl; + nixDir += std::string { i }; if (fs::create_directory(nixDir)) break; } #else - auto tmpl = nix::defaultTempDir() + "/tests_nix-store.XXXXXX"; + auto tmpl = nix::defaultTempDir() / "tests_nix-store.XXXXXX"; nixDir = mkdtemp((char *) tmpl.c_str()); #endif diff --git a/tests/unit/libstore/machines.cc b/tests/unit/libstore/machines.cc index 9fd7fda54cc3..d984b5fa6761 100644 --- a/tests/unit/libstore/machines.cc +++ b/tests/unit/libstore/machines.cc @@ -143,7 +143,7 @@ TEST(machines, getMachinesWithCorrectFileReference) { auto path = absPath("tests/unit/libstore/test-data/machines.valid"); ASSERT_TRUE(pathExists(path)); - settings.builders = std::string("@") + path; + settings.builders = std::string("@") + path.native(); Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(3)); EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")))); diff --git a/tests/unit/libutil-support/tests/characterization.hh b/tests/unit/libutil-support/tests/characterization.hh index 9d6c850f017c..ba84cda72029 100644 --- a/tests/unit/libutil-support/tests/characterization.hh +++ b/tests/unit/libutil-support/tests/characterization.hh @@ -35,7 +35,7 @@ protected: * While the "golden master" for this characterization test is * located. It should not be shared with any other test. */ - virtual Path goldenMaster(PathView testStem) const = 0; + virtual Path goldenMaster(std::string_view testStem) const = 0; public: /** @@ -44,7 +44,7 @@ public: * @param test hook that takes the contents of the file and does the * actual work */ - void readTest(PathView testStem, auto && test) + void readTest(std::string_view testStem, auto && test) { auto file = goldenMaster(testStem); @@ -68,7 +68,7 @@ public: * actual work */ void writeTest( - PathView testStem, auto && test, auto && readFile2, auto && writeFile2) + std::string_view testStem, auto && test, auto && readFile2, auto && writeFile2) { auto file = goldenMaster(testStem); @@ -92,7 +92,7 @@ public: /** * Specialize to `std::string` */ - void writeTest(PathView testStem, auto && test) + void writeTest(std::string_view testStem, auto && test) { writeTest( testStem, test,