Skip to content

Commit ae71c42

Browse files
authored
Merge pull request #321 from DeterminateSystems/provenance-detsys
Provenance
2 parents d69e6ae + ec59646 commit ae71c42

79 files changed

Lines changed: 978 additions & 133 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/manual/source/protocols/json/schema/store-object-info-v2.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@ $defs:
179179
The total size of this store object and every other object in its [closure](@docroot@/glossary.md#gloss-closure).
180180
181181
> This field is not stored at all, but computed by traversing the other fields across all the store objects in a closure.
182+
183+
provenance:
184+
oneOf:
185+
- type: "null"
186+
- type: object # FIXME
187+
title: Provenance
188+
description: |
189+
An arbitrary JSON object containing provenance information about the store object, or `null` if not available.
190+
182191
additionalProperties: false
183192

184193
narInfo:
@@ -262,4 +271,13 @@ $defs:
262271
> This is an impure "`.narinfo`" field that may not be included in certain contexts.
263272
264273
> This field is not stored at all, but computed by traversing the other fields across all the store objects in a closure.
274+
275+
provenance:
276+
oneOf:
277+
- type: "null"
278+
- type: object # FIXME
279+
title: Provenance
280+
description: |
281+
An arbitrary JSON object containing provenance information about the store object, or `null` if not available.
282+
265283
additionalProperties: false

src/libcmd/include/nix/cmd/installable-flake.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct InstallableFlake : InstallableValue
7272
ref<flake::LockedFlake> getLockedFlake() const;
7373

7474
FlakeRef nixpkgsFlakeRef() const;
75+
76+
std::shared_ptr<const Provenance> makeProvenance(std::string_view attrPath) const;
7577
};
7678

7779
/**

src/libcmd/installable-flake.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "nix/util/url.hh"
1818
#include "nix/fetchers/registry.hh"
1919
#include "nix/store/build-result.hh"
20+
#include "nix/flake/provenance.hh"
2021

2122
#include <regex>
2223
#include <queue>
@@ -84,6 +85,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
8485

8586
auto attrPath = attr->getAttrPathStr();
8687

88+
PushProvenance pushedProvenance(*state, makeProvenance(attrPath));
89+
8790
if (!attr->isDerivation()) {
8891

8992
// FIXME: use eval cache?
@@ -172,6 +175,8 @@ std::vector<ref<eval_cache::AttrCursor>> InstallableFlake::getCursors(EvalState
172175
for (auto & attrPath : attrPaths) {
173176
debug("trying flake output attribute '%s'", attrPath);
174177

178+
PushProvenance pushedProvenance(state, makeProvenance(attrPath));
179+
175180
auto attr = root->findAlongAttrPath(AttrPath::parse(state, attrPath));
176181
if (attr) {
177182
res.push_back(ref(*attr));
@@ -212,4 +217,14 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const
212217
return defaultNixpkgsFlakeRef();
213218
}
214219

220+
std::shared_ptr<const Provenance> InstallableFlake::makeProvenance(std::string_view attrPath) const
221+
{
222+
if (!evalSettings.pureEval)
223+
return nullptr;
224+
auto provenance = getLockedFlake()->flake.provenance;
225+
if (!provenance)
226+
return nullptr;
227+
return std::make_shared<const FlakeProvenance>(provenance, std::string(attrPath));
228+
}
229+
215230
} // namespace nix

src/libexpr/eval.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ EvalMemory::EvalMemory()
257257
assertGCInitialized();
258258
}
259259

260+
thread_local EvalState::EvalContext EvalState::evalContext;
261+
260262
EvalState::EvalState(
261263
const LookupPath & lookupPathFromArguments,
262264
ref<Store> store,

src/libexpr/include/nix/expr/eval.hh

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ enum RepairFlag : bool;
5252
struct MemorySourceAccessor;
5353
struct MountedSourceAccessor;
5454
struct AsyncPathWriter;
55+
struct Provenance;
56+
struct Executor;
5557

5658
namespace eval_cache {
5759
class EvalCache;
5860
}
59-
struct Executor;
6061

6162
/**
6263
* Increments a count on construction and decrements on destruction.
@@ -1128,6 +1129,45 @@ private:
11281129
friend class ListBuilder;
11291130

11301131
public:
1132+
1133+
/**
1134+
* Per-thread evaluation context. This context is propagated to worker threads when a value is evaluated
1135+
* asynchronously.
1136+
*/
1137+
struct EvalContext
1138+
{
1139+
std::shared_ptr<const Provenance> provenance;
1140+
};
1141+
1142+
thread_local static EvalContext evalContext;
1143+
1144+
/**
1145+
* Create a work item that propagates the current evaluation context.
1146+
*/
1147+
template<typename T>
1148+
auto makeWork(T && t)
1149+
{
1150+
return [this, t{std::move(t)}, evalContext(evalContext)]() {
1151+
this->evalContext = evalContext;
1152+
t();
1153+
};
1154+
}
1155+
1156+
/**
1157+
* Add a work item to the given work vector that propagates the current evaluation context.
1158+
*/
1159+
template<typename WorkItems, typename T>
1160+
void addWork(WorkItems & work, uint8_t priority, T && t)
1161+
{
1162+
work.emplace_back(makeWork(std::move(t)), priority);
1163+
}
1164+
1165+
template<typename FuturesVector, typename T>
1166+
void spawn(FuturesVector & futures, uint8_t priority, T && t)
1167+
{
1168+
futures.spawn(priority, makeWork(std::move(t)));
1169+
}
1170+
11311171
/**
11321172
* Worker threads manager.
11331173
*
@@ -1173,6 +1213,24 @@ SourcePath resolveExprPath(SourcePath path, bool addDefaultNix = true);
11731213
*/
11741214
bool isAllowedURI(std::string_view uri, const Strings & allowedPaths);
11751215

1216+
struct PushProvenance
1217+
{
1218+
EvalState & state;
1219+
std::shared_ptr<const Provenance> prev;
1220+
1221+
PushProvenance(EvalState & state, std::shared_ptr<const Provenance> prov)
1222+
: state(state)
1223+
{
1224+
state.evalContext.provenance.swap(prev);
1225+
state.evalContext.provenance.swap(prov);
1226+
}
1227+
1228+
~PushProvenance()
1229+
{
1230+
state.evalContext.provenance.swap(prev);
1231+
}
1232+
};
1233+
11761234
} // namespace nix
11771235

11781236
#include "nix/expr/eval-inline.hh"

src/libexpr/include/nix/expr/parallel-eval.hh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ struct Executor
5757

5858
void worker();
5959

60-
std::vector<std::future<void>> spawn(std::vector<std::pair<work_t, uint8_t>> && items);
60+
using WorkItems = std::vector<std::pair<Executor::work_t, uint8_t>>;
61+
62+
std::vector<std::future<void>> spawn(WorkItems && items);
6163

6264
static thread_local bool amWorkerThread;
6365
};
@@ -77,7 +79,7 @@ struct FutureVector
7779

7880
// FIXME: add a destructor that cancels/waits for all futures.
7981

80-
void spawn(std::vector<std::pair<Executor::work_t, uint8_t>> && work);
82+
void spawn(Executor::WorkItems && work);
8183

8284
void spawn(uint8_t prioPrefix, Executor::work_t && work)
8385
{

src/libexpr/parallel-eval.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ void Executor::worker()
110110
}
111111
}
112112

113-
std::vector<std::future<void>> Executor::spawn(std::vector<std::pair<work_t, uint8_t>> && items)
113+
std::vector<std::future<void>> Executor::spawn(WorkItems && items)
114114
{
115115
if (items.empty())
116116
return {};
@@ -146,7 +146,7 @@ FutureVector::~FutureVector()
146146
}
147147
}
148148

149-
void FutureVector::spawn(std::vector<std::pair<Executor::work_t, uint8_t>> && work)
149+
void FutureVector::spawn(Executor::WorkItems && work)
150150
{
151151
auto futures = executor.spawn(std::move(work));
152152
auto state(state_.lock());
@@ -273,10 +273,11 @@ static void prim_parallel(EvalState & state, const PosIdx pos, Value ** args, Va
273273
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.parallel");
274274

275275
if (state.executor->evalCores > 1) {
276-
std::vector<std::pair<Executor::work_t, uint8_t>> work;
276+
Executor::WorkItems work;
277277
for (auto value : args[0]->listView())
278278
if (!value->isFinished())
279-
work.emplace_back([value(allocRootValue(value)), &state, pos]() { state.forceValue(**value, pos); }, 0);
279+
state.addWork(
280+
work, 0, [value(allocRootValue(value)), &state, pos]() { state.forceValue(**value, pos); });
280281
state.executor->spawn(std::move(work));
281282
}
282283

src/libexpr/primops.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,8 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
18471847
}
18481848

18491849
/* Write the resulting term into the Nix store directory. */
1850-
auto drvPath = writeDerivation(*state.store, *state.asyncPathWriter, drv, state.repair);
1850+
auto drvPath =
1851+
writeDerivation(*state.store, *state.asyncPathWriter, drv, state.repair, false, state.evalContext.provenance);
18511852
auto drvPathS = state.store->printStorePath(drvPath);
18521853

18531854
printMsg(lvlChatty, "instantiated '%1%' -> '%2%'", drvName, drvPathS);
@@ -2750,7 +2751,8 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value ** args, Valu
27502751
ContentAddressMethod::Raw::Text,
27512752
HashAlgorithm::SHA256,
27522753
refs,
2753-
state.repair);
2754+
state.repair,
2755+
state.evalContext.provenance);
27542756
});
27552757

27562758
/* Note: we don't need to add `context' to the context of the

src/libexpr/value-to-json.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static void parallelForceDeep(EvalState & state, Value & v, PosIdx pos)
1818
{
1919
state.forceValue(v, pos);
2020

21-
std::vector<std::pair<Executor::work_t, uint8_t>> work;
21+
Executor::WorkItems work;
2222

2323
switch (v.type()) {
2424

@@ -29,8 +29,9 @@ static void parallelForceDeep(EvalState & state, Value & v, PosIdx pos)
2929
if (v.attrs()->get(state.s.outPath))
3030
return;
3131
for (auto & a : *v.attrs())
32-
work.emplace_back(
33-
[value(allocRootValue(a.value)), pos(a.pos), &state]() { parallelForceDeep(state, **value, pos); }, 0);
32+
state.addWork(work, 0, [value(allocRootValue(a.value)), pos(a.pos), &state]() {
33+
parallelForceDeep(state, **value, pos);
34+
});
3435
break;
3536
}
3637

src/libfetchers/attrs.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ nlohmann::json attrsToJSON(const Attrs & attrs)
2727
{
2828
nlohmann::json json;
2929
for (auto & attr : attrs) {
30+
/* The __final attribute is purely internal, so never serialize it. */
31+
if (attr.first == "__final")
32+
continue;
3033
if (auto v = std::get_if<uint64_t>(&attr.second)) {
3134
json[attr.first] = *v;
3235
} else if (auto v = std::get_if<std::string>(&attr.second)) {

0 commit comments

Comments
 (0)