1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-27 12:41:00 +01:00

Convert profiles to use std::filesystem::path

Co-authored-by: Vinayak Goyal <vinayakankugoyal@gmail.com>
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
This commit is contained in:
John Ericson 2024-08-26 17:37:52 -04:00
parent c7b61f3d13
commit 504c5e7cf9
20 changed files with 154 additions and 103 deletions

View file

@ -297,7 +297,7 @@ void MixProfile::updateProfile(const BuiltPaths & buildables)
MixDefaultProfile::MixDefaultProfile() MixDefaultProfile::MixDefaultProfile()
{ {
profile = getDefaultProfile(); profile = getDefaultProfile().string();
} }
MixEnvironment::MixEnvironment() MixEnvironment::MixEnvironment()
@ -391,7 +391,7 @@ void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & bu
auto symlink = outLink; auto symlink = outLink;
if (i) if (i)
symlink += fmt("-%d", i); symlink += fmt("-%d", i);
store.addPermRoot(bo.path, absPath(symlink.string())); store.addPermRoot(bo.path, absPath(symlink).string());
}, },
[&](const BuiltPath::Built & bfd) { [&](const BuiltPath::Built & bfd) {
for (auto & output : bfd.outputs) { for (auto & output : bfd.outputs) {
@ -400,7 +400,7 @@ void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & bu
symlink += fmt("-%d", i); symlink += fmt("-%d", i);
if (output.first != "out") if (output.first != "out")
symlink += fmt("-%s", output.first); symlink += fmt("-%s", output.first);
store.addPermRoot(output.second, absPath(symlink.string())); store.addPermRoot(output.second, absPath(symlink).string());
} }
}, },
}, },

View file

@ -60,18 +60,18 @@ EvalSettings::EvalSettings(bool & readOnlyMode, EvalSettings::LookupPathHooks lo
Strings EvalSettings::getDefaultNixPath() Strings EvalSettings::getDefaultNixPath()
{ {
Strings res; Strings res;
auto add = [&](const Path & p, const std::string & s = std::string()) { auto add = [&](const std::filesystem::path & p, const std::string & s = std::string()) {
if (std::filesystem::exists(p)) { if (std::filesystem::exists(p)) {
if (s.empty()) { if (s.empty()) {
res.push_back(p); res.push_back(p.string());
} else { } else {
res.push_back(s + "=" + p); res.push_back(s + "=" + p.string());
} }
} }
}; };
add(getNixDefExpr() + "/channels"); add(std::filesystem::path{getNixDefExpr()} / "channels");
add(rootChannelsDir() + "/nixpkgs", "nixpkgs"); add(rootChannelsDir() / "nixpkgs", "nixpkgs");
add(rootChannelsDir()); add(rootChannelsDir());
return res; return res;
@ -108,4 +108,4 @@ Path getNixDefExpr()
return settings.useXDGBaseDirectories ? getStateDir() + "/defexpr" : getHome() + "/.nix-defexpr"; return settings.useXDGBaseDirectories ? getStateDir() + "/defexpr" : getHome() + "/.nix-defexpr";
} }
} // namespace nix } // namespace nix

View file

@ -50,7 +50,8 @@ protected:
#else #else
// resolve any symlinks in i.e. on macOS /tmp -> /private/tmp // resolve any symlinks in i.e. on macOS /tmp -> /private/tmp
// because this is not allowed for a nix store. // because this is not allowed for a nix store.
auto tmpl = nix::absPath(std::filesystem::path(nix::defaultTempDir()) / "tests_nix-store.XXXXXX", true); auto tmpl =
nix::absPath(std::filesystem::path(nix::defaultTempDir()) / "tests_nix-store.XXXXXX", std::nullopt, true);
nixDir = mkdtemp((char *) tmpl.c_str()); nixDir = mkdtemp((char *) tmpl.c_str());
#endif #endif

View file

