forked from lix-project/lix
Merge remote-tracking branch 'origin/master' into markdown
This commit is contained in:
commit
0c94c17644
|
@ -21,13 +21,13 @@ clean-files += $(GCH) $(PCH)
|
||||||
|
|
||||||
ifeq ($(PRECOMPILE_HEADERS), 1)
|
ifeq ($(PRECOMPILE_HEADERS), 1)
|
||||||
|
|
||||||
ifeq ($(CXX), g++)
|
ifeq ($(findstring g++,$(CXX)), g++)
|
||||||
|
|
||||||
GLOBAL_CXXFLAGS_PCH += -include $(buildprefix)precompiled-headers.h -Winvalid-pch
|
GLOBAL_CXXFLAGS_PCH += -include $(buildprefix)precompiled-headers.h -Winvalid-pch
|
||||||
|
|
||||||
GLOBAL_ORDER_AFTER += $(GCH)
|
GLOBAL_ORDER_AFTER += $(GCH)
|
||||||
|
|
||||||
else ifeq ($(CXX), clang++)
|
else ifeq ($(findstring clang++,$(CXX)), clang++)
|
||||||
|
|
||||||
GLOBAL_CXXFLAGS_PCH += -include-pch $(PCH) -Winvalid-pch
|
GLOBAL_CXXFLAGS_PCH += -include-pch $(PCH) -Winvalid-pch
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ SV * queryReferences(char * path)
|
||||||
SV * queryPathHash(char * path)
|
SV * queryPathHash(char * path)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(Base32, true);
|
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash->to_string(Base32, true);
|
||||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
|
@ -106,7 +106,7 @@ SV * queryPathInfo(char * path, int base32)
|
||||||
XPUSHs(&PL_sv_undef);
|
XPUSHs(&PL_sv_undef);
|
||||||
else
|
else
|
||||||
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
|
||||||
auto s = info->narHash.to_string(base32 ? Base32 : Base16, true);
|
auto s = info->narHash->to_string(base32 ? Base32 : Base16, true);
|
||||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||||
mXPUSHi(info->registrationTime);
|
mXPUSHi(info->registrationTime);
|
||||||
mXPUSHi(info->narSize);
|
mXPUSHi(info->narSize);
|
||||||
|
@ -304,7 +304,10 @@ SV * derivationFromPath(char * drvPath)
|
||||||
|
|
||||||
HV * outputs = newHV();
|
HV * outputs = newHV();
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
hv_store(outputs, i.first.c_str(), i.first.size(), newSVpv(store()->printStorePath(i.second.path).c_str(), 0), 0);
|
hv_store(
|
||||||
|
outputs, i.first.c_str(), i.first.size(),
|
||||||
|
newSVpv(store()->printStorePath(i.second.path(*store(), drv.name)).c_str(), 0),
|
||||||
|
0);
|
||||||
hv_stores(hash, "outputs", newRV((SV *) outputs));
|
hv_stores(hash, "outputs", newRV((SV *) outputs));
|
||||||
|
|
||||||
AV * inputDrvs = newAV();
|
AV * inputDrvs = newAV();
|
||||||
|
|
|
@ -285,11 +285,10 @@ static std::shared_ptr<AttrDb> makeAttrDb(const Hash & fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalCache::EvalCache(
|
EvalCache::EvalCache(
|
||||||
bool useCache,
|
std::optional<std::reference_wrapper<const Hash>> useCache,
|
||||||
const Hash & fingerprint,
|
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
RootLoader rootLoader)
|
RootLoader rootLoader)
|
||||||
: db(useCache ? makeAttrDb(fingerprint) : nullptr)
|
: db(useCache ? makeAttrDb(*useCache) : nullptr)
|
||||||
, state(state)
|
, state(state)
|
||||||
, rootLoader(rootLoader)
|
, rootLoader(rootLoader)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace nix::eval_cache {
|
namespace nix::eval_cache {
|
||||||
|
@ -26,8 +27,7 @@ class EvalCache : public std::enable_shared_from_this<EvalCache>
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalCache(
|
EvalCache(
|
||||||
bool useCache,
|
std::optional<std::reference_wrapper<const Hash>> useCache,
|
||||||
const Hash & fingerprint,
|
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
RootLoader rootLoader);
|
RootLoader rootLoader);
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,6 @@ void emitTreeAttrs(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
const fetchers::Tree & tree,
|
const fetchers::Tree & tree,
|
||||||
const fetchers::Input & input,
|
const fetchers::Input & input,
|
||||||
Value & v);
|
Value & v, bool emptyRevFallback = false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
|
||||||
if (i == drv.outputs.end())
|
if (i == drv.outputs.end())
|
||||||
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
|
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
|
||||||
|
|
||||||
outPath = store->printStorePath(i->second.path);
|
outPath = store->printStorePath(i->second.path(*store, drv.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ void EvalState::realiseContext(const PathSet & context)
|
||||||
DerivationOutputs::iterator i = drv.outputs.find(outputName);
|
DerivationOutputs::iterator i = drv.outputs.find(outputName);
|
||||||
if (i == drv.outputs.end())
|
if (i == drv.outputs.end())
|
||||||
throw Error("derivation '%s' does not have an output named '%s'", ctxS, outputName);
|
throw Error("derivation '%s' does not have an output named '%s'", ctxS, outputName);
|
||||||
allowedPaths->insert(store->printStorePath(i->second.path));
|
allowedPaths->insert(store->printStorePath(i->second.path(*store, drv.name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,8 +91,17 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
||||||
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
|
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
if (state.store->isStorePath(path) && state.store->isValidPath(state.store->parseStorePath(path)) && isDerivation(path)) {
|
auto isValidDerivationInStore = [&]() -> std::optional<StorePath> {
|
||||||
Derivation drv = readDerivation(*state.store, realPath);
|
if (!state.store->isStorePath(path))
|
||||||
|
return std::nullopt;
|
||||||
|
auto storePath = state.store->parseStorePath(path);
|
||||||
|
if (!(state.store->isValidPath(storePath) && isDerivation(path)))
|
||||||
|
return std::nullopt;
|
||||||
|
return storePath;
|
||||||
|
};
|
||||||
|
if (auto optStorePath = isValidDerivationInStore()) {
|
||||||
|
auto storePath = *optStorePath;
|
||||||
|
Derivation drv = readDerivation(*state.store, realPath, Derivation::nameFromPath(storePath));
|
||||||
Value & w = *state.allocValue();
|
Value & w = *state.allocValue();
|
||||||
state.mkAttrs(w, 3 + drv.outputs.size());
|
state.mkAttrs(w, 3 + drv.outputs.size());
|
||||||
Value * v2 = state.allocAttr(w, state.sDrvPath);
|
Value * v2 = state.allocAttr(w, state.sDrvPath);
|
||||||
|
@ -106,7 +115,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
||||||
|
|
||||||
for (const auto & o : drv.outputs) {
|
for (const auto & o : drv.outputs) {
|
||||||
v2 = state.allocAttr(w, state.symbols.create(o.first));
|
v2 = state.allocAttr(w, state.symbols.create(o.first));
|
||||||
mkString(*v2, state.store->printStorePath(o.second.path), {"!" + o.first + "!" + path});
|
mkString(*v2, state.store->printStorePath(o.second.path(*state.store, drv.name)), {"!" + o.first + "!" + path});
|
||||||
outputsVal->listElems()[outputs_index] = state.allocValue();
|
outputsVal->listElems()[outputs_index] = state.allocValue();
|
||||||
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
||||||
}
|
}
|
||||||
|
@ -570,6 +579,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
|
|
||||||
/* Build the derivation expression by processing the attributes. */
|
/* Build the derivation expression by processing the attributes. */
|
||||||
Derivation drv;
|
Derivation drv;
|
||||||
|
drv.name = drvName;
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
|
||||||
|
@ -764,11 +774,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
auto outPath = state.store->makeFixedOutputPath(ingestionMethod, h, drvName);
|
auto outPath = state.store->makeFixedOutputPath(ingestionMethod, h, drvName);
|
||||||
if (!jsonObject) drv.env["out"] = state.store->printStorePath(outPath);
|
if (!jsonObject) drv.env["out"] = state.store->printStorePath(outPath);
|
||||||
drv.outputs.insert_or_assign("out", DerivationOutput {
|
drv.outputs.insert_or_assign("out", DerivationOutput {
|
||||||
.path = std::move(outPath),
|
.output = DerivationOutputFixed {
|
||||||
.hash = FixedOutputHash {
|
.hash = FixedOutputHash {
|
||||||
.method = ingestionMethod,
|
.method = ingestionMethod,
|
||||||
.hash = std::move(h),
|
.hash = std::move(h),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,8 +794,9 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
if (!jsonObject) drv.env[i] = "";
|
if (!jsonObject) drv.env[i] = "";
|
||||||
drv.outputs.insert_or_assign(i,
|
drv.outputs.insert_or_assign(i,
|
||||||
DerivationOutput {
|
DerivationOutput {
|
||||||
.path = StorePath::dummy,
|
.output = DerivationOutputInputAddressed {
|
||||||
.hash = std::optional<FixedOutputHash> {},
|
.path = StorePath::dummy,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,8 +807,9 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
if (!jsonObject) drv.env[i] = state.store->printStorePath(outPath);
|
if (!jsonObject) drv.env[i] = state.store->printStorePath(outPath);
|
||||||
drv.outputs.insert_or_assign(i,
|
drv.outputs.insert_or_assign(i,
|
||||||
DerivationOutput {
|
DerivationOutput {
|
||||||
.path = std::move(outPath),
|
.output = DerivationOutputInputAddressed {
|
||||||
.hash = std::optional<FixedOutputHash>(),
|
.path = std::move(outPath),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -817,7 +830,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), drvPathS, {"=" + drvPathS});
|
mkString(*state.allocAttr(v, state.sDrvPath), drvPathS, {"=" + drvPathS});
|
||||||
for (auto & i : drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
mkString(*state.allocAttr(v, state.symbols.create(i.first)),
|
mkString(*state.allocAttr(v, state.symbols.create(i.first)),
|
||||||
state.store->printStorePath(i.second.path), {"!" + i.first + "!" + drvPathS});
|
state.store->printStorePath(i.second.path(*state.store, drv.name)), {"!" + i.first + "!" + drvPathS});
|
||||||
}
|
}
|
||||||
v.attrs->sort();
|
v.attrs->sort();
|
||||||
}
|
}
|
||||||
|
@ -1111,7 +1124,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
|
|
||||||
|
|
||||||
static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_,
|
static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_,
|
||||||
Value * filterFun, FileIngestionMethod method, const Hash & expectedHash, Value & v)
|
Value * filterFun, FileIngestionMethod method, const std::optional<Hash> expectedHash, Value & v)
|
||||||
{
|
{
|
||||||
const auto path = evalSettings.pureEval && expectedHash ?
|
const auto path = evalSettings.pureEval && expectedHash ?
|
||||||
path_ :
|
path_ :
|
||||||
|
@ -1142,7 +1155,7 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
|
||||||
|
|
||||||
std::optional<StorePath> expectedStorePath;
|
std::optional<StorePath> expectedStorePath;
|
||||||
if (expectedHash)
|
if (expectedHash)
|
||||||
expectedStorePath = state.store->makeFixedOutputPath(method, expectedHash, name);
|
expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name);
|
||||||
Path dstPath;
|
Path dstPath;
|
||||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||||
dstPath = state.store->printStorePath(settings.readOnlyMode
|
dstPath = state.store->printStorePath(settings.readOnlyMode
|
||||||
|
@ -1176,7 +1189,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
|
|
||||||
addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, Hash(), v);
|
addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
@ -1186,7 +1199,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
string name;
|
string name;
|
||||||
Value * filterFun = nullptr;
|
Value * filterFun = nullptr;
|
||||||
auto method = FileIngestionMethod::Recursive;
|
auto method = FileIngestionMethod::Recursive;
|
||||||
Hash expectedHash;
|
Hash expectedHash(htSHA256);
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs) {
|
||||||
const string & n(attr.name);
|
const string & n(attr.name);
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
#include "primops.hh"
|
|
||||||
#include "eval-inline.hh"
|
|
||||||
#include "store-api.hh"
|
|
||||||
#include "hash.hh"
|
|
||||||
#include "fetchers.hh"
|
|
||||||
#include "url.hh"
|
|
||||||
|
|
||||||
namespace nix {
|
|
||||||
|
|
||||||
static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
|
||||||
{
|
|
||||||
std::string url;
|
|
||||||
std::optional<std::string> ref;
|
|
||||||
std::optional<Hash> rev;
|
|
||||||
std::string name = "source";
|
|
||||||
bool fetchSubmodules = false;
|
|
||||||
PathSet context;
|
|
||||||
|
|
||||||
state.forceValue(*args[0]);
|
|
||||||
|
|
||||||
if (args[0]->type == tAttrs) {
|
|
||||||
|
|
||||||
state.forceAttrs(*args[0], pos);
|
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
|
||||||
string n(attr.name);
|
|
||||||
if (n == "url")
|
|
||||||
url = state.coerceToString(*attr.pos, *attr.value, context, false, false);
|
|
||||||
else if (n == "ref")
|
|
||||||
ref = state.forceStringNoCtx(*attr.value, *attr.pos);
|
|
||||||
else if (n == "rev")
|
|
||||||
rev = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA1);
|
|
||||||
else if (n == "name")
|
|
||||||
name = state.forceStringNoCtx(*attr.value, *attr.pos);
|
|
||||||
else if (n == "submodules")
|
|
||||||
fetchSubmodules = state.forceBool(*attr.value, *attr.pos);
|
|
||||||
else
|
|
||||||
throw EvalError({
|
|
||||||
.hint = hintfmt("unsupported argument '%s' to 'fetchGit'", attr.name),
|
|
||||||
.errPos = *attr.pos
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.empty())
|
|
||||||
throw EvalError({
|
|
||||||
.hint = hintfmt("'url' argument required"),
|
|
||||||
.errPos = pos
|
|
||||||
});
|
|
||||||
|
|
||||||
} else
|
|
||||||
url = state.coerceToString(pos, *args[0], context, false, false);
|
|
||||||
|
|
||||||
// FIXME: git externals probably can be used to bypass the URI
|
|
||||||
// whitelist. Ah well.
|
|
||||||
state.checkURI(url);
|
|
||||||
|
|
||||||
if (evalSettings.pureEval && !rev)
|
|
||||||
throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
|
|
||||||
|
|
||||||
fetchers::Attrs attrs;
|
|
||||||
attrs.insert_or_assign("type", "git");
|
|
||||||
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
|
|
||||||
if (ref) attrs.insert_or_assign("ref", *ref);
|
|
||||||
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
|
|
||||||
if (fetchSubmodules) attrs.insert_or_assign("submodules", fetchers::Explicit<bool>{true});
|
|
||||||
auto input = fetchers::Input::fromAttrs(std::move(attrs));
|
|
||||||
|
|
||||||
// FIXME: use name?
|
|
||||||
auto [tree, input2] = input.fetch(state.store);
|
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
|
||||||
auto storePath = state.store->printStorePath(tree.storePath);
|
|
||||||
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
|
|
||||||
// Backward compatibility: set 'rev' to
|
|
||||||
// 0000000000000000000000000000000000000000 for a dirty tree.
|
|
||||||
auto rev2 = input2.getRev().value_or(Hash(htSHA1));
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev());
|
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev2.gitShortRev());
|
|
||||||
// Backward compatibility: set 'revCount' to 0 for a dirty tree.
|
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")),
|
|
||||||
input2.getRevCount().value_or(0));
|
|
||||||
mkBool(*state.allocAttr(v, state.symbols.create("submodules")), fetchSubmodules);
|
|
||||||
v.attrs->sort();
|
|
||||||
|
|
||||||
if (state.allowedPaths)
|
|
||||||
state.allowedPaths->insert(tree.actualPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,7 +14,8 @@ void emitTreeAttrs(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
const fetchers::Tree & tree,
|
const fetchers::Tree & tree,
|
||||||
const fetchers::Input & input,
|
const fetchers::Input & input,
|
||||||
Value & v)
|
Value & v,
|
||||||
|
bool emptyRevFallback)
|
||||||
{
|
{
|
||||||
assert(input.isImmutable());
|
assert(input.isImmutable());
|
||||||
|
|
||||||
|
@ -34,10 +35,20 @@ void emitTreeAttrs(
|
||||||
if (auto rev = input.getRev()) {
|
if (auto rev = input.getRev()) {
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
|
||||||
|
} else if (emptyRevFallback) {
|
||||||
|
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
||||||
|
auto emptyHash = Hash(htSHA1);
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), emptyHash.gitRev());
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), emptyHash.gitRev());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.getType() == "git")
|
||||||
|
mkBool(*state.allocAttr(v, state.symbols.create("submodules")), maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
|
||||||
|
|
||||||
if (auto revCount = input.getRevCount())
|
if (auto revCount = input.getRevCount())
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
||||||
|
else if (emptyRevFallback)
|
||||||
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), 0);
|
||||||
|
|
||||||
if (auto lastModified = input.getLastModified()) {
|
if (auto lastModified = input.getLastModified()) {
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
|
mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
|
||||||
|
@ -48,10 +59,26 @@ void emitTreeAttrs(
|
||||||
v.attrs->sort();
|
v.attrs->sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
std::string fixURI(std::string uri, EvalState &state)
|
||||||
{
|
{
|
||||||
settings.requireExperimentalFeature("flakes");
|
state.checkURI(uri);
|
||||||
|
return uri.find("://") != std::string::npos ? uri : "file://" + uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addURI(EvalState &state, fetchers::Attrs &attrs, Symbol name, std::string v)
|
||||||
|
{
|
||||||
|
string n(name);
|
||||||
|
attrs.emplace(name, n == "url" ? fixURI(v, state) : v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fetchTree(
|
||||||
|
EvalState &state,
|
||||||
|
const Pos &pos,
|
||||||
|
Value **args,
|
||||||
|
Value &v,
|
||||||
|
const std::optional<std::string> type,
|
||||||
|
bool emptyRevFallback = false
|
||||||
|
) {
|
||||||
fetchers::Input input;
|
fetchers::Input input;
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
|
||||||
|
@ -64,8 +91,15 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs) {
|
||||||
state.forceValue(*attr.value);
|
state.forceValue(*attr.value);
|
||||||
if (attr.value->type == tString)
|
if (attr.value->type == tPath || attr.value->type == tString)
|
||||||
attrs.emplace(attr.name, attr.value->string.s);
|
addURI(
|
||||||
|
state,
|
||||||
|
attrs,
|
||||||
|
attr.name,
|
||||||
|
state.coerceToString(*attr.pos, *attr.value, context, false, false)
|
||||||
|
);
|
||||||
|
else if (attr.value->type == tString)
|
||||||
|
addURI(state, attrs, attr.name, attr.value->string.s);
|
||||||
else if (attr.value->type == tBool)
|
else if (attr.value->type == tBool)
|
||||||
attrs.emplace(attr.name, fetchers::Explicit<bool>{attr.value->boolean});
|
attrs.emplace(attr.name, fetchers::Explicit<bool>{attr.value->boolean});
|
||||||
else if (attr.value->type == tInt)
|
else if (attr.value->type == tInt)
|
||||||
|
@ -75,6 +109,9 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
attr.name, showType(*attr.value));
|
attr.name, showType(*attr.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
attrs.emplace("type", type.value());
|
||||||
|
|
||||||
if (!attrs.count("type"))
|
if (!attrs.count("type"))
|
||||||
throw Error({
|
throw Error({
|
||||||
.hint = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
|
.hint = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
|
||||||
|
@ -82,8 +119,18 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
});
|
});
|
||||||
|
|
||||||
input = fetchers::Input::fromAttrs(std::move(attrs));
|
input = fetchers::Input::fromAttrs(std::move(attrs));
|
||||||
} else
|
} else {
|
||||||
input = fetchers::Input::fromURL(state.coerceToString(pos, *args[0], context, false, false));
|
auto url = fixURI(state.coerceToString(pos, *args[0], context, false, false), state);
|
||||||
|
|
||||||
|
if (type == "git") {
|
||||||
|
fetchers::Attrs attrs;
|
||||||
|
attrs.emplace("type", "git");
|
||||||
|
attrs.emplace("url", url);
|
||||||
|
input = fetchers::Input::fromAttrs(std::move(attrs));
|
||||||
|
} else {
|
||||||
|
input = fetchers::Input::fromURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!evalSettings.pureEval && !input.isDirect())
|
if (!evalSettings.pureEval && !input.isDirect())
|
||||||
input = lookupInRegistries(state.store, input).first;
|
input = lookupInRegistries(state.store, input).first;
|
||||||
|
@ -96,7 +143,13 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
if (state.allowedPaths)
|
if (state.allowedPaths)
|
||||||
state.allowedPaths->insert(tree.actualPath);
|
state.allowedPaths->insert(tree.actualPath);
|
||||||
|
|
||||||
emitTreeAttrs(state, tree, input2, v);
|
emitTreeAttrs(state, tree, input2, v, emptyRevFallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
settings.requireExperimentalFeature("flakes");
|
||||||
|
fetchTree(state, pos, args, v, std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r("fetchTree", 1, prim_fetchTree);
|
static RegisterPrimOp r("fetchTree", 1, prim_fetchTree);
|
||||||
|
@ -159,7 +212,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
||||||
: hashFile(htSHA256, path);
|
: hashFile(htSHA256, path);
|
||||||
if (hash != *expectedHash)
|
if (hash != *expectedHash)
|
||||||
throw Error((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
|
throw Error((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
|
||||||
*url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true));
|
*url, expectedHash->to_string(Base32, true), hash->to_string(Base32, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.allowedPaths)
|
if (state.allowedPaths)
|
||||||
|
@ -178,7 +231,13 @@ static void prim_fetchTarball(EvalState & state, const Pos & pos, Value * * args
|
||||||
fetch(state, pos, args, v, "fetchTarball", true, "source");
|
fetch(state, pos, args, v, "fetchTarball", true, "source");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prim_fetchGit(EvalState &state, const Pos &pos, Value **args, Value &v)
|
||||||
|
{
|
||||||
|
fetchTree(state, pos, args, v, "git", true);
|
||||||
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r2("__fetchurl", 1, prim_fetchurl);
|
static RegisterPrimOp r2("__fetchurl", 1, prim_fetchurl);
|
||||||
static RegisterPrimOp r3("fetchTarball", 1, prim_fetchTarball);
|
static RegisterPrimOp r3("fetchTarball", 1, prim_fetchTarball);
|
||||||
|
static RegisterPrimOp r4("fetchGit", 1, prim_fetchGit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,12 +130,12 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
|
||||||
tree.actualPath = store->toRealPath(tree.storePath);
|
tree.actualPath = store->toRealPath(tree.storePath);
|
||||||
|
|
||||||
auto narHash = store->queryPathInfo(tree.storePath)->narHash;
|
auto narHash = store->queryPathInfo(tree.storePath)->narHash;
|
||||||
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
|
input.attrs.insert_or_assign("narHash", narHash->to_string(SRI, true));
|
||||||
|
|
||||||
if (auto prevNarHash = getNarHash()) {
|
if (auto prevNarHash = getNarHash()) {
|
||||||
if (narHash != *prevNarHash)
|
if (narHash != *prevNarHash)
|
||||||
throw Error("NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
|
throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
|
||||||
to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash.to_string(SRI, true));
|
to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash->to_string(SRI, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto prevLastModified = getLastModified()) {
|
if (auto prevLastModified = getLastModified()) {
|
||||||
|
|
|
@ -178,7 +178,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource
|
||||||
auto [fileHash, fileSize] = fileHashSink.finish();
|
auto [fileHash, fileSize] = fileHashSink.finish();
|
||||||
narInfo->fileHash = fileHash;
|
narInfo->fileHash = fileHash;
|
||||||
narInfo->fileSize = fileSize;
|
narInfo->fileSize = fileSize;
|
||||||
narInfo->url = "nar/" + narInfo->fileHash.to_string(Base32, false) + ".nar"
|
narInfo->url = "nar/" + narInfo->fileHash->to_string(Base32, false) + ".nar"
|
||||||
+ (compression == "xz" ? ".xz" :
|
+ (compression == "xz" ? ".xz" :
|
||||||
compression == "bzip2" ? ".bz2" :
|
compression == "bzip2" ? ".bz2" :
|
||||||
compression == "br" ? ".br" :
|
compression == "br" ? ".br" :
|
||||||
|
@ -372,7 +372,7 @@ StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath
|
||||||
method for very large paths, but `copyPath' is mainly used for
|
method for very large paths, but `copyPath' is mainly used for
|
||||||
small files. */
|
small files. */
|
||||||
StringSink sink;
|
StringSink sink;
|
||||||
Hash h;
|
std::optional<Hash> h;
|
||||||
if (method == FileIngestionMethod::Recursive) {
|
if (method == FileIngestionMethod::Recursive) {
|
||||||
dumpPath(srcPath, sink, filter);
|
dumpPath(srcPath, sink, filter);
|
||||||
h = hashString(hashAlgo, *sink.s);
|
h = hashString(hashAlgo, *sink.s);
|
||||||
|
@ -382,7 +382,7 @@ StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath
|
||||||
h = hashString(hashAlgo, s);
|
h = hashString(hashAlgo, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidPathInfo info(makeFixedOutputPath(method, h, name));
|
ValidPathInfo info(makeFixedOutputPath(method, *h, name));
|
||||||
|
|
||||||
auto source = StringSource { *sink.s };
|
auto source = StringSource { *sink.s };
|
||||||
addToStore(info, source, repair, CheckSigs);
|
addToStore(info, source, repair, CheckSigs);
|
||||||
|
|
|
@ -1047,7 +1047,7 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation
|
||||||
{
|
{
|
||||||
this->drv = std::make_unique<BasicDerivation>(BasicDerivation(drv));
|
this->drv = std::make_unique<BasicDerivation>(BasicDerivation(drv));
|
||||||
state = &DerivationGoal::haveDerivation;
|
state = &DerivationGoal::haveDerivation;
|
||||||
name = fmt("building of %s", worker.store.showPaths(drv.outputPaths()));
|
name = fmt("building of %s", worker.store.showPaths(drv.outputPaths(worker.store)));
|
||||||
trace("created");
|
trace("created");
|
||||||
|
|
||||||
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
|
||||||
|
@ -1182,7 +1182,7 @@ void DerivationGoal::haveDerivation()
|
||||||
retrySubstitution = false;
|
retrySubstitution = false;
|
||||||
|
|
||||||
for (auto & i : drv->outputs)
|
for (auto & i : drv->outputs)
|
||||||
worker.store.addTempRoot(i.second.path);
|
worker.store.addTempRoot(i.second.path(worker.store, drv->name));
|
||||||
|
|
||||||
/* Check what outputs paths are not already valid. */
|
/* Check what outputs paths are not already valid. */
|
||||||
auto invalidOutputs = checkPathValidity(false, buildMode == bmRepair);
|
auto invalidOutputs = checkPathValidity(false, buildMode == bmRepair);
|
||||||
|
@ -1290,12 +1290,12 @@ void DerivationGoal::repairClosure()
|
||||||
StorePathSet outputClosure;
|
StorePathSet outputClosure;
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
if (!wantOutput(i.first, wantedOutputs)) continue;
|
if (!wantOutput(i.first, wantedOutputs)) continue;
|
||||||
worker.store.computeFSClosure(i.second.path, outputClosure);
|
worker.store.computeFSClosure(i.second.path(worker.store, drv->name), outputClosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter out our own outputs (which we have already checked). */
|
/* Filter out our own outputs (which we have already checked). */
|
||||||
for (auto & i : drv->outputs)
|
for (auto & i : drv->outputs)
|
||||||
outputClosure.erase(i.second.path);
|
outputClosure.erase(i.second.path(worker.store, drv->name));
|
||||||
|
|
||||||
/* Get all dependencies of this derivation so that we know which
|
/* Get all dependencies of this derivation so that we know which
|
||||||
derivation is responsible for which path in the output
|
derivation is responsible for which path in the output
|
||||||
|
@ -1307,7 +1307,7 @@ void DerivationGoal::repairClosure()
|
||||||
if (i.isDerivation()) {
|
if (i.isDerivation()) {
|
||||||
Derivation drv = worker.store.derivationFromPath(i);
|
Derivation drv = worker.store.derivationFromPath(i);
|
||||||
for (auto & j : drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
outputsToDrv.insert_or_assign(j.second.path, i);
|
outputsToDrv.insert_or_assign(j.second.path(worker.store, drv.name), i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check each path (slow!). */
|
/* Check each path (slow!). */
|
||||||
|
@ -1379,7 +1379,7 @@ void DerivationGoal::inputsRealised()
|
||||||
for (auto & j : i.second) {
|
for (auto & j : i.second) {
|
||||||
auto k = inDrv.outputs.find(j);
|
auto k = inDrv.outputs.find(j);
|
||||||
if (k != inDrv.outputs.end())
|
if (k != inDrv.outputs.end())
|
||||||
worker.store.computeFSClosure(k->second.path, inputPaths);
|
worker.store.computeFSClosure(k->second.path(worker.store, inDrv.name), inputPaths);
|
||||||
else
|
else
|
||||||
throw Error(
|
throw Error(
|
||||||
"derivation '%s' requires non-existent output '%s' from input derivation '%s'",
|
"derivation '%s' requires non-existent output '%s' from input derivation '%s'",
|
||||||
|
@ -1432,7 +1432,7 @@ void DerivationGoal::tryToBuild()
|
||||||
goal can start a build, and if not, the main loop will sleep a
|
goal can start a build, and if not, the main loop will sleep a
|
||||||
few seconds and then retry this goal. */
|
few seconds and then retry this goal. */
|
||||||
PathSet lockFiles;
|
PathSet lockFiles;
|
||||||
for (auto & outPath : drv->outputPaths())
|
for (auto & outPath : drv->outputPaths(worker.store))
|
||||||
lockFiles.insert(worker.store.Store::toRealPath(outPath));
|
lockFiles.insert(worker.store.Store::toRealPath(outPath));
|
||||||
|
|
||||||
if (!outputLocks.lockPaths(lockFiles, "", false)) {
|
if (!outputLocks.lockPaths(lockFiles, "", false)) {
|
||||||
|
@ -1460,16 +1460,16 @@ void DerivationGoal::tryToBuild()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPaths = drv->outputPaths();
|
missingPaths = drv->outputPaths(worker.store);
|
||||||
if (buildMode != bmCheck)
|
if (buildMode != bmCheck)
|
||||||
for (auto & i : validPaths) missingPaths.erase(i);
|
for (auto & i : validPaths) missingPaths.erase(i);
|
||||||
|
|
||||||
/* If any of the outputs already exist but are not valid, delete
|
/* If any of the outputs already exist but are not valid, delete
|
||||||
them. */
|
them. */
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
if (worker.store.isValidPath(i.second.path)) continue;
|
if (worker.store.isValidPath(i.second.path(worker.store, drv->name))) continue;
|
||||||
debug("removing invalid path '%s'", worker.store.printStorePath(i.second.path));
|
debug("removing invalid path '%s'", worker.store.printStorePath(i.second.path(worker.store, drv->name)));
|
||||||
deletePath(worker.store.Store::toRealPath(i.second.path));
|
deletePath(worker.store.Store::toRealPath(i.second.path(worker.store, drv->name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't do a remote build if the derivation has the attribute
|
/* Don't do a remote build if the derivation has the attribute
|
||||||
|
@ -1692,7 +1692,7 @@ void DerivationGoal::buildDone()
|
||||||
fmt("running post-build-hook '%s'", settings.postBuildHook),
|
fmt("running post-build-hook '%s'", settings.postBuildHook),
|
||||||
Logger::Fields{worker.store.printStorePath(drvPath)});
|
Logger::Fields{worker.store.printStorePath(drvPath)});
|
||||||
PushActivity pact(act.id);
|
PushActivity pact(act.id);
|
||||||
auto outputPaths = drv->outputPaths();
|
auto outputPaths = drv->outputPaths(worker.store);
|
||||||
std::map<std::string, std::string> hookEnvironment = getEnv();
|
std::map<std::string, std::string> hookEnvironment = getEnv();
|
||||||
|
|
||||||
hookEnvironment.emplace("DRV_PATH", worker.store.printStorePath(drvPath));
|
hookEnvironment.emplace("DRV_PATH", worker.store.printStorePath(drvPath));
|
||||||
|
@ -1920,7 +1920,7 @@ StorePathSet DerivationGoal::exportReferences(const StorePathSet & storePaths)
|
||||||
if (j.isDerivation()) {
|
if (j.isDerivation()) {
|
||||||
Derivation drv = worker.store.derivationFromPath(j);
|
Derivation drv = worker.store.derivationFromPath(j);
|
||||||
for (auto & k : drv.outputs)
|
for (auto & k : drv.outputs)
|
||||||
worker.store.computeFSClosure(k.second.path, paths);
|
worker.store.computeFSClosure(k.second.path(worker.store, drv.name), paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,7 +2015,7 @@ void DerivationGoal::startBuilder()
|
||||||
|
|
||||||
/* Substitute output placeholders with the actual output paths. */
|
/* Substitute output placeholders with the actual output paths. */
|
||||||
for (auto & output : drv->outputs)
|
for (auto & output : drv->outputs)
|
||||||
inputRewrites[hashPlaceholder(output.first)] = worker.store.printStorePath(output.second.path);
|
inputRewrites[hashPlaceholder(output.first)] = worker.store.printStorePath(output.second.path(worker.store, drv->name));
|
||||||
|
|
||||||
/* Construct the environment passed to the builder. */
|
/* Construct the environment passed to the builder. */
|
||||||
initEnv();
|
initEnv();
|
||||||
|
@ -2200,7 +2200,7 @@ void DerivationGoal::startBuilder()
|
||||||
(typically the dependencies of /bin/sh). Throw them
|
(typically the dependencies of /bin/sh). Throw them
|
||||||
out. */
|
out. */
|
||||||
for (auto & i : drv->outputs)
|
for (auto & i : drv->outputs)
|
||||||
dirsInChroot.erase(worker.store.printStorePath(i.second.path));
|
dirsInChroot.erase(worker.store.printStorePath(i.second.path(worker.store, drv->name)));
|
||||||
|
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
/* We don't really have any parent prep work to do (yet?)
|
/* We don't really have any parent prep work to do (yet?)
|
||||||
|
@ -2613,7 +2613,7 @@ void DerivationGoal::writeStructuredAttrs()
|
||||||
/* Add an "outputs" object containing the output paths. */
|
/* Add an "outputs" object containing the output paths. */
|
||||||
nlohmann::json outputs;
|
nlohmann::json outputs;
|
||||||
for (auto & i : drv->outputs)
|
for (auto & i : drv->outputs)
|
||||||
outputs[i.first] = rewriteStrings(worker.store.printStorePath(i.second.path), inputRewrites);
|
outputs[i.first] = rewriteStrings(worker.store.printStorePath(i.second.path(worker.store, drv->name)), inputRewrites);
|
||||||
json["outputs"] = outputs;
|
json["outputs"] = outputs;
|
||||||
|
|
||||||
/* Handle exportReferencesGraph. */
|
/* Handle exportReferencesGraph. */
|
||||||
|
@ -2817,7 +2817,7 @@ struct RestrictedStore : public LocalFSStore
|
||||||
auto drv = derivationFromPath(path.path);
|
auto drv = derivationFromPath(path.path);
|
||||||
for (auto & output : drv.outputs)
|
for (auto & output : drv.outputs)
|
||||||
if (wantOutput(output.first, path.outputs))
|
if (wantOutput(output.first, path.outputs))
|
||||||
newPaths.insert(output.second.path);
|
newPaths.insert(output.second.path(*this, drv.name));
|
||||||
} else if (!goal.isAllowed(path.path))
|
} else if (!goal.isAllowed(path.path))
|
||||||
throw InvalidPath("cannot build unknown path '%s' in recursive Nix", printStorePath(path.path));
|
throw InvalidPath("cannot build unknown path '%s' in recursive Nix", printStorePath(path.path));
|
||||||
}
|
}
|
||||||
|
@ -3579,7 +3579,7 @@ StorePathSet parseReferenceSpecifiers(Store & store, const BasicDerivation & drv
|
||||||
if (store.isStorePath(i))
|
if (store.isStorePath(i))
|
||||||
result.insert(store.parseStorePath(i));
|
result.insert(store.parseStorePath(i));
|
||||||
else if (drv.outputs.count(i))
|
else if (drv.outputs.count(i))
|
||||||
result.insert(drv.outputs.find(i)->second.path);
|
result.insert(drv.outputs.find(i)->second.path(store, drv.name));
|
||||||
else throw BuildError("derivation contains an illegal reference specifier '%s'", i);
|
else throw BuildError("derivation contains an illegal reference specifier '%s'", i);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -3617,7 +3617,7 @@ void DerivationGoal::registerOutputs()
|
||||||
if (hook) {
|
if (hook) {
|
||||||
bool allValid = true;
|
bool allValid = true;
|
||||||
for (auto & i : drv->outputs)
|
for (auto & i : drv->outputs)
|
||||||
if (!worker.store.isValidPath(i.second.path)) allValid = false;
|
if (!worker.store.isValidPath(i.second.path(worker.store, drv->name))) allValid = false;
|
||||||
if (allValid) return;
|
if (allValid) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3638,23 +3638,23 @@ void DerivationGoal::registerOutputs()
|
||||||
Nix calls. */
|
Nix calls. */
|
||||||
StorePathSet referenceablePaths;
|
StorePathSet referenceablePaths;
|
||||||
for (auto & p : inputPaths) referenceablePaths.insert(p);
|
for (auto & p : inputPaths) referenceablePaths.insert(p);
|
||||||
for (auto & i : drv->outputs) referenceablePaths.insert(i.second.path);
|
for (auto & i : drv->outputs) referenceablePaths.insert(i.second.path(worker.store, drv->name));
|
||||||
for (auto & p : addedPaths) referenceablePaths.insert(p);
|
for (auto & p : addedPaths) referenceablePaths.insert(p);
|
||||||
|
|
||||||
/* Check whether the output paths were created, and grep each
|
/* Check whether the output paths were created, and grep each
|
||||||
output path to determine what other paths it references. Also make all
|
output path to determine what other paths it references. Also make all
|
||||||
output paths read-only. */
|
output paths read-only. */
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
auto path = worker.store.printStorePath(i.second.path);
|
auto path = worker.store.printStorePath(i.second.path(worker.store, drv->name));
|
||||||
if (!missingPaths.count(i.second.path)) continue;
|
if (!missingPaths.count(i.second.path(worker.store, drv->name))) continue;
|
||||||
|
|
||||||
Path actualPath = path;
|
Path actualPath = path;
|
||||||
if (needsHashRewrite()) {
|
if (needsHashRewrite()) {
|
||||||
auto r = redirectedOutputs.find(i.second.path);
|
auto r = redirectedOutputs.find(i.second.path(worker.store, drv->name));
|
||||||
if (r != redirectedOutputs.end()) {
|
if (r != redirectedOutputs.end()) {
|
||||||
auto redirected = worker.store.Store::toRealPath(r->second);
|
auto redirected = worker.store.Store::toRealPath(r->second);
|
||||||
if (buildMode == bmRepair
|
if (buildMode == bmRepair
|
||||||
&& redirectedBadOutputs.count(i.second.path)
|
&& redirectedBadOutputs.count(i.second.path(worker.store, drv->name))
|
||||||
&& pathExists(redirected))
|
&& pathExists(redirected))
|
||||||
replaceValidPath(path, redirected);
|
replaceValidPath(path, redirected);
|
||||||
if (buildMode == bmCheck)
|
if (buildMode == bmCheck)
|
||||||
|
@ -3723,7 +3723,9 @@ void DerivationGoal::registerOutputs()
|
||||||
|
|
||||||
if (fixedOutput) {
|
if (fixedOutput) {
|
||||||
|
|
||||||
if (i.second.hash->method == FileIngestionMethod::Flat) {
|
FixedOutputHash outputHash = std::get<DerivationOutputFixed>(i.second.output).hash;
|
||||||
|
|
||||||
|
if (outputHash.method == FileIngestionMethod::Flat) {
|
||||||
/* The output path should be a regular file without execute permission. */
|
/* The output path should be a regular file without execute permission. */
|
||||||
if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
|
if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
|
||||||
throw BuildError(
|
throw BuildError(
|
||||||
|
@ -3734,13 +3736,13 @@ void DerivationGoal::registerOutputs()
|
||||||
|
|
||||||
/* Check the hash. In hash mode, move the path produced by
|
/* Check the hash. In hash mode, move the path produced by
|
||||||
the derivation to its content-addressed location. */
|
the derivation to its content-addressed location. */
|
||||||
Hash h2 = i.second.hash->method == FileIngestionMethod::Recursive
|
Hash h2 = outputHash.method == FileIngestionMethod::Recursive
|
||||||
? hashPath(*i.second.hash->hash.type, actualPath).first
|
? hashPath(outputHash.hash.type, actualPath).first
|
||||||
: hashFile(*i.second.hash->hash.type, actualPath);
|
: hashFile(outputHash.hash.type, actualPath);
|
||||||
|
|
||||||
auto dest = worker.store.makeFixedOutputPath(i.second.hash->method, h2, i.second.path.name());
|
auto dest = worker.store.makeFixedOutputPath(outputHash.method, h2, i.second.path(worker.store, drv->name).name());
|
||||||
|
|
||||||
if (i.second.hash->hash != h2) {
|
if (outputHash.hash != h2) {
|
||||||
|
|
||||||
/* Throw an error after registering the path as
|
/* Throw an error after registering the path as
|
||||||
valid. */
|
valid. */
|
||||||
|
@ -3748,7 +3750,7 @@ void DerivationGoal::registerOutputs()
|
||||||
delayedException = std::make_exception_ptr(
|
delayedException = std::make_exception_ptr(
|
||||||
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
|
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
|
||||||
worker.store.printStorePath(dest),
|
worker.store.printStorePath(dest),
|
||||||
i.second.hash->hash.to_string(SRI, true),
|
outputHash.hash.to_string(SRI, true),
|
||||||
h2.to_string(SRI, true)));
|
h2.to_string(SRI, true)));
|
||||||
|
|
||||||
Path actualDest = worker.store.Store::toRealPath(dest);
|
Path actualDest = worker.store.Store::toRealPath(dest);
|
||||||
|
@ -3770,7 +3772,7 @@ void DerivationGoal::registerOutputs()
|
||||||
assert(worker.store.parseStorePath(path) == dest);
|
assert(worker.store.parseStorePath(path) == dest);
|
||||||
|
|
||||||
ca = FixedOutputHash {
|
ca = FixedOutputHash {
|
||||||
.method = i.second.hash->method,
|
.method = outputHash.method,
|
||||||
.hash = h2,
|
.hash = h2,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3785,8 +3787,10 @@ void DerivationGoal::registerOutputs()
|
||||||
time. The hash is stored in the database so that we can
|
time. The hash is stored in the database so that we can
|
||||||
verify later on whether nobody has messed with the store. */
|
verify later on whether nobody has messed with the store. */
|
||||||
debug("scanning for references inside '%1%'", path);
|
debug("scanning for references inside '%1%'", path);
|
||||||
HashResult hash;
|
// HashResult hash;
|
||||||
auto references = worker.store.parseStorePathSet(scanForReferences(actualPath, worker.store.printStorePathSet(referenceablePaths), hash));
|
auto pathSetAndHash = scanForReferences(actualPath, worker.store.printStorePathSet(referenceablePaths));
|
||||||
|
auto references = worker.store.parseStorePathSet(pathSetAndHash.first);
|
||||||
|
HashResult hash = pathSetAndHash.second;
|
||||||
|
|
||||||
if (buildMode == bmCheck) {
|
if (buildMode == bmCheck) {
|
||||||
if (!worker.store.isValidPath(worker.store.parseStorePath(path))) continue;
|
if (!worker.store.isValidPath(worker.store.parseStorePath(path))) continue;
|
||||||
|
@ -3894,7 +3898,7 @@ void DerivationGoal::registerOutputs()
|
||||||
/* If this is the first round of several, then move the output out of the way. */
|
/* If this is the first round of several, then move the output out of the way. */
|
||||||
if (nrRounds > 1 && curRound == 1 && curRound < nrRounds && keepPreviousRound) {
|
if (nrRounds > 1 && curRound == 1 && curRound < nrRounds && keepPreviousRound) {
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
auto path = worker.store.printStorePath(i.second.path);
|
auto path = worker.store.printStorePath(i.second.path(worker.store, drv->name));
|
||||||
Path prev = path + checkSuffix;
|
Path prev = path + checkSuffix;
|
||||||
deletePath(prev);
|
deletePath(prev);
|
||||||
Path dst = path + checkSuffix;
|
Path dst = path + checkSuffix;
|
||||||
|
@ -3912,7 +3916,7 @@ void DerivationGoal::registerOutputs()
|
||||||
if the result was not determistic? */
|
if the result was not determistic? */
|
||||||
if (curRound == nrRounds) {
|
if (curRound == nrRounds) {
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
Path prev = worker.store.printStorePath(i.second.path) + checkSuffix;
|
Path prev = worker.store.printStorePath(i.second.path(worker.store, drv->name)) + checkSuffix;
|
||||||
deletePath(prev);
|
deletePath(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4213,9 +4217,9 @@ StorePathSet DerivationGoal::checkPathValidity(bool returnValid, bool checkHash)
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
if (!wantOutput(i.first, wantedOutputs)) continue;
|
if (!wantOutput(i.first, wantedOutputs)) continue;
|
||||||
bool good =
|
bool good =
|
||||||
worker.store.isValidPath(i.second.path) &&
|
worker.store.isValidPath(i.second.path(worker.store, drv->name)) &&
|
||||||
(!checkHash || worker.pathContentsGood(i.second.path));
|
(!checkHash || worker.pathContentsGood(i.second.path(worker.store, drv->name)));
|
||||||
if (good == returnValid) result.insert(i.second.path);
|
if (good == returnValid) result.insert(i.second.path(worker.store, drv->name));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -5008,7 +5012,7 @@ bool Worker::pathContentsGood(const StorePath & path)
|
||||||
if (!pathExists(store.printStorePath(path)))
|
if (!pathExists(store.printStorePath(path)))
|
||||||
res = false;
|
res = false;
|
||||||
else {
|
else {
|
||||||
HashResult current = hashPath(*info->narHash.type, store.printStorePath(path));
|
HashResult current = hashPath(info->narHash->type, store.printStorePath(path));
|
||||||
Hash nullHash(htSHA256);
|
Hash nullHash(htSHA256);
|
||||||
res = info->narHash == nullHash || info->narHash == current.first;
|
res = info->narHash == nullHash || info->narHash == current.first;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,16 +63,19 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
||||||
auto & output = drv.outputs.begin()->second;
|
auto & output = drv.outputs.begin()->second;
|
||||||
|
|
||||||
/* Try the hashed mirrors first. */
|
/* Try the hashed mirrors first. */
|
||||||
if (output.hash && output.hash->method == FileIngestionMethod::Flat)
|
if (auto hash = std::get_if<DerivationOutputFixed>(&output.output)) {
|
||||||
for (auto hashedMirror : settings.hashedMirrors.get())
|
if (hash->hash.method == FileIngestionMethod::Flat) {
|
||||||
try {
|
for (auto hashedMirror : settings.hashedMirrors.get()) {
|
||||||
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
|
try {
|
||||||
auto & h = output.hash->hash;
|
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
|
||||||
fetch(hashedMirror + printHashType(*h.type) + "/" + h.to_string(Base16, false));
|
fetch(hashedMirror + printHashType(hash->hash.hash.type) + "/" + hash->hash.hash.to_string(Base16, false));
|
||||||
return;
|
return;
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
debug(e.what());
|
debug(e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Otherwise try the specified URL. */
|
/* Otherwise try the specified URL. */
|
||||||
fetch(mainUrl);
|
fetch(mainUrl);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
std::string FixedOutputHash::printMethodAlgo() const {
|
std::string FixedOutputHash::printMethodAlgo() const {
|
||||||
return makeFileIngestionPrefix(method) + printHashType(*hash.type);
|
return makeFileIngestionPrefix(method) + printHashType(hash.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string makeFileIngestionPrefix(const FileIngestionMethod m) {
|
std::string makeFileIngestionPrefix(const FileIngestionMethod m) {
|
||||||
|
@ -46,7 +46,7 @@ ContentAddress parseContentAddress(std::string_view rawCa) {
|
||||||
if (prefix == "text") {
|
if (prefix == "text") {
|
||||||
auto hashTypeAndHash = rawCa.substr(prefixSeparator+1, string::npos);
|
auto hashTypeAndHash = rawCa.substr(prefixSeparator+1, string::npos);
|
||||||
Hash hash = Hash(string(hashTypeAndHash));
|
Hash hash = Hash(string(hashTypeAndHash));
|
||||||
if (*hash.type != htSHA256) {
|
if (hash.type != htSHA256) {
|
||||||
throw Error("parseContentAddress: the text hash should have type SHA256");
|
throw Error("parseContentAddress: the text hash should have type SHA256");
|
||||||
}
|
}
|
||||||
return TextHash { hash };
|
return TextHash { hash };
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct TunnelLogger : public Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
/* startWork() means that we're starting an operation for which we
|
/* startWork() means that we're starting an operation for which we
|
||||||
want to send out stderr to the client. */
|
want to send out stderr to the client. */
|
||||||
void startWork()
|
void startWork()
|
||||||
{
|
{
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
|
@ -289,7 +289,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
auto hash = store->queryPathInfo(path)->narHash;
|
auto hash = store->queryPathInfo(path)->narHash;
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
to << hash.to_string(Base16, false);
|
to << hash->to_string(Base16, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
case wopBuildDerivation: {
|
case wopBuildDerivation: {
|
||||||
auto drvPath = store->parseStorePath(readString(from));
|
auto drvPath = store->parseStorePath(readString(from));
|
||||||
BasicDerivation drv;
|
BasicDerivation drv;
|
||||||
readDerivation(from, *store, drv);
|
readDerivation(from, *store, drv, Derivation::nameFromPath(drvPath));
|
||||||
BuildMode buildMode = (BuildMode) readInt(from);
|
BuildMode buildMode = (BuildMode) readInt(from);
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
if (!trusted)
|
if (!trusted)
|
||||||
|
@ -632,7 +632,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 17)
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 17)
|
||||||
to << 1;
|
to << 1;
|
||||||
to << (info->deriver ? store->printStorePath(*info->deriver) : "")
|
to << (info->deriver ? store->printStorePath(*info->deriver) : "")
|
||||||
<< info->narHash.to_string(Base16, false);
|
<< info->narHash->to_string(Base16, false);
|
||||||
writeStorePaths(*store, to, info->references);
|
writeStorePaths(*store, to, info->references);
|
||||||
to << info->registrationTime << info->narSize;
|
to << info->registrationTime << info->narSize;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
|
||||||
|
@ -703,24 +703,84 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
if (!trusted)
|
if (!trusted)
|
||||||
info.ultimate = false;
|
info.ultimate = false;
|
||||||
|
|
||||||
std::unique_ptr<Source> source;
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 23) {
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 21)
|
|
||||||
source = std::make_unique<TunnelSource>(from, to);
|
struct FramedSource : Source
|
||||||
else {
|
{
|
||||||
StringSink saved;
|
Source & from;
|
||||||
TeeSource tee { from, saved };
|
bool eof = false;
|
||||||
ParseSink ether;
|
std::vector<unsigned char> pending;
|
||||||
parseDump(ether, tee);
|
size_t pos = 0;
|
||||||
source = std::make_unique<StringSource>(std::move(*saved.s));
|
|
||||||
|
FramedSource(Source & from) : from(from)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~FramedSource()
|
||||||
|
{
|
||||||
|
if (!eof) {
|
||||||
|
while (true) {
|
||||||
|
auto n = readInt(from);
|
||||||
|
if (!n) break;
|
||||||
|
std::vector<unsigned char> data(n);
|
||||||
|
from(data.data(), n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read(unsigned char * data, size_t len) override
|
||||||
|
{
|
||||||
|
if (eof) throw EndOfFile("reached end of FramedSource");
|
||||||
|
|
||||||
|
if (pos >= pending.size()) {
|
||||||
|
size_t len = readInt(from);
|
||||||
|
if (!len) {
|
||||||
|
eof = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pending = std::vector<unsigned char>(len);
|
||||||
|
pos = 0;
|
||||||
|
from(pending.data(), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto n = std::min(len, pending.size() - pos);
|
||||||
|
memcpy(data, pending.data() + pos, n);
|
||||||
|
pos += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
logger->startWork();
|
||||||
|
|
||||||
|
{
|
||||||
|
FramedSource source(from);
|
||||||
|
store->addToStore(info, source, (RepairFlag) repair,
|
||||||
|
dontCheckSigs ? NoCheckSigs : CheckSigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->stopWork();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger->startWork();
|
else {
|
||||||
|
std::unique_ptr<Source> source;
|
||||||
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 21)
|
||||||
|
source = std::make_unique<TunnelSource>(from, to);
|
||||||
|
else {
|
||||||
|
StringSink saved;
|
||||||
|
TeeSource tee { from, saved };
|
||||||
|
ParseSink ether;
|
||||||
|
parseDump(ether, tee);
|
||||||
|
source = std::make_unique<StringSource>(std::move(*saved.s));
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: race if addToStore doesn't read source?
|
logger->startWork();
|
||||||
store->addToStore(info, *source, (RepairFlag) repair,
|
|
||||||
dontCheckSigs ? NoCheckSigs : CheckSigs);
|
// FIXME: race if addToStore doesn't read source?
|
||||||
|
store->addToStore(info, *source, (RepairFlag) repair,
|
||||||
|
dontCheckSigs ? NoCheckSigs : CheckSigs);
|
||||||
|
|
||||||
|
logger->stopWork();
|
||||||
|
}
|
||||||
|
|
||||||
logger->stopWork();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,22 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
// FIXME Put this somewhere?
|
||||||
|
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
|
StorePath DerivationOutput::path(const Store & store, std::string_view drvName) const
|
||||||
|
{
|
||||||
|
return std::visit(overloaded {
|
||||||
|
[](DerivationOutputInputAddressed doi) {
|
||||||
|
return doi.path;
|
||||||
|
},
|
||||||
|
[&](DerivationOutputFixed dof) {
|
||||||
|
return store.makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName);
|
||||||
|
}
|
||||||
|
}, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BasicDerivation::isBuiltin() const
|
bool BasicDerivation::isBuiltin() const
|
||||||
{
|
{
|
||||||
|
@ -99,7 +115,6 @@ static DerivationOutput parseDerivationOutput(const Store & store, std::istrings
|
||||||
expect(str, ","); const auto hash = parseString(str);
|
expect(str, ","); const auto hash = parseString(str);
|
||||||
expect(str, ")");
|
expect(str, ")");
|
||||||
|
|
||||||
std::optional<FixedOutputHash> fsh;
|
|
||||||
if (hashAlgo != "") {
|
if (hashAlgo != "") {
|
||||||
auto method = FileIngestionMethod::Flat;
|
auto method = FileIngestionMethod::Flat;
|
||||||
if (string(hashAlgo, 0, 2) == "r:") {
|
if (string(hashAlgo, 0, 2) == "r:") {
|
||||||
|
@ -107,22 +122,29 @@ static DerivationOutput parseDerivationOutput(const Store & store, std::istrings
|
||||||
hashAlgo = string(hashAlgo, 2);
|
hashAlgo = string(hashAlgo, 2);
|
||||||
}
|
}
|
||||||
const HashType hashType = parseHashType(hashAlgo);
|
const HashType hashType = parseHashType(hashAlgo);
|
||||||
fsh = FixedOutputHash {
|
|
||||||
.method = std::move(method),
|
|
||||||
.hash = Hash(hash, hashType),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return DerivationOutput {
|
return DerivationOutput {
|
||||||
.path = std::move(path),
|
.output = DerivationOutputFixed {
|
||||||
.hash = std::move(fsh),
|
.hash = FixedOutputHash {
|
||||||
};
|
.method = std::move(method),
|
||||||
|
.hash = Hash(hash, hashType),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
return DerivationOutput {
|
||||||
|
.output = DerivationOutputInputAddressed {
|
||||||
|
.path = std::move(path),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Derivation parseDerivation(const Store & store, std::string && s)
|
static Derivation parseDerivation(const Store & store, std::string && s, std::string_view name)
|
||||||
{
|
{
|
||||||
Derivation drv;
|
Derivation drv;
|
||||||
|
drv.name = name;
|
||||||
|
|
||||||
std::istringstream str(std::move(s));
|
std::istringstream str(std::move(s));
|
||||||
expect(str, "Derive([");
|
expect(str, "Derive([");
|
||||||
|
|
||||||
|
@ -166,10 +188,10 @@ static Derivation parseDerivation(const Store & store, std::string && s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Derivation readDerivation(const Store & store, const Path & drvPath)
|
Derivation readDerivation(const Store & store, const Path & drvPath, std::string_view name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return parseDerivation(store, readFile(drvPath));
|
return parseDerivation(store, readFile(drvPath), name);
|
||||||
} catch (FormatError & e) {
|
} catch (FormatError & e) {
|
||||||
throw Error("error parsing derivation '%1%': %2%", drvPath, e.msg());
|
throw Error("error parsing derivation '%1%': %2%", drvPath, e.msg());
|
||||||
}
|
}
|
||||||
|
@ -187,7 +209,7 @@ Derivation Store::readDerivation(const StorePath & drvPath)
|
||||||
{
|
{
|
||||||
auto accessor = getFSAccessor();
|
auto accessor = getFSAccessor();
|
||||||
try {
|
try {
|
||||||
return parseDerivation(*this, accessor->readFile(printStorePath(drvPath)));
|
return parseDerivation(*this, accessor->readFile(printStorePath(drvPath)), Derivation::nameFromPath(drvPath));
|
||||||
} catch (FormatError & e) {
|
} catch (FormatError & e) {
|
||||||
throw Error("error parsing derivation '%s': %s", printStorePath(drvPath), e.msg());
|
throw Error("error parsing derivation '%s': %s", printStorePath(drvPath), e.msg());
|
||||||
}
|
}
|
||||||
|
@ -255,10 +277,14 @@ string Derivation::unparse(const Store & store, bool maskOutputs,
|
||||||
for (auto & i : outputs) {
|
for (auto & i : outputs) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printUnquotedString(s, i.first);
|
s += '('; printUnquotedString(s, i.first);
|
||||||
s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(i.second.path));
|
s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(i.second.path(store, name)));
|
||||||
s += ','; printUnquotedString(s, i.second.hash ? i.second.hash->printMethodAlgo() : "");
|
if (auto hash = std::get_if<DerivationOutputFixed>(&i.second.output)) {
|
||||||
s += ','; printUnquotedString(s,
|
s += ','; printUnquotedString(s, hash->hash.printMethodAlgo());
|
||||||
i.second.hash ? i.second.hash->hash.to_string(Base16, false) : "");
|
s += ','; printUnquotedString(s, hash->hash.hash.to_string(Base16, false));
|
||||||
|
} else {
|
||||||
|
s += ','; printUnquotedString(s, "");
|
||||||
|
s += ','; printUnquotedString(s, "");
|
||||||
|
}
|
||||||
s += ')';
|
s += ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +340,7 @@ bool BasicDerivation::isFixedOutput() const
|
||||||
{
|
{
|
||||||
return outputs.size() == 1 &&
|
return outputs.size() == 1 &&
|
||||||
outputs.begin()->first == "out" &&
|
outputs.begin()->first == "out" &&
|
||||||
outputs.begin()->second.hash;
|
std::holds_alternative<DerivationOutputFixed>(outputs.begin()->second.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -346,10 +372,11 @@ Hash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutput
|
||||||
/* Return a fixed hash for fixed-output derivations. */
|
/* Return a fixed hash for fixed-output derivations. */
|
||||||
if (drv.isFixedOutput()) {
|
if (drv.isFixedOutput()) {
|
||||||
DerivationOutputs::const_iterator i = drv.outputs.begin();
|
DerivationOutputs::const_iterator i = drv.outputs.begin();
|
||||||
|
auto hash = std::get<DerivationOutputFixed>(i->second.output);
|
||||||
return hashString(htSHA256, "fixed:out:"
|
return hashString(htSHA256, "fixed:out:"
|
||||||
+ i->second.hash->printMethodAlgo() + ":"
|
+ hash.hash.printMethodAlgo() + ":"
|
||||||
+ i->second.hash->hash.to_string(Base16, false) + ":"
|
+ hash.hash.hash.to_string(Base16, false) + ":"
|
||||||
+ store.printStorePath(i->second.path));
|
+ store.printStorePath(i->second.path(store, drv.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For other derivations, replace the inputs paths with recursive
|
/* For other derivations, replace the inputs paths with recursive
|
||||||
|
@ -383,11 +410,11 @@ bool wantOutput(const string & output, const std::set<string> & wanted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StorePathSet BasicDerivation::outputPaths() const
|
StorePathSet BasicDerivation::outputPaths(const Store & store) const
|
||||||
{
|
{
|
||||||
StorePathSet paths;
|
StorePathSet paths;
|
||||||
for (auto & i : outputs)
|
for (auto & i : outputs)
|
||||||
paths.insert(i.second.path);
|
paths.insert(i.second.path(store, name));
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +424,6 @@ static DerivationOutput readDerivationOutput(Source & in, const Store & store)
|
||||||
auto hashAlgo = readString(in);
|
auto hashAlgo = readString(in);
|
||||||
auto hash = readString(in);
|
auto hash = readString(in);
|
||||||
|
|
||||||
std::optional<FixedOutputHash> fsh;
|
|
||||||
if (hashAlgo != "") {
|
if (hashAlgo != "") {
|
||||||
auto method = FileIngestionMethod::Flat;
|
auto method = FileIngestionMethod::Flat;
|
||||||
if (string(hashAlgo, 0, 2) == "r:") {
|
if (string(hashAlgo, 0, 2) == "r:") {
|
||||||
|
@ -405,16 +431,20 @@ static DerivationOutput readDerivationOutput(Source & in, const Store & store)
|
||||||
hashAlgo = string(hashAlgo, 2);
|
hashAlgo = string(hashAlgo, 2);
|
||||||
}
|
}
|
||||||
auto hashType = parseHashType(hashAlgo);
|
auto hashType = parseHashType(hashAlgo);
|
||||||
fsh = FixedOutputHash {
|
return DerivationOutput {
|
||||||
.method = std::move(method),
|
.output = DerivationOutputFixed {
|
||||||
.hash = Hash(hash, hashType),
|
.hash = FixedOutputHash {
|
||||||
|
.method = std::move(method),
|
||||||
|
.hash = Hash(hash, hashType),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
return DerivationOutput {
|
||||||
|
.output = DerivationOutputInputAddressed {
|
||||||
|
.path = std::move(path),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return DerivationOutput {
|
|
||||||
.path = std::move(path),
|
|
||||||
.hash = std::move(fsh),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSet BasicDerivation::outputNames() const
|
StringSet BasicDerivation::outputNames() const
|
||||||
|
@ -426,8 +456,19 @@ StringSet BasicDerivation::outputNames() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv)
|
std::string_view BasicDerivation::nameFromPath(const StorePath & drvPath) {
|
||||||
|
auto nameWithSuffix = drvPath.name();
|
||||||
|
constexpr std::string_view extension = ".drv";
|
||||||
|
assert(hasSuffix(nameWithSuffix, extension));
|
||||||
|
nameWithSuffix.remove_suffix(extension.size());
|
||||||
|
return nameWithSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, std::string_view name)
|
||||||
{
|
{
|
||||||
|
drv.name = name;
|
||||||
|
|
||||||
drv.outputs.clear();
|
drv.outputs.clear();
|
||||||
auto nr = readNum<size_t>(in);
|
auto nr = readNum<size_t>(in);
|
||||||
for (size_t n = 0; n < nr; n++) {
|
for (size_t n = 0; n < nr; n++) {
|
||||||
|
@ -456,10 +497,10 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
out << drv.outputs.size();
|
out << drv.outputs.size();
|
||||||
for (auto & i : drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
out << i.first
|
out << i.first
|
||||||
<< store.printStorePath(i.second.path);
|
<< store.printStorePath(i.second.path(store, drv.name));
|
||||||
if (i.second.hash) {
|
if (auto hash = std::get_if<DerivationOutputFixed>(&i.second.output)) {
|
||||||
out << i.second.hash->printMethodAlgo()
|
out << hash->hash.printMethodAlgo()
|
||||||
<< i.second.hash->hash.to_string(Base16, false);
|
<< hash->hash.hash.to_string(Base16, false);
|
||||||
} else {
|
} else {
|
||||||
out << "" << "";
|
out << "" << "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,20 @@ namespace nix {
|
||||||
|
|
||||||
/* Abstract syntax of derivations. */
|
/* Abstract syntax of derivations. */
|
||||||
|
|
||||||
struct DerivationOutput
|
struct DerivationOutputInputAddressed
|
||||||
{
|
{
|
||||||
StorePath path;
|
StorePath path;
|
||||||
std::optional<FixedOutputHash> hash; /* hash used for expected hash computation */
|
};
|
||||||
|
|
||||||
|
struct DerivationOutputFixed
|
||||||
|
{
|
||||||
|
FixedOutputHash hash; /* hash used for expected hash computation */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DerivationOutput
|
||||||
|
{
|
||||||
|
std::variant<DerivationOutputInputAddressed, DerivationOutputFixed> output;
|
||||||
|
StorePath path(const Store & store, std::string_view drvName) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<string, DerivationOutput> DerivationOutputs;
|
typedef std::map<string, DerivationOutput> DerivationOutputs;
|
||||||
|
@ -35,6 +45,7 @@ struct BasicDerivation
|
||||||
Path builder;
|
Path builder;
|
||||||
Strings args;
|
Strings args;
|
||||||
StringPairs env;
|
StringPairs env;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
BasicDerivation() { }
|
BasicDerivation() { }
|
||||||
virtual ~BasicDerivation() { };
|
virtual ~BasicDerivation() { };
|
||||||
|
@ -45,10 +56,12 @@ struct BasicDerivation
|
||||||
bool isFixedOutput() const;
|
bool isFixedOutput() const;
|
||||||
|
|
||||||
/* Return the output paths of a derivation. */
|
/* Return the output paths of a derivation. */
|
||||||
StorePathSet outputPaths() const;
|
StorePathSet outputPaths(const Store & store) const;
|
||||||
|
|
||||||
/* Return the output names of a derivation. */
|
/* Return the output names of a derivation. */
|
||||||
StringSet outputNames() const;
|
StringSet outputNames() const;
|
||||||
|
|
||||||
|
static std::string_view nameFromPath(const StorePath & storePath);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Derivation : BasicDerivation
|
struct Derivation : BasicDerivation
|
||||||
|
@ -72,7 +85,7 @@ StorePath writeDerivation(ref<Store> store,
|
||||||
const Derivation & drv, std::string_view name, RepairFlag repair = NoRepair);
|
const Derivation & drv, std::string_view name, RepairFlag repair = NoRepair);
|
||||||
|
|
||||||
/* Read a derivation from a file. */
|
/* Read a derivation from a file. */
|
||||||
Derivation readDerivation(const Store & store, const Path & drvPath);
|
Derivation readDerivation(const Store & store, const Path & drvPath, std::string_view name);
|
||||||
|
|
||||||
// FIXME: remove
|
// FIXME: remove
|
||||||
bool isDerivation(const string & fileName);
|
bool isDerivation(const string & fileName);
|
||||||
|
@ -89,7 +102,7 @@ bool wantOutput(const string & output, const std::set<string> & wanted);
|
||||||
struct Source;
|
struct Source;
|
||||||
struct Sink;
|
struct Sink;
|
||||||
|
|
||||||
Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv);
|
Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, std::string_view name);
|
||||||
void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv);
|
void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv);
|
||||||
|
|
||||||
std::string hashPlaceholder(const std::string & outputName);
|
std::string hashPlaceholder(const std::string & outputName);
|
||||||
|
|
|
@ -38,9 +38,9 @@ void Store::exportPath(const StorePath & path, Sink & sink)
|
||||||
filesystem corruption from spreading to other machines.
|
filesystem corruption from spreading to other machines.
|
||||||
Don't complain if the stored hash is zero (unknown). */
|
Don't complain if the stored hash is zero (unknown). */
|
||||||
Hash hash = hashSink.currentHash().first;
|
Hash hash = hashSink.currentHash().first;
|
||||||
if (hash != info->narHash && info->narHash != Hash(*info->narHash.type))
|
if (hash != info->narHash && info->narHash != Hash(info->narHash->type))
|
||||||
throw Error("hash of path '%s' has changed from '%s' to '%s'!",
|
throw Error("hash of path '%s' has changed from '%s' to '%s'!",
|
||||||
printStorePath(path), info->narHash.to_string(Base32, true), hash.to_string(Base32, true));
|
printStorePath(path), info->narHash->to_string(Base32, true), hash.to_string(Base32, true));
|
||||||
|
|
||||||
teeSink
|
teeSink
|
||||||
<< exportMagic
|
<< exportMagic
|
||||||
|
|
|
@ -113,7 +113,7 @@ struct LegacySSHStore : public Store
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4) {
|
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4) {
|
||||||
auto s = readString(conn->from);
|
auto s = readString(conn->from);
|
||||||
info->narHash = s.empty() ? Hash() : Hash(s);
|
info->narHash = s.empty() ? std::optional<Hash>{} : Hash{s};
|
||||||
info->ca = parseContentAddressOpt(readString(conn->from));
|
info->ca = parseContentAddressOpt(readString(conn->from));
|
||||||
info->sigs = readStrings<StringSet>(conn->from);
|
info->sigs = readStrings<StringSet>(conn->from);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ struct LegacySSHStore : public Store
|
||||||
<< cmdAddToStoreNar
|
<< cmdAddToStoreNar
|
||||||
<< printStorePath(info.path)
|
<< printStorePath(info.path)
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< info.narHash.to_string(Base16, false);
|
<< info.narHash->to_string(Base16, false);
|
||||||
writeStorePaths(*this, conn->to, info.references);
|
writeStorePaths(*this, conn->to, info.references);
|
||||||
conn->to
|
conn->to
|
||||||
<< info.registrationTime
|
<< info.registrationTime
|
||||||
|
|
|
@ -560,19 +560,12 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
|
||||||
DerivationOutputs::const_iterator out = drv.outputs.find("out");
|
DerivationOutputs::const_iterator out = drv.outputs.find("out");
|
||||||
if (out == drv.outputs.end())
|
if (out == drv.outputs.end())
|
||||||
throw Error("derivation '%s' does not have an output named 'out'", printStorePath(drvPath));
|
throw Error("derivation '%s' does not have an output named 'out'", printStorePath(drvPath));
|
||||||
|
|
||||||
check(
|
|
||||||
makeFixedOutputPath(
|
|
||||||
out->second.hash->method,
|
|
||||||
out->second.hash->hash,
|
|
||||||
drvName),
|
|
||||||
out->second.path, "out");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
Hash h = hashDerivationModulo(*this, drv, true);
|
Hash h = hashDerivationModulo(*this, drv, true);
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
check(makeOutputPath(i.first, h, drvName), i.second.path, i.first);
|
check(makeOutputPath(i.first, h, drvName), i.second.path(*this, drv.name), i.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +579,7 @@ uint64_t LocalStore::addValidPath(State & state,
|
||||||
|
|
||||||
state.stmtRegisterValidPath.use()
|
state.stmtRegisterValidPath.use()
|
||||||
(printStorePath(info.path))
|
(printStorePath(info.path))
|
||||||
(info.narHash.to_string(Base16, true))
|
(info.narHash->to_string(Base16, true))
|
||||||
(info.registrationTime == 0 ? time(0) : info.registrationTime)
|
(info.registrationTime == 0 ? time(0) : info.registrationTime)
|
||||||
(info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver)
|
(info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver)
|
||||||
(info.narSize, info.narSize != 0)
|
(info.narSize, info.narSize != 0)
|
||||||
|
@ -614,7 +607,7 @@ uint64_t LocalStore::addValidPath(State & state,
|
||||||
state.stmtAddDerivationOutput.use()
|
state.stmtAddDerivationOutput.use()
|
||||||
(id)
|
(id)
|
||||||
(i.first)
|
(i.first)
|
||||||
(printStorePath(i.second.path))
|
(printStorePath(i.second.path(*this, drv.name)))
|
||||||
.exec();
|
.exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -686,7 +679,7 @@ void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info)
|
||||||
{
|
{
|
||||||
state.stmtUpdatePathInfo.use()
|
state.stmtUpdatePathInfo.use()
|
||||||
(info.narSize, info.narSize != 0)
|
(info.narSize, info.narSize != 0)
|
||||||
(info.narHash.to_string(Base16, true))
|
(info.narHash->to_string(Base16, true))
|
||||||
(info.ultimate ? 1 : 0, info.ultimate)
|
(info.ultimate ? 1 : 0, info.ultimate)
|
||||||
(concatStringsSep(" ", info.sigs), !info.sigs.empty())
|
(concatStringsSep(" ", info.sigs), !info.sigs.empty())
|
||||||
(renderContentAddress(info.ca), (bool) info.ca)
|
(renderContentAddress(info.ca), (bool) info.ca)
|
||||||
|
@ -900,7 +893,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
|
||||||
StorePathSet paths;
|
StorePathSet paths;
|
||||||
|
|
||||||
for (auto & i : infos) {
|
for (auto & i : infos) {
|
||||||
assert(i.narHash.type == htSHA256);
|
assert(i.narHash && i.narHash->type == htSHA256);
|
||||||
if (isValidPath_(*state, i.path))
|
if (isValidPath_(*state, i.path))
|
||||||
updatePathInfo(*state, i);
|
updatePathInfo(*state, i);
|
||||||
else
|
else
|
||||||
|
@ -1013,7 +1006,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
|
|
||||||
if (hashResult.first != info.narHash)
|
if (hashResult.first != info.narHash)
|
||||||
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
|
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
|
||||||
printStorePath(info.path), info.narHash.to_string(Base32, true), hashResult.first.to_string(Base32, true));
|
printStorePath(info.path), info.narHash->to_string(Base32, true), hashResult.first.to_string(Base32, true));
|
||||||
|
|
||||||
if (hashResult.second != info.narSize)
|
if (hashResult.second != info.narSize)
|
||||||
throw Error("size mismatch importing path '%s';\n wanted: %s\n got: %s",
|
throw Error("size mismatch importing path '%s';\n wanted: %s\n got: %s",
|
||||||
|
@ -1309,9 +1302,9 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
||||||
|
|
||||||
std::unique_ptr<AbstractHashSink> hashSink;
|
std::unique_ptr<AbstractHashSink> hashSink;
|
||||||
if (!info->ca || !info->references.count(info->path))
|
if (!info->ca || !info->references.count(info->path))
|
||||||
hashSink = std::make_unique<HashSink>(*info->narHash.type);
|
hashSink = std::make_unique<HashSink>(info->narHash->type);
|
||||||
else
|
else
|
||||||
hashSink = std::make_unique<HashModuloSink>(*info->narHash.type, std::string(info->path.hashPart()));
|
hashSink = std::make_unique<HashModuloSink>(info->narHash->type, std::string(info->path.hashPart()));
|
||||||
|
|
||||||
dumpPath(Store::toRealPath(i), *hashSink);
|
dumpPath(Store::toRealPath(i), *hashSink);
|
||||||
auto current = hashSink->finish();
|
auto current = hashSink->finish();
|
||||||
|
@ -1320,7 +1313,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
||||||
logError({
|
logError({
|
||||||
.name = "Invalid hash - path modified",
|
.name = "Invalid hash - path modified",
|
||||||
.hint = hintfmt("path '%s' was modified! expected hash '%s', got '%s'",
|
.hint = hintfmt("path '%s' was modified! expected hash '%s', got '%s'",
|
||||||
printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true))
|
printStorePath(i), info->narHash->to_string(Base32, true), current.first.to_string(Base32, true))
|
||||||
});
|
});
|
||||||
if (repair) repairPath(i); else errors = true;
|
if (repair) repairPath(i); else errors = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -198,8 +198,8 @@ void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
|
||||||
PathSet invalid;
|
PathSet invalid;
|
||||||
for (auto & j : drv->outputs)
|
for (auto & j : drv->outputs)
|
||||||
if (wantOutput(j.first, path.outputs)
|
if (wantOutput(j.first, path.outputs)
|
||||||
&& !isValidPath(j.second.path))
|
&& !isValidPath(j.second.path(*this, drv->name)))
|
||||||
invalid.insert(printStorePath(j.second.path));
|
invalid.insert(printStorePath(j.second.path(*this, drv->name)));
|
||||||
if (invalid.empty()) return;
|
if (invalid.empty()) return;
|
||||||
|
|
||||||
if (settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
|
if (settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
|
||||||
|
|
|
@ -230,9 +230,9 @@ public:
|
||||||
(std::string(info->path.name()))
|
(std::string(info->path.name()))
|
||||||
(narInfo ? narInfo->url : "", narInfo != 0)
|
(narInfo ? narInfo->url : "", narInfo != 0)
|
||||||
(narInfo ? narInfo->compression : "", narInfo != 0)
|
(narInfo ? narInfo->compression : "", narInfo != 0)
|
||||||
(narInfo && narInfo->fileHash ? narInfo->fileHash.to_string(Base32, true) : "", narInfo && narInfo->fileHash)
|
(narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(Base32, true) : "", narInfo && narInfo->fileHash)
|
||||||
(narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)
|
(narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)
|
||||||
(info->narHash.to_string(Base32, true))
|
(info->narHash->to_string(Base32, true))
|
||||||
(info->narSize)
|
(info->narSize)
|
||||||
(concatStringsSep(" ", info->shortRefs()))
|
(concatStringsSep(" ", info->shortRefs()))
|
||||||
(info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver)
|
(info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver)
|
||||||
|
|
|
@ -7,15 +7,14 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
: ValidPathInfo(StorePath(StorePath::dummy)) // FIXME: hack
|
: ValidPathInfo(StorePath(StorePath::dummy)) // FIXME: hack
|
||||||
{
|
{
|
||||||
auto corrupt = [&]() {
|
auto corrupt = [&]() {
|
||||||
throw Error("NAR info file '%1%' is corrupt", whence);
|
return Error("NAR info file '%1%' is corrupt", whence);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parseHashField = [&](const string & s) {
|
auto parseHashField = [&](const string & s) {
|
||||||
try {
|
try {
|
||||||
return Hash(s);
|
return Hash(s);
|
||||||
} catch (BadHash &) {
|
} catch (BadHash &) {
|
||||||
corrupt();
|
throw corrupt();
|
||||||
return Hash(); // never reached
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,12 +24,12 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
while (pos < s.size()) {
|
while (pos < s.size()) {
|
||||||
|
|
||||||
size_t colon = s.find(':', pos);
|
size_t colon = s.find(':', pos);
|
||||||
if (colon == std::string::npos) corrupt();
|
if (colon == std::string::npos) throw corrupt();
|
||||||
|
|
||||||
std::string name(s, pos, colon - pos);
|
std::string name(s, pos, colon - pos);
|
||||||
|
|
||||||
size_t eol = s.find('\n', colon + 2);
|
size_t eol = s.find('\n', colon + 2);
|
||||||
if (eol == std::string::npos) corrupt();
|
if (eol == std::string::npos) throw corrupt();
|
||||||
|
|
||||||
std::string value(s, colon + 2, eol - colon - 2);
|
std::string value(s, colon + 2, eol - colon - 2);
|
||||||
|
|
||||||
|
@ -45,16 +44,16 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
else if (name == "FileHash")
|
else if (name == "FileHash")
|
||||||
fileHash = parseHashField(value);
|
fileHash = parseHashField(value);
|
||||||
else if (name == "FileSize") {
|
else if (name == "FileSize") {
|
||||||
if (!string2Int(value, fileSize)) corrupt();
|
if (!string2Int(value, fileSize)) throw corrupt();
|
||||||
}
|
}
|
||||||
else if (name == "NarHash")
|
else if (name == "NarHash")
|
||||||
narHash = parseHashField(value);
|
narHash = parseHashField(value);
|
||||||
else if (name == "NarSize") {
|
else if (name == "NarSize") {
|
||||||
if (!string2Int(value, narSize)) corrupt();
|
if (!string2Int(value, narSize)) throw corrupt();
|
||||||
}
|
}
|
||||||
else if (name == "References") {
|
else if (name == "References") {
|
||||||
auto refs = tokenizeString<Strings>(value, " ");
|
auto refs = tokenizeString<Strings>(value, " ");
|
||||||
if (!references.empty()) corrupt();
|
if (!references.empty()) throw corrupt();
|
||||||
for (auto & r : refs)
|
for (auto & r : refs)
|
||||||
references.insert(StorePath(r));
|
references.insert(StorePath(r));
|
||||||
}
|
}
|
||||||
|
@ -67,7 +66,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
else if (name == "Sig")
|
else if (name == "Sig")
|
||||||
sigs.insert(value);
|
sigs.insert(value);
|
||||||
else if (name == "CA") {
|
else if (name == "CA") {
|
||||||
if (ca) corrupt();
|
if (ca) throw corrupt();
|
||||||
// FIXME: allow blank ca or require skipping field?
|
// FIXME: allow blank ca or require skipping field?
|
||||||
ca = parseContentAddressOpt(value);
|
ca = parseContentAddressOpt(value);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +76,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
|
|
||||||
if (compression == "") compression = "bzip2";
|
if (compression == "") compression = "bzip2";
|
||||||
|
|
||||||
if (!havePath || url.empty() || narSize == 0 || !narHash) corrupt();
|
if (!havePath || url.empty() || narSize == 0 || !narHash) throw corrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NarInfo::to_string(const Store & store) const
|
std::string NarInfo::to_string(const Store & store) const
|
||||||
|
@ -87,11 +86,11 @@ std::string NarInfo::to_string(const Store & store) const
|
||||||
res += "URL: " + url + "\n";
|
res += "URL: " + url + "\n";
|
||||||
assert(compression != "");
|
assert(compression != "");
|
||||||
res += "Compression: " + compression + "\n";
|
res += "Compression: " + compression + "\n";
|
||||||
assert(fileHash.type == htSHA256);
|
assert(fileHash && fileHash->type == htSHA256);
|
||||||
res += "FileHash: " + fileHash.to_string(Base32, true) + "\n";
|
res += "FileHash: " + fileHash->to_string(Base32, true) + "\n";
|
||||||
res += "FileSize: " + std::to_string(fileSize) + "\n";
|
res += "FileSize: " + std::to_string(fileSize) + "\n";
|
||||||
assert(narHash.type == htSHA256);
|
assert(narHash && narHash->type == htSHA256);
|
||||||
res += "NarHash: " + narHash.to_string(Base32, true) + "\n";
|
res += "NarHash: " + narHash->to_string(Base32, true) + "\n";
|
||||||
res += "NarSize: " + std::to_string(narSize) + "\n";
|
res += "NarSize: " + std::to_string(narSize) + "\n";
|
||||||
|
|
||||||
res += "References: " + concatStringsSep(" ", shortRefs()) + "\n";
|
res += "References: " + concatStringsSep(" ", shortRefs()) + "\n";
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct NarInfo : ValidPathInfo
|
||||||
{
|
{
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string compression;
|
std::string compression;
|
||||||
Hash fileHash;
|
std::optional<Hash> fileHash;
|
||||||
uint64_t fileSize = 0;
|
uint64_t fileSize = 0;
|
||||||
std::string system;
|
std::string system;
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,8 @@ void RefScanSink::operator () (const unsigned char * data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet scanForReferences(const string & path,
|
std::pair<PathSet, HashResult> scanForReferences(const string & path,
|
||||||
const PathSet & refs, HashResult & hash)
|
const PathSet & refs)
|
||||||
{
|
{
|
||||||
RefScanSink refsSink;
|
RefScanSink refsSink;
|
||||||
HashSink hashSink { htSHA256 };
|
HashSink hashSink { htSHA256 };
|
||||||
|
@ -111,9 +111,9 @@ PathSet scanForReferences(const string & path,
|
||||||
found.insert(j->second);
|
found.insert(j->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = hashSink.finish();
|
auto hash = hashSink.finish();
|
||||||
|
|
||||||
return found;
|
return std::pair<PathSet, HashResult>(found, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
PathSet scanForReferences(const Path & path, const PathSet & refs,
|
std::pair<PathSet, HashResult> scanForReferences(const Path & path, const PathSet & refs);
|
||||||
HashResult & hash);
|
|
||||||
|
|
||||||
struct RewritingSink : Sink
|
struct RewritingSink : Sink
|
||||||
{
|
{
|
||||||
|
|
|
@ -498,14 +498,89 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
conn->to << wopAddToStoreNar
|
conn->to << wopAddToStoreNar
|
||||||
<< printStorePath(info.path)
|
<< printStorePath(info.path)
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< info.narHash.to_string(Base16, false);
|
<< info.narHash->to_string(Base16, false);
|
||||||
writeStorePaths(*this, conn->to, info.references);
|
writeStorePaths(*this, conn->to, info.references);
|
||||||
conn->to << info.registrationTime << info.narSize
|
conn->to << info.registrationTime << info.narSize
|
||||||
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
|
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
|
||||||
<< repair << !checkSigs;
|
<< repair << !checkSigs;
|
||||||
bool tunnel = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21;
|
|
||||||
if (!tunnel) copyNAR(source, conn->to);
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 23) {
|
||||||
conn.processStderr(0, tunnel ? &source : nullptr);
|
|
||||||
|
std::exception_ptr ex;
|
||||||
|
|
||||||
|
struct FramedSink : BufferedSink
|
||||||
|
{
|
||||||
|
ConnectionHandle & conn;
|
||||||
|
std::exception_ptr & ex;
|
||||||
|
|
||||||
|
FramedSink(ConnectionHandle & conn, std::exception_ptr & ex) : conn(conn), ex(ex)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~FramedSink()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
conn->to << 0;
|
||||||
|
conn->to.flush();
|
||||||
|
} catch (...) {
|
||||||
|
ignoreException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(const unsigned char * data, size_t len) override
|
||||||
|
{
|
||||||
|
/* Don't send more data if the remote has
|
||||||
|
encountered an error. */
|
||||||
|
if (ex) {
|
||||||
|
auto ex2 = ex;
|
||||||
|
ex = nullptr;
|
||||||
|
std::rethrow_exception(ex2);
|
||||||
|
}
|
||||||
|
conn->to << len;
|
||||||
|
conn->to(data, len);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Handle log messages / exceptions from the remote on a
|
||||||
|
separate thread. */
|
||||||
|
std::thread stderrThread([&]()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
conn.processStderr();
|
||||||
|
} catch (...) {
|
||||||
|
ex = std::current_exception();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Finally joinStderrThread([&]()
|
||||||
|
{
|
||||||
|
if (stderrThread.joinable()) {
|
||||||
|
stderrThread.join();
|
||||||
|
if (ex) {
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ex);
|
||||||
|
} catch (...) {
|
||||||
|
ignoreException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
FramedSink sink(conn, ex);
|
||||||
|
copyNAR(source, sink);
|
||||||
|
sink.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
stderrThread.join();
|
||||||
|
if (ex)
|
||||||
|
std::rethrow_exception(ex);
|
||||||
|
|
||||||
|
} else if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21) {
|
||||||
|
conn.processStderr(0, &source);
|
||||||
|
} else {
|
||||||
|
copyNAR(source, conn->to);
|
||||||
|
conn.processStderr(0, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -343,13 +343,10 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1)
|
std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
auto size = istream->tellg();
|
printInfo("uploaded 's3://%s/%s' in %d ms",
|
||||||
|
bucketName, path, duration);
|
||||||
printInfo("uploaded 's3://%s/%s' (%d bytes) in %d ms",
|
|
||||||
bucketName, path, size, duration);
|
|
||||||
|
|
||||||
stats.putTimeMs += duration;
|
stats.putTimeMs += duration;
|
||||||
stats.putBytes += size;
|
|
||||||
stats.put++;
|
stats.put++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ public:
|
||||||
struct Stats
|
struct Stats
|
||||||
{
|
{
|
||||||
std::atomic<uint64_t> put{0};
|
std::atomic<uint64_t> put{0};
|
||||||
std::atomic<uint64_t> putBytes{0};
|
|
||||||
std::atomic<uint64_t> putTimeMs{0};
|
std::atomic<uint64_t> putTimeMs{0};
|
||||||
std::atomic<uint64_t> get{0};
|
std::atomic<uint64_t> get{0};
|
||||||
std::atomic<uint64_t> getBytes{0};
|
std::atomic<uint64_t> getBytes{0};
|
||||||
|
|
|
@ -538,7 +538,7 @@ string Store::makeValidityRegistration(const StorePathSet & paths,
|
||||||
auto info = queryPathInfo(i);
|
auto info = queryPathInfo(i);
|
||||||
|
|
||||||
if (showHash) {
|
if (showHash) {
|
||||||
s += info->narHash.to_string(Base16, false) + "\n";
|
s += info->narHash->to_string(Base16, false) + "\n";
|
||||||
s += (format("%1%\n") % info->narSize).str();
|
s += (format("%1%\n") % info->narSize).str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +570,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
|
||||||
auto info = queryPathInfo(storePath);
|
auto info = queryPathInfo(storePath);
|
||||||
|
|
||||||
jsonPath
|
jsonPath
|
||||||
.attr("narHash", info->narHash.to_string(hashBase, true))
|
.attr("narHash", info->narHash->to_string(hashBase, true))
|
||||||
.attr("narSize", info->narSize);
|
.attr("narSize", info->narSize);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -613,7 +613,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
|
||||||
if (!narInfo->url.empty())
|
if (!narInfo->url.empty())
|
||||||
jsonPath.attr("url", narInfo->url);
|
jsonPath.attr("url", narInfo->url);
|
||||||
if (narInfo->fileHash)
|
if (narInfo->fileHash)
|
||||||
jsonPath.attr("downloadHash", narInfo->fileHash.to_string(hashBase, true));
|
jsonPath.attr("downloadHash", narInfo->fileHash->to_string(hashBase, true));
|
||||||
if (narInfo->fileSize)
|
if (narInfo->fileSize)
|
||||||
jsonPath.attr("downloadSize", narInfo->fileSize);
|
jsonPath.attr("downloadSize", narInfo->fileSize);
|
||||||
if (showClosureSize)
|
if (showClosureSize)
|
||||||
|
@ -729,9 +729,9 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & st
|
||||||
{
|
{
|
||||||
auto valid = dstStore->queryValidPaths(storePaths, substitute);
|
auto valid = dstStore->queryValidPaths(storePaths, substitute);
|
||||||
|
|
||||||
PathSet missing;
|
StorePathSet missing;
|
||||||
for (auto & path : storePaths)
|
for (auto & path : storePaths)
|
||||||
if (!valid.count(path)) missing.insert(srcStore->printStorePath(path));
|
if (!valid.count(path)) missing.insert(path);
|
||||||
|
|
||||||
if (missing.empty()) return;
|
if (missing.empty()) return;
|
||||||
|
|
||||||
|
@ -748,29 +748,27 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & st
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool;
|
||||||
|
|
||||||
processGraph<Path>(pool,
|
processGraph<StorePath>(pool,
|
||||||
PathSet(missing.begin(), missing.end()),
|
StorePathSet(missing.begin(), missing.end()),
|
||||||
|
|
||||||
[&](const Path & storePath) {
|
[&](const StorePath & storePath) {
|
||||||
if (dstStore->isValidPath(dstStore->parseStorePath(storePath))) {
|
if (dstStore->isValidPath(storePath)) {
|
||||||
nrDone++;
|
nrDone++;
|
||||||
showProgress();
|
showProgress();
|
||||||
return PathSet();
|
return StorePathSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto info = srcStore->queryPathInfo(srcStore->parseStorePath(storePath));
|
auto info = srcStore->queryPathInfo(storePath);
|
||||||
|
|
||||||
bytesExpected += info->narSize;
|
bytesExpected += info->narSize;
|
||||||
act.setExpected(actCopyPath, bytesExpected);
|
act.setExpected(actCopyPath, bytesExpected);
|
||||||
|
|
||||||
return srcStore->printStorePathSet(info->references);
|
return info->references;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](const Path & storePathS) {
|
[&](const StorePath & storePath) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
auto storePath = dstStore->parseStorePath(storePathS);
|
|
||||||
|
|
||||||
if (!dstStore->isValidPath(storePath)) {
|
if (!dstStore->isValidPath(storePath)) {
|
||||||
MaintainCount<decltype(nrRunning)> mc(nrRunning);
|
MaintainCount<decltype(nrRunning)> mc(nrRunning);
|
||||||
showProgress();
|
showProgress();
|
||||||
|
@ -780,7 +778,7 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & st
|
||||||
nrFailed++;
|
nrFailed++;
|
||||||
if (!settings.keepGoing)
|
if (!settings.keepGoing)
|
||||||
throw e;
|
throw e;
|
||||||
logger->log(lvlError, fmt("could not copy %s: %s", storePathS, e.what()));
|
logger->log(lvlError, fmt("could not copy %s: %s", dstStore->printStorePath(storePath), e.what()));
|
||||||
showProgress();
|
showProgress();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -854,7 +852,7 @@ std::string ValidPathInfo::fingerprint(const Store & store) const
|
||||||
store.printStorePath(path));
|
store.printStorePath(path));
|
||||||
return
|
return
|
||||||
"1;" + store.printStorePath(path) + ";"
|
"1;" + store.printStorePath(path) + ";"
|
||||||
+ narHash.to_string(Base32, true) + ";"
|
+ narHash->to_string(Base32, true) + ";"
|
||||||
+ std::to_string(narSize) + ";"
|
+ std::to_string(narSize) + ";"
|
||||||
+ concatStringsSep(",", store.printStorePathSet(references));
|
+ concatStringsSep(",", store.printStorePathSet(references));
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,8 @@ struct ValidPathInfo
|
||||||
{
|
{
|
||||||
StorePath path;
|
StorePath path;
|
||||||
std::optional<StorePath> deriver;
|
std::optional<StorePath> deriver;
|
||||||
Hash narHash;
|
// TODO document this
|
||||||
|
std::optional<Hash> narHash;
|
||||||
StorePathSet references;
|
StorePathSet references;
|
||||||
time_t registrationTime = 0;
|
time_t registrationTime = 0;
|
||||||
uint64_t narSize = 0; // 0 = unknown
|
uint64_t narSize = 0; // 0 = unknown
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace nix {
|
||||||
#define WORKER_MAGIC_1 0x6e697863
|
#define WORKER_MAGIC_1 0x6e697863
|
||||||
#define WORKER_MAGIC_2 0x6478696f
|
#define WORKER_MAGIC_2 0x6478696f
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 0x116
|
#define PROTOCOL_VERSION 0x117
|
||||||
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
|
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
|
||||||
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
||||||
|
|
||||||
|
|
|
@ -15,19 +15,22 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
static size_t regularHashSize(HashType type) {
|
||||||
|
switch (type) {
|
||||||
|
case htMD5: return md5HashSize;
|
||||||
|
case htSHA1: return sha1HashSize;
|
||||||
|
case htSHA256: return sha256HashSize;
|
||||||
|
case htSHA512: return sha512HashSize;
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
std::set<std::string> hashTypes = { "md5", "sha1", "sha256", "sha512" };
|
std::set<std::string> hashTypes = { "md5", "sha1", "sha256", "sha512" };
|
||||||
|
|
||||||
|
|
||||||
void Hash::init()
|
void Hash::init()
|
||||||
{
|
{
|
||||||
assert(type);
|
hashSize = regularHashSize(type);
|
||||||
switch (*type) {
|
|
||||||
case htMD5: hashSize = md5HashSize; break;
|
|
||||||
case htSHA1: hashSize = sha1HashSize; break;
|
|
||||||
case htSHA256: hashSize = sha256HashSize; break;
|
|
||||||
case htSHA512: hashSize = sha512HashSize; break;
|
|
||||||
}
|
|
||||||
assert(hashSize <= maxHashSize);
|
assert(hashSize <= maxHashSize);
|
||||||
memset(hash, 0, maxHashSize);
|
memset(hash, 0, maxHashSize);
|
||||||
}
|
}
|
||||||
|
@ -108,17 +111,11 @@ string printHash16or32(const Hash & hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HashType assertInitHashType(const Hash & h)
|
|
||||||
{
|
|
||||||
assert(h.type);
|
|
||||||
return *h.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Hash::to_string(Base base, bool includeType) const
|
std::string Hash::to_string(Base base, bool includeType) const
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
if (base == SRI || includeType) {
|
if (base == SRI || includeType) {
|
||||||
s += printHashType(assertInitHashType(*this));
|
s += printHashType(type);
|
||||||
s += base == SRI ? '-' : ':';
|
s += base == SRI ? '-' : ':';
|
||||||
}
|
}
|
||||||
switch (base) {
|
switch (base) {
|
||||||
|
@ -139,60 +136,66 @@ std::string Hash::to_string(Base base, bool includeType) const
|
||||||
Hash::Hash(std::string_view s, HashType type) : Hash(s, std::optional { type }) { }
|
Hash::Hash(std::string_view s, HashType type) : Hash(s, std::optional { type }) { }
|
||||||
Hash::Hash(std::string_view s) : Hash(s, std::optional<HashType>{}) { }
|
Hash::Hash(std::string_view s) : Hash(s, std::optional<HashType>{}) { }
|
||||||
|
|
||||||
Hash::Hash(std::string_view s, std::optional<HashType> type)
|
Hash::Hash(std::string_view original, std::optional<HashType> optType)
|
||||||
: type(type)
|
|
||||||
{
|
{
|
||||||
|
auto rest = original;
|
||||||
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
bool isSRI = false;
|
bool isSRI = false;
|
||||||
|
|
||||||
auto sep = s.find(':');
|
// Parse the has type before the separater, if there was one.
|
||||||
if (sep == string::npos) {
|
std::optional<HashType> optParsedType;
|
||||||
sep = s.find('-');
|
{
|
||||||
if (sep != string::npos) {
|
auto sep = rest.find(':');
|
||||||
isSRI = true;
|
if (sep == std::string_view::npos) {
|
||||||
} else if (! type)
|
sep = rest.find('-');
|
||||||
throw BadHash("hash '%s' does not include a type", s);
|
if (sep != std::string_view::npos)
|
||||||
|
isSRI = true;
|
||||||
|
}
|
||||||
|
if (sep != std::string_view::npos) {
|
||||||
|
auto hashRaw = rest.substr(0, sep);
|
||||||
|
optParsedType = parseHashType(hashRaw);
|
||||||
|
rest = rest.substr(sep + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sep != string::npos) {
|
// Either the string or user must provide the type, if they both do they
|
||||||
string hts = string(s, 0, sep);
|
// must agree.
|
||||||
this->type = parseHashType(hts);
|
if (!optParsedType && !optType) {
|
||||||
if (!this->type)
|
throw BadHash("hash '%s' does not include a type, nor is the type otherwise known from context.", rest);
|
||||||
throw BadHash("unknown hash type '%s'", hts);
|
} else {
|
||||||
if (type && type != this->type)
|
this->type = optParsedType ? *optParsedType : *optType;
|
||||||
throw BadHash("hash '%s' should have type '%s'", s, printHashType(*type));
|
if (optParsedType && optType && *optParsedType != *optType)
|
||||||
pos = sep + 1;
|
throw BadHash("hash '%s' should have type '%s'", original, printHashType(*optType));
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
size_t size = s.size() - pos;
|
if (!isSRI && rest.size() == base16Len()) {
|
||||||
|
|
||||||
if (!isSRI && size == base16Len()) {
|
|
||||||
|
|
||||||
auto parseHexDigit = [&](char c) {
|
auto parseHexDigit = [&](char c) {
|
||||||
if (c >= '0' && c <= '9') return c - '0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
throw BadHash("invalid base-16 hash '%s'", s);
|
throw BadHash("invalid base-16 hash '%s'", original);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < hashSize; i++) {
|
for (unsigned int i = 0; i < hashSize; i++) {
|
||||||
hash[i] =
|
hash[i] =
|
||||||
parseHexDigit(s[pos + i * 2]) << 4
|
parseHexDigit(rest[pos + i * 2]) << 4
|
||||||
| parseHexDigit(s[pos + i * 2 + 1]);
|
| parseHexDigit(rest[pos + i * 2 + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!isSRI && size == base32Len()) {
|
else if (!isSRI && rest.size() == base32Len()) {
|
||||||
|
|
||||||
for (unsigned int n = 0; n < size; ++n) {
|
for (unsigned int n = 0; n < rest.size(); ++n) {
|
||||||
char c = s[pos + size - n - 1];
|
char c = rest[rest.size() - n - 1];
|
||||||
unsigned char digit;
|
unsigned char digit;
|
||||||
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
|
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
|
||||||
if (base32Chars[digit] == c) break;
|
if (base32Chars[digit] == c) break;
|
||||||
if (digit >= 32)
|
if (digit >= 32)
|
||||||
throw BadHash("invalid base-32 hash '%s'", s);
|
throw BadHash("invalid base-32 hash '%s'", original);
|
||||||
unsigned int b = n * 5;
|
unsigned int b = n * 5;
|
||||||
unsigned int i = b / 8;
|
unsigned int i = b / 8;
|
||||||
unsigned int j = b % 8;
|
unsigned int j = b % 8;
|
||||||
|
@ -202,21 +205,21 @@ Hash::Hash(std::string_view s, std::optional<HashType> type)
|
||||||
hash[i + 1] |= digit >> (8 - j);
|
hash[i + 1] |= digit >> (8 - j);
|
||||||
} else {
|
} else {
|
||||||
if (digit >> (8 - j))
|
if (digit >> (8 - j))
|
||||||
throw BadHash("invalid base-32 hash '%s'", s);
|
throw BadHash("invalid base-32 hash '%s'", original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isSRI || size == base64Len()) {
|
else if (isSRI || rest.size() == base64Len()) {
|
||||||
auto d = base64Decode(s.substr(pos));
|
auto d = base64Decode(rest);
|
||||||
if (d.size() != hashSize)
|
if (d.size() != hashSize)
|
||||||
throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", s);
|
throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", original);
|
||||||
assert(hashSize);
|
assert(hashSize);
|
||||||
memcpy(hash, d.data(), hashSize);
|
memcpy(hash, d.data(), hashSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(*type));
|
throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht)
|
Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht)
|
||||||
|
@ -269,7 +272,7 @@ static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hash hashString(HashType ht, const string & s)
|
Hash hashString(HashType ht, std::string_view s)
|
||||||
{
|
{
|
||||||
Ctx ctx;
|
Ctx ctx;
|
||||||
Hash hash(ht);
|
Hash hash(ht);
|
||||||
|
@ -336,7 +339,7 @@ HashResult hashPath(
|
||||||
|
|
||||||
Hash compressHash(const Hash & hash, unsigned int newSize)
|
Hash compressHash(const Hash & hash, unsigned int newSize)
|
||||||
{
|
{
|
||||||
Hash h;
|
Hash h(hash.type);
|
||||||
h.hashSize = newSize;
|
h.hashSize = newSize;
|
||||||
for (unsigned int i = 0; i < hash.hashSize; ++i)
|
for (unsigned int i = 0; i < hash.hashSize; ++i)
|
||||||
h.hash[i % newSize] ^= hash.hash[i];
|
h.hash[i % newSize] ^= hash.hash[i];
|
||||||
|
@ -344,7 +347,7 @@ Hash compressHash(const Hash & hash, unsigned int newSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::optional<HashType> parseHashTypeOpt(const string & s)
|
std::optional<HashType> parseHashTypeOpt(std::string_view s)
|
||||||
{
|
{
|
||||||
if (s == "md5") return htMD5;
|
if (s == "md5") return htMD5;
|
||||||
else if (s == "sha1") return htSHA1;
|
else if (s == "sha1") return htSHA1;
|
||||||
|
@ -353,7 +356,7 @@ std::optional<HashType> parseHashTypeOpt(const string & s)
|
||||||
else return std::optional<HashType> {};
|
else return std::optional<HashType> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
HashType parseHashType(const string & s)
|
HashType parseHashType(std::string_view s)
|
||||||
{
|
{
|
||||||
auto opt_h = parseHashTypeOpt(s);
|
auto opt_h = parseHashTypeOpt(s);
|
||||||
if (opt_h)
|
if (opt_h)
|
||||||
|
|
|
@ -27,14 +27,11 @@ enum Base : int { Base64, Base32, Base16, SRI };
|
||||||
|
|
||||||
struct Hash
|
struct Hash
|
||||||
{
|
{
|
||||||
static const unsigned int maxHashSize = 64;
|
constexpr static size_t maxHashSize = 64;
|
||||||
unsigned int hashSize = 0;
|
size_t hashSize = 0;
|
||||||
unsigned char hash[maxHashSize] = {};
|
uint8_t hash[maxHashSize] = {};
|
||||||
|
|
||||||
std::optional<HashType> type = {};
|
HashType type;
|
||||||
|
|
||||||
/* Create an unset hash object. */
|
|
||||||
Hash() { };
|
|
||||||
|
|
||||||
/* Create a zero-filled hash object. */
|
/* Create a zero-filled hash object. */
|
||||||
Hash(HashType type) : type(type) { init(); };
|
Hash(HashType type) : type(type) { init(); };
|
||||||
|
@ -107,7 +104,7 @@ Hash newHashAllowEmpty(std::string hashStr, std::optional<HashType> ht);
|
||||||
string printHash16or32(const Hash & hash);
|
string printHash16or32(const Hash & hash);
|
||||||
|
|
||||||
/* Compute the hash of the given string. */
|
/* Compute the hash of the given string. */
|
||||||
Hash hashString(HashType ht, const string & s);
|
Hash hashString(HashType ht, std::string_view s);
|
||||||
|
|
||||||
/* Compute the hash of the given file. */
|
/* Compute the hash of the given file. */
|
||||||
Hash hashFile(HashType ht, const Path & path);
|
Hash hashFile(HashType ht, const Path & path);
|
||||||
|
@ -123,10 +120,10 @@ HashResult hashPath(HashType ht, const Path & path,
|
||||||
Hash compressHash(const Hash & hash, unsigned int newSize);
|
Hash compressHash(const Hash & hash, unsigned int newSize);
|
||||||
|
|
||||||
/* Parse a string representing a hash type. */
|
/* Parse a string representing a hash type. */
|
||||||
HashType parseHashType(const string & s);
|
HashType parseHashType(std::string_view s);
|
||||||
|
|
||||||
/* Will return nothing on parse error */
|
/* Will return nothing on parse error */
|
||||||
std::optional<HashType> parseHashTypeOpt(const string & s);
|
std::optional<HashType> parseHashTypeOpt(std::string_view s);
|
||||||
|
|
||||||
/* And the reverse. */
|
/* And the reverse. */
|
||||||
string printHashType(HashType ht);
|
string printHashType(HashType ht);
|
||||||
|
|
|
@ -1581,7 +1581,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
if (path.size() >= sizeof(addr.sun_path))
|
if (path.size() + 1 >= sizeof(addr.sun_path))
|
||||||
throw Error("socket path '%1%' is too long", path);
|
throw Error("socket path '%1%' is too long", path);
|
||||||
strcpy(addr.sun_path, path.c_str());
|
strcpy(addr.sun_path, path.c_str());
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ static int _main(int argc, char * * argv)
|
||||||
/* If an expected hash is given, the file may already exist in
|
/* If an expected hash is given, the file may already exist in
|
||||||
the store. */
|
the store. */
|
||||||
std::optional<Hash> expectedHash;
|
std::optional<Hash> expectedHash;
|
||||||
Hash hash;
|
Hash hash(ht);
|
||||||
std::optional<StorePath> storePath;
|
std::optional<StorePath> storePath;
|
||||||
if (args.size() == 2) {
|
if (args.size() == 2) {
|
||||||
expectedHash = Hash(args[1], ht);
|
expectedHash = Hash(args[1], ht);
|
||||||
|
|
|
@ -77,7 +77,7 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true)
|
||||||
if (i == drv.outputs.end())
|
if (i == drv.outputs.end())
|
||||||
throw Error("derivation '%s' does not have an output named '%s'",
|
throw Error("derivation '%s' does not have an output named '%s'",
|
||||||
store2->printStorePath(path.path), j);
|
store2->printStorePath(path.path), j);
|
||||||
auto outPath = store2->printStorePath(i->second.path);
|
auto outPath = store2->printStorePath(i->second.path(*store, drv.name));
|
||||||
if (store2) {
|
if (store2) {
|
||||||
if (gcRoot == "")
|
if (gcRoot == "")
|
||||||
printGCWarning();
|
printGCWarning();
|
||||||
|
@ -219,7 +219,7 @@ static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput,
|
||||||
auto drv = store->derivationFromPath(storePath);
|
auto drv = store->derivationFromPath(storePath);
|
||||||
StorePathSet outputs;
|
StorePathSet outputs;
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
outputs.insert(i.second.path);
|
outputs.insert(i.second.path(*store, drv.name));
|
||||||
return outputs;
|
return outputs;
|
||||||
}
|
}
|
||||||
else return {storePath};
|
else return {storePath};
|
||||||
|
@ -313,7 +313,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
if (forceRealise) realisePath({i2});
|
if (forceRealise) realisePath({i2});
|
||||||
Derivation drv = store->derivationFromPath(i2);
|
Derivation drv = store->derivationFromPath(i2);
|
||||||
for (auto & j : drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
cout << fmt("%1%\n", store->printStorePath(j.second.path));
|
cout << fmt("%1%\n", store->printStorePath(j.second.path(*store, drv.name)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -372,8 +372,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) {
|
for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) {
|
||||||
auto info = store->queryPathInfo(j);
|
auto info = store->queryPathInfo(j);
|
||||||
if (query == qHash) {
|
if (query == qHash) {
|
||||||
assert(info->narHash.type == htSHA256);
|
assert(info->narHash && info->narHash->type == htSHA256);
|
||||||
cout << fmt("%s\n", info->narHash.to_string(Base32, true));
|
cout << fmt("%s\n", info->narHash->to_string(Base32, true));
|
||||||
} else if (query == qSize)
|
} else if (query == qSize)
|
||||||
cout << fmt("%d\n", info->narSize);
|
cout << fmt("%d\n", info->narSize);
|
||||||
}
|
}
|
||||||
|
@ -725,7 +725,7 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
|
||||||
auto path = store->followLinksToStorePath(i);
|
auto path = store->followLinksToStorePath(i);
|
||||||
printMsg(lvlTalkative, "checking path '%s'...", store->printStorePath(path));
|
printMsg(lvlTalkative, "checking path '%s'...", store->printStorePath(path));
|
||||||
auto info = store->queryPathInfo(path);
|
auto info = store->queryPathInfo(path);
|
||||||
HashSink sink(*info->narHash.type);
|
HashSink sink(info->narHash->type);
|
||||||
store->narFromPath(path, sink);
|
store->narFromPath(path, sink);
|
||||||
auto current = sink.finish();
|
auto current = sink.finish();
|
||||||
if (current.first != info->narHash) {
|
if (current.first != info->narHash) {
|
||||||
|
@ -734,7 +734,7 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
|
||||||
.hint = hintfmt(
|
.hint = hintfmt(
|
||||||
"path '%s' was modified! expected hash '%s', got '%s'",
|
"path '%s' was modified! expected hash '%s', got '%s'",
|
||||||
store->printStorePath(path),
|
store->printStorePath(path),
|
||||||
info->narHash.to_string(Base32, true),
|
info->narHash->to_string(Base32, true),
|
||||||
current.first.to_string(Base32, true))
|
current.first.to_string(Base32, true))
|
||||||
});
|
});
|
||||||
status = 1;
|
status = 1;
|
||||||
|
@ -864,7 +864,9 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
out << info->narSize // downloadSize
|
out << info->narSize // downloadSize
|
||||||
<< info->narSize;
|
<< info->narSize;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 4)
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 4)
|
||||||
out << (info->narHash ? info->narHash.to_string(Base32, true) : "") << renderContentAddress(info->ca) << info->sigs;
|
out << (info->narHash ? info->narHash->to_string(Base32, true) : "")
|
||||||
|
<< renderContentAddress(info->ca)
|
||||||
|
<< info->sigs;
|
||||||
} catch (InvalidPath &) {
|
} catch (InvalidPath &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,9 +916,9 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
|
|
||||||
if (!writeAllowed) throw Error("building paths is not allowed");
|
if (!writeAllowed) throw Error("building paths is not allowed");
|
||||||
|
|
||||||
auto drvPath = store->parseStorePath(readString(in)); // informational only
|
auto drvPath = store->parseStorePath(readString(in));
|
||||||
BasicDerivation drv;
|
BasicDerivation drv;
|
||||||
readDerivation(in, *store, drv);
|
readDerivation(in, *store, drv, Derivation::nameFromPath(drvPath));
|
||||||
|
|
||||||
getBuildSettings();
|
getBuildSettings();
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ struct CmdAddToStore : MixDryRun, StoreCommand
|
||||||
info.narSize = sink.s->size();
|
info.narSize = sink.s->size();
|
||||||
info.ca = std::optional { FixedOutputHash {
|
info.ca = std::optional { FixedOutputHash {
|
||||||
.method = FileIngestionMethod::Recursive,
|
.method = FileIngestionMethod::Recursive,
|
||||||
.hash = info.narHash,
|
.hash = *info.narHash,
|
||||||
} };
|
} };
|
||||||
|
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
|
|
|
@ -68,22 +68,22 @@ BuildEnvironment readEnvironment(const Path & path)
|
||||||
|
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
|
|
||||||
if (std::regex_search(pos, file.cend(), match, declareRegex)) {
|
if (std::regex_search(pos, file.cend(), match, declareRegex, std::regex_constants::match_continuous)) {
|
||||||
pos = match[0].second;
|
pos = match[0].second;
|
||||||
exported.insert(match[1]);
|
exported.insert(match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (std::regex_search(pos, file.cend(), match, varRegex)) {
|
else if (std::regex_search(pos, file.cend(), match, varRegex, std::regex_constants::match_continuous)) {
|
||||||
pos = match[0].second;
|
pos = match[0].second;
|
||||||
res.env.insert({match[1], Var { .exported = exported.count(match[1]) > 0, .value = match[2] }});
|
res.env.insert({match[1], Var { .exported = exported.count(match[1]) > 0, .value = match[2] }});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (std::regex_search(pos, file.cend(), match, assocArrayRegex)) {
|
else if (std::regex_search(pos, file.cend(), match, assocArrayRegex, std::regex_constants::match_continuous)) {
|
||||||
pos = match[0].second;
|
pos = match[0].second;
|
||||||
res.env.insert({match[1], Var { .associative = true, .value = match[2] }});
|
res.env.insert({match[1], Var { .associative = true, .value = match[2] }});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (std::regex_search(pos, file.cend(), match, functionRegex)) {
|
else if (std::regex_search(pos, file.cend(), match, functionRegex, std::regex_constants::match_continuous)) {
|
||||||
res.bashFunctions = std::string(pos, file.cend());
|
res.bashFunctions = std::string(pos, file.cend());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -130,14 +130,16 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath)
|
||||||
drvName += "-env";
|
drvName += "-env";
|
||||||
for (auto & output : drv.outputs)
|
for (auto & output : drv.outputs)
|
||||||
drv.env.erase(output.first);
|
drv.env.erase(output.first);
|
||||||
drv.outputs = {{"out", DerivationOutput { .path = StorePath::dummy }}};
|
drv.outputs = {{"out", DerivationOutput { .output = DerivationOutputInputAddressed { .path = StorePath::dummy }}}};
|
||||||
drv.env["out"] = "";
|
drv.env["out"] = "";
|
||||||
drv.env["_outputs_saved"] = drv.env["outputs"];
|
drv.env["_outputs_saved"] = drv.env["outputs"];
|
||||||
drv.env["outputs"] = "out";
|
drv.env["outputs"] = "out";
|
||||||
drv.inputSrcs.insert(std::move(getEnvShPath));
|
drv.inputSrcs.insert(std::move(getEnvShPath));
|
||||||
Hash h = hashDerivationModulo(*store, drv, true);
|
Hash h = hashDerivationModulo(*store, drv, true);
|
||||||
auto shellOutPath = store->makeOutputPath("out", h, drvName);
|
auto shellOutPath = store->makeOutputPath("out", h, drvName);
|
||||||
drv.outputs.insert_or_assign("out", DerivationOutput { .path = shellOutPath });
|
drv.outputs.insert_or_assign("out", DerivationOutput { .output = DerivationOutputInputAddressed {
|
||||||
|
.path = shellOutPath
|
||||||
|
} });
|
||||||
drv.env["out"] = store->printStorePath(shellOutPath);
|
drv.env["out"] = store->printStorePath(shellOutPath);
|
||||||
auto shellDrvPath2 = writeDerivation(store, drv, drvName);
|
auto shellDrvPath2 = writeDerivation(store, drv, drvName);
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||||
Installable::getCursors(EvalState & state, bool useEvalCache)
|
Installable::getCursors(EvalState & state, bool useEvalCache)
|
||||||
{
|
{
|
||||||
auto evalCache =
|
auto evalCache =
|
||||||
std::make_shared<nix::eval_cache::EvalCache>(false, Hash(), state,
|
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
|
||||||
[&]() { return toValue(state).first; });
|
[&]() { return toValue(state).first; });
|
||||||
return {{evalCache->getRoot(), ""}};
|
return {{evalCache->getRoot(), ""}};
|
||||||
}
|
}
|
||||||
|
@ -304,8 +304,9 @@ struct InstallableStorePath : Installable
|
||||||
{
|
{
|
||||||
if (storePath.isDerivation()) {
|
if (storePath.isDerivation()) {
|
||||||
std::map<std::string, StorePath> outputs;
|
std::map<std::string, StorePath> outputs;
|
||||||
for (auto & [name, output] : store->readDerivation(storePath).outputs)
|
auto drv = store->readDerivation(storePath);
|
||||||
outputs.emplace(name, output.path);
|
for (auto & [name, output] : drv.outputs)
|
||||||
|
outputs.emplace(name, output.path(*store, drv.name));
|
||||||
return {
|
return {
|
||||||
Buildable {
|
Buildable {
|
||||||
.drvPath = storePath,
|
.drvPath = storePath,
|
||||||
|
@ -436,9 +437,11 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake,
|
std::shared_ptr<flake::LockedFlake> lockedFlake,
|
||||||
bool useEvalCache)
|
bool useEvalCache)
|
||||||
{
|
{
|
||||||
return ref(std::make_shared<nix::eval_cache::EvalCache>(
|
auto fingerprint = lockedFlake->getFingerprint();
|
||||||
useEvalCache && evalSettings.pureEval,
|
return make_ref<nix::eval_cache::EvalCache>(
|
||||||
lockedFlake->getFingerprint(),
|
useEvalCache && evalSettings.pureEval
|
||||||
|
? std::optional { std::cref(fingerprint) }
|
||||||
|
: std::nullopt,
|
||||||
state,
|
state,
|
||||||
[&state, lockedFlake]()
|
[&state, lockedFlake]()
|
||||||
{
|
{
|
||||||
|
@ -456,7 +459,7 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||||
assert(aOutputs);
|
assert(aOutputs);
|
||||||
|
|
||||||
return aOutputs->value;
|
return aOutputs->value;
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
||||||
|
|
|
@ -84,7 +84,7 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
|
||||||
info.narSize = sink.s->size();
|
info.narSize = sink.s->size();
|
||||||
info.ca = FixedOutputHash {
|
info.ca = FixedOutputHash {
|
||||||
.method = FileIngestionMethod::Recursive,
|
.method = FileIngestionMethod::Recursive,
|
||||||
.hash = info.narHash,
|
.hash = *info.narHash,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!json)
|
if (!json)
|
||||||
|
|
|
@ -133,7 +133,7 @@ struct ProfileManifest
|
||||||
info.references = std::move(references);
|
info.references = std::move(references);
|
||||||
info.narHash = narHash;
|
info.narHash = narHash;
|
||||||
info.narSize = sink.s->size();
|
info.narSize = sink.s->size();
|
||||||
info.ca = FixedOutputHash { .method = FileIngestionMethod::Recursive, .hash = info.narHash };
|
info.ca = FixedOutputHash { .method = FileIngestionMethod::Recursive, .hash = *info.narHash };
|
||||||
|
|
||||||
auto source = StringSource { *sink.s };
|
auto source = StringSource { *sink.s };
|
||||||
store->addToStore(info, source);
|
store->addToStore(info, source);
|
||||||
|
|
|
@ -483,10 +483,10 @@ bool NixRepl::processLine(string line)
|
||||||
but doing it in a child makes it easier to recover from
|
but doing it in a child makes it easier to recover from
|
||||||
problems / SIGINT. */
|
problems / SIGINT. */
|
||||||
if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPath}) == 0) {
|
if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPath}) == 0) {
|
||||||
auto drv = readDerivation(*state->store, drvPath);
|
auto drv = readDerivation(*state->store, drvPath, Derivation::nameFromPath(state->store->parseStorePath(drvPath)));
|
||||||
std::cout << std::endl << "this derivation produced the following outputs:" << std::endl;
|
std::cout << std::endl << "this derivation produced the following outputs:" << std::endl;
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(i.second.path));
|
std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(i.second.path(*state->store, drv.name)));
|
||||||
}
|
}
|
||||||
} else if (command == ":i") {
|
} else if (command == ":i") {
|
||||||
runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPath});
|
runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPath});
|
||||||
|
|
|
@ -69,10 +69,10 @@ struct CmdShowDerivation : InstallablesCommand
|
||||||
auto outputsObj(drvObj.object("outputs"));
|
auto outputsObj(drvObj.object("outputs"));
|
||||||
for (auto & output : drv.outputs) {
|
for (auto & output : drv.outputs) {
|
||||||
auto outputObj(outputsObj.object(output.first));
|
auto outputObj(outputsObj.object(output.first));
|
||||||
outputObj.attr("path", store->printStorePath(output.second.path));
|
outputObj.attr("path", store->printStorePath(output.second.path(*store, drv.name)));
|
||||||
if (output.second.hash) {
|
if (auto hash = std::get_if<DerivationOutputFixed>(&output.second.output)) {
|
||||||
outputObj.attr("hashAlgo", output.second.hash->printMethodAlgo());
|
outputObj.attr("hashAlgo", hash->hash.printMethodAlgo());
|
||||||
outputObj.attr("hash", output.second.hash->hash.to_string(Base16, false));
|
outputObj.attr("hash", hash->hash.hash.to_string(Base16, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,15 +91,15 @@ struct CmdVerify : StorePathsCommand
|
||||||
|
|
||||||
std::unique_ptr<AbstractHashSink> hashSink;
|
std::unique_ptr<AbstractHashSink> hashSink;
|
||||||
if (!info->ca)
|
if (!info->ca)
|
||||||
hashSink = std::make_unique<HashSink>(*info->narHash.type);
|
hashSink = std::make_unique<HashSink>(info->narHash->type);
|
||||||
else
|
else
|
||||||
hashSink = std::make_unique<HashModuloSink>(*info->narHash.type, std::string(info->path.hashPart()));
|
hashSink = std::make_unique<HashModuloSink>(info->narHash->type, std::string(info->path.hashPart()));
|
||||||
|
|
||||||
store->narFromPath(info->path, *hashSink);
|
store->narFromPath(info->path, *hashSink);
|
||||||
|
|
||||||
auto hash = hashSink->finish();
|
auto hash = hashSink->finish();
|
||||||
|
|
||||||
if (hash.first != info->narHash) {
|
if (hash.first != *info->narHash) {
|
||||||
corrupted++;
|
corrupted++;
|
||||||
act2.result(resCorruptedPath, store->printStorePath(info->path));
|
act2.result(resCorruptedPath, store->printStorePath(info->path));
|
||||||
logError({
|
logError({
|
||||||
|
@ -107,7 +107,7 @@ struct CmdVerify : StorePathsCommand
|
||||||
.hint = hintfmt(
|
.hint = hintfmt(
|
||||||
"path '%s' was modified! expected hash '%s', got '%s'",
|
"path '%s' was modified! expected hash '%s', got '%s'",
|
||||||
store->printStorePath(info->path),
|
store->printStorePath(info->path),
|
||||||
info->narHash.to_string(Base32, true),
|
info->narHash->to_string(Base32, true),
|
||||||
hash.first.to_string(Base32, true))
|
hash.first.to_string(Base32, true))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ rev2=$(git -C $repo rev-parse HEAD)
|
||||||
# Fetch a worktree
|
# Fetch a worktree
|
||||||
unset _NIX_FORCE_HTTP
|
unset _NIX_FORCE_HTTP
|
||||||
path0=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath")
|
path0=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath")
|
||||||
|
path0_=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = file://$TEST_ROOT/worktree; }).outPath")
|
||||||
|
[[ $path0 = $path0_ ]]
|
||||||
export _NIX_FORCE_HTTP=1
|
export _NIX_FORCE_HTTP=1
|
||||||
[[ $(tail -n 1 $path0/hello) = "hello" ]]
|
[[ $(tail -n 1 $path0/hello) = "hello" ]]
|
||||||
|
|
||||||
|
@ -102,6 +104,12 @@ git -C $repo commit -m 'Bla3' -a
|
||||||
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
||||||
[[ $path2 = $path4 ]]
|
[[ $path2 = $path4 ]]
|
||||||
|
|
||||||
|
nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$?
|
||||||
|
[[ "$status" = "102" ]]
|
||||||
|
|
||||||
|
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath")
|
||||||
|
[[ $path = $path5 ]]
|
||||||
|
|
||||||
# tarball-ttl should be ignored if we specify a rev
|
# tarball-ttl should be ignored if we specify a rev
|
||||||
echo delft > $repo/hello
|
echo delft > $repo/hello
|
||||||
git -C $repo add hello
|
git -C $repo add hello
|
||||||
|
|
|
@ -27,10 +27,13 @@ test_tarball() {
|
||||||
|
|
||||||
nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"
|
nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"
|
||||||
|
|
||||||
nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)"
|
nix-build -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)"
|
||||||
nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })"
|
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })"
|
||||||
nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })"
|
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })"
|
||||||
nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input'
|
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input'
|
||||||
|
|
||||||
|
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" >&2
|
||||||
|
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" 2>&1 | grep 'true'
|
||||||
|
|
||||||
nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar$ext
|
nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar$ext
|
||||||
nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball$ext
|
nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball$ext
|
||||||
|
|
Loading…
Reference in a new issue