Skip to content

Commit 6fa6902

Browse files
committedJan 31, 2018
Add 'nix upgrade-nix' command
This command upgrades Nix to the latest stable version by installing a store path obtained from https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix which is the same store path that the installer at https://nixos.org/nix/install.sh uses. The upgrade fails if Nix is not installed in a profile (e.g. on NixOS, or when installed outside of the Nix store).
1 parent 8af911b commit 6fa6902

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed
 

‎doc/manual/release-notes/rl-1.12.xml

+5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@
7979

8080
<listitem><para><command>nix add-to-store</command> (970366266b8df712f5f9cedb45af183ef5a8357f).</para></listitem>
8181

82+
<listitem><para><command>nix upgrade-nix</command> upgrades Nix
83+
to the latest stable version. This requires that Nix is
84+
installed in a profile. (Thus it won’t work on NixOS, or if it’s
85+
installed outside of the Nix store.)</para></listitem>
86+
8287
<listitem><para>Progress indicator.</para></listitem>
8388

8489
<listitem><para>All options are available as flags now

‎src/nix/command.hh

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
namespace nix {
77

8+
extern std::string programPath;
9+
810
struct Value;
911
class Bindings;
1012
class EvalState;

‎src/nix/main.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ void chrootHelper(int argc, char * * argv);
1616

1717
namespace nix {
1818

19+
std::string programPath;
20+
1921
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
2022
{
2123
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix")
@@ -78,7 +80,8 @@ void mainWrapped(int argc, char * * argv)
7880
initNix();
7981
initGC();
8082

81-
string programName = baseNameOf(argv[0]);
83+
programPath = argv[0];
84+
string programName = baseNameOf(programPath);
8285

8386
{
8487
auto legacy = (*RegisterLegacyCommand::commands)[programName];

‎src/nix/upgrade-nix.cc

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include "command.hh"
2+
#include "store-api.hh"
3+
#include "download.hh"
4+
#include "eval.hh"
5+
#include "attr-path.hh"
6+
7+
using namespace nix;
8+
9+
struct CmdUpgradeNix : StoreCommand
10+
{
11+
Path profileDir;
12+
13+
CmdUpgradeNix()
14+
{
15+
mkFlag()
16+
.longName("profile")
17+
.shortName('p')
18+
.labels({"profile-dir"})
19+
.description("the Nix profile to upgrade")
20+
.dest(&profileDir);
21+
}
22+
23+
std::string name() override
24+
{
25+
return "upgrade-nix";
26+
}
27+
28+
std::string description() override
29+
{
30+
return "upgrade Nix to the latest stable version";
31+
}
32+
33+
Examples examples() override
34+
{
35+
return {
36+
Example{
37+
"To upgrade Nix to the latest stable version:",
38+
"nix upgrade-nix"
39+
},
40+
Example{
41+
"To upgrade Nix in a specific profile:",
42+
"nix upgrade-nix -p /nix/var/nix/profiles/per-user/alice/profile"
43+
},
44+
};
45+
}
46+
47+
void run(ref<Store> store) override
48+
{
49+
settings.pureEval = true;
50+
51+
if (profileDir == "")
52+
profileDir = getProfileDir(store);
53+
54+
printInfo("upgrading Nix in profile '%s'", profileDir);
55+
56+
Path storePath;
57+
{
58+
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
59+
storePath = getLatestNix(store);
60+
}
61+
62+
{
63+
Activity act(*logger, lvlInfo, actUnknown, fmt("downloading '%s'...", storePath));
64+
store->ensurePath(storePath);
65+
}
66+
67+
{
68+
Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", storePath));
69+
auto program = storePath + "/bin/nix-env";
70+
auto s = runProgram(program, false, {"--version"});
71+
if (s.find("Nix") == std::string::npos)
72+
throw Error("could not verify that '%s' works", program);
73+
}
74+
75+
{
76+
Activity act(*logger, lvlInfo, actUnknown, fmt("installing '%s' into profile '%s'...", storePath, profileDir));
77+
runProgram(settings.nixBinDir + "/nix-env", false,
78+
{"--profile", profileDir, "-i", storePath, "--no-sandbox"});
79+
}
80+
}
81+
82+
/* Return the profile in which Nix is installed. */
83+
Path getProfileDir(ref<Store> store)
84+
{
85+
Path where;
86+
87+
for (auto & dir : tokenizeString<Strings>(getEnv("PATH"), ":"))
88+
if (pathExists(dir + "/nix-env")) {
89+
where = dir;
90+
break;
91+
}
92+
93+
if (where == "")
94+
throw Error("couldn't figure out how Nix is installed, so I can't upgrade it");
95+
96+
printInfo("found Nix in '%s'", where);
97+
98+
if (hasPrefix(where, "/run/current-system"))
99+
throw Error("Nix on NixOS must be upgraded via 'nixos-rebuild'");
100+
101+
Path profileDir;
102+
Path userEnv;
103+
104+
if (baseNameOf(where) != "bin" ||
105+
!hasSuffix(userEnv = canonPath(profileDir = dirOf(where), true), "user-environment"))
106+
throw Error("directory '%s' does not appear to be part of a Nix profile", where);
107+
108+
if (!store->isValidPath(userEnv))
109+
throw Error("directory '%s' is not in the Nix store", userEnv);
110+
111+
return profileDir;
112+
}
113+
114+
/* Return the store path of the latest stable Nix. */
115+
Path getLatestNix(ref<Store> store)
116+
{
117+
// FIXME: use nixos.org?
118+
auto req = DownloadRequest("https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix");
119+
auto res = getDownloader()->download(req);
120+
121+
EvalState state(Strings(), store);
122+
auto v = state.allocValue();
123+
state.eval(state.parseExprFromString(*res.data, "/no-such-path"), *v);
124+
Bindings & bindings(*state.allocBindings(0));
125+
auto v2 = findAlongAttrPath(state, settings.thisSystem, bindings, *v);
126+
127+
return state.forceString(*v2);
128+
}
129+
};
130+
131+
static RegisterCommand r1(make_ref<CmdUpgradeNix>());

2 commit comments

Comments
 (2)

shlevy commented on Jan 31, 2018

@shlevy
Member

Will this fail if you're using unstable and the latest stable is "older"?

edolstra commented on Jan 31, 2018

@edolstra
MemberAuthor

No.

Please sign in to comment.