Add "nix profile rollback" command
This commit is contained in:
parent
1fbaf36729
commit
817562e694
|
@ -236,6 +236,37 @@ void switchLink(Path link, Path target)
|
|||
}
|
||||
|
||||
|
||||
void switchGeneration(
|
||||
const Path & profile,
|
||||
std::optional<GenerationNumber> dstGen,
|
||||
bool dryRun)
|
||||
{
|
||||
PathLocks lock;
|
||||
lockProfile(lock, profile);
|
||||
|
||||
auto [gens, curGen] = findGenerations(profile);
|
||||
|
||||
std::optional<Generation> dst;
|
||||
for (auto & i : gens)
|
||||
if ((!dstGen && i.number < curGen) ||
|
||||
(dstGen && i.number == *dstGen))
|
||||
dst = i;
|
||||
|
||||
if (!dst) {
|
||||
if (dstGen)
|
||||
throw Error("generation %1% does not exist", *dstGen);
|
||||
else
|
||||
throw Error("no generation older than the current (%1%) exists", curGen.value_or(0));
|
||||
}
|
||||
|
||||
notice("switching from generation %d to %d", curGen.value_or(0), dst->number);
|
||||
|
||||
if (dryRun) return;
|
||||
|
||||
switchLink(profile, dst->path);
|
||||
}
|
||||
|
||||
|
||||
void lockProfile(PathLocks & lock, const Path & profile)
|
||||
{
|
||||
lock.lockPaths({profile}, (format("waiting for lock on profile '%1%'") % profile).str());
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace nix {
|
|||
class StorePath;
|
||||
|
||||
|
||||
typedef unsigned int GenerationNumber;
|
||||
typedef uint64_t GenerationNumber;
|
||||
|
||||
struct Generation
|
||||
{
|
||||
|
@ -46,6 +46,13 @@ void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, b
|
|||
|
||||
void switchLink(Path link, Path target);
|
||||
|
||||
/* Roll back a profile to the specified generation, or to the most
|
||||
recent one older than the current. */
|
||||
void switchGeneration(
|
||||
const Path & profile,
|
||||
std::optional<GenerationNumber> dstGen,
|
||||
bool dryRun);
|
||||
|
||||
/* Ensure exclusive access to a profile. Any command that modifies
|
||||
the profile first acquires this lock. */
|
||||
void lockProfile(PathLocks & lock, const Path & profile);
|
||||
|
|
|
@ -91,6 +91,14 @@ protected:
|
|||
})
|
||||
, arity(1)
|
||||
{ }
|
||||
|
||||
template<class I>
|
||||
Handler(std::optional<I> * dest)
|
||||
: fun([=](std::vector<std::string> ss) {
|
||||
*dest = string2IntWithUnitPrefix<I>(ss[0]);
|
||||
})
|
||||
, arity(1)
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Options. */
|
||||
|
|
|
@ -1204,37 +1204,6 @@ static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
}
|
||||
|
||||
|
||||
static constexpr GenerationNumber prevGen = std::numeric_limits<GenerationNumber>::max();
|
||||
|
||||
|
||||
static void switchGeneration(Globals & globals, GenerationNumber dstGen)
|
||||
{
|
||||
PathLocks lock;
|
||||
lockProfile(lock, globals.profile);
|
||||
|
||||
auto [gens, curGen] = findGenerations(globals.profile);
|
||||
|
||||
std::optional<Generation> dst;
|
||||
for (auto & i : gens)
|
||||
if ((dstGen == prevGen && i.number < curGen) ||
|
||||
(dstGen >= 0 && i.number == dstGen))
|
||||
dst = i;
|
||||
|
||||
if (!dst) {
|
||||
if (dstGen == prevGen)
|
||||
throw Error("no generation older than the current (%1%) exists", curGen.value_or(0));
|
||||
else
|
||||
throw Error("generation %1% does not exist", dstGen);
|
||||
}
|
||||
|
||||
printInfo("switching from generation %1% to %2%", curGen.value_or(0), dst->number);
|
||||
|
||||
if (globals.dryRun) return;
|
||||
|
||||
switchLink(globals.profile, dst->path);
|
||||
}
|
||||
|
||||
|
||||
static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
{
|
||||
if (opFlags.size() > 0)
|
||||
|
@ -1243,7 +1212,7 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
|
|||
throw UsageError("exactly one argument expected");
|
||||
|
||||
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
||||
switchGeneration(globals, *dstGen);
|
||||
switchGeneration(globals.profile, *dstGen, globals.dryRun);
|
||||
else
|
||||
throw UsageError("expected a generation number");
|
||||
}
|
||||
|
@ -1256,7 +1225,7 @@ static void opRollback(Globals & globals, Strings opFlags, Strings opArgs)
|
|||
if (opArgs.size() != 0)
|
||||
throw UsageError("no arguments expected");
|
||||
|
||||
switchGeneration(globals, prevGen);
|
||||
switchGeneration(globals.profile, {}, globals.dryRun);
|
||||
}
|
||||
|
||||
|
||||
|
|
26
src/nix/profile-rollback.md
Normal file
26
src/nix/profile-rollback.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
R""(
|
||||
|
||||
# Examples
|
||||
|
||||
* Roll back your default profile to the previous version:
|
||||
|
||||
```console
|
||||
# nix profile rollback
|
||||
switching from generation 519 to 518
|
||||
```
|
||||
|
||||
* Switch your default profile to version 510:
|
||||
|
||||
```console
|
||||
# nix profile rollback --to 510
|
||||
switching from generation 518 to 510
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
This command switches a profile to the most recent version older
|
||||
than the currently active version, or if `--to` *N* is given, to
|
||||
version *N* of the profile. To see the available versions of a
|
||||
profile, use `nix profile history`.
|
||||
|
||||
)""
|
|
@ -543,6 +543,38 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile
|
|||
}
|
||||
};
|
||||
|
||||
struct CmdProfileRollback : virtual StoreCommand, MixDefaultProfile, MixDryRun
|
||||
{
|
||||
std::optional<GenerationNumber> version;
|
||||
|
||||
CmdProfileRollback()
|
||||
{
|
||||
addFlag({
|
||||
.longName = "to",
|
||||
.description = "The profile version to roll back to.",
|
||||
.labels = {"version"},
|
||||
.handler = {&version},
|
||||
});
|
||||
}
|
||||
|
||||
std::string description() override
|
||||
{
|
||||
return "roll back to the previous version or a specified version of this profile";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "profile-rollback.md"
|
||||
;
|
||||
}
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
switchGeneration(*profile, version, dryRun);
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdProfile : NixMultiCommand
|
||||
{
|
||||
CmdProfile()
|
||||
|
@ -553,6 +585,7 @@ struct CmdProfile : NixMultiCommand
|
|||
{"list", []() { return make_ref<CmdProfileList>(); }},
|
||||
{"diff-closures", []() { return make_ref<CmdProfileDiffClosures>(); }},
|
||||
{"history", []() { return make_ref<CmdProfileHistory>(); }},
|
||||
{"rollback", []() { return make_ref<CmdProfileRollback>(); }},
|
||||
})
|
||||
{ }
|
||||
|
||||
|
|
Loading…
Reference in a new issue