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

Commits on Oct 21, 2019

  1. Copy the full SHA
    a7aabd7 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b82f754 View commit details
  3. Allow content-addressable paths to have references

    This adds a command 'nix make-content-addressable' that rewrites the
    specified store paths into content-addressable paths. The advantage of
    such paths is that 1) they can be imported without signatures; 2) they
    can enable deduplication in cases where derivation changes do not
    cause output changes (apart from store path hashes).
    
    For example,
    
      $ nix make-content-addressable -r nixpkgs.cowsay
      rewrote '/nix/store/g1g31ah55xdia1jdqabv1imf6mcw0nb1-glibc-2.25-49' to '/nix/store/48jfj7bg78a8n4f2nhg269rgw1936vj4-glibc-2.25-49'
      ...
      rewrote '/nix/store/qbi6rzpk0bxjw8lw6azn2mc7ynnn455q-cowsay-3.03+dfsg1-16' to '/nix/store/iq6g2x4q62xp7y7493bibx0qn5w7xz67-cowsay-3.03+dfsg1-16'
    
    We can then copy the resulting closure to another store without
    signatures:
    
      $ nix copy --trusted-public-keys '' ---to ~/my-nix /nix/store/iq6g2x4q62xp7y7493bibx0qn5w7xz67-cowsay-3.03+dfsg1-16
    
    In order to support self-references in content-addressable paths,
    these paths are hashed "modulo" self-references, meaning that
    self-references are zeroed out during hashing. Somewhat annoyingly,
    this means that the NAR hash stored in the Nix database is no longer
    necessarily equal to the output of "nix hash-path"; for
    content-addressable paths, you need to pass the --modulo flag:
    
      $ nix path-info --json /nix/store/iq6g2x4q62xp7y7493bibx0qn5w7xz67-cowsay-3.03+dfsg1-16  | jq -r .[].narHash
      sha256:0ri611gdilz2c9rsibqhsipbfs9vwcqvs811a52i2bnkhv7w9mgw
    
      $ nix hash-path --type sha256 --base32 /nix/store/iq6g2x4q62xp7y7493bibx0qn5w7xz67-cowsay-3.03+dfsg1-16
      1ggznh07khq0hz6id09pqws3a8q9pn03ya3c03nwck1kwq8rclzs
    
      $ nix hash-path --type sha256 --base32 /nix/store/iq6g2x4q62xp7y7493bibx0qn5w7xz67-cowsay-3.03+dfsg1-16 --modulo iq6g2x4q62xp7y7493bibx0qn5w7xz67
      0ri611gdilz2c9rsibqhsipbfs9vwcqvs811a52i2bnkhv7w9mgw
    edolstra committed Oct 21, 2019
    Copy the full SHA
    0abb3ad View commit details
  4. Fix build

    edolstra committed Oct 21, 2019
    Copy the full SHA
    d77970f View commit details
  5. Copy the full SHA
    e687369 View commit details
  6. 1
    Copy the full SHA
    629b9b0 View commit details
  7. Copy the full SHA
    9a18f54 View commit details
  8. Fix build

    edolstra committed Oct 21, 2019
    Copy the full SHA
    cb1a79a View commit details
  9. 2
    Copy the full SHA
    45b740c View commit details
  10. exportGitHub(): Don't rely on the ETag from GitHub

    We relied on it being the Git revision, but that stopped being the
    case.
    edolstra committed Oct 21, 2019
    Copy the full SHA
    1e23b82 View commit details
2 changes: 2 additions & 0 deletions src/libexpr/flake/lockfile.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "lockfile.hh"
#include "store-api.hh"

#include <nlohmann/json.hpp>

