@@ -52,132 +52,112 @@ Goal::Co PathSubstitutionGoal::init()
5252 if (settings.readOnlyMode )
5353 throw Error (" cannot substitute path '%s' - no write access to the Nix store" , worker.store .printStorePath (storePath));
5454
55- subs = settings.useSubstitutes ? getDefaultSubstituters () : std::list<ref<Store>>();
55+ auto subs = settings.useSubstitutes ? getDefaultSubstituters () : std::list<ref<Store>>();
5656
57- trace ( " calling tryNext " ) ;
57+ bool substituterFailed = false ;
5858
59- co_return tryNext ();
60- }
59+ for ( auto sub : subs) {
60+ trace ( " trying next substituter " );
6161
62+ cleanup ();
6263
63- Goal::Co PathSubstitutionGoal::tryNext ()
64- {
65- trace ( " trying next substituter " ) ;
64+ /* The path the substituter refers to the path as. This will be
65+ * different when the stores have different names. */
66+ std::optional<StorePath> subPath ;
6667
67- cleanup ();
68+ /* Path info returned by the substituter's query info operation. */
69+ std::shared_ptr<const ValidPathInfo> info;
6870
69- if (subs.size () == 0 ) {
70- /* None left. Terminate this goal and let someone else deal
71- with it. */
71+ if (ca) {
72+ subPath = sub->makeFixedOutputPathFromCA (
73+ std::string { storePath.name () },
74+ ContentAddressWithReferences::withoutRefs (*ca));
75+ if (sub->storeDir == worker.store .storeDir )
76+ assert (subPath == storePath);
77+ } else if (sub->storeDir != worker.store .storeDir ) {
78+ continue ;
79+ }
7280
73- if (substituterFailed) {
74- worker.failedSubstitutions ++;
75- worker.updateProgress ();
81+ try {
82+ // FIXME: make async
83+ info = sub->queryPathInfo (subPath ? *subPath : storePath);
84+ } catch (InvalidPath &) {
85+ continue ;
86+ } catch (SubstituterDisabled & e) {
87+ if (settings.tryFallback ) continue ;
88+ else throw e;
89+ } catch (Error & e) {
90+ if (settings.tryFallback ) {
91+ logError (e.info ());
92+ continue ;
93+ } else throw e;
7694 }
7795
78- /* Hack: don't indicate failure if there were no substituters.
79- In that case the calling derivation should just do a
80- build. */
81- co_return done (
82- substituterFailed ? ecFailed : ecNoSubstituters,
83- BuildResult::NoSubstituters,
84- fmt (" path '%s' is required, but there is no substituter that can build it" , worker.store .printStorePath (storePath)));
85- }
96+ if (info->path != storePath) {
97+ if (info->isContentAddressed (*sub) && info->references .empty ()) {
98+ auto info2 = std::make_shared<ValidPathInfo>(*info);
99+ info2->path = storePath;
100+ info = info2;
101+ } else {
102+ printError (" asked '%s' for '%s' but got '%s'" ,
103+ sub->getUri (), worker.store .printStorePath (storePath), sub->printStorePath (info->path ));
104+ continue ;
105+ }
106+ }
86107
87- sub = subs.front ();
88- subs.pop_front ();
89-
90- if (ca) {
91- subPath = sub->makeFixedOutputPathFromCA (
92- std::string { storePath.name () },
93- ContentAddressWithReferences::withoutRefs (*ca));
94- if (sub->storeDir == worker.store .storeDir )
95- assert (subPath == storePath);
96- } else if (sub->storeDir != worker.store .storeDir ) {
97- co_return tryNext ();
98- }
108+ /* Update the total expected download size. */
109+ auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
99110
100- // Horrible, horrible code.
101- // Needed because we can't `co_*` inside a catch-clause.
102- // `std::variant` would be cleaner perhaps.
103- int i = 0 ;
104- std::optional<Error> e;
105- try {
106- // FIXME: make async
107- info = sub->queryPathInfo (subPath ? *subPath : storePath);
108- } catch (InvalidPath &) {
109- i = 1 ;
110- } catch (SubstituterDisabled & e_) {
111- i = 2 ;
112- e = e_;
113- } catch (Error & e_) {
114- i = 3 ;
115- e = e_;
116- }
117- switch (i) {
118- case 0 :
119- break ;
120- case 1 :
121- co_return tryNext ();
122- case 2 :
123- if (settings.tryFallback ) {
124- co_return tryNext ();
125- }
126- throw *e;
127- case 3 :
128- if (settings.tryFallback ) {
129- logError (e->info ());
130- co_return tryNext ();
131- }
132- throw *e;
133- }
111+ maintainExpectedNar = std::make_unique<MaintainCount<uint64_t >>(worker.expectedNarSize , info->narSize );
134112
135- if (info->path != storePath) {
136- if (info->isContentAddressed (*sub) && info->references .empty ()) {
137- auto info2 = std::make_shared<ValidPathInfo>(*info);
138- info2->path = storePath;
139- info = info2;
140- } else {
141- printError (" asked '%s' for '%s' but got '%s'" ,
142- sub->getUri (), worker.store .printStorePath (storePath), sub->printStorePath (info->path ));
143- co_return tryNext ();
144- }
145- }
113+ maintainExpectedDownload =
114+ narInfo && narInfo->fileSize
115+ ? std::make_unique<MaintainCount<uint64_t >>(worker.expectedDownloadSize , narInfo->fileSize )
116+ : nullptr ;
146117
147- /* Update the total expected download size. */
148- auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
118+ worker.updateProgress ();
149119
150- maintainExpectedNar = std::make_unique<MaintainCount<uint64_t >>(worker.expectedNarSize , info->narSize );
120+ /* Bail out early if this substituter lacks a valid
121+ signature. LocalStore::addToStore() also checks for this, but
122+ only after we've downloaded the path. */
123+ if (!sub->isTrusted && worker.store .pathInfoIsUntrusted (*info))
124+ {
125+ warn (" ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'" ,
126+ worker.store .printStorePath (storePath), sub->getUri ());
127+ continue ;
128+ }
151129
152- maintainExpectedDownload =
153- narInfo && narInfo->fileSize
154- ? std::make_unique<MaintainCount<uint64_t >>(worker.expectedDownloadSize , narInfo->fileSize )
155- : nullptr ;
130+ /* To maintain the closure invariant, we first have to realise the
131+ paths referenced by this one. */
132+ for (auto & i : info->references )
133+ if (i != storePath) /* ignore self-references */
134+ addWaitee (worker.makePathSubstitutionGoal (i));
156135
157- worker. updateProgress () ;
136+ if (!waitees. empty ()) co_await SuspendGoal{} ;
158137
159- /* Bail out early if this substituter lacks a valid
160- signature. LocalStore::addToStore() also checks for this, but
161- only after we've downloaded the path. */
162- if (!sub->isTrusted && worker.store .pathInfoIsUntrusted (*info))
163- {
164- warn (" ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'" ,
165- worker.store .printStorePath (storePath), sub->getUri ());
166- co_return tryNext ();
138+ // FIXME: consider returning boolean instead of passing in reference
139+ bool out = false ; // is mutated by tryToRun
140+ co_await tryToRun (subPath ? *subPath : storePath, sub, info, out);
141+ substituterFailed = substituterFailed || out;
167142 }
168143
169- /* To maintain the closure invariant, we first have to realise the
170- paths referenced by this one . */
171- for ( auto & i : info-> references )
172- if (i != storePath) /* ignore self-references */
173- addWaitee ( worker.makePathSubstitutionGoal (i) );
144+ /* None left. Terminate this goal and let someone else deal
145+ with it . */
146+
147+ worker. failedSubstitutions ++;
148+ worker.updateProgress ( );
174149
175- if (!waitees.empty ()) co_await SuspendGoal{};
176- co_return referencesValid ();
150+ /* Hack: don't indicate failure if there were no substituters.
151+ In that case the calling derivation should just do a
152+ build. */
153+ co_return done (
154+ substituterFailed ? ecFailed : ecNoSubstituters,
155+ BuildResult::NoSubstituters,
156+ fmt (" path '%s' is required, but there is no substituter that can build it" , worker.store .printStorePath (storePath)));
177157}
178158
179159
180- Goal::Co PathSubstitutionGoal::referencesValid ( )
160+ Goal::Co PathSubstitutionGoal::tryToRun (StorePath subPath, nix::ref<Store> sub, std::shared_ptr< const ValidPathInfo> info, bool & substituterFailed )
181161{
182162 trace (" all references realised" );
183163
@@ -194,12 +174,7 @@ Goal::Co PathSubstitutionGoal::referencesValid()
194174
195175 worker.wakeUp (shared_from_this ());
196176 co_await SuspendGoal{};
197- co_return tryToRun ();
198- }
199177
200-
201- Goal::Co PathSubstitutionGoal::tryToRun ()
202- {
203178 trace (" trying to run" );
204179
205180 /* Make sure that we are allowed to start a substitution. Note that even
@@ -210,7 +185,7 @@ Goal::Co PathSubstitutionGoal::tryToRun()
210185 co_await SuspendGoal{};
211186 }
212187
213- maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t >>(worker.runningSubstitutions );
188+ auto maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t >>(worker.runningSubstitutions );
214189 worker.updateProgress ();
215190
216191#ifndef _WIN32
@@ -219,9 +194,9 @@ Goal::Co PathSubstitutionGoal::tryToRun()
219194 outPipe.createAsyncPipe (worker.ioport .get ());
220195#endif
221196
222- promise = std::promise<void >();
197+ auto promise = std::promise<void >();
223198
224- thr = std::thread ([this ]() {
199+ thr = std::thread ([this , &promise, &subPath, &sub ]() {
225200 try {
226201 ReceiveInterrupts receiveInterrupts;
227202
@@ -232,7 +207,7 @@ Goal::Co PathSubstitutionGoal::tryToRun()
232207 PushActivity pact (act.id );
233208
234209 copyStorePath (*sub, worker.store ,
235- subPath ? *subPath : storePath , repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
210+ subPath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
236211
237212 promise.set_value ();
238213 } catch (...) {
@@ -249,12 +224,7 @@ Goal::Co PathSubstitutionGoal::tryToRun()
249224 }, true , false );
250225
251226 co_await SuspendGoal{};
252- co_return finished ();
253- }
254-
255227
256- Goal::Co PathSubstitutionGoal::finished ()
257- {
258228 trace (" substitute finished" );
259229
260230 thr.join ();
@@ -276,8 +246,7 @@ Goal::Co PathSubstitutionGoal::finished()
276246 substituterFailed = true ;
277247 }
278248
279- /* Try the next substitute. */
280- co_return tryNext ();
249+ co_return Return{};
281250 }
282251
283252 worker.markContentsGood (storePath);
@@ -295,6 +264,7 @@ Goal::Co PathSubstitutionGoal::finished()
295264 worker.doneDownloadSize += fileSize;
296265 }
297266
267+ assert (maintainExpectedNar);
298268 worker.doneNarSize += maintainExpectedNar->delta ;
299269 maintainExpectedNar.reset ();
300270
@@ -304,14 +274,12 @@ Goal::Co PathSubstitutionGoal::finished()
304274}
305275
306276
307- void PathSubstitutionGoal::handleChildOutput (Descriptor fd, std::string_view data)
308- {
309- }
277+ void PathSubstitutionGoal::handleChildOutput (Descriptor fd, std::string_view data) {}
310278
311279
312280void PathSubstitutionGoal::handleEOF (Descriptor fd)
313281{
314- if (fd == outPipe. readSide . get ()) worker.wakeUp (shared_from_this ());
282+ worker.wakeUp (shared_from_this ());
315283}
316284
317285
0 commit comments