@ -307,7 +307,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
crashes. If we can't acquire the lock, then continue; hopefully some crashes. If we can't acquire the lock, then continue; hopefully some
other goal can start a build, and if not, the main loop will sleep a few other goal can start a build, and if not, the main loop will sleep a few
seconds and then retry this goal. */ seconds and then retry this goal. */
PathSet lockFiles; std::set<std::filesystem::path> lockFiles;
/* FIXME: Should lock something like the drv itself so we don't build same /* FIXME: Should lock something like the drv itself so we don't build same
CA drv concurrently */ CA drv concurrently */
if (auto * localStore = dynamic_cast<LocalStore *>(&worker.store)) { if (auto * localStore = dynamic_cast<LocalStore *>(&worker.store)) {

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
///@file ///@file
#include <filesystem>
#include "nix/util/file-descriptor.hh" #include "nix/util/file-descriptor.hh"
namespace nix { namespace nix {
@ -10,12 +12,12 @@ namespace nix {
* -1 is returned if create is false and the lock could not be opened * -1 is returned if create is false and the lock could not be opened
* because it doesn't exist. Any other error throws an exception. * because it doesn't exist. Any other error throws an exception.
*/ */
AutoCloseFD openLockFile(const Path & path, bool create); AutoCloseFD openLockFile(const std::filesystem::path & path, bool create);
/** /**
* Delete an open lock file. * Delete an open lock file.
*/ */
void deleteLockFile(const Path & path, Descriptor desc); void deleteLockFile(const std::filesystem::path & path, Descriptor desc);
enum LockType { ltRead, ltWrite, ltNone }; enum LockType { ltRead, ltWrite, ltNone };
@ -24,14 +26,14 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait);
class PathLocks class PathLocks
{ {
private: private:
typedef std::pair<Descriptor, Path> FDPair; typedef std::pair<Descriptor, std::filesystem::path> FDPair;
std::list<FDPair> fds; std::list<FDPair> fds;
bool deletePaths; bool deletePaths;
public: public:
PathLocks(); PathLocks();
PathLocks(const PathSet & paths, const std::string & waitMsg = ""); PathLocks(const std::set<std::filesystem::path> & paths, const std::string & waitMsg = "");
bool lockPaths(const PathSet & _paths, const std::string & waitMsg = "", bool wait = true); bool lockPaths(const std::set<std::filesystem::path> & _paths, const std::string & waitMsg = "", bool wait = true);
~PathLocks(); ~PathLocks();
void unlock(); void unlock();
void setDeletion(bool deletePaths); void setDeletion(bool deletePaths);

View file

@ -7,12 +7,13 @@
* See the manual for additional information. * See the manual for additional information.
*/ */
#include "nix/util/types.hh" #include <filesystem>
#include "nix/store/pathlocks.hh"
#include <optional> #include <optional>
#include <time.h> #include <time.h>
#include "nix/util/types.hh"
#include "nix/store/pathlocks.hh"
namespace nix { namespace nix {
class StorePath; class StorePath;
@ -47,9 +48,9 @@ struct Generation
* distinct contents to avoid bloat, but nothing stops two * distinct contents to avoid bloat, but nothing stops two
* non-adjacent generations from having the same contents. * non-adjacent generations from having the same contents.
* *
* @todo Use `StorePath` instead of `Path`? * @todo Use `StorePath` instead of `std::filesystem::path`?
*/ */
Path path; std::filesystem::path path;
/** /**
* When the generation was created. This is extra metadata about the * When the generation was created. This is extra metadata about the
@ -81,7 +82,7 @@ typedef std::list<Generation> Generations;
* *
* Note that the current/active generation need not be the latest one. * Note that the current/active generation need not be the latest one.
*/ */
std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path profile); std::pair<Generations, std::optional<GenerationNumber>> findGenerations(std::filesystem::path profile);
struct LocalFSStore; struct LocalFSStore;
@ -96,7 +97,7 @@ struct LocalFSStore;
* The behavior of reusing existing generations like this makes this * The behavior of reusing existing generations like this makes this
* procedure idempotent. It also avoids clutter. * procedure idempotent. It also avoids clutter.
*/ */
Path createGeneration(LocalFSStore & store, Path profile, StorePath outPath); std::filesystem::path createGeneration(LocalFSStore & store, std::filesystem::path profile, StorePath outPath);
/** /**
* Unconditionally delete a generation * Unconditionally delete a generation
@ -111,7 +112,7 @@ Path createGeneration(LocalFSStore & store, Path profile, StorePath outPath);
* *
* @todo Should we expose this at all? * @todo Should we expose this at all?
*/ */
void deleteGeneration(const Path & profile, GenerationNumber gen); void deleteGeneration(const std::filesystem::path & profile, GenerationNumber gen);
/** /**
* Delete the given set of generations. * Delete the given set of generations.
@ -128,7 +129,8 @@ void deleteGeneration(const Path & profile, GenerationNumber gen);
* Trying to delete the currently active generation will fail, and cause * Trying to delete the currently active generation will fail, and cause
* no generations to be deleted. * no generations to be deleted.
*/ */
void deleteGenerations(const Path & profile, const std::set<GenerationNumber> & gensToDelete, bool dryRun); void deleteGenerations(
const std::filesystem::path & profile, const std::set<GenerationNumber> & gensToDelete, bool dryRun);
/** /**
* Delete generations older than `max` passed the current generation. * Delete generations older than `max` passed the current generation.
@ -142,7 +144,7 @@ void deleteGenerations(const Path & profile, const std::set<GenerationNumber> &
* @param dryRun Log what would be deleted instead of actually doing * @param dryRun Log what would be deleted instead of actually doing
* so. * so.
*/ */
void deleteGenerationsGreaterThan(const Path & profile, GenerationNumber max, bool dryRun); void deleteGenerationsGreaterThan(const std::filesystem::path & profile, GenerationNumber max, bool dryRun);
/** /**
* Delete all generations other than the current one * Delete all generations other than the current one
@ -153,7 +155,7 @@ void deleteGenerationsGreaterThan(const Path & profile, GenerationNumber max, bo
* @param dryRun Log what would be deleted instead of actually doing * @param dryRun Log what would be deleted instead of actually doing
* so. * so.
*/ */
void deleteOldGenerations(const Path & profile, bool dryRun); void deleteOldGenerations(const std::filesystem::path & profile, bool dryRun);
/** /**
* Delete generations older than `t`, except for the most recent one * Delete generations older than `t`, except for the most recent one
@ -165,7 +167,7 @@ void deleteOldGenerations(const Path & profile, bool dryRun);
* @param dryRun Log what would be deleted instead of actually doing * @param dryRun Log what would be deleted instead of actually doing
* so. * so.
*/ */
void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun); void deleteGenerationsOlderThan(const std::filesystem::path & profile, time_t t, bool dryRun);
/** /**
* Parse a temp spec intended for `deleteGenerationsOlderThan()`. * Parse a temp spec intended for `deleteGenerationsOlderThan()`.
@ -180,19 +182,19 @@ time_t parseOlderThanTimeSpec(std::string_view timeSpec);
* *
* @todo Always use `switchGeneration()` instead, and delete this. * @todo Always use `switchGeneration()` instead, and delete this.
*/ */
void switchLink(Path link, Path target); void switchLink(std::filesystem::path link, std::filesystem::path target);
/** /**
* Roll back a profile to the specified generation, or to the most * Roll back a profile to the specified generation, or to the most
* recent one older than the current. * recent one older than the current.
*/ */
void switchGeneration(const Path & profile, std::optional<GenerationNumber> dstGen, bool dryRun); void switchGeneration(const std::filesystem::path & profile, std::optional<GenerationNumber> dstGen, bool dryRun);
/** /**
* Ensure exclusive access to a profile. Any command that modifies * Ensure exclusive access to a profile. Any command that modifies
* the profile first acquires this lock. * the profile first acquires this lock.
*/ */
void lockProfile(PathLocks & lock, const Path & profile); void lockProfile(PathLocks & lock, const std::filesystem::path & profile);
/** /**
* Optimistic locking is used by long-running operations like `nix-env * Optimistic locking is used by long-running operations like `nix-env
@ -205,34 +207,34 @@ void lockProfile(PathLocks & lock, const Path & profile);
* store. Most of the time, only the user environment has to be * store. Most of the time, only the user environment has to be
* rebuilt. * rebuilt.
*/ */
std::string optimisticLockProfile(const Path & profile); std::string optimisticLockProfile(const std::filesystem::path & profile);
/** /**
* Create and return the path to a directory suitable for storing the users * Create and return the path to a directory suitable for storing the users
* profiles. * profiles.
*/ */
Path profilesDir(); std::filesystem::path profilesDir();
/** /**
* Return the path to the profile directory for root (but don't try creating it) * Return the path to the profile directory for root (but don't try creating it)
*/ */
Path rootProfilesDir(); std::filesystem::path rootProfilesDir();
/** /**
* Create and return the path to the file used for storing the users's channels * Create and return the path to the file used for storing the users's channels
*/ */
Path defaultChannelsDir(); std::filesystem::path defaultChannelsDir();
/** /**
* Return the path to the channel directory for root (but don't try creating it) * Return the path to the channel directory for root (but don't try creating it)
*/ */
Path rootChannelsDir(); std::filesystem::path rootChannelsDir();
/** /**
* Resolve the default profile (~/.nix-profile by default, * Resolve the default profile (~/.nix-profile by default,
* $XDG_STATE_HOME/nix/profile if XDG Base Directory Support is enabled), * $XDG_STATE_HOME/nix/profile if XDG Base Directory Support is enabled),
* and create if doesn't exist * and create if doesn't exist
*/ */
Path getDefaultProfile(); std::filesystem::path getDefaultProfile();
} // namespace nix } // namespace nix

View file

@ -996,6 +996,12 @@ OutputPathMap resolveDerivedPath(Store &, const DerivedPath::Built &, Store * ev
*/ */
std::string showPaths(const PathSet & paths); std::string showPaths(const PathSet & paths);
/**
* Display a set of paths in human-readable form (i.e., between quotes
* and separated by commas).
*/
std::string showPaths(const std::set<std::filesystem::path> paths);
std::optional<ValidPathInfo> std::optional<ValidPathInfo>
decodeValidPathInfo(const Store & store, std::istream & str, std::optional<HashResult> hashGiven = std::nullopt); decodeValidPathInfo(const Store & store, std::istream & str, std::optional<HashResult> hashGiven = std::nullopt);

View file

@ -13,7 +13,7 @@ PathLocks::PathLocks()
{ {
} }
PathLocks::PathLocks(const PathSet & paths, const std::string & waitMsg) PathLocks::PathLocks(const std::set<std::filesystem::path> & paths, const std::string & waitMsg)
: deletePaths(false) : deletePaths(false)
{ {
lockPaths(paths, waitMsg); lockPaths(paths, waitMsg);

View file

@ -31,12 +31,12 @@ static std::optional<GenerationNumber> parseName(const std::string & profileName
return {}; return {};
} }
std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path profile) std::pair<Generations, std::optional<GenerationNumber>> findGenerations(std::filesystem::path profile)
{ {
Generations gens; Generations gens;
std::filesystem::path profileDir = dirOf(profile); std::filesystem::path profileDir = profile.parent_path();
auto profileName = std::string(baseNameOf(profile)); auto profileName = profile.filename().string();
for (auto & i : DirectoryIterator{profileDir}) { for (auto & i : DirectoryIterator{profileDir}) {
checkInterrupt(); checkInterrupt();
@ -48,18 +48,20 @@ std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path pro
gens.sort([](const Generation & a, const Generation & b) { return a.number < b.number; }); gens.sort([](const Generation & a, const Generation & b) { return a.number < b.number; });
return {gens, pathExists(profile) ? parseName(profileName, readLink(profile)) : std::nullopt}; return {gens, pathExists(profile) ? parseName(profileName, readLink(profile).string()) : std::nullopt};
} }
/** /**
* Create a generation name that can be parsed by `parseName()`. * Create a generation name that can be parsed by `parseName()`.
*/ */
static Path makeName(const Path & profile, GenerationNumber num) static std::filesystem::path makeName(const std::filesystem::path & profile, GenerationNumber num)
{ {
return fmt("%s-%s-link", profile, num); /* NB std::filesystem::path when put in format strings is
quoted automatically. */
return fmt("%s-%s-link", profile.string(), num);
} }
Path createGeneration(LocalFSStore & store, Path profile, StorePath outPath) std::filesystem::path createGeneration(LocalFSStore & store, std::filesystem::path profile, StorePath outPath)
{ {
/* The new generation number should be higher than old the /* The new generation number should be higher than old the
previous ones. */ previous ones. */
@ -90,21 +92,24 @@ Path createGeneration(LocalFSStore & store, Path profile, StorePath outPath)
to the permanent roots (of which the GC would have a stale to the permanent roots (of which the GC would have a stale
view). If we didn't do it this way, the GC might remove the view). If we didn't do it this way, the GC might remove the
user environment etc. we've just built. */ user environment etc. we've just built. */
Path generation = makeName(profile, num + 1); auto generation = makeName(profile, num + 1);
store.addPermRoot(outPath, generation); store.addPermRoot(outPath, generation.string());
return generation; return generation;
} }
static void removeFile(const Path & path) static void removeFile(const std::filesystem::path & path)
{ {
if (remove(path.c_str()) == -1) try {
throw SysError("cannot unlink '%1%'", path); std::filesystem::remove(path);
} catch (std::filesystem::filesystem_error & e) {
throw SysError("removing file '%1%'", path);
}
} }
void deleteGeneration(const Path & profile, GenerationNumber gen) void deleteGeneration(const std::filesystem::path & profile, GenerationNumber gen)
{ {
Path generation = makeName(profile, gen); std::filesystem::path generation = makeName(profile, gen);
removeFile(generation); removeFile(generation);
} }
@ -117,7 +122,7 @@ void deleteGeneration(const Path & profile, GenerationNumber gen)
* *
* - We only actually delete if `dryRun` is false. * - We only actually delete if `dryRun` is false.
*/ */
static void deleteGeneration2(const Path & profile, GenerationNumber gen, bool dryRun) static void deleteGeneration2(const std::filesystem::path & profile, GenerationNumber gen, bool dryRun)
{ {
if (dryRun) if (dryRun)
notice("would remove profile version %1%", gen); notice("would remove profile version %1%", gen);
@ -127,7 +132,8 @@ static void deleteGeneration2(const Path & profile, GenerationNumber gen, bool d
} }
} }
void deleteGenerations(const Path & profile, const std::set<GenerationNumber> & gensToDelete, bool dryRun) void deleteGenerations(
const std::filesystem::path & profile, const std::set<GenerationNumber> & gensToDelete, bool dryRun)
{ {
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
@ -153,7 +159,7 @@ static inline void iterDropUntil(Generations & gens, auto && i, auto && cond)
; ;
} }
void deleteGenerationsGreaterThan(const Path & profile, GenerationNumber max, bool dryRun) void deleteGenerationsGreaterThan(const std::filesystem::path & profile, GenerationNumber max, bool dryRun)
{ {
if (max == 0) if (max == 0)
throw Error("Must keep at least one generation, otherwise the current one would be deleted"); throw Error("Must keep at least one generation, otherwise the current one would be deleted");
@ -178,7 +184,7 @@ void deleteGenerationsGreaterThan(const Path & profile, GenerationNumber max, bo
deleteGeneration2(profile, i->number, dryRun); deleteGeneration2(profile, i->number, dryRun);
} }
void deleteOldGenerations(const Path & profile, bool dryRun) void deleteOldGenerations(const std::filesystem::path & profile, bool dryRun)
{ {
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
@ -190,7 +196,7 @@ void deleteOldGenerations(const Path & profile, bool dryRun)
deleteGeneration2(profile, i.number, dryRun); deleteGeneration2(profile, i.number, dryRun);
} }
void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun) void deleteGenerationsOlderThan(const std::filesystem::path & profile, time_t t, bool dryRun)
{ {
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
@ -238,16 +244,16 @@ time_t parseOlderThanTimeSpec(std::string_view timeSpec)
return curTime - *days * 24 * 3600; return curTime - *days * 24 * 3600;
} }
void switchLink(Path link, Path target) void switchLink(std::filesystem::path link, std::filesystem::path target)
{ {
/* Hacky. */ /* Hacky. */
if (dirOf(target) == dirOf(link)) if (target.parent_path() == link.parent_path())
target = baseNameOf(target); target = target.filename();
replaceSymlink(target, link); replaceSymlink(target, link);
} }
void switchGeneration(const Path & profile, std::optional<GenerationNumber> dstGen, bool dryRun) void switchGeneration(const std::filesystem::path & profile, std::optional<GenerationNumber> dstGen, bool dryRun)
{ {
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
@ -274,44 +280,47 @@ void switchGeneration(const Path & profile, std::optional<GenerationNumber> dstG
switchLink(profile, dst->path); switchLink(profile, dst->path);
} }
void lockProfile(PathLocks & lock, const Path & profile) void lockProfile(PathLocks & lock, const std::filesystem::path & profile)
{ {
lock.lockPaths({profile}, fmt("waiting for lock on profile '%1%'", profile)); lock.lockPaths({profile}, fmt("waiting for lock on profile '%1%'", profile));
lock.setDeletion(true); lock.setDeletion(true);
} }
std::string optimisticLockProfile(const Path & profile) std::string optimisticLockProfile(const std::filesystem::path & profile)
{ {
return pathExists(profile) ? readLink(profile) : ""; return pathExists(profile) ? readLink(profile).string() : "";
} }
Path profilesDir() std::filesystem::path profilesDir()
{ {
auto profileRoot = isRootUser() ? rootProfilesDir() : createNixStateDir() + "/profiles"; auto profileRoot = isRootUser() ? rootProfilesDir() : std::filesystem::path{createNixStateDir()} / "profiles";
createDirs(profileRoot); createDirs(profileRoot);
return profileRoot; return profileRoot;
} }
Path rootProfilesDir() std::filesystem::path rootProfilesDir()
{ {
return settings.nixStateDir + "/profiles/per-user/root"; return std::filesystem::path{settings.nixStateDir} / "profiles/per-user/root";
} }
Path getDefaultProfile() std::filesystem::path getDefaultProfile()
{ {
Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile"; std::filesystem::path profileLink = settings.useXDGBaseDirectories
? std::filesystem::path{createNixStateDir()} / "profile"
: std::filesystem::path{getHome()} / ".nix-profile";
try { try {
auto profile = profilesDir() + "/profile"; auto profile = profilesDir() / "profile";
if (!pathExists(profileLink)) { if (!pathExists(profileLink)) {
replaceSymlink(profile, profileLink); replaceSymlink(profile, profileLink);
} }
// Backwards compatibility measure: Make root's profile available as // Backwards compatibility measure: Make root's profile available as
// `.../default` as it's what NixOS and most of the init scripts expect // `.../default` as it's what NixOS and most of the init scripts expect
Path globalProfileLink = settings.nixStateDir + "/profiles/default"; auto globalProfileLink = std::filesystem::path{settings.nixStateDir} / "profiles" / "default";
if (isRootUser() && !pathExists(globalProfileLink)) { if (isRootUser() && !pathExists(globalProfileLink)) {
replaceSymlink(profile, globalProfileLink); replaceSymlink(profile, globalProfileLink);
} }
return absPath(readLink(profileLink), dirOf(profileLink)); auto linkDir = profileLink.parent_path();
return absPath(readLink(profileLink), &linkDir);
} catch (Error &) { } catch (Error &) {
return profileLink; return profileLink;
} catch (std::filesystem::filesystem_error &) { } catch (std::filesystem::filesystem_error &) {
@ -319,14 +328,14 @@ Path getDefaultProfile()
} }
} }
Path defaultChannelsDir() std::filesystem::path defaultChannelsDir()
{ {
return profilesDir() + "/channels"; return profilesDir() / "channels";
} }
Path rootChannelsDir() std::filesystem::path rootChannelsDir()
{ {
return rootProfilesDir() + "/channels"; return rootProfilesDir() / "channels";
} }
} // namespace nix } // namespace nix

View file

@ -1126,6 +1126,11 @@ std::string StoreDirConfig::showPaths(const StorePathSet & paths) const
return s; return s;
} }
std::string showPaths(const std::set<std::filesystem::path> paths)
{
return concatStringsSep(", ", quoteFSPaths(paths));
}
std::string showPaths(const PathSet & paths) std::string showPaths(const PathSet & paths)
{ {
return concatStringsSep(", ", quoteStrings(paths)); return concatStringsSep(", ", quoteStrings(paths));

View file

@ -13,7 +13,7 @@
namespace nix { namespace nix {
AutoCloseFD openLockFile(const Path & path, bool create) AutoCloseFD openLockFile(const std::filesystem::path & path, bool create)
{ {
AutoCloseFD fd; AutoCloseFD fd;
@ -24,7 +24,7 @@ AutoCloseFD openLockFile(const Path & path, bool create)
return fd; return fd;
} }
void deleteLockFile(const Path & path, Descriptor desc) void deleteLockFile(const std::filesystem::path & path, Descriptor desc)
{ {
/* Get rid of the lock file. Have to be careful not to introduce /* Get rid of the lock file. Have to be careful not to introduce
races. Write a (meaningless) token to the file to indicate to races. Write a (meaningless) token to the file to indicate to
@ -69,7 +69,7 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait)
return true; return true;
} }
bool PathLocks::lockPaths(const PathSet & paths, const std::string & waitMsg, bool wait) bool PathLocks::lockPaths(const std::set<std::filesystem::path> & paths, const std::string & waitMsg, bool wait)
{ {
assert(fds.empty()); assert(fds.empty());
@ -81,7 +81,7 @@ bool PathLocks::lockPaths(const PathSet & paths, const std::string & waitMsg, bo
preventing deadlocks. */ preventing deadlocks. */
for (auto & path : paths) { for (auto & path : paths) {
checkInterrupt(); checkInterrupt();
Path lockPath = path + ".lock"; std::filesystem::path lockPath = path + ".lock";
debug("locking path '%1%'", path); debug("locking path '%1%'", path);

View file

@ -13,10 +13,10 @@ namespace nix {
using namespace nix::windows; using namespace nix::windows;
void deleteLockFile(const Path & path, Descriptor desc) void deleteLockFile(const std::filesystem::path & path, Descriptor desc)
{ {
int exit = DeleteFileA(path.c_str()); int exit = DeleteFileW(path.c_str());
if (exit == 0) if (exit == 0)
warn("%s: &s", path, std::to_string(GetLastError())); warn("%s: &s", path, std::to_string(GetLastError()));
} }
@ -36,9 +36,9 @@ void PathLocks::unlock()
fds.clear(); fds.clear();
} }
AutoCloseFD openLockFile(const Path & path, bool create) AutoCloseFD openLockFile(const std::filesystem::path & path, bool create)
{ {
AutoCloseFD desc = CreateFileA( AutoCloseFD desc = CreateFileW(
path.c_str(), path.c_str(),
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -103,13 +103,14 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait)
} }
} }
bool PathLocks::lockPaths(const PathSet & paths, const std::string & waitMsg, bool wait) bool PathLocks::lockPaths(const std::set<std::filesystem::path> & paths, const std::string & waitMsg, bool wait)
{ {
assert(fds.empty()); assert(fds.empty());
for (auto & path : paths) { for (auto & path : paths) {
checkInterrupt(); checkInterrupt();
Path lockPath = path + ".lock"; std::filesystem::path lockPath = path;
lockPath += L".lock";
debug("locking path '%1%'", path); debug("locking path '%1%'", path);
AutoCloseFD fd; AutoCloseFD fd;

View file

@ -109,7 +109,7 @@ std::optional<Path> getSelfExe()
{ {
static auto cached = []() -> std::optional<Path> { static auto cached = []() -> std::optional<Path> {
#if defined(__linux__) || defined(__GNU__) #if defined(__linux__) || defined(__GNU__)
return readLink("/proc/self/exe"); return readLink(std::filesystem::path{"/proc/self/exe"});
#elif defined(__APPLE__) #elif defined(__APPLE__)
char buf[1024]; char buf[1024];
uint32_t size = sizeof(buf); uint32_t size = sizeof(buf);

View file

@ -101,9 +101,11 @@ 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) std::filesystem::path
absPath(const std::filesystem::path & path, const std::filesystem::path * dir_, bool resolveSymlinks)
{ {
return absPath(path.string(), std::nullopt, resolveSymlinks); std::optional<std::string> dir = dir_ ? std::optional<std::string>{dir_->string()} : std::nullopt;
return absPath(PathView{path.string()}, dir.transform([](auto & p) { return PathView(p); }), resolveSymlinks);
} }
Path canonPath(PathView path, bool resolveSymlinks) Path canonPath(PathView path, bool resolveSymlinks)
@ -242,10 +244,15 @@ bool pathAccessible(const std::filesystem::path & path)
} }
} }
Path readLink(const Path & path) std::filesystem::path readLink(const std::filesystem::path & path)
{ {
checkInterrupt(); checkInterrupt();
return std::filesystem::read_symlink(path).string(); return std::filesystem::read_symlink(path);
}
Path readLink(const Path & path)
{
return readLink(std::filesystem::path{path}).string();
} }
std::string readFile(const Path & path) std::string readFile(const Path & path)

View file

@ -55,7 +55,8 @@ inline Path absPath(const Path & path, std::optional<PathView> dir = {}, bool re
return absPath(PathView{path}, dir, resolveSymlinks); return absPath(PathView{path}, dir, resolveSymlinks);
} }
std::filesystem::path absPath(const std::filesystem::path & path, bool resolveSymlinks = false); std::filesystem::path
absPath(const std::filesystem::path & path, const std::filesystem::path * dir = nullptr, bool resolveSymlinks = false);
/** /**
* Canonicalise a path by removing all `.` or `..` components and * Canonicalise a path by removing all `.` or `..` components and
@ -152,6 +153,12 @@ bool pathAccessible(const std::filesystem::path & path);
*/ */
Path readLink(const Path & path); Path readLink(const Path & path);
/**
* Read the contents (target) of a symbolic link. The result is not
* in any way canonicalised.
*/
std::filesystem::path readLink(const std::filesystem::path & path);
/** /**
* Open a `Descriptor` with read-only access to the given directory. * Open a `Descriptor` with read-only access to the given directory.
*/ */

View file

@ -58,6 +58,12 @@ Strings quoteStrings(const C & c, char quote = '\'')
return res; return res;
} }
inline Strings quoteFSPaths(const std::set<std::filesystem::path> & paths, char quote = '\'')
{
return paths | std::views::transform([&](const auto & p) { return quoteString(p.string(), quote); })
| std::ranges::to<Strings>();
}
/** /**
* Remove trailing whitespace from a string. * Remove trailing whitespace from a string.
* *

View file

@ -91,7 +91,7 @@ static int main_nix_collect_garbage(int argc, char ** argv)
std::set<std::filesystem::path> dirsToClean = { std::set<std::filesystem::path> dirsToClean = {
profilesDir(), profilesDir(),
std::filesystem::path{settings.nixStateDir} / "profiles", std::filesystem::path{settings.nixStateDir} / "profiles",
std::filesystem::path{getDefaultProfile()}.parent_path(), getDefaultProfile().parent_path(),
}; };
for (auto & dir : dirsToClean) for (auto & dir : dirsToClean)
removeOldGenerations(dir); removeOldGenerations(dir);

View file

@ -761,7 +761,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal); globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal);
debug("switching to new user environment"); debug("switching to new user environment");
Path generation = createGeneration(*store2, globals.profile, drv.queryOutPath()); auto generation = createGeneration(*store2, globals.profile, drv.queryOutPath());
switchLink(globals.profile, generation); switchLink(globals.profile, generation);
} }
@ -1407,14 +1407,15 @@ static int main_nix_env(int argc, char ** argv)
globals.instSource.type = srcUnknown; globals.instSource.type = srcUnknown;
globals.instSource.systemFilter = "*"; globals.instSource.systemFilter = "*";
Path nixExprPath = getNixDefExpr(); std::filesystem::path nixExprPath = getNixDefExpr();
if (!pathExists(nixExprPath)) { if (!pathExists(nixExprPath)) {
try { try {
createDirs(nixExprPath); createDirs(nixExprPath);
replaceSymlink(defaultChannelsDir(), nixExprPath + "/channels"); replaceSymlink(defaultChannelsDir(), nixExprPath / "channels");
if (!isRootUser()) if (!isRootUser())
replaceSymlink(rootChannelsDir(), nixExprPath + "/channels_root"); replaceSymlink(rootChannelsDir(), nixExprPath / "channels_root");
} catch (std::filesystem::filesystem_error &) {
} catch (Error &) { } catch (Error &) {
} }
} }
@ -1511,7 +1512,8 @@ static int main_nix_env(int argc, char ** argv)
globals.state->repair = myArgs.repair; globals.state->repair = myArgs.repair;
globals.instSource.nixExprPath = std::make_shared<SourcePath>( globals.instSource.nixExprPath = std::make_shared<SourcePath>(
file != "" ? lookupFileArg(*globals.state, file) : globals.state->rootPath(CanonPath(nixExprPath))); file != "" ? lookupFileArg(*globals.state, file)
: globals.state->rootPath(CanonPath(nixExprPath.string())));
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state); globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);
@ -1519,7 +1521,7 @@ static int main_nix_env(int argc, char ** argv)
globals.profile = getEnv("NIX_PROFILE").value_or(""); globals.profile = getEnv("NIX_PROFILE").value_or("");
if (globals.profile == "") if (globals.profile == "")
globals.profile = getDefaultProfile(); globals.profile = getDefaultProfile().string();
op(globals, std::move(opFlags), std::move(opArgs)); op(globals, std::move(opFlags), std::move(opArgs));

View file

@ -161,14 +161,14 @@ bool createUserEnv(
PathLocks lock; PathLocks lock;
lockProfile(lock, profile); lockProfile(lock, profile);
Path lockTokenCur = optimisticLockProfile(profile); std::filesystem::path lockTokenCur = optimisticLockProfile(profile);
if (lockToken != lockTokenCur) { if (lockToken != lockTokenCur) {
printInfo("profile '%1%' changed while we were busy; restarting", profile); printInfo("profile '%1%' changed while we were busy; restarting", profile);
return false; return false;
} }
debug("switching to new user environment"); debug("switching to new user environment");
Path generation = createGeneration(*store2, profile, topLevelOut); std::filesystem::path generation = createGeneration(*store2, profile, topLevelOut);
switchLink(profile, generation); switchLink(profile, generation);
} }

View file

@ -849,7 +849,10 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile
first = false; first = false;
logger->cout("Version %d -> %d:", prevGen->number, gen.number); logger->cout("Version %d -> %d:", prevGen->number, gen.number);
printClosureDiff( printClosureDiff(
store, store->followLinksToStorePath(prevGen->path), store->followLinksToStorePath(gen.path), " "); store,
store->followLinksToStorePath(prevGen->path.string()),
store->followLinksToStorePath(gen.path.string()),
" ");
} }
prevGen = gen; prevGen = gen;