namespace nix::flake {

LockedInput::LockedInput(const nlohmann::json & json)
2 changes: 1 addition & 1 deletion src/libexpr/flake/lockfile.hh
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

#include "flakeref.hh"

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

namespace nix {
class Store;
22 changes: 13 additions & 9 deletions src/libexpr/primops/fetchGit.cc
Original file line number Diff line number Diff line change
@@ -286,11 +286,21 @@ GitInfo exportGitHub(
return *gitInfo;
}

if (!rev) {
auto url = fmt("https://api.github.com/repos/%s/%s/commits/%s",
owner, repo, ref ? *ref : "master");
CachedDownloadRequest request(url);
request.ttl = rev ? 1000000000 : settings.tarballTtl;
auto result = getDownloader()->downloadCached(store, request);
auto json = nlohmann::json::parse(readFile(result.path));
rev = Hash(json["sha"], htSHA1);
}

// FIXME: use regular /archive URLs instead? api.github.com
// might have stricter rate limits.

auto url = fmt("https://api.github.com/repos/%s/%s/tarball/%s",
owner, repo, rev ? rev->to_string(Base16, false) : ref ? *ref : "master");
owner, repo, rev->to_string(Base16, false));

std::string accessToken = settings.githubAccessToken.get();
if (accessToken != "")
@@ -299,21 +309,15 @@ GitInfo exportGitHub(
CachedDownloadRequest request(url);
request.unpack = true;
request.name = "source";
request.ttl = rev ? 1000000000 : settings.tarballTtl;
request.ttl = 1000000000;
request.getLastModified = true;
auto result = getDownloader()->downloadCached(store, request);

if (!result.etag)
throw Error("did not receive an ETag header from '%s'", url);

if (result.etag->size() != 42 || (*result.etag)[0] != '"' || (*result.etag)[41] != '"')
throw Error("ETag header '%s' from '%s' is not a Git revision", *result.etag, url);

assert(result.lastModified);

GitInfo gitInfo;
gitInfo.storePath = result.storePath;
gitInfo.rev = Hash(std::string(*result.etag, 1, result.etag->size() - 2), htSHA1);
gitInfo.rev = *rev;
gitInfo.lastModified = *result.lastModified;

// FIXME: this can overwrite a cache file that contains a revCount.
22 changes: 3 additions & 19 deletions src/libstore/build.cc
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
#include "archive.hh"
#include "affinity.hh"
#include "builtins.hh"
#include "builtins/buildenv.hh"
#include "download.hh"
#include "finally.hh"
#include "compression.hh"
@@ -727,23 +728,6 @@ HookInstance::~HookInstance()
//////////////////////////////////////////////////////////////////////


typedef map<std::string, std::string> StringRewrites;


std::string rewriteStrings(std::string s, const StringRewrites & rewrites)
{
for (auto & i : rewrites) {
size_t j = 0;
while ((j = s.find(i.first, j)) != string::npos)
s.replace(j, i.first.size(), i.second);
}
return s;
}


//////////////////////////////////////////////////////////////////////


typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;

class SubstitutionGoal;
@@ -865,7 +849,7 @@ class DerivationGoal : public Goal
#endif

/* Hash rewriting. */
StringRewrites inputRewrites, outputRewrites;
StringMap inputRewrites, outputRewrites;
typedef map<Path, Path> RedirectedOutputs;
RedirectedOutputs redirectedOutputs;

@@ -2537,7 +2521,7 @@ static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*");

void DerivationGoal::writeStructuredAttrs()
{
auto & structuredAttrs = parsedDrv->getStructuredAttrs();
auto structuredAttrs = parsedDrv->getStructuredAttrs();
if (!structuredAttrs) return;

auto json = *structuredAttrs;
1 change: 0 additions & 1 deletion src/libstore/builtins.hh
Original file line number Diff line number Diff line change
@@ -6,6 +6,5 @@ namespace nix {

// TODO: make pluggable.
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
void builtinBuildenv(const BasicDerivation & drv);

}
120 changes: 55 additions & 65 deletions src/libstore/builtins/buildenv.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "builtins.hh"
#include "buildenv.hh"

#include <sys/stat.h>
#include <sys/types.h>
@@ -7,16 +7,14 @@

namespace nix {

typedef std::map<Path,int> Priorities;

// FIXME: change into local variables.

static Priorities priorities;

static unsigned long symlinks;
struct State
{
std::map<Path, int> priorities;
unsigned long symlinks = 0;
};

/* For each activated package, create symlinks */
static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
static void createLinks(State & state, const Path & srcDir, const Path & dstDir, int priority)
{
DirEntries srcFiles;

@@ -67,7 +65,7 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISDIR(dstSt.st_mode)) {
createLinks(srcFile, dstFile, priority);
createLinks(state, srcFile, dstFile, priority);
continue;
} else if (S_ISLNK(dstSt.st_mode)) {
auto target = canonPath(dstFile, true);
@@ -77,8 +75,8 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
throw SysError(format("unlinking '%1%'") % dstFile);
if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'"));
createLinks(target, dstFile, priorities[dstFile]);
createLinks(srcFile, dstFile, priority);
createLinks(state, target, dstFile, state.priorities[dstFile]);
createLinks(state, srcFile, dstFile, priority);
continue;
}
} else if (errno != ENOENT)
@@ -90,7 +88,7 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = priorities[dstFile];
auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority)
throw Error(
"packages '%1%' and '%2%' have the same priority %3%; "
@@ -109,41 +107,57 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
}

createSymlink(srcFile, dstFile);
priorities[dstFile] = priority;
symlinks++;
state.priorities[dstFile] = priority;
state.symlinks++;
}
}

