@@ -327,47 +327,59 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
327
327
if (!scheme)
328
328
throw Error (" cannot fetch unsupported input '%s'" , attrsToJSON (toAttrs ()));
329
329
330
- /* The tree may already be in the Nix store, or it could be
331
- substituted (which is often faster than fetching from the
332
- original source). So check that. We only do this for final
333
- inputs, otherwise there is a risk that we don't return the
334
- same attributes (like `lastModified`) that the "real" fetcher
335
- would return.
336
-
337
- FIXME: add a setting to disable this.
338
- FIXME: substituting may be slower than fetching normally,
339
- e.g. for fetchers like Git that are incremental!
340
- */
341
- if (isFinal () && getNarHash ()) {
342
- try {
343
- auto storePath = computeStorePath (*store);
344
-
345
- store->ensurePath (storePath);
330
+ std::optional<StorePath> storePath;
331
+ if (isFinal () && getNarHash ())
332
+ storePath = computeStorePath (*store);
346
333
347
- debug (" using substituted/cached input '%s' in '%s'" , to_string (), store->printStorePath (storePath));
334
+ auto makeStoreAccessor = [&]() -> std::pair<ref<SourceAccessor>, Input> {
335
+ auto accessor = make_ref<SubstitutedSourceAccessor>(makeStorePathAccessor (store, *storePath));
348
336
349
- auto accessor = make_ref<SubstitutedSourceAccessor>( makeStorePathAccessor ( store, storePath) );
337
+ accessor-> fingerprint = getFingerprint ( store);
350
338
351
- accessor->fingerprint = getFingerprint (store);
339
+ // FIXME: ideally we would use the `showPath()` of the
340
+ // "real" accessor for this fetcher type.
341
+ accessor->setPathDisplay (" «" + to_string () + " »" );
352
342
353
- // FIXME: ideally we would use the `showPath()` of the
354
- // "real" accessor for this fetcher type.
355
- accessor->setPathDisplay (" «" + to_string () + " »" );
343
+ return {accessor, *this };
344
+ };
356
345
357
- return {accessor, *this };
358
- } catch (Error & e) {
359
- debug (" substitution of input '%s' failed: %s" , to_string (), e.what ());
360
- }
346
+ /* If a tree with the expected hash is already in the Nix store,
347
+ reuse it. We only do this for final inputs, since otherwise
348
+ there is a risk that we don't return the same attributes (like
349
+ `lastModified`) that the "real" fetcher would return. */
350
+ if (storePath && store->isValidPath (*storePath)) {
351
+ debug (" using input '%s' in '%s'" , to_string (), store->printStorePath (*storePath));
352
+ return makeStoreAccessor ();
361
353
}
362
354
363
- auto [accessor, result] = scheme->getAccessor (store, *this );
355
+ try {
356
+ auto [accessor, result] = scheme->getAccessor (store, *this );
364
357
365
- if (!accessor->fingerprint )
366
- accessor->fingerprint = result.getFingerprint (store);
367
- else
368
- result.cachedFingerprint = accessor->fingerprint ;
358
+ if (!accessor->fingerprint )
359
+ accessor->fingerprint = result.getFingerprint (store);
360
+ else
361
+ result.cachedFingerprint = accessor->fingerprint ;
369
362
370
- return {accessor, std::move (result)};
363
+ return {accessor, std::move (result)};
364
+ } catch (Error & e) {
365
+ if (storePath) {
366
+ // Fall back to substitution.
367
+ try {
368
+ store->ensurePath (*storePath);
369
+ warn (
370
+ " Successfully substituted input '%s' after failing to fetch it from its original location: %s" ,
371
+ to_string (),
372
+ e.info ().msg );
373
+ return makeStoreAccessor ();
374
+ }
375
+ // Ignore any substitution error, rethrow the original error.
376
+ catch (Error & e2 ) {
377
+ debug (" substitution of input '%s' failed: %s" , to_string (), e2 .info ().msg );
378
+ } catch (...) {
379
+ }
380
+ }
381
+ throw ;
382
+ }
371
383
}
372
384
373
385
Input Input::applyOverrides (std::optional<std::string> ref, std::optional<Hash> rev) const
0 commit comments