Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into substitute-other-st…
Browse files Browse the repository at this point in the history
…oredir
  • Loading branch information
matthewbauer committed Jun 22, 2020
2 parents f2a6cee + 965b803 commit 66a62b3
Show file tree
Hide file tree
Showing 29 changed files with 278 additions and 199 deletions.
2 changes: 1 addition & 1 deletion src/libexpr/get-drvs.cc
@@ -1,7 +1,7 @@
#include "get-drvs.hh"
#include "util.hh"
#include "eval-inline.hh"
#include "derivations.hh"
#include "store-api.hh"

#include <cstring>
#include <regex>
Expand Down
6 changes: 3 additions & 3 deletions src/libexpr/primops.cc
Expand Up @@ -776,7 +776,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (!jsonObject) drv.env["out"] = state.store->printStorePath(outPath);
drv.outputs.insert_or_assign("out", DerivationOutput {
.path = std::move(outPath),
.hash = DerivationOutputHash {
.hash = FixedOutputHash {
.method = ingestionMethod,
.hash = std::move(h),
},
Expand All @@ -795,7 +795,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.outputs.insert_or_assign(i,
DerivationOutput {
.path = StorePath::dummy,
.hash = std::optional<DerivationOutputHash> {},
.hash = std::optional<FixedOutputHash> {},
});
}

Expand All @@ -807,7 +807,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.outputs.insert_or_assign(i,
DerivationOutput {
.path = std::move(outPath),
.hash = std::optional<DerivationOutputHash>(),
.hash = std::optional<FixedOutputHash>(),
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/primops/context.cc
@@ -1,6 +1,6 @@
#include "primops.hh"
#include "eval-inline.hh"
#include "derivations.hh"
#include "store-api.hh"

namespace nix {

Expand Down
5 changes: 4 additions & 1 deletion src/libfetchers/tarball.cc
Expand Up @@ -70,7 +70,10 @@ DownloadFileResult downloadFile(
ValidPathInfo info(store->makeFixedOutputPath(FileIngestionMethod::Flat, hash, name));
info.narHash = hashString(htSHA256, *sink.s);
info.narSize = sink.s->size();
info.ca = makeFixedOutputCA(FileIngestionMethod::Flat, hash);
info.ca = FixedOutputHash {
.method = FileIngestionMethod::Flat,
.hash = hash,
};
auto source = StringSource { *sink.s };
store->addToStore(info, source, NoRepair, NoCheckSigs);
storePath = std::move(info.path);
Expand Down
26 changes: 16 additions & 10 deletions src/libstore/build.cc
Expand Up @@ -297,7 +297,7 @@ class Worker
GoalPtr makeDerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
std::shared_ptr<DerivationGoal> makeBasicDerivationGoal(const StorePath & drvPath,
const BasicDerivation & drv, BuildMode buildMode = bmNormal);
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<std::string> ca = std::nullopt);
GoalPtr makeSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);

/* Remove a dead goal. */
void removeGoal(GoalPtr goal);
Expand Down Expand Up @@ -3714,7 +3714,7 @@ void DerivationGoal::registerOutputs()
/* Check that fixed-output derivations produced the right
outputs (i.e., the content hash should match the specified
hash). */
std::string ca;
std::optional<ContentAddress> ca;

if (fixedOutput) {

Expand Down Expand Up @@ -3764,7 +3764,10 @@ void DerivationGoal::registerOutputs()
else
assert(worker.store.parseStorePath(path) == dest);

ca = makeFixedOutputCA(i.second.hash->method, h2);
ca = FixedOutputHash {
.method = i.second.hash->method,
.hash = h2,
};
}

/* Get rid of all weird permissions. This also checks that
Expand Down Expand Up @@ -3837,7 +3840,10 @@ void DerivationGoal::registerOutputs()
info.ca = ca;
worker.store.signPathInfo(info);

if (!info.references.empty()) info.ca.clear();
if (!info.references.empty()) {
// FIXME don't we have an experimental feature for fixed output with references?
info.ca = {};
}

infos.emplace(i.first, std::move(info));
}
Expand Down Expand Up @@ -4295,10 +4301,10 @@ class SubstitutionGoal : public Goal
GoalState state;

/* Content address for recomputing store path */
std::optional<std::string> ca;
std::optional<ContentAddress> ca;

public:
SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<std::string> ca = std::nullopt);
SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
~SubstitutionGoal();

void timedOut(Error && ex) override { abort(); };
Expand Down Expand Up @@ -4328,7 +4334,7 @@ class SubstitutionGoal : public Goal
};


SubstitutionGoal::SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional<std::string> ca)
SubstitutionGoal::SubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
: Goal(worker)
, storePath(storePath)
, repair(repair)
Expand Down Expand Up @@ -4408,7 +4414,7 @@ void SubstitutionGoal::tryNext()
subs.pop_front();

auto subPath = storePath;
if (ca && (hasPrefix(*ca, "fixed:") || hasPrefix(*ca, "text:"))) {
if (ca) {
subPath = sub->makeFixedOutputPathFromCA(storePath.name(), *ca);
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
Expand Down Expand Up @@ -4537,7 +4543,7 @@ void SubstitutionGoal::tryToRun()
PushActivity pact(act.id);

auto subPath = storePath;
if (ca && (hasPrefix(*ca, "fixed:") || hasPrefix(*ca, "text:"))) {
if (ca) {
subPath = sub->makeFixedOutputPathFromCA(storePath.name(), *ca);
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
Expand Down Expand Up @@ -4677,7 +4683,7 @@ std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath
}


GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<std::string> ca)
GoalPtr Worker::makeSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca)
{
GoalPtr goal = substitutionGoals[path].lock(); // FIXME
if (!goal) {
Expand Down
85 changes: 85 additions & 0 deletions src/libstore/content-address.cc
@@ -0,0 +1,85 @@
#include "content-address.hh"

namespace nix {

std::string FixedOutputHash::printMethodAlgo() const {
return makeFileIngestionPrefix(method) + printHashType(*hash.type);
}

std::string makeFileIngestionPrefix(const FileIngestionMethod m) {
switch (m) {
case FileIngestionMethod::Flat:
return "";
case FileIngestionMethod::Recursive:
return "r:";
default:
throw Error("impossible, caught both cases");
}
}

std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash)
{
return "fixed:"
+ makeFileIngestionPrefix(method)
+ hash.to_string(Base32, true);
}

// FIXME Put this somewhere?
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

std::string renderContentAddress(ContentAddress ca) {
return std::visit(overloaded {
[](TextHash th) {
return "text:" + th.hash.to_string(Base32, true);
},
[](FixedOutputHash fsh) {
return makeFixedOutputCA(fsh.method, fsh.hash);
}
}, ca);
}

ContentAddress parseContentAddress(std::string_view rawCa) {
auto prefixSeparator = rawCa.find(':');
if (prefixSeparator != string::npos) {
auto prefix = string(rawCa, 0, prefixSeparator);
if (prefix == "text") {
auto hashTypeAndHash = rawCa.substr(prefixSeparator+1, string::npos);
Hash hash = Hash(string(hashTypeAndHash));
if (*hash.type != htSHA256) {
throw Error("parseContentAddress: the text hash should have type SHA256");
}
return TextHash { hash };
} else if (prefix == "fixed") {
// This has to be an inverse of makeFixedOutputCA
auto methodAndHash = rawCa.substr(prefixSeparator+1, string::npos);
if (methodAndHash.substr(0,2) == "r:") {
std::string_view hashRaw = methodAndHash.substr(2,string::npos);
return FixedOutputHash {
.method = FileIngestionMethod::Recursive,
.hash = Hash(string(hashRaw)),
};
} else {
std::string_view hashRaw = methodAndHash;
return FixedOutputHash {
.method = FileIngestionMethod::Flat,
.hash = Hash(string(hashRaw)),
};
}
} else {
throw Error("parseContentAddress: format not recognized; has to be text or fixed");
}
} else {
throw Error("Not a content address because it lacks an appropriate prefix");
}
};

std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt) {
return rawCaOpt == "" ? std::optional<ContentAddress> {} : parseContentAddress(rawCaOpt);
};

std::string renderContentAddress(std::optional<ContentAddress> ca) {
return ca ? renderContentAddress(*ca) : "";
}

}
56 changes: 56 additions & 0 deletions src/libstore/content-address.hh
@@ -0,0 +1,56 @@
#pragma once

#include <variant>
#include "hash.hh"

namespace nix {

enum struct FileIngestionMethod : uint8_t {
Flat = false,
Recursive = true
};

struct TextHash {
Hash hash;
};

/// Pair of a hash, and how the file system was ingested
struct FixedOutputHash {
FileIngestionMethod method;
Hash hash;
std::string printMethodAlgo() const;
};

/*
We've accumulated several types of content-addressed paths over the years;
fixed-output derivations support multiple hash algorithms and serialisation
methods (flat file vs NAR). Thus, ‘ca’ has one of the following forms:
* ‘text:sha256:<sha256 hash of file contents>’: For paths
computed by makeTextPath() / addTextToStore().
* ‘fixed:<r?>:<ht>:<h>’: For paths computed by
makeFixedOutputPath() / addToStore().
*/
typedef std::variant<
TextHash, // for paths computed by makeTextPath() / addTextToStore
FixedOutputHash // for path computed by makeFixedOutputPath
> ContentAddress;

/* Compute the prefix to the hash algorithm which indicates how the files were
ingested. */
std::string makeFileIngestionPrefix(const FileIngestionMethod m);

/* Compute the content-addressability assertion (ValidPathInfo::ca)
for paths created by makeFixedOutputPath() / addToStore(). */
std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash);

std::string renderContentAddress(ContentAddress ca);

std::string renderContentAddress(std::optional<ContentAddress> ca);

ContentAddress parseContentAddress(std::string_view rawCa);

std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt);

}
5 changes: 3 additions & 2 deletions src/libstore/daemon.cc
Expand Up @@ -658,7 +658,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
to << info->ultimate
<< info->sigs
<< info->ca;
<< renderContentAddress(info->ca);
}
} else {
assert(GET_PROTOCOL_MINOR(clientVersion) >= 17);
Expand Down Expand Up @@ -716,7 +716,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
info.references = readStorePaths<StorePathSet>(*store, from);
from >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(from);
from >> info.ca >> repair >> dontCheckSigs;
info.ca = parseContentAddressOpt(readString(from));
from >> repair >> dontCheckSigs;
if (!trusted && dontCheckSigs)
dontCheckSigs = false;
if (!trusted)
Expand Down
13 changes: 4 additions & 9 deletions src/libstore/derivations.cc
Expand Up @@ -8,11 +8,6 @@

namespace nix {

std::string DerivationOutputHash::printMethodAlgo() const {
return makeFileIngestionPrefix(method) + printHashType(*hash.type);
}


const StorePath & BasicDerivation::findOutput(const string & id) const
{
auto i = outputs.find(id);
Expand Down Expand Up @@ -113,15 +108,15 @@ static DerivationOutput parseDerivationOutput(const Store & store, istringstream
expect(str, ","); const auto hash = parseString(str);
expect(str, ")");

std::optional<DerivationOutputHash> fsh;
std::optional<FixedOutputHash> fsh;
if (hashAlgo != "") {
auto method = FileIngestionMethod::Flat;
if (string(hashAlgo, 0, 2) == "r:") {
method = FileIngestionMethod::Recursive;
hashAlgo = string(hashAlgo, 2);
}
const HashType hashType = parseHashType(hashAlgo);
fsh = DerivationOutputHash {
fsh = FixedOutputHash {
.method = std::move(method),
.hash = Hash(hash, hashType),
};
Expand Down Expand Up @@ -411,15 +406,15 @@ static DerivationOutput readDerivationOutput(Source & in, const Store & store)
auto hashAlgo = readString(in);
const auto hash = readString(in);

std::optional<DerivationOutputHash> fsh;
std::optional<FixedOutputHash> fsh;
if (hashAlgo != "") {
auto method = FileIngestionMethod::Flat;
if (string(hashAlgo, 0, 2) == "r:") {
method = FileIngestionMethod::Recursive;
hashAlgo = string(hashAlgo, 2);
}
const HashType hashType = parseHashType(hashAlgo);
fsh = DerivationOutputHash {
fsh = FixedOutputHash {
.method = std::move(method),
.hash = Hash(hash, hashType),
};
Expand Down
14 changes: 4 additions & 10 deletions src/libstore/derivations.hh
@@ -1,8 +1,9 @@
#pragma once

#include "path.hh"
#include "types.hh"
#include "hash.hh"
#include "store-api.hh"
#include "content-address.hh"

#include <map>

Expand All @@ -12,18 +13,10 @@ namespace nix {

/* Abstract syntax of derivations. */

/// Pair of a hash, and how the file system was ingested
struct DerivationOutputHash {
FileIngestionMethod method;
Hash hash;
std::string printMethodAlgo() const;
};

struct DerivationOutput
{
StorePath path;
std::optional<DerivationOutputHash> hash; /* hash used for expected hash computation */
void parseHashInfo(FileIngestionMethod & recursive, Hash & hash) const;
std::optional<FixedOutputHash> hash; /* hash used for expected hash computation */
};

typedef std::map<string, DerivationOutput> DerivationOutputs;
Expand Down Expand Up @@ -76,6 +69,7 @@ struct Derivation : BasicDerivation

class Store;

enum RepairFlag : bool { NoRepair = false, Repair = true };

/* Write a derivation to the Nix store, and return its path. */
StorePath writeDerivation(ref<Store> store,
Expand Down

0 comments on commit 66a62b3

Please sign in to comment.