typedef std::set<Path> FileProp;
void buildProfile(const Path & out, Packages && pkgs)
{
State state;

static FileProp done;
static FileProp postponed = FileProp{};
std::set<Path> done, postponed;

static Path out;
auto addPkg = [&](const Path & pkgDir, int priority) {
if (!done.insert(pkgDir).second) return;
createLinks(state, pkgDir, out, priority);

static void addPkg(const Path & pkgDir, int priority)
{
if (!done.insert(pkgDir).second) return;
createLinks(pkgDir, out, priority);
try {
for (const auto & p : tokenizeString<std::vector<string>>(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
if (!done.count(p))
postponed.insert(p);
} catch (SysError & e) {
if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
}
};

try {
for (const auto & p : tokenizeString<std::vector<string>>(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
if (!done.count(p))
postponed.insert(p);
} catch (SysError & e) {
if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
}
}
/* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
});
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);

struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};
/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
std::set<Path> pkgDirs;
postponed.swap(pkgDirs);
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}

typedef std::vector<Package> Packages;
printError("created %d symlinks in user environment", state.symlinks);
}

void builtinBuildenv(const BasicDerivation & drv)
{
@@ -153,7 +167,7 @@ void builtinBuildenv(const BasicDerivation & drv)
return i->second;
};

out = getAttr("out");
Path out = getAttr("out");
createDirs(out);

/* Convert the stuff we get from the environment back into a
@@ -171,31 +185,7 @@ void builtinBuildenv(const BasicDerivation & drv)
}
}

/* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
});
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);

/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
auto pkgDirs = postponed;
postponed = FileProp{};
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}

printError("created %d symlinks in user environment", symlinks);
buildProfile(out, std::move(pkgs));

createSymlink(getAttr("manifest"), out + "/manifest.nix");
}
21 changes: 21 additions & 0 deletions src/libstore/builtins/buildenv.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "derivations.hh"
#include "store-api.hh"

namespace nix {

struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};

typedef std::vector<Package> Packages;

void buildProfile(const Path & out, Packages && pkgs);

void builtinBuildenv(const BasicDerivation & drv);

}
24 changes: 20 additions & 4 deletions src/libstore/local-store.cc
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
#include "worker-protocol.hh"
#include "derivations.hh"
#include "nar-info.hh"
#include "references.hh"

#include <iostream>
#include <algorithm>
@@ -1002,17 +1003,24 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,

/* While restoring the path from the NAR, compute the hash
of the NAR. */
HashSink hashSink(htSHA256);
std::unique_ptr<AbstractHashSink> hashSink;
if (info.ca == "")
hashSink = std::make_unique<HashSink>(htSHA256);
else {
if (!info.references.empty())
settings.requireExperimentalFeature("ca-references");
hashSink = std::make_unique<HashModuloSink>(htSHA256, storePathToHash(info.path));
}

LambdaSource wrapperSource([&](unsigned char * data, size_t len) -> size_t {
size_t n = source.read(data, len);
hashSink(data, n);
(*hashSink)(data, n);
return n;
});

restorePath(realPath, wrapperSource);

auto hashResult = hashSink.finish();
auto hashResult = hashSink->finish();

if (hashResult.first != info.narHash)
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
@@ -1234,7 +1242,15 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)

/* Check the content hash (optionally - slow). */
printMsg(lvlTalkative, format("checking contents of '%1%'") % i);
HashResult current = hashPath(info->narHash.type, toRealPath(i));

std::unique_ptr<AbstractHashSink> hashSink;
if (info->ca == "")
hashSink = std::make_unique<HashSink>(info->narHash.type);
else
hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(info->path));

dumpPath(toRealPath(i), *hashSink);
auto current = hashSink->finish();

if (info->narHash != nullHash && info->narHash != current.first) {
printError(format("path '%1%' was modified! "
Loading