|
| 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
shlevy commentedon Jan 31, 2018
Will this fail if you're using unstable and the latest stable is "older"?
edolstra commentedon Jan 31, 2018
No.