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:
parent
c7b61f3d13
commit
504c5e7cf9
20 changed files with 154 additions and 103 deletions
|
|
@ -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());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 user’s
|
* Create and return the path to a directory suitable for storing the user’s
|
||||||
* 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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue