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: ce279209363c
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ac9b427541cd
Choose a head ref
  • 4 commits
  • 2 files changed
  • 1 contributor

Commits on Oct 21, 2019

  1. Copy the full SHA
    555ca59 View commit details

Commits on Oct 22, 2019

  1. Copy the full SHA
    e30a015 View commit details
  2. Copy the full SHA
    af78643 View commit details
  3. Copy the full SHA
    ac9b427 View commit details
Showing with 198 additions and 8 deletions.
  1. +1 −1 src/libstore/builtins/buildenv.cc
  2. +197 −7 src/nix/profile.cc
2 changes: 1 addition & 1 deletion src/libstore/builtins/buildenv.cc
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ void buildProfile(const Path & out, Packages && pkgs)
addPkg(pkgDir, priorityCounter++);
}

printError("created %d symlinks in user environment", state.symlinks);
debug("created %d symlinks in user environment", state.symlinks);
}

void builtinBuildenv(const BasicDerivation & drv)
204 changes: 197 additions & 7 deletions src/nix/profile.cc
Original file line number Diff line number Diff line change
@@ -6,14 +6,17 @@
#include "archive.hh"
#include "builtins/buildenv.hh"
#include "flake/flakeref.hh"
#include "nix-env/user-env.hh"

#include <nlohmann/json.hpp>
#include <regex>

using namespace nix;

struct ProfileElementSource
{
FlakeRef originalRef;
// FIXME: record original attrpath.
FlakeRef resolvedRef;
std::string attrPath;
// FIXME: output names
@@ -31,7 +34,9 @@ struct ProfileManifest
{
std::vector<ProfileElement> elements;

ProfileManifest(const Path & profile)
ProfileManifest() { }

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

@@ -57,6 +62,22 @@ struct ProfileManifest
elements.emplace_back(std::move(element));
}
}

else if (pathExists(profile + "/manifest.nix")) {
// FIXME: needed because of pure mode; ugly.
if (state.allowedPaths) {
state.allowedPaths->insert(state.store->followLinksToStore(profile));
state.allowedPaths->insert(state.store->followLinksToStore(profile + "/manifest.nix"));
}

auto drvInfos = queryInstalled(state, state.store->followLinksToStore(profile));

for (auto & drvInfo : drvInfos) {
ProfileElement element;
element.storePaths = {drvInfo.queryOutPath()};
elements.emplace_back(std::move(element));
}
}
}

std::string toJSON() const
@@ -143,7 +164,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile

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

PathSet pathsToBuild;

@@ -172,11 +193,177 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
}
};

struct CmdProfileInfo : virtual StoreCommand, MixDefaultProfile
class MixProfileElementMatchers : virtual Args
{
std::vector<std::string> _matchers;

public:

MixProfileElementMatchers()
{
expectArgs("elements", &_matchers);
}

typedef std::variant<size_t, Path, std::regex> Matcher;

std::vector<Matcher> getMatchers(ref<Store> store)
{
std::vector<Matcher> res;

for (auto & s : _matchers) {
size_t n;
if (string2Int(s, n))
res.push_back(n);
else if (store->isStorePath(s))
res.push_back(s);
else
res.push_back(std::regex(s, std::regex::extended | std::regex::icase));
}

return res;
}

bool matches(const ProfileElement & element, size_t pos, std::vector<Matcher> matchers)
{
for (auto & matcher : matchers) {
if (auto n = std::get_if<size_t>(&matcher)) {
if (*n == pos) return true;
} else if (auto path = std::get_if<Path>(&matcher)) {
if (element.storePaths.count(*path)) return true;
} else if (auto regex = std::get_if<std::regex>(&matcher)) {
if (element.source
&& std::regex_match(element.source->attrPath, *regex))
return true;
}
}

return false;
}
};

struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElementMatchers
{
std::string description() override
{
return "remove packages from a profile";
}

Examples examples() override
{
return {
Example{
"To remove a package by attribute path:",
"nix profile remove packages.x86_64-linux.hello"
},
Example{
"To remove all packages:",
"nix profile remove '.*'"
},
Example{
"To remove a package by store path:",
"nix profile remove /nix/store/rr3y0c6zyk7kjjl8y19s4lsrhn4aiq1z-hello-2.10"
},
Example{
"To remove a package by position:",
"nix profile remove 3"
},
};
}

void run(ref<Store> store) override
{
ProfileManifest oldManifest(*getEvalState(), *profile);

auto matchers = getMatchers(store);

ProfileManifest newManifest;

for (size_t i = 0; i < oldManifest.elements.size(); ++i) {
auto & element(oldManifest.elements[i]);
if (!matches(element, i, matchers))
newManifest.elements.push_back(element);
}

// FIXME: warn about unused matchers?

printInfo("removed %d packages, kept %d packages",
oldManifest.elements.size() - newManifest.elements.size(),
newManifest.elements.size());

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

struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProfileElementMatchers
{
std::string description() override
{
return "upgrade packages using their most recent flake";
}

Examples examples() override
{
return {
Example{
"To upgrade all packages that were installed using a mutable flake reference:",
"nix profile upgrade '.*'"
},
Example{
"To upgrade a specific package:",
"nix profile upgrade packages.x86_64-linux.hello"
},
};
}

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

auto matchers = getMatchers(store);

// FIXME: code duplication
PathSet pathsToBuild;

for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
if (element.source
&& !element.source->originalRef.isImmutable()
&& matches(element, i, matchers))
{
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath));

InstallableFlake installable(*this, FlakeRef(element.source->originalRef), {element.source->attrPath});

auto [attrPath, resolvedRef, drv] = installable.toDerivation();

if (element.source->resolvedRef == resolvedRef) continue;

printInfo("upgrading '%s' from flake '%s' to '%s'",
element.source->attrPath, element.source->resolvedRef, resolvedRef);

element.storePaths = {drv.outPath}; // FIXME
element.source = ProfileElementSource{
installable.flakeRef,
resolvedRef,
attrPath,
};

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

store->buildPaths(pathsToBuild);

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

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

Examples examples() override
@@ -191,10 +378,11 @@ struct CmdProfileInfo : virtual StoreCommand, MixDefaultProfile

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

for (auto & element : manifest.elements) {
std::cout << fmt("%s %s\n",
for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
std::cout << fmt("%d %s %s %s\n", i,
element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath : "-",
element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-",
concatStringsSep(" ", element.storePaths));
@@ -207,6 +395,8 @@ struct CmdProfile : virtual MultiCommand, virtual Command
CmdProfile()
: MultiCommand({
{"install", []() { return make_ref<CmdProfileInstall>(); }},
{"remove", []() { return make_ref<CmdProfileRemove>(); }},
{"upgrade", []() { return make_ref<CmdProfileUpgrade>(); }},
{"info", []() { return make_ref<CmdProfileInfo>(); }},
})
{ }