Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nix
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1e23b82a5303
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ce279209363c
Choose a head ref
  • 2 commits
  • 6 files changed
  • 1 contributor

Commits on Oct 21, 2019

  1. Fix "nixpkgs." compatibility

    edolstra committed Oct 21, 2019

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    91a88f3 View commit details
  2. 1
    Copy the full SHA
    ce27920 View commit details
Showing with 257 additions and 4 deletions.
  1. +5 −0 src/nix/command.cc
  2. +5 −0 src/nix/command.hh
  3. +1 −0 src/nix/flake.cc
  4. +9 −4 src/nix/installables.cc
  5. +3 −0 src/nix/installables.hh
  6. +234 −0 src/nix/profile.cc
5 changes: 5 additions & 0 deletions src/nix/command.cc
Original file line number Diff line number Diff line change
@@ -123,4 +123,9 @@ void MixProfile::updateProfile(const Buildables & buildables)
updateProfile(*result);
}

MixDefaultProfile::MixDefaultProfile()
{
profile = getDefaultProfile();
}

}
5 changes: 5 additions & 0 deletions src/nix/command.hh
Original file line number Diff line number Diff line change
@@ -188,4 +188,9 @@ struct MixProfile : virtual Args, virtual StoreCommand
void updateProfile(const Buildables & buildables);
};

struct MixDefaultProfile : MixProfile
{
MixDefaultProfile();
};

}
1 change: 1 addition & 0 deletions src/nix/flake.cc
Original file line number Diff line number Diff line change
@@ -653,6 +653,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command
{
if (!command)
throw UsageError("'nix flake' requires a sub-command.");
command->prepare();
command->run();
}

13 changes: 9 additions & 4 deletions src/nix/installables.cc
Original file line number Diff line number Diff line change
@@ -294,7 +294,7 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Resolv
return (*aOutputs)->value;
}

std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> InstallableFlake::toDerivation()
{
auto state = cmd.getEvalState();

@@ -312,7 +312,7 @@ std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
auto drv = evalCache.getDerivation(fingerprint, attrPath);
if (drv) {
if (state->store->isValidPath(drv->drvPath))
return {*drv};
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, *drv};
}

if (!vOutputs)
@@ -334,7 +334,7 @@ std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()

evalCache.addDerivation(fingerprint, attrPath, drv);

return {drv};
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, drv};
} catch (AttrPathNotFound & e) {
}
}
@@ -343,6 +343,11 @@ std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
}

std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
{
return {std::get<2>(toDerivation())};
}

Value * InstallableFlake::toValue(EvalState & state)
{
auto resFlake = resolveFlake(state, flakeRef, cmd.getLockFileMode());
@@ -409,7 +414,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
bool static warned;
warnOnce(warned, "the syntax 'nixpkgs.<attr>' is deprecated; use 'nixpkgs:<attr>' instead");
result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"),
Strings{"legacyPackages." + std::string(s, 8)}));
Strings{"legacyPackages." + settings.thisSystem.get() + "." + std::string(s, 8)}));
}

else if ((hash = s.rfind('#')) != std::string::npos)
3 changes: 3 additions & 0 deletions src/nix/installables.hh
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
namespace nix {

struct Value;
struct DrvInfo;
class EvalState;
class SourceExprCommand;

@@ -89,6 +90,8 @@ struct InstallableFlake : InstallableValue

Value * getFlakeOutputs(EvalState & state, const flake::ResolvedFlake & resFlake);

std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> toDerivation();

std::vector<flake::EvalCache::Derivation> toDerivations() override;

Value * toValue(EvalState & state) override;
234 changes: 234 additions & 0 deletions src/nix/profile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "archive.hh"
#include "builtins/buildenv.hh"
#include "flake/flakeref.hh"

#include <nlohmann/json.hpp>

using namespace nix;

struct ProfileElementSource
{
FlakeRef originalRef;
FlakeRef resolvedRef;
std::string attrPath;
// FIXME: output names
};

struct ProfileElement
{
PathSet storePaths;
std::optional<ProfileElementSource> source;
bool active = true;
// FIXME: priority
};

struct ProfileManifest
{
std::vector<ProfileElement> elements;

ProfileManifest(const Path & profile)
{
auto manifestPath = profile + "/manifest.json";

if (pathExists(manifestPath)) {
auto json = nlohmann::json::parse(readFile(manifestPath));

auto version = json.value("version", 0);
if (version != 1)
throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version);

for (auto & e : json["elements"]) {
ProfileElement element;
for (auto & p : e["storePaths"])
element.storePaths.insert((std::string) p);
element.active = e["active"];
if (e.value("uri", "") != "") {
element.source = ProfileElementSource{
FlakeRef(e["originalUri"]),
FlakeRef(e["uri"]),
e["attrPath"]
};
}
elements.emplace_back(std::move(element));
}
}
}

std::string toJSON() const
{
auto array = nlohmann::json::array();
for (auto & element : elements) {
auto paths = nlohmann::json::array();
for (auto & path : element.storePaths)
paths.push_back(path);
nlohmann::json obj;
obj["storePaths"] = paths;
obj["active"] = element.active;
if (element.source) {
obj["originalUri"] = element.source->originalRef.to_string();
obj["uri"] = element.source->resolvedRef.to_string();
obj["attrPath"] = element.source->attrPath;
}
array.push_back(obj);
}
nlohmann::json json;
json["version"] = 1;
json["elements"] = array;
return json.dump();
}

Path build(ref<Store> store)
{
auto tempDir = createTempDir();

ValidPathInfo info;

Packages pkgs;
for (auto & element : elements) {
for (auto & path : element.storePaths) {
if (element.active)
pkgs.emplace_back(path, true, 5);
info.references.insert(path);
}
}

buildProfile(tempDir, std::move(pkgs));

writeFile(tempDir + "/manifest.json", toJSON());

/* Add the symlink tree to the store. */
StringSink sink;
dumpPath(tempDir, sink);

info.narHash = hashString(htSHA256, *sink.s);
info.narSize = sink.s->size();
info.path = store->makeFixedOutputPath(true, info.narHash, "profile", info.references);
info.ca = makeFixedOutputCA(true, info.narHash);

store->addToStore(info, sink.s);

return info.path;
}
};

struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
std::string description() override
{
return "install a package into a profile";
}

Examples examples() override
{
return {
Example{
"To install a package from Nixpkgs:",
"nix profile install nixpkgs#hello"
},
Example{
"To install a package from a specific branch of Nixpkgs:",
"nix profile install nixpkgs/release-19.09#hello"
},
Example{
"To install a package from a specific revision of Nixpkgs:",
"nix profile install nixpkgs/1028bb33859f8dfad7f98e1c8d185f3d1aaa7340#hello"
},
};
}

void run(ref<Store> store) override
{
ProfileManifest manifest(*profile);

PathSet pathsToBuild;

for (auto & installable : installables) {
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();

ProfileElement element;
element.storePaths = {drv.outPath}; // FIXME
element.source = ProfileElementSource{
installable2->flakeRef,
resolvedRef,
attrPath,
};

pathsToBuild.insert(makeDrvPathWithOutputs(drv.drvPath, {"out"})); // FIXME

manifest.elements.emplace_back(std::move(element));
} else
throw Error("'nix profile install' does not support argument '%s'", installable->what());
}

store->buildPaths(pathsToBuild);

updateProfile(manifest.build(store));
}
};

struct CmdProfileInfo : virtual StoreCommand, MixDefaultProfile
{
std::string description() override
{
return "info";
}

Examples examples() override
{
return {
Example{
"To show what packages are installed in the default profile:",
"nix profile info"
},
};
}

void run(ref<Store> store) override
{
ProfileManifest manifest(*profile);

for (auto & element : manifest.elements) {
std::cout << fmt("%s %s\n",
element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath : "-",
element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-",
concatStringsSep(" ", element.storePaths));
}
}
};

struct CmdProfile : virtual MultiCommand, virtual Command
{
CmdProfile()
: MultiCommand({
{"install", []() { return make_ref<CmdProfileInstall>(); }},
{"info", []() { return make_ref<CmdProfileInfo>(); }},
})
{ }

std::string description() override
{
return "manage Nix profiles";
}

void run() override
{
if (!command)
throw UsageError("'nix profile' requires a sub-command.");
command->prepare();
command->run();
}

void printHelp(const string & programName, std::ostream & out) override
{
MultiCommand::printHelp(programName, out);
}
};

static auto r1 = registerCommand<CmdProfile>("profile");