2020-06-17 03:56:48 +00:00
# include "fs-accessor.hh"
2006-11-30 17:43:04 +00:00
# include "globals.hh"
2022-03-17 22:29:15 +00:00
# include "derivations.hh"
2016-03-24 10:41:00 +00:00
# include "store-api.hh"
2016-04-20 12:12:38 +00:00
# include "nar-info-disk-cache.hh"
2016-07-18 22:50:27 +00:00
# include "thread-pool.hh"
2020-03-30 14:04:18 +00:00
# include "url.hh"
2020-10-07 13:52:20 +00:00
# include "references.hh"
2020-07-10 11:21:37 +00:00
# include "archive.hh"
2021-07-16 07:37:33 +00:00
# include "remote-store.hh"
2024-03-10 06:36:47 +00:00
# include "signals.hh"
2024-03-04 03:59:31 +00:00
// FIXME this should not be here, see TODO below on
// `addMultipleToStore`.
# include "worker-protocol.hh"
2024-05-28 13:40:03 +00:00
# include "users.hh"
2019-07-10 17:46:15 +00:00
2022-11-16 15:49:49 +00:00
# include <nlohmann/json.hpp>
2020-12-05 14:33:16 +00:00
# include <regex>
2022-11-16 15:49:49 +00:00
using json = nlohmann : : json ;
2006-11-30 17:43:04 +00:00
namespace nix {
2024-05-25 02:45:05 +00:00
BuildMode buildModeFromInteger ( int raw ) {
switch ( raw ) {
case bmNormal : return bmNormal ;
case bmRepair : return bmRepair ;
case bmCheck : return bmCheck ;
default : throw Error ( " Invalid BuildMode " ) ;
}
}
2006-11-30 17:43:04 +00:00
2022-12-07 11:58:58 +00:00
bool Store : : isInStore ( PathView path ) const
2006-11-30 17:43:04 +00:00
{
2016-06-01 12:49:12 +00:00
return isInDir ( path , storeDir ) ;
2006-11-30 17:43:04 +00:00
}
2022-12-07 11:58:58 +00:00
std : : pair < StorePath , Path > Store : : toStorePath ( PathView path ) const
2006-11-30 17:43:04 +00:00
{
if ( ! isInStore ( path ) )
2020-04-21 23:07:07 +00:00
throw Error ( " path '%1%' is not in the Nix store " , path ) ;
2022-12-07 11:58:58 +00:00
auto slash = path . find ( ' / ' , storeDir . size ( ) + 1 ) ;
2006-11-30 17:43:04 +00:00
if ( slash = = Path : : npos )
2020-07-13 14:19:37 +00:00
return { parseStorePath ( path ) , " " } ;
2006-11-30 17:43:04 +00:00
else
2022-12-07 11:58:58 +00:00
return { parseStorePath ( path . substr ( 0 , slash ) ) , ( Path ) path . substr ( slash ) } ;
2006-11-30 17:43:04 +00:00
}
2019-12-16 18:11:47 +00:00
Path Store : : followLinksToStore ( std : : string_view _path ) const
2007-11-29 16:18:24 +00:00
{
2019-12-16 18:11:47 +00:00
Path path = absPath ( std : : string ( _path ) ) ;
2007-11-29 16:18:24 +00:00
while ( ! isInStore ( path ) ) {
if ( ! isLink ( path ) ) break ;
2022-02-25 15:00:00 +00:00
auto target = readLink ( path ) ;
2007-11-29 16:18:24 +00:00
path = absPath ( target , dirOf ( path ) ) ;
}
if ( ! isInStore ( path ) )
2020-07-13 14:19:37 +00:00
throw BadStorePath ( " path '%1%' is not in the Nix store " , path ) ;
2007-11-29 16:18:24 +00:00
return path ;
}
2019-12-16 18:11:47 +00:00
StorePath Store : : followLinksToStorePath ( std : : string_view path ) const
2007-11-29 16:18:24 +00:00
{
2020-07-13 14:19:37 +00:00
return toStorePath ( followLinksToStore ( path ) ) . first ;
2016-02-15 11:49:01 +00:00
}
2008-12-03 15:06:30 +00:00
/* Store paths have the following form:
2020-06-03 20:08:32 +00:00
< realized - path > = < store > / < h > - < name >
2008-12-03 15:06:30 +00:00
where
< store > = the location of the Nix store , usually / nix / store
2015-07-17 17:24:28 +00:00
2008-12-03 15:06:30 +00:00
< name > = a human readable name for the path , typically obtained
from the name attribute of the derivation , or the name of the
2011-07-20 18:10:47 +00:00
source file from which the store path is created . For derivation
outputs other than the default " out " output , the string " -<id> "
is suffixed to < name > .
2015-07-17 17:24:28 +00:00
2008-12-03 15:06:30 +00:00
< h > = base - 32 representation of the first 160 bits of a SHA - 256
hash of < s > ; the hash part of the store name
2015-07-17 17:24:28 +00:00
2008-12-03 15:06:30 +00:00
< s > = the string " <type>:sha256:<h2>:<store>:<name> " ;
note that it includes the location of the store as well as the
name to make sure that changes to either of those are reflected
in the hash ( e . g . you won ' t get / nix / store / < h > - name1 and
/ nix / store / < h > - name2 with equal hash parts ) .
2015-07-17 17:24:28 +00:00
2008-12-03 15:06:30 +00:00
< type > = one of :
" text:<r1>:<r2>:...<rN> "
for plain text files written to the store using
2020-06-03 20:08:32 +00:00
addTextToStore ( ) ; < r1 > . . . < rN > are the store paths referenced
by this path , in the form described by < realized - path >
" source:<r1>:<r2>:...:<rN>:self "
2008-12-03 15:06:30 +00:00
for paths copied to the store using addToStore ( ) when recursive
2020-06-03 20:08:32 +00:00
= true and hashAlgo = " sha256 " . Just like in the text case , we
can have the store paths referenced by the path .
Additionally , we can have an optional : self label to denote self
reference .
2011-07-20 18:10:47 +00:00
" output:<id> "
2008-12-03 15:06:30 +00:00
for either the outputs created by derivations , OR paths copied
to the store using addToStore ( ) with recursive ! = true or
hashAlgo ! = " sha256 " ( in that case " source " is used ; it ' s
2011-07-20 18:10:47 +00:00
silly , but it ' s done that way for compatibility ) . < id > is the
name of the output ( usually , " out " ) .
2008-12-03 15:06:30 +00:00
2023-02-28 16:49:13 +00:00
< h2 > = base - 16 representation of a SHA - 256 hash of < s2 >
< s2 > =
2008-12-03 15:06:30 +00:00
if < type > = " text:... " :
the string written to the resulting store path
2023-02-28 16:49:13 +00:00
if < type > = " source:... " :
2008-12-03 15:06:30 +00:00
the serialisation of the path from which this store path is
copied , as returned by hashPath ( )
2016-03-24 10:27:58 +00:00
if < type > = " output:<id> " :
2008-12-03 15:06:30 +00:00
for non - fixed derivation outputs :
the derivation ( see hashDerivationModulo ( ) in
primops . cc )
for paths copied by addToStore ( ) or produced by fixed - output
derivations :
the string " fixed:out:<rec><algo>:<hash>: " , where
2016-03-24 10:27:58 +00:00
< rec > = " r: " for recursive ( path ) hashes , or " " for flat
2008-12-03 15:06:30 +00:00
( file ) hashes
< algo > = " md5 " , " sha1 " or " sha256 "
< hash > = base - 16 representation of the path or flat hash of
the contents of the path ( or expected contents of the
path for fixed - output derivations )
2020-06-03 20:08:32 +00:00
Note that since an output derivation has always type output , while
something added by addToStore can have type output or source depending
on the hash , this means that the same input can be hashed differently
if added to the store via addToStore or via a derivation , in the sha256
recursive case .
2008-12-03 15:06:30 +00:00
It would have been nicer to handle fixed - output derivations under
" source " , e . g . have something like " source:<rec><algo> " , but we ' re
stuck with this for now . . .
The main reason for this way of computing names is to prevent name
collisions ( for security ) . For instance , it shouldn ' t be feasible
to come up with a derivation whose output path collides with the
path for a copied source . The former would have a < s > starting with
2017-05-11 12:02:03 +00:00
" output:out: " , while the latter would have a < s > starting with
2008-12-03 15:06:30 +00:00
" source: " .
*/
2020-08-07 19:09:26 +00:00
StorePath Store : : makeStorePath ( std : : string_view type ,
std : : string_view hash , std : : string_view name ) const
2006-11-30 17:43:04 +00:00
{
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
2022-02-25 15:00:00 +00:00
auto s = std : : string ( type ) + " : " + std : : string ( hash )
+ " : " + storeDir + " : " + std : : string ( name ) ;
2019-12-05 18:11:09 +00:00
auto h = compressHash ( hashString ( htSHA256 , s ) , 20 ) ;
2020-06-16 12:16:39 +00:00
return StorePath ( h , name ) ;
2006-11-30 17:43:04 +00:00
}
2020-08-07 19:09:26 +00:00
StorePath Store : : makeStorePath ( std : : string_view type ,
const Hash & hash , std : : string_view name ) const
{
return makeStorePath ( type , hash . to_string ( Base16 , true ) , name ) ;
}
StorePath Store : : makeOutputPath ( std : : string_view id ,
2019-12-05 18:11:09 +00:00
const Hash & hash , std : : string_view name ) const
2011-07-20 18:10:47 +00:00
{
2020-08-07 19:09:26 +00:00
return makeStorePath ( " output: " + std : : string { id } , hash , outputPathName ( name , id ) ) ;
2011-07-20 18:10:47 +00:00
}
2020-10-07 13:52:20 +00:00
/* Stuff the references (if any) into the type. This is a bit
2023-02-28 16:49:13 +00:00
hacky , but we can ' t put them in , say , < s2 > ( per the grammar above )
since that would be ambiguous . */
2019-12-05 18:11:09 +00:00
static std : : string makeType (
const Store & store ,
2022-02-25 15:00:00 +00:00
std : : string & & type ,
2023-01-06 20:36:05 +00:00
const StoreReferences & references )
2018-03-29 22:56:13 +00:00
{
2023-01-06 20:36:05 +00:00
for ( auto & i : references . others ) {
2018-03-29 22:56:13 +00:00
type + = " : " ;
2019-12-05 18:11:09 +00:00
type + = store . printStorePath ( i ) ;
2018-03-29 22:56:13 +00:00
}
2023-01-06 20:36:05 +00:00
if ( references . self ) type + = " :self " ;
2019-11-26 20:07:44 +00:00
return std : : move ( type ) ;
2018-03-29 22:56:13 +00:00
}
2020-10-07 13:52:20 +00:00
StorePath Store : : makeFixedOutputPath ( std : : string_view name , const FixedOutputInfo & info ) const
2006-11-30 17:43:04 +00:00
{
2023-07-05 22:53:44 +00:00
if ( info . hash . type = = htSHA256 & & info . method = = FileIngestionMethod : : Recursive ) {
return makeStorePath ( makeType ( * this , " source " , info . references ) , info . hash , name ) ;
2018-03-29 22:56:13 +00:00
} else {
2024-03-04 06:50:02 +00:00
if ( ! info . references . empty ( ) ) {
throw Error ( " fixed output derivation '%s' is not allowed to refer to other store paths. \n You may need to use the 'unsafeDiscardReferences' derivation attribute, see the manual for more details. " ,
name ) ;
}
2020-03-30 22:31:51 +00:00
return makeStorePath ( " output:out " ,
hashString ( htSHA256 ,
" fixed:out: "
2023-07-05 22:53:44 +00:00
+ makeFileIngestionPrefix ( info . method )
+ info . hash . to_string ( Base16 , true ) + " : " ) ,
2020-03-30 22:31:51 +00:00
name ) ;
2018-03-29 22:56:13 +00:00
}
2006-11-30 17:43:04 +00:00
}
2020-10-07 13:52:20 +00:00
StorePath Store : : makeTextPath ( std : : string_view name , const TextInfo & info ) const
{
2023-07-05 22:53:44 +00:00
assert ( info . hash . type = = htSHA256 ) ;
2020-10-07 13:52:20 +00:00
return makeStorePath (
2023-01-14 21:38:43 +00:00
makeType ( * this , " text " , StoreReferences {
. others = info . references ,
. self = false ,
} ) ,
2023-07-05 22:53:44 +00:00
info . hash ,
2020-10-07 13:52:20 +00:00
name ) ;
}
2023-01-23 17:58:11 +00:00
StorePath Store : : makeFixedOutputPathFromCA ( std : : string_view name , const ContentAddressWithReferences & ca ) const
2020-06-12 21:36:35 +00:00
{
2020-06-22 17:08:11 +00:00
// New template
return std : : visit ( overloaded {
2021-10-01 17:12:54 +00:00
[ & ] ( const TextInfo & ti ) {
2023-01-23 17:58:11 +00:00
return makeTextPath ( name , ti ) ;
2020-06-22 17:08:11 +00:00
} ,
2021-10-01 17:12:54 +00:00
[ & ] ( const FixedOutputInfo & foi ) {
2023-01-23 17:58:11 +00:00
return makeFixedOutputPath ( name , foi ) ;
2020-06-22 17:08:11 +00:00
}
2023-03-30 21:12:49 +00:00
} , ca . raw ) ;
2016-08-03 11:17:11 +00:00
}
2019-12-05 18:11:09 +00:00
std : : pair < StorePath , Hash > Store : : computeStorePathForPath ( std : : string_view name ,
2020-05-27 18:04:20 +00:00
const Path & srcPath , FileIngestionMethod method , HashType hashAlgo , PathFilter & filter ) const
2006-12-01 18:00:01 +00:00
{
2020-05-27 18:04:20 +00:00
Hash h = method = = FileIngestionMethod : : Recursive
2020-03-30 22:31:51 +00:00
? hashPath ( hashAlgo , srcPath , filter ) . first
: hashFile ( hashAlgo , srcPath ) ;
2020-10-07 13:52:20 +00:00
FixedOutputInfo caInfo {
2023-07-05 22:53:44 +00:00
. method = method ,
. hash = h ,
2023-02-28 16:57:20 +00:00
. references = { } ,
2020-10-07 13:52:20 +00:00
} ;
return std : : make_pair ( makeFixedOutputPath ( name , caInfo ) , h ) ;
2006-12-01 18:00:01 +00:00
}
2022-02-25 15:00:00 +00:00
StorePath Store : : computeStorePathForText (
std : : string_view name ,
std : : string_view s ,
2019-12-05 18:11:09 +00:00
const StorePathSet & references ) const
2006-12-01 18:00:01 +00:00
{
2020-10-07 13:52:20 +00:00
return makeTextPath ( name , TextInfo {
2023-07-05 22:53:44 +00:00
. hash = hashString ( htSHA256 , s ) ,
. references = references ,
2020-10-07 13:52:20 +00:00
} ) ;
2006-12-01 18:00:01 +00:00
}
2022-02-25 15:00:00 +00:00
StorePath Store : : addToStore (
std : : string_view name ,
const Path & _srcPath ,
FileIngestionMethod method ,
HashType hashAlgo ,
PathFilter & filter ,
RepairFlag repair ,
const StorePathSet & references )
2020-08-03 04:13:45 +00:00
{
Path srcPath ( absPath ( _srcPath ) ) ;
2024-03-23 23:44:57 +00:00
auto source = GeneratorSource {
method = = FileIngestionMethod : : Recursive ? dumpPath ( srcPath , filter ) . decay ( )
: readFileSource ( srcPath )
} ;
return addToStoreFromDump ( source , name , method , hashAlgo , repair , references ) ;
2020-08-03 04:13:45 +00:00
}
2022-06-03 15:01:16 +00:00
void Store : : addMultipleToStore (
2022-06-08 12:03:46 +00:00
PathsSource & pathsToCopy ,
2022-06-03 15:01:16 +00:00
Activity & act ,
RepairFlag repair ,
CheckSigsFlag checkSigs )
{
std : : atomic < size_t > nrDone { 0 } ;
std : : atomic < size_t > nrFailed { 0 } ;
std : : atomic < uint64_t > bytesExpected { 0 } ;
std : : atomic < uint64_t > nrRunning { 0 } ;
using PathWithInfo = std : : pair < ValidPathInfo , std : : unique_ptr < Source > > ;
2022-08-23 12:14:47 +00:00
std : : map < StorePath , PathWithInfo * > infosMap ;
2022-06-03 15:01:16 +00:00
StorePathSet storePathsToAdd ;
for ( auto & thingToAdd : pathsToCopy ) {
infosMap . insert_or_assign ( thingToAdd . first . path , & thingToAdd ) ;
storePathsToAdd . insert ( thingToAdd . first . path ) ;
}
auto showProgress = [ & ] ( ) {
act . progress ( nrDone , pathsToCopy . size ( ) , nrRunning , nrFailed ) ;
} ;
ThreadPool pool ;
processGraph < StorePath > ( pool ,
storePathsToAdd ,
[ & ] ( const StorePath & path ) {
2022-08-23 12:14:47 +00:00
auto & [ info , _ ] = * infosMap . at ( path ) ;
2022-06-03 15:01:16 +00:00
if ( isValidPath ( info . path ) ) {
nrDone + + ;
showProgress ( ) ;
return StorePathSet ( ) ;
}
bytesExpected + = info . narSize ;
act . setExpected ( actCopyPath , bytesExpected ) ;
2023-01-14 21:38:43 +00:00
return info . references ;
2022-06-03 15:01:16 +00:00
} ,
[ & ] ( const StorePath & path ) {
checkInterrupt ( ) ;
2022-08-24 12:11:03 +00:00
auto & [ info_ , source_ ] = * infosMap . at ( path ) ;
2022-07-19 17:46:00 +00:00
auto info = info_ ;
info . ultimate = false ;
2022-06-03 15:01:16 +00:00
2022-08-23 12:14:47 +00:00
/* Make sure that the Source object is destroyed when
we ' re done . In particular , a SinkToSource object must
be destroyed to ensure that the destructors on its
stack frame are run ; this includes
LegacySSHStore : : narFromPath ( ) ' s connection lock . */
2022-08-24 12:49:58 +00:00
auto source = std : : move ( source_ ) ;
2022-08-23 12:14:47 +00:00
2022-06-03 15:01:16 +00:00
if ( ! isValidPath ( info . path ) ) {
MaintainCount < decltype ( nrRunning ) > mc ( nrRunning ) ;
showProgress ( ) ;
try {
addToStore ( info , * source , repair , checkSigs ) ;
2022-08-23 12:14:47 +00:00
} catch ( Error & e ) {
2022-06-03 15:01:16 +00:00
nrFailed + + ;
if ( ! settings . keepGoing )
throw e ;
printMsg ( lvlError , " could not copy %s: %s " , printStorePath ( path ) , e . what ( ) ) ;
showProgress ( ) ;
return ;
}
}
nrDone + + ;
showProgress ( ) ;
} ) ;
}
2020-08-03 04:13:45 +00:00
2021-07-26 11:31:09 +00:00
void Store : : addMultipleToStore (
Source & source ,
RepairFlag repair ,
CheckSigsFlag checkSigs )
{
2024-05-25 02:45:05 +00:00
auto remoteVersion = getProtocol ( ) ;
2021-07-26 11:31:09 +00:00
auto expected = readNum < uint64_t > ( source ) ;
for ( uint64_t i = 0 ; i < expected ; + + i ) {
2024-05-25 02:45:05 +00:00
// FIXME we should not be using the worker protocol here at all!
2024-03-04 03:59:31 +00:00
auto info = WorkerProto : : Serialise < ValidPathInfo > : : read ( * this ,
2024-05-25 02:45:05 +00:00
WorkerProto : : ReadConn { source , remoteVersion }
) ;
2021-07-26 11:31:09 +00:00
info . ultimate = false ;
addToStore ( info , source , repair , checkSigs ) ;
}
}
2020-07-21 00:18:12 +00:00
/*
The aim of this function is to compute in one pass the correct ValidPathInfo for
the files that we are trying to add to the store . To accomplish that in one
pass , given the different kind of inputs that we can take ( normal nar archives ,
nar archives with non SHA - 256 hashes , and flat files ) , we set up a net of sinks
and aliases . Also , since the dataflow is obfuscated by this , we include here a
graphviz diagram :
digraph graphname {
node [ shape = box ]
fileSource - > narSink
narSink [ style = dashed ]
narSink - > unsualHashTee [ style = dashed , label = " Recursive && !SHA-256 " ]
narSink - > narHashSink [ style = dashed , label = " else " ]
unsualHashTee - > narHashSink
unsualHashTee - > caHashSink
fileSource - > parseSink
parseSink [ style = dashed ]
parseSink - > fileSink [ style = dashed , label = " Flat " ]
parseSink - > blank [ style = dashed , label = " Recursive " ]
fileSink - > caHashSink
}
*/
2020-07-10 11:21:37 +00:00
ValidPathInfo Store : : addToStoreSlow ( std : : string_view name , const Path & srcPath ,
FileIngestionMethod method , HashType hashAlgo ,
std : : optional < Hash > expectedCAHash )
{
2020-07-16 05:09:41 +00:00
HashSink narHashSink { htSHA256 } ;
HashSink caHashSink { hashAlgo } ;
2020-07-10 11:21:37 +00:00
2020-07-21 00:18:12 +00:00
/* Note that fileSink and unusualHashTee must be mutually exclusive, since
they both write to caHashSink . Note that that requisite is currently true
because the former is only used in the flat case . */
RetrieveRegularNARSink fileSink { caHashSink } ;
TeeSink unusualHashTee { narHashSink , caHashSink } ;
2020-07-10 13:56:24 +00:00
2020-07-21 00:18:12 +00:00
auto & narSink = method = = FileIngestionMethod : : Recursive & & hashAlgo ! = htSHA256
? static_cast < Sink & > ( unusualHashTee )
2020-07-16 05:09:41 +00:00
: narHashSink ;
2020-07-21 00:18:12 +00:00
/* Functionally, this means that fileSource will yield the content of
srcPath . The fact that we use scratchpadSink as a temporary buffer here
is an implementation detail . */
2024-03-22 23:47:16 +00:00
auto fileSource = GeneratorSource { dumpPath ( srcPath ) } ;
2020-07-10 11:21:37 +00:00
2020-07-21 00:18:12 +00:00
/* tapped provides the same data as fileSource, but we also write all the
information to narSink . */
2024-03-22 23:47:16 +00:00
TeeSource tapped { fileSource , narSink } ;
2020-07-10 13:56:24 +00:00
2020-07-16 05:09:41 +00:00
ParseSink blank ;
auto & parseSink = method = = FileIngestionMethod : : Flat
? fileSink
: blank ;
2020-07-21 00:18:12 +00:00
/* The information that flows from tapped (besides being replicated in
narSink ) , is now put in parseSink . */
parseDump ( parseSink , tapped ) ;
2020-07-16 05:09:41 +00:00
2020-07-21 00:18:12 +00:00
/* We extract the result of the computation from the sink by calling
finish . */
2020-07-16 05:09:41 +00:00
auto [ narHash , narSize ] = narHashSink . finish ( ) ;
auto hash = method = = FileIngestionMethod : : Recursive & & hashAlgo = = htSHA256
? narHash
: caHashSink . finish ( ) . first ;
2020-07-10 11:21:37 +00:00
if ( expectedCAHash & & expectedCAHash ! = hash )
throw Error ( " hash mismatch for '%s' " , srcPath ) ;
2020-08-06 18:31:48 +00:00
ValidPathInfo info {
2020-10-07 13:52:20 +00:00
* this ,
2023-01-23 17:58:11 +00:00
name ,
FixedOutputInfo {
2023-07-05 22:53:44 +00:00
. method = method ,
. hash = hash ,
2023-02-28 16:57:20 +00:00
. references = { } ,
2020-10-07 13:52:20 +00:00
} ,
2020-08-06 18:31:48 +00:00
narHash ,
} ;
2020-07-10 11:21:37 +00:00
info . narSize = narSize ;
if ( ! isValidPath ( info . path ) ) {
2024-03-22 23:47:16 +00:00
auto source = GeneratorSource { dumpPath ( srcPath ) } ;
addToStore ( info , source ) ;
2020-07-10 11:21:37 +00:00
}
return info ;
}
2021-06-11 06:37:59 +00:00
StringSet StoreConfig : : getDefaultSystemFeatures ( )
{
auto res = settings . systemFeatures . get ( ) ;
2021-11-19 02:28:20 +00:00
2023-03-17 14:33:48 +00:00
if ( experimentalFeatureSettings . isEnabled ( Xp : : CaDerivations ) )
2021-06-11 06:37:59 +00:00
res . insert ( " ca-derivations " ) ;
2021-11-19 02:28:20 +00:00
2023-03-17 14:33:48 +00:00
if ( experimentalFeatureSettings . isEnabled ( Xp : : RecursiveNix ) )
2021-11-19 02:28:20 +00:00
res . insert ( " recursive-nix " ) ;
2021-06-11 06:37:59 +00:00
return res ;
}
2020-07-10 11:21:37 +00:00
2016-06-01 12:49:12 +00:00
Store : : Store ( const Params & params )
2020-09-10 08:55:51 +00:00
: StoreConfig ( params )
2017-04-13 13:55:38 +00:00
, state ( { ( size_t ) pathInfoCacheSize } )
2016-06-01 12:49:12 +00:00
{
2022-12-19 13:06:07 +00:00
assertLibStoreInitialized ( ) ;
2016-06-01 12:49:12 +00:00
}
2016-04-20 12:12:38 +00:00
std : : string Store : : getUri ( )
{
return " " ;
}
2020-03-11 19:04:47 +00:00
bool Store : : PathInfoCacheValue : : isKnownNow ( )
{
std : : chrono : : duration ttl = didExist ( )
? std : : chrono : : seconds ( settings . ttlPositiveNarInfoCache )
: std : : chrono : : seconds ( settings . ttlNegativeNarInfoCache ) ;
return std : : chrono : : steady_clock : : now ( ) < time_point + ttl ;
}
2016-04-20 12:12:38 +00:00
2023-07-19 18:52:35 +00:00
std : : map < std : : string , std : : optional < StorePath > > Store : : queryStaticPartialDerivationOutputMap ( const StorePath & path )
2020-12-17 10:35:24 +00:00
{
std : : map < std : : string , std : : optional < StorePath > > outputs ;
auto drv = readInvalidDerivation ( path ) ;
2023-07-19 18:52:35 +00:00
for ( auto & [ outputName , output ] : drv . outputsAndOptPaths ( * this ) ) {
2020-12-17 10:35:24 +00:00
outputs . emplace ( outputName , output . second ) ;
}
return outputs ;
}
2023-07-19 18:52:35 +00:00
std : : map < std : : string , std : : optional < StorePath > > Store : : queryPartialDerivationOutputMap (
const StorePath & path ,
Store * evalStore_ )
{
auto & evalStore = evalStore_ ? * evalStore_ : * this ;
auto outputs = evalStore . queryStaticPartialDerivationOutputMap ( path ) ;
if ( ! experimentalFeatureSettings . isEnabled ( Xp : : CaDerivations ) )
return outputs ;
auto drv = evalStore . readInvalidDerivation ( path ) ;
auto drvHashes = staticOutputHashes ( * this , drv ) ;
for ( auto & [ outputName , hash ] : drvHashes ) {
auto realisation = queryRealisation ( DrvOutput { hash , outputName } ) ;
if ( realisation ) {
outputs . insert_or_assign ( outputName , realisation - > outPath ) ;
} else {
// queryStaticPartialDerivationOutputMap is not guaranteed
// to return std::nullopt for outputs which are not
// statically known.
outputs . insert ( { outputName , std : : nullopt } ) ;
}
}
return outputs ;
}
2024-03-04 06:13:33 +00:00
OutputPathMap Store : : queryDerivationOutputMap ( const StorePath & path , Store * evalStore ) {
auto resp = queryPartialDerivationOutputMap ( path , evalStore ) ;
2020-08-04 22:28:10 +00:00
OutputPathMap result ;
for ( auto & [ outName , optOutPath ] : resp ) {
if ( ! optOutPath )
2023-07-19 18:52:35 +00:00
throw MissingRealisation ( printStorePath ( path ) , outName ) ;
2020-08-04 22:28:10 +00:00
result . insert_or_assign ( outName , * optOutPath ) ;
}
return result ;
2020-07-24 21:02:51 +00:00
}
2020-06-10 09:20:52 +00:00
StorePathSet Store : : queryDerivationOutputs ( const StorePath & path )
{
auto outputMap = this - > queryDerivationOutputMap ( path ) ;
StorePathSet outputPaths ;
for ( auto & i : outputMap ) {
outputPaths . emplace ( std : : move ( i . second ) ) ;
}
return outputPaths ;
}
2023-04-03 00:28:10 +00:00
void Store : : querySubstitutablePathInfos ( const StorePathCAMap & paths , SubstitutablePathInfos & infos )
{
if ( ! settings . useSubstitutes ) return ;
for ( auto & sub : getDefaultSubstituters ( ) ) {
for ( auto & path : paths ) {
if ( infos . count ( path . first ) )
// Choose first succeeding substituter.
continue ;
auto subPath ( path . first ) ;
// Recompute store path so that we can use a different store root.
if ( path . second ) {
2023-04-08 00:39:04 +00:00
subPath = makeFixedOutputPathFromCA (
path . first . name ( ) ,
ContentAddressWithReferences : : withoutRefs ( * path . second ) ) ;
2023-04-03 00:28:10 +00:00
if ( sub - > storeDir = = storeDir )
assert ( subPath = = path . first ) ;
if ( subPath ! = path . first )
debug ( " replaced path '%s' with '%s' for substituter '%s' " , printStorePath ( path . first ) , sub - > printStorePath ( subPath ) , sub - > getUri ( ) ) ;
} else if ( sub - > storeDir ! = storeDir ) continue ;
debug ( " checking substituter '%s' for path '%s' " , sub - > getUri ( ) , sub - > printStorePath ( subPath ) ) ;
try {
auto info = sub - > queryPathInfo ( subPath ) ;
if ( sub - > storeDir ! = storeDir & & ! ( info - > isContentAddressed ( * sub ) & & info - > references . empty ( ) ) )
continue ;
auto narInfo = std : : dynamic_pointer_cast < const NarInfo > (
std : : shared_ptr < const ValidPathInfo > ( info ) ) ;
infos . insert_or_assign ( path . first , SubstitutablePathInfo {
2023-04-08 00:39:04 +00:00
. deriver = info - > deriver ,
. references = info - > references ,
. downloadSize = narInfo ? narInfo - > fileSize : 0 ,
. narSize = info - > narSize ,
} ) ;
2023-04-03 00:28:10 +00:00
} catch ( InvalidPath & ) {
} catch ( SubstituterDisabled & ) {
} catch ( Error & e ) {
if ( settings . tryFallback )
logError ( e . info ( ) ) ;
else
throw ;
}
}
}
}
2019-12-05 18:11:09 +00:00
bool Store : : isValidPath ( const StorePath & storePath )
2016-02-15 13:48:38 +00:00
{
2016-04-19 16:50:15 +00:00
{
auto state_ ( state . lock ( ) ) ;
2021-10-14 11:28:22 +00:00
auto res = state_ - > pathInfoCache . get ( std : : string ( storePath . to_string ( ) ) ) ;
2020-03-11 19:04:47 +00:00
if ( res & & res - > isKnownNow ( ) ) {
2016-04-19 16:50:15 +00:00
stats . narInfoReadAverted + + ;
2020-03-11 19:04:47 +00:00
return res - > didExist ( ) ;
2016-04-19 16:50:15 +00:00
}
}
2016-04-20 12:12:38 +00:00
if ( diskCache ) {
2021-10-14 11:28:22 +00:00
auto res = diskCache - > lookupNarInfo ( getUri ( ) , std : : string ( storePath . hashPart ( ) ) ) ;
2016-04-20 12:12:38 +00:00
if ( res . first ! = NarInfoDiskCache : : oUnknown ) {
2016-04-21 15:53:47 +00:00
stats . narInfoReadAverted + + ;
2016-04-20 12:12:38 +00:00
auto state_ ( state . lock ( ) ) ;
2021-10-14 11:28:22 +00:00
state_ - > pathInfoCache . upsert ( std : : string ( storePath . to_string ( ) ) ,
2020-03-11 19:04:47 +00:00
res . first = = NarInfoDiskCache : : oInvalid ? PathInfoCacheValue { } : PathInfoCacheValue { . value = res . second } ) ;
2016-04-20 12:12:38 +00:00
return res . first = = NarInfoDiskCache : : oValid ;
}
}
2016-06-20 15:39:05 +00:00
bool valid = isValidPathUncached ( storePath ) ;
2016-04-20 12:12:38 +00:00
2016-06-20 15:39:05 +00:00
if ( diskCache & & ! valid )
// FIXME: handle valid = true case.
2021-10-14 11:28:22 +00:00
diskCache - > upsertNarInfo ( getUri ( ) , std : : string ( storePath . hashPart ( ) ) , 0 ) ;
2016-06-20 15:39:05 +00:00
return valid ;
2016-04-19 16:50:15 +00:00
}
2017-02-07 18:22:48 +00:00
/* Default implementation for stores that only implement
queryPathInfoUncached ( ) . */
2019-12-05 18:11:09 +00:00
bool Store : : isValidPathUncached ( const StorePath & path )
2017-02-07 18:22:48 +00:00
{
try {
queryPathInfo ( path ) ;
return true ;
} catch ( InvalidPath & ) {
return false ;
}
}
2024-05-18 05:38:33 +00:00
static void ensureGoodStorePath ( Store * store , const StorePath & expected , const StorePath & actual )
2020-07-13 18:17:00 +00:00
{
2024-05-18 05:38:33 +00:00
if ( expected . hashPart ( ) ! = actual . hashPart ( ) ) {
throw Error (
" the queried store path hash '%s' did not match expected '%s' while querying the store path '%s' " ,
expected . hashPart ( ) , actual . hashPart ( ) , store - > printStorePath ( expected )
) ;
} else if ( expected . name ( ) ! = Store : : MissingName & & expected . name ( ) ! = actual . name ( ) ) {
throw Error (
" the queried store path name '%s' did not match expected '%s' while querying the store path '%s' " ,
expected . name ( ) , actual . name ( ) , store - > printStorePath ( expected )
) ;
}
2020-07-13 18:17:00 +00:00
}
2024-04-27 19:24:36 +00:00
ref < const ValidPathInfo > Store : : queryPathInfo ( const StorePath & storePath )
2016-04-19 16:50:15 +00:00
{
2021-10-14 11:28:22 +00:00
auto hashPart = std : : string ( storePath . hashPart ( ) ) ;
2016-04-21 15:53:47 +00:00
2024-04-27 19:24:36 +00:00
{
auto res = state . lock ( ) - > pathInfoCache . get ( std : : string ( storePath . to_string ( ) ) ) ;
if ( res & & res - > isKnownNow ( ) ) {
stats . narInfoReadAverted + + ;
if ( ! res - > didExist ( ) )
2024-05-18 05:38:33 +00:00
throw InvalidPath ( " path '%s' does not exist in the store " , printStorePath ( storePath ) ) ;
2024-04-27 19:24:36 +00:00
return ref < const ValidPathInfo > ( res - > value ) ;
2016-04-19 16:50:15 +00:00
}
2024-04-27 19:24:36 +00:00
}
2016-04-19 16:50:15 +00:00
2024-04-27 19:24:36 +00:00
if ( diskCache ) {
auto res = diskCache - > lookupNarInfo ( getUri ( ) , hashPart ) ;
if ( res . first ! = NarInfoDiskCache : : oUnknown ) {
stats . narInfoReadAverted + + ;
{
auto state_ ( state . lock ( ) ) ;
state_ - > pathInfoCache . upsert ( std : : string ( storePath . to_string ( ) ) ,
res . first = = NarInfoDiskCache : : oInvalid ? PathInfoCacheValue { } : PathInfoCacheValue { . value = res . second } ) ;
2024-05-18 05:38:33 +00:00
if ( res . first = = NarInfoDiskCache : : oInvalid )
throw InvalidPath ( " path '%s' does not exist in the store " , printStorePath ( storePath ) ) ;
2016-09-16 16:54:14 +00:00
}
2024-04-27 19:24:36 +00:00
return ref < const ValidPathInfo > ( res . second ) ;
2016-04-20 12:12:38 +00:00
}
2024-04-27 19:24:36 +00:00
}
2016-09-16 16:54:14 +00:00
2024-04-27 19:24:36 +00:00
auto info = queryPathInfoUncached ( storePath ) ;
2024-05-18 05:38:33 +00:00
if ( info ) {
// first, before we cache anything, check that the store gave us valid data.
ensureGoodStorePath ( this , storePath , info - > path ) ;
}
2016-04-19 16:50:15 +00:00
2024-05-18 05:38:33 +00:00
if ( diskCache ) {
2024-04-27 19:24:36 +00:00
diskCache - > upsertNarInfo ( getUri ( ) , hashPart , info ) ;
2024-05-18 05:38:33 +00:00
}
2016-04-20 12:12:38 +00:00
2024-04-27 19:24:36 +00:00
{
auto state_ ( state . lock ( ) ) ;
state_ - > pathInfoCache . upsert ( std : : string ( storePath . to_string ( ) ) , PathInfoCacheValue { . value = info } ) ;
}
2016-09-16 16:54:14 +00:00
2024-05-18 05:38:33 +00:00
if ( ! info ) {
2024-04-27 19:24:36 +00:00
stats . narInfoMissing + + ;
2024-05-18 05:38:33 +00:00
throw InvalidPath ( " path '%s' does not exist in the store " , printStorePath ( storePath ) ) ;
2024-04-27 19:24:36 +00:00
}
2016-04-19 16:50:15 +00:00
2024-04-27 19:24:36 +00:00
return ref < const ValidPathInfo > ( info ) ;
2016-02-15 13:48:38 +00:00
}
2024-04-27 22:56:10 +00:00
std : : shared_ptr < const Realisation > Store : : queryRealisation ( const DrvOutput & id )
2021-10-27 09:36:51 +00:00
{
2024-04-27 22:56:10 +00:00
if ( diskCache ) {
auto [ cacheOutcome , maybeCachedRealisation ]
= diskCache - > lookupRealisation ( getUri ( ) , id ) ;
switch ( cacheOutcome ) {
case NarInfoDiskCache : : oValid :
debug ( " Returning a cached realisation for %s " , id . to_string ( ) ) ;
return maybeCachedRealisation ;
case NarInfoDiskCache : : oInvalid :
debug (
" Returning a cached missing realisation for %s " ,
id . to_string ( ) ) ;
return nullptr ;
case NarInfoDiskCache : : oUnknown :
break ;
2021-10-27 09:36:51 +00:00
}
}
2024-04-27 22:56:10 +00:00
auto info = queryRealisationUncached ( id ) ;
2021-10-27 09:36:51 +00:00
2024-04-27 22:56:10 +00:00
if ( diskCache ) {
if ( info )
diskCache - > upsertRealisation ( getUri ( ) , * info ) ;
else
diskCache - > upsertAbsentRealisation ( getUri ( ) , id ) ;
2024-04-27 21:44:12 +00:00
}
2021-10-27 09:36:51 +00:00
2024-04-27 22:56:10 +00:00
return info ;
2021-10-27 09:36:51 +00:00
}
2016-02-15 13:48:38 +00:00
2020-10-21 19:31:19 +00:00
void Store : : substitutePaths ( const StorePathSet & paths )
{
2021-04-05 13:48:18 +00:00
std : : vector < DerivedPath > paths2 ;
2020-10-21 19:31:19 +00:00
for ( auto & path : paths )
if ( ! path . isDerivation ( ) )
2024-03-04 04:27:35 +00:00
paths2 . emplace_back ( DerivedPath : : Opaque { path } ) ;
2020-10-21 19:31:19 +00:00
uint64_t downloadSize , narSize ;
StorePathSet willBuild , willSubstitute , unknown ;
queryMissing ( paths2 ,
willBuild , willSubstitute , unknown , downloadSize , narSize ) ;
if ( ! willSubstitute . empty ( ) )
try {
2021-04-05 13:48:18 +00:00
std : : vector < DerivedPath > subs ;
2024-03-04 07:59:58 +00:00
for ( auto & p : willSubstitute ) subs . emplace_back ( DerivedPath : : Opaque { p } ) ;
2020-10-21 19:31:19 +00:00
buildPaths ( subs ) ;
} catch ( Error & e ) {
logWarning ( e . info ( ) ) ;
}
}
2019-12-05 18:11:09 +00:00
StorePathSet Store : : queryValidPaths ( const StorePathSet & paths , SubstituteFlag maybeSubstitute )
2016-10-07 17:20:47 +00:00
{
2016-10-07 17:43:36 +00:00
struct State
{
size_t left ;
2019-12-05 18:11:09 +00:00
StorePathSet valid ;
2016-10-07 17:43:36 +00:00
std : : exception_ptr exc ;
} ;
2016-10-07 17:20:47 +00:00
2019-12-05 18:11:09 +00:00
Sync < State > state_ ( State { paths . size ( ) , StorePathSet ( ) } ) ;
2016-10-07 17:20:47 +00:00
2016-10-07 17:43:36 +00:00
std : : condition_variable wakeup ;
2017-10-25 15:13:49 +00:00
ThreadPool pool ;
2016-10-07 17:43:36 +00:00
2020-10-07 13:52:20 +00:00
auto doQuery = [ & ] ( const StorePath & path ) {
2017-10-25 15:51:45 +00:00
checkInterrupt ( ) ;
2024-06-15 20:10:03 +00:00
bool exists = false ;
std : : exception_ptr newExc { } ;
2024-04-27 19:24:36 +00:00
try {
2024-06-15 20:10:03 +00:00
queryPathInfo ( path ) ;
exists = true ;
2024-04-27 19:24:36 +00:00
} catch ( InvalidPath & ) {
} catch ( . . . ) {
2024-06-15 20:10:03 +00:00
newExc = std : : current_exception ( ) ;
}
{
auto state ( state_ . lock ( ) ) ;
if ( exists ) {
state - > valid . insert ( path ) ;
}
if ( newExc ! = nullptr ) {
state - > exc = newExc ;
}
assert ( state - > left ) ;
if ( ! - - state - > left )
wakeup . notify_one ( ) ;
2024-04-27 19:24:36 +00:00
}
2017-10-25 15:13:49 +00:00
} ;
for ( auto & path : paths )
2020-10-07 13:52:20 +00:00
pool . enqueue ( std : : bind ( doQuery , path ) ) ;
2017-10-25 15:13:49 +00:00
pool . process ( ) ;
2016-10-07 17:43:36 +00:00
while ( true ) {
auto state ( state_ . lock ( ) ) ;
if ( ! state - > left ) {
if ( state - > exc ) std : : rethrow_exception ( state - > exc ) ;
2019-12-05 18:11:09 +00:00
return std : : move ( state - > valid ) ;
2016-10-07 17:43:36 +00:00
}
state . wait ( wakeup ) ;
}
2016-10-07 17:20:47 +00:00
}
2008-01-29 18:17:36 +00:00
/* Return a string accepted by decodeValidPathInfo() that
registers the specified paths as valid . Note : it ' s the
responsibility of the caller to provide a closure . */
2022-02-25 15:00:00 +00:00
std : : string Store : : makeValidityRegistration ( const StorePathSet & paths ,
2008-01-29 18:17:36 +00:00
bool showDerivers , bool showHash )
{
2022-02-25 15:00:00 +00:00
std : : string s = " " ;
2008-01-29 18:17:36 +00:00
2015-07-17 17:24:28 +00:00
for ( auto & i : paths ) {
2019-12-05 18:11:09 +00:00
s + = printStorePath ( i ) + " \n " ;
2015-07-17 17:24:28 +00:00
2016-04-19 16:50:15 +00:00
auto info = queryPathInfo ( i ) ;
2008-01-29 18:17:36 +00:00
2010-11-16 17:11:46 +00:00
if ( showHash ) {
2017-07-04 12:47:59 +00:00
s + = info - > narHash . to_string ( Base16 , false ) + " \n " ;
2023-03-02 14:44:19 +00:00
s + = fmt ( " %1% \n " , info - > narSize ) ;
2010-11-16 17:11:46 +00:00
}
2019-12-05 18:11:09 +00:00
auto deriver = showDerivers & & info - > deriver ? printStorePath ( * info - > deriver ) : " " ;
2008-01-29 18:17:36 +00:00
s + = deriver + " \n " ;
2023-03-02 14:44:19 +00:00
s + = fmt ( " %1% \n " , info - > references . size ( ) ) ;
2008-01-29 18:17:36 +00:00
2023-01-14 21:38:43 +00:00
for ( auto & j : info - > references )
2019-12-05 18:11:09 +00:00
s + = printStorePath ( j ) + " \n " ;
2008-01-29 18:17:36 +00:00
}
return s ;
}
2021-05-02 15:24:14 +00:00
StorePathSet Store : : exportReferences ( const StorePathSet & storePaths , const StorePathSet & inputPaths )
{
StorePathSet paths ;
for ( auto & storePath : storePaths ) {
if ( ! inputPaths . count ( storePath ) )
throw BuildError ( " cannot export references of path '%s' because it is not in the input closure of the derivation " , printStorePath ( storePath ) ) ;
computeFSClosure ( { storePath } , paths ) ;
}
/* If there are derivations in the graph, then include their
outputs as well . This is useful if you want to do things
like passing all build - time dependencies of some path to a
derivation that builds a NixOS DVD image . */
auto paths2 = paths ;
for ( auto & j : paths2 ) {
if ( j . isDerivation ( ) ) {
Derivation drv = derivationFromPath ( j ) ;
for ( auto & k : drv . outputsAndOptPaths ( * this ) ) {
if ( ! k . second . second )
/* FIXME: I am confused why we are calling
` computeFSClosure ` on the output path , rather than
derivation itself . That doesn ' t seem right to me , so I
won ' t try to implemented this for CA derivations . */
throw UnimplementedError ( " exportReferences on CA derivations is not yet implemented " ) ;
computeFSClosure ( * k . second . second , paths ) ;
}
}
}
return paths ;
}
2022-11-16 15:49:49 +00:00
json Store : : pathInfoToJSON ( const StorePathSet & storePaths ,
2020-02-11 22:50:16 +00:00
bool includeImpureInfo , bool showClosureSize ,
Base hashBase ,
AllowInvalidFlag allowInvalid )
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
{
2022-11-16 15:49:49 +00:00
json : : array_t jsonList = json : : array ( ) ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2019-12-05 18:11:09 +00:00
for ( auto & storePath : storePaths ) {
2022-11-16 15:49:49 +00:00
auto & jsonPath = jsonList . emplace_back ( json : : object ( ) ) ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2017-07-14 13:27:21 +00:00
try {
auto info = queryPathInfo ( storePath ) ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2022-11-16 15:49:49 +00:00
jsonPath [ " path " ] = printStorePath ( info - > path ) ;
2023-02-28 23:04:17 +00:00
jsonPath [ " valid " ] = true ;
2022-11-16 15:49:49 +00:00
jsonPath [ " narHash " ] = info - > narHash . to_string ( hashBase , true ) ;
jsonPath [ " narSize " ] = info - > narSize ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2017-07-14 13:27:21 +00:00
{
2022-11-16 15:49:49 +00:00
auto & jsonRefs = ( jsonPath [ " references " ] = json : : array ( ) ) ;
2023-01-14 21:38:43 +00:00
for ( auto & ref : info - > references )
2022-11-16 15:49:49 +00:00
jsonRefs . emplace_back ( printStorePath ( ref ) ) ;
2017-07-14 13:27:21 +00:00
}
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2020-06-01 22:53:31 +00:00
if ( info - > ca )
2022-11-16 15:49:49 +00:00
jsonPath [ " ca " ] = renderContentAddress ( info - > ca ) ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2017-07-14 15:36:49 +00:00
std : : pair < uint64_t , uint64_t > closureSizes ;
if ( showClosureSize ) {
2019-12-05 18:11:09 +00:00
closureSizes = getClosureSize ( info - > path ) ;
2022-11-16 15:49:49 +00:00
jsonPath [ " closureSize " ] = closureSizes . first ;
2017-07-14 15:36:49 +00:00
}
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2017-07-14 13:27:21 +00:00
if ( includeImpureInfo ) {
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2019-12-05 18:11:09 +00:00
if ( info - > deriver )
2022-11-16 15:49:49 +00:00
jsonPath [ " deriver " ] = printStorePath ( * info - > deriver ) ;
2017-07-14 13:27:21 +00:00
if ( info - > registrationTime )
2022-11-16 15:49:49 +00:00
jsonPath [ " registrationTime " ] = info - > registrationTime ;
2017-07-14 13:27:21 +00:00
if ( info - > ultimate )
2022-11-16 15:49:49 +00:00
jsonPath [ " ultimate " ] = info - > ultimate ;
2017-07-14 13:27:21 +00:00
if ( ! info - > sigs . empty ( ) ) {
for ( auto & sig : info - > sigs )
2022-11-16 15:49:49 +00:00
jsonPath [ " signatures " ] . push_back ( sig ) ;
2017-07-14 13:27:21 +00:00
}
2017-05-08 11:36:23 +00:00
2017-07-14 15:36:49 +00:00
auto narInfo = std : : dynamic_pointer_cast < const NarInfo > (
std : : shared_ptr < const ValidPathInfo > ( info ) ) ;
if ( narInfo ) {
2017-11-24 17:08:50 +00:00
if ( ! narInfo - > url . empty ( ) )
2022-11-16 15:49:49 +00:00
jsonPath [ " url " ] = narInfo - > url ;
2017-07-14 15:36:49 +00:00
if ( narInfo - > fileHash )
2022-11-16 15:49:49 +00:00
jsonPath [ " downloadHash " ] = narInfo - > fileHash - > to_string ( hashBase , true ) ;
2017-07-14 15:36:49 +00:00
if ( narInfo - > fileSize )
2022-11-16 15:49:49 +00:00
jsonPath [ " downloadSize " ] = narInfo - > fileSize ;
2017-07-14 15:36:49 +00:00
if ( showClosureSize )
2022-11-16 15:49:49 +00:00
jsonPath [ " closureDownloadSize " ] = closureSizes . second ;
2017-07-14 15:36:49 +00:00
}
2017-05-08 11:36:23 +00:00
}
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
2017-07-14 13:27:21 +00:00
} catch ( InvalidPath & ) {
2022-11-16 15:49:49 +00:00
jsonPath [ " path " ] = printStorePath ( storePath ) ;
jsonPath [ " valid " ] = false ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
}
}
2022-11-16 15:49:49 +00:00
return jsonList ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
}
2019-12-05 18:11:09 +00:00
std : : pair < uint64_t , uint64_t > Store : : getClosureSize ( const StorePath & storePath )
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
{
2017-07-14 15:36:49 +00:00
uint64_t totalNarSize = 0 , totalDownloadSize = 0 ;
2019-12-05 18:11:09 +00:00
StorePathSet closure ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
computeFSClosure ( storePath , closure , false , false ) ;
2017-07-14 15:36:49 +00:00
for ( auto & p : closure ) {
auto info = queryPathInfo ( p ) ;
totalNarSize + = info - > narSize ;
auto narInfo = std : : dynamic_pointer_cast < const NarInfo > (
std : : shared_ptr < const ValidPathInfo > ( info ) ) ;
if ( narInfo )
totalDownloadSize + = narInfo - > fileSize ;
}
return { totalNarSize , totalDownloadSize } ;
exportReferencesGraph: Export more complete info in JSON format
This writes info about every path in the closure in the same format as
‘nix path-info --json’. Thus it also includes NAR hashes and sizes.
Example:
[
{
"path": "/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"narHash": "sha256:0ckdc4z20kkmpqdilx0wl6cricxv90lh85xpv2qljppcmz6vzcxl",
"narSize": 197648,
"references": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20939776
},
{
"path": "/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24",
"narHash": "sha256:1nfn3m3p98y1c0kd0brp80dn9n5mycwgrk183j17rajya0h7gax3",
"narSize": 20742128,
"references": [
"/nix/store/27binbdy296qvjycdgr1535v8872vz3z-glibc-2.24"
],
"closureSize": 20742128
}
]
Fixes #1134.
2017-01-26 19:36:20 +00:00
}
2016-04-19 16:50:15 +00:00
const Store : : Stats & Store : : getStats ( )
{
2016-04-20 12:12:38 +00:00
{
auto state_ ( state . lock ( ) ) ;
stats . pathInfoCacheSize = state_ - > pathInfoCache . size ( ) ;
}
2016-04-19 16:50:15 +00:00
return stats ;
}
2021-07-26 11:31:09 +00:00
static std : : string makeCopyPathMessage (
std : : string_view srcUri ,
std : : string_view dstUri ,
std : : string_view storePath )
2016-05-03 12:45:50 +00:00
{
2021-07-26 11:31:09 +00:00
return srcUri = = " local " | | srcUri = = " daemon "
? fmt ( " copying path '%s' to '%s' " , storePath , dstUri )
: dstUri = = " local " | | dstUri = = " daemon "
? fmt ( " copying path '%s' from '%s' " , storePath , srcUri )
: fmt ( " copying path '%s' from '%s' to '%s' " , storePath , srcUri , dstUri ) ;
}
2019-07-10 17:46:15 +00:00
2021-07-19 10:01:06 +00:00
void copyStorePath (
Store & srcStore ,
Store & dstStore ,
const StorePath & storePath ,
RepairFlag repair ,
CheckSigsFlag checkSigs )
2016-05-03 12:45:50 +00:00
{
2024-03-04 07:16:28 +00:00
/* Bail out early (before starting a download from srcStore) if
dstStore already has this path . */
if ( ! repair & & dstStore . isValidPath ( storePath ) )
return ;
2021-07-19 10:01:06 +00:00
auto srcUri = srcStore . getUri ( ) ;
auto dstUri = dstStore . getUri ( ) ;
2021-07-26 11:31:09 +00:00
auto storePathS = srcStore . printStorePath ( storePath ) ;
2019-07-10 17:46:15 +00:00
Activity act ( * logger , lvlInfo , actCopyPath ,
2021-07-26 11:31:09 +00:00
makeCopyPathMessage ( srcUri , dstUri , storePathS ) ,
{ storePathS , srcUri , dstUri } ) ;
2019-07-10 17:46:15 +00:00
PushActivity pact ( act . id ) ;
2021-07-19 10:01:06 +00:00
auto info = srcStore . queryPathInfo ( storePath ) ;
2019-07-10 17:46:15 +00:00
2020-06-12 14:49:09 +00:00
// recompute store path on the chance dstStore does it differently
2020-06-22 17:08:11 +00:00
if ( info - > ca & & info - > references . empty ( ) ) {
2020-06-12 14:49:09 +00:00
auto info2 = make_ref < ValidPathInfo > ( * info ) ;
2021-09-30 22:36:50 +00:00
info2 - > path = dstStore . makeFixedOutputPathFromCA (
2023-01-23 17:58:11 +00:00
info - > path . name ( ) ,
2023-02-28 16:34:18 +00:00
info - > contentAddressWithReferences ( ) . value ( ) ) ;
2021-07-19 10:01:06 +00:00
if ( dstStore . storeDir = = srcStore . storeDir )
2020-06-17 18:04:46 +00:00
assert ( info - > path = = info2 - > path ) ;
2020-06-12 14:49:09 +00:00
info = info2 ;
}
2019-07-10 17:46:15 +00:00
if ( info - > ultimate ) {
auto info2 = make_ref < ValidPathInfo > ( * info ) ;
info2 - > ultimate = false ;
info = info2 ;
}
2017-05-01 18:03:25 +00:00
2019-07-10 17:46:15 +00:00
auto source = sinkToSource ( [ & ] ( Sink & sink ) {
2024-04-27 17:15:51 +00:00
LambdaSink progressSink ( [ & , total = 0ULL ] ( std : : string_view data ) mutable {
2020-12-02 13:00:43 +00:00
total + = data . size ( ) ;
2019-07-10 17:46:15 +00:00
act . progress ( total , info - > narSize ) ;
2018-03-16 19:22:34 +00:00
} ) ;
2020-08-13 14:47:53 +00:00
TeeSink tee { sink , progressSink } ;
2024-05-16 15:58:27 +00:00
tee < < srcStore . narFromPath ( storePath ) ;
2019-06-24 19:48:52 +00:00
} ) ;
2019-07-10 17:46:15 +00:00
2021-07-19 10:01:06 +00:00
dstStore . addToStore ( * info , * source , repair , checkSigs ) ;
2016-05-03 12:45:50 +00:00
}
2021-07-19 10:01:06 +00:00
std : : map < StorePath , StorePath > copyPaths (
Store & srcStore ,
Store & dstStore ,
const RealisedPath : : Set & paths ,
RepairFlag repair ,
CheckSigsFlag checkSigs ,
SubstituteFlag substitute )
2020-12-14 18:43:53 +00:00
{
StorePathSet storePaths ;
2021-05-19 08:36:48 +00:00
std : : set < Realisation > toplevelRealisations ;
2021-02-25 16:10:45 +00:00
for ( auto & path : paths ) {
2020-12-14 18:43:53 +00:00
storePaths . insert ( path . path ( ) ) ;
2021-02-25 15:58:27 +00:00
if ( auto realisation = std : : get_if < Realisation > ( & path . raw ) ) {
2023-03-17 14:33:48 +00:00
experimentalFeatureSettings . require ( Xp : : CaDerivations ) ;
2021-05-19 08:36:48 +00:00
toplevelRealisations . insert ( * realisation ) ;
2021-02-25 15:58:27 +00:00
}
2020-12-14 18:43:53 +00:00
}
auto pathsMap = copyPaths ( srcStore , dstStore , storePaths , repair , checkSigs , substitute ) ;
2021-05-19 08:36:48 +00:00
ThreadPool pool ;
2021-02-19 16:58:28 +00:00
try {
2021-05-19 08:36:48 +00:00
// Copy the realisation closure
processGraph < Realisation > (
2021-07-19 10:01:06 +00:00
pool , Realisation : : closure ( srcStore , toplevelRealisations ) ,
2021-06-25 13:35:14 +00:00
[ & ] ( const Realisation & current ) - > std : : set < Realisation > {
2021-05-19 08:36:48 +00:00
std : : set < Realisation > children ;
2021-06-25 13:35:14 +00:00
for ( const auto & [ drvOutput , _ ] : current . dependentRealisations ) {
2021-07-19 10:01:06 +00:00
auto currentChild = srcStore . queryRealisation ( drvOutput ) ;
2021-05-19 08:36:48 +00:00
if ( ! currentChild )
throw Error (
2021-06-25 13:35:14 +00:00
" incomplete realisation closure: '%s' is a "
" dependency of '%s' but isn't registered " ,
2021-05-19 08:36:48 +00:00
drvOutput . to_string ( ) , current . id . to_string ( ) ) ;
children . insert ( * currentChild ) ;
}
return children ;
} ,
[ & ] ( const Realisation & current ) - > void {
2021-07-19 10:01:06 +00:00
dstStore . registerDrvOutput ( current , checkSigs ) ;
2021-05-19 08:36:48 +00:00
} ) ;
2021-02-19 16:58:28 +00:00
} catch ( MissingExperimentalFeature & e ) {
// Don't fail if the remote doesn't support CA derivations is it might
2021-02-25 16:10:45 +00:00
// not be within our control to change that, and we might still want
2021-02-19 16:58:28 +00:00
// to at least copy the output paths.
2021-10-25 13:53:01 +00:00
if ( e . missingFeature = = Xp : : CaDerivations )
2021-02-19 16:58:28 +00:00
ignoreException ( ) ;
else
throw ;
2020-12-14 18:43:53 +00:00
}
return pathsMap ;
}
2021-07-19 10:01:06 +00:00
std : : map < StorePath , StorePath > copyPaths (
Store & srcStore ,
Store & dstStore ,
const StorePathSet & storePaths ,
RepairFlag repair ,
CheckSigsFlag checkSigs ,
SubstituteFlag substitute )
2016-10-07 17:15:25 +00:00
{
2021-07-19 10:01:06 +00:00
auto valid = dstStore . queryValidPaths ( storePaths , substitute ) ;
2017-06-28 16:11:01 +00:00
2020-07-28 22:24:55 +00:00
StorePathSet missing ;
2016-10-07 17:15:25 +00:00
for ( auto & path : storePaths )
2020-07-28 22:24:55 +00:00
if ( ! valid . count ( path ) ) missing . insert ( path ) ;
2016-10-07 17:15:25 +00:00
2022-06-08 12:03:46 +00:00
Activity act ( * logger , lvlInfo , actCopyPaths , fmt ( " copying %d paths " , missing . size ( ) ) ) ;
// In the general case, `addMultipleToStore` requires a sorted list of
// store paths to add, so sort them right now
auto sortedMissing = srcStore . topoSortPaths ( missing ) ;
std : : reverse ( sortedMissing . begin ( ) , sortedMissing . end ( ) ) ;
2020-06-19 18:48:57 +00:00
std : : map < StorePath , StorePath > pathsMap ;
for ( auto & path : storePaths )
pathsMap . insert_or_assign ( path , path ) ;
2022-06-08 12:03:46 +00:00
Store : : PathsSource pathsToCopy ;
2021-07-26 11:31:09 +00:00
2022-06-08 13:13:11 +00:00
auto computeStorePathForDst = [ & ] ( const ValidPathInfo & currentPathInfo ) - > StorePath {
auto storePathForSrc = currentPathInfo . path ;
auto storePathForDst = storePathForSrc ;
if ( currentPathInfo . ca & & currentPathInfo . references . empty ( ) ) {
2023-01-06 15:35:20 +00:00
storePathForDst = dstStore . makeFixedOutputPathFromCA (
2023-01-23 17:58:11 +00:00
currentPathInfo . path . name ( ) ,
2023-02-28 16:34:18 +00:00
currentPathInfo . contentAddressWithReferences ( ) . value ( ) ) ;
2022-06-08 13:13:11 +00:00
if ( dstStore . storeDir = = srcStore . storeDir )
assert ( storePathForDst = = storePathForSrc ) ;
if ( storePathForDst ! = storePathForSrc )
debug ( " replaced path '%s' to '%s' for substituter '%s' " ,
srcStore . printStorePath ( storePathForSrc ) ,
dstStore . printStorePath ( storePathForDst ) ,
dstStore . getUri ( ) ) ;
}
return storePathForDst ;
} ;
2017-08-14 13:28:16 +00:00
2022-06-08 12:03:46 +00:00
for ( auto & missingPath : sortedMissing ) {
2022-06-03 15:01:16 +00:00
auto info = srcStore . queryPathInfo ( missingPath ) ;
2021-07-26 11:31:09 +00:00
2022-06-08 13:13:11 +00:00
auto storePathForDst = computeStorePathForDst ( * info ) ;
pathsMap . insert_or_assign ( missingPath , storePathForDst ) ;
ValidPathInfo infoForDst = * info ;
infoForDst . path = storePathForDst ;
2024-06-15 23:39:14 +00:00
auto source =
sinkToSource ( [ & srcStore , & dstStore , missingPath = missingPath , info = std : : move ( info ) ] ( Sink & sink ) {
// We can reasonably assume that the copy will happen whenever we
// read the path, so log something about that at that point
auto srcUri = srcStore . getUri ( ) ;
auto dstUri = dstStore . getUri ( ) ;
auto storePathS = srcStore . printStorePath ( missingPath ) ;
Activity act (
* logger ,
lvlInfo ,
actCopyPath ,
makeCopyPathMessage ( srcUri , dstUri , storePathS ) ,
{ storePathS , srcUri , dstUri }
) ;
PushActivity pact ( act . id ) ;
LambdaSink progressSink ( [ & , total = 0ULL ] ( std : : string_view data ) mutable {
total + = data . size ( ) ;
act . progress ( total , info - > narSize ) ;
} ) ;
TeeSink tee { sink , progressSink } ;
2023-03-09 12:03:48 +00:00
2024-05-16 15:58:27 +00:00
tee < < srcStore . narFromPath ( missingPath ) ;
2024-06-15 23:39:14 +00:00
} ) ;
2022-06-08 13:13:11 +00:00
pathsToCopy . push_back ( std : : pair { infoForDst , std : : move ( source ) } ) ;
2022-06-03 15:01:16 +00:00
}
2017-10-18 13:02:58 +00:00
2022-06-03 15:01:16 +00:00
dstStore . addMultipleToStore ( pathsToCopy , act , repair , checkSigs ) ;
2021-07-26 11:31:09 +00:00
2020-06-19 18:48:57 +00:00
return pathsMap ;
2017-06-28 16:11:01 +00:00
}
2016-10-07 17:15:25 +00:00
2021-07-16 07:37:33 +00:00
void copyClosure (
2021-07-19 10:01:06 +00:00
Store & srcStore ,
Store & dstStore ,
2021-07-16 07:37:33 +00:00
const RealisedPath : : Set & paths ,
RepairFlag repair ,
CheckSigsFlag checkSigs ,
SubstituteFlag substitute )
{
2021-07-19 10:01:06 +00:00
if ( & srcStore = = & dstStore ) return ;
2021-07-16 07:37:33 +00:00
RealisedPath : : Set closure ;
2021-07-19 10:01:06 +00:00
RealisedPath : : closure ( srcStore , paths , closure ) ;
2021-07-16 07:37:33 +00:00
copyPaths ( srcStore , dstStore , closure , repair , checkSigs , substitute ) ;
}
2022-01-20 20:45:34 +00:00
void copyClosure (
Store & srcStore ,
Store & dstStore ,
const StorePathSet & storePaths ,
RepairFlag repair ,
CheckSigsFlag checkSigs ,
SubstituteFlag substitute )
{
if ( & srcStore = = & dstStore ) return ;
StorePathSet closure ;
srcStore . computeFSClosure ( storePaths , closure ) ;
copyPaths ( srcStore , dstStore , closure , repair , checkSigs , substitute ) ;
}
2020-08-06 18:31:48 +00:00
std : : optional < ValidPathInfo > decodeValidPathInfo ( const Store & store , std : : istream & str , std : : optional < HashResult > hashGiven )
2007-08-12 00:29:28 +00:00
{
2019-12-05 18:11:09 +00:00
std : : string path ;
getline ( str , path ) ;
if ( str . eof ( ) ) { return { } ; }
2020-08-06 18:31:48 +00:00
if ( ! hashGiven ) {
2022-02-25 15:00:00 +00:00
std : : string s ;
2008-01-29 18:17:36 +00:00
getline ( str , s ) ;
2020-08-06 18:31:48 +00:00
auto narHash = Hash : : parseAny ( s , htSHA256 ) ;
2010-11-16 17:11:46 +00:00
getline ( str , s ) ;
2021-01-08 11:22:21 +00:00
auto narSize = string2Int < uint64_t > ( s ) ;
if ( ! narSize ) throw Error ( " number expected " ) ;
hashGiven = { narHash , * narSize } ;
2008-01-29 18:17:36 +00:00
}
2020-08-06 18:31:48 +00:00
ValidPathInfo info ( store . parseStorePath ( path ) , hashGiven - > first ) ;
info . narSize = hashGiven - > second ;
2019-12-05 18:11:09 +00:00
std : : string deriver ;
getline ( str , deriver ) ;
if ( deriver ! = " " ) info . deriver = store . parseStorePath ( deriver ) ;
2022-02-25 15:00:00 +00:00
std : : string s ;
2007-08-12 00:29:28 +00:00
getline ( str , s ) ;
2021-01-08 11:22:21 +00:00
auto n = string2Int < int > ( s ) ;
if ( ! n ) throw Error ( " number expected " ) ;
while ( ( * n ) - - ) {
2007-08-12 00:29:28 +00:00
getline ( str , s ) ;
2023-01-14 21:38:43 +00:00
info . references . insert ( store . parseStorePath ( s ) ) ;
2007-08-12 00:29:28 +00:00
}
if ( ! str | | str . eof ( ) ) throw Error ( " missing input " ) ;
2019-12-05 18:11:09 +00:00
return std : : optional < ValidPathInfo > ( std : : move ( info ) ) ;
}
std : : string Store : : showPaths ( const StorePathSet & paths )
{
std : : string s ;
for ( auto & i : paths ) {
if ( s . size ( ) ! = 0 ) s + = " , " ;
s + = " ' " + printStorePath ( i ) + " ' " ;
}
return s ;
2007-08-12 00:29:28 +00:00
}
2022-02-25 15:00:00 +00:00
std : : string showPaths ( const PathSet & paths )
2008-06-09 13:52:45 +00:00
{
2019-05-02 19:09:52 +00:00
return concatStringsSep ( " , " , quoteStrings ( paths ) ) ;
2008-06-09 13:52:45 +00:00
}
2023-01-14 21:38:43 +00:00
2020-06-17 03:56:48 +00:00
Derivation Store : : derivationFromPath ( const StorePath & drvPath )
{
ensurePath ( drvPath ) ;
return readDerivation ( drvPath ) ;
}
2020-12-15 09:54:24 +00:00
Derivation readDerivationCommon ( Store & store , const StorePath & drvPath , bool requireValidPath )
2020-06-17 03:56:48 +00:00
{
2020-12-15 09:54:24 +00:00
auto accessor = store . getFSAccessor ( ) ;
2020-06-17 03:56:48 +00:00
try {
2020-12-15 09:54:24 +00:00
return parseDerivation ( store ,
accessor - > readFile ( store . printStorePath ( drvPath ) , requireValidPath ) ,
2020-08-01 19:38:35 +00:00
Derivation : : nameFromPath ( drvPath ) ) ;
2020-06-17 03:56:48 +00:00
} catch ( FormatError & e ) {
2020-12-15 09:54:24 +00:00
throw Error ( " error parsing derivation '%s': %s " , store . printStorePath ( drvPath ) , e . msg ( ) ) ;
2020-06-17 03:56:48 +00:00
}
}
2022-03-08 05:02:25 +00:00
std : : optional < StorePath > Store : : getBuildDerivationPath ( const StorePath & path )
{
if ( ! path . isDerivation ( ) ) {
try {
auto info = queryPathInfo ( path ) ;
if ( ! info - > deriver ) return std : : nullopt ;
return * info - > deriver ;
} catch ( InvalidPath & ) {
return std : : nullopt ;
}
}
2023-03-17 14:33:48 +00:00
if ( ! experimentalFeatureSettings . isEnabled ( Xp : : CaDerivations ) | | ! isValidPath ( path ) )
2022-03-08 05:02:25 +00:00
return path ;
auto drv = readDerivation ( path ) ;
2022-12-08 21:59:21 +00:00
if ( ! drv . type ( ) . hasKnownOutputPaths ( ) ) {
2022-03-08 05:02:25 +00:00
// The build log is actually attached to the corresponding
// resolved derivation, so we need to get it first
auto resolvedDrv = drv . tryResolve ( * this ) ;
if ( resolvedDrv )
return writeDerivation ( * this , * resolvedDrv , NoRepair , true ) ;
}
return path ;
}
2020-12-15 09:54:24 +00:00
Derivation Store : : readDerivation ( const StorePath & drvPath )
{ return readDerivationCommon ( * this , drvPath , true ) ; }
2020-11-17 12:58:55 +00:00
Derivation Store : : readInvalidDerivation ( const StorePath & drvPath )
2020-12-15 09:54:24 +00:00
{ return readDerivationCommon ( * this , drvPath , false ) ; }
2020-11-17 12:58:55 +00:00
2006-11-30 17:43:04 +00:00
}
# include "local-store.hh"
2020-10-11 16:01:53 +00:00
# include "uds-remote-store.hh"
2006-11-30 17:43:04 +00:00
namespace nix {
2019-02-21 10:44:25 +00:00
/* Split URI into protocol+hierarchy part and its parameter set. */
std : : pair < std : : string , Store : : Params > splitUriAndParams ( const std : : string & uri_ )
2006-11-30 17:43:04 +00:00
{
2016-04-29 14:26:16 +00:00
auto uri ( uri_ ) ;
2019-02-21 10:44:25 +00:00
Store : : Params params ;
2016-04-29 14:26:16 +00:00
auto q = uri . find ( ' ? ' ) ;
if ( q ! = std : : string : : npos ) {
2020-03-30 14:04:18 +00:00
params = decodeQuery ( uri . substr ( q + 1 ) ) ;
2016-04-29 14:26:16 +00:00
uri = uri_ . substr ( 0 , q ) ;
}
2019-02-21 10:44:25 +00:00
return { uri , params } ;
}
2022-06-23 14:29:50 +00:00
static bool isNonUriPath ( const std : : string & spec )
{
2020-07-21 15:39:47 +00:00
return
// is not a URL
spec . find ( " :// " ) = = std : : string : : npos
// Has at least one path separator, and so isn't a single word that
// might be special like "auto"
& & spec . find ( " / " ) ! = std : : string : : npos ;
}
2016-02-29 15:11:11 +00:00
2020-09-16 22:35:24 +00:00
std : : shared_ptr < Store > openFromNonUri ( const std : : string & uri , const Store : : Params & params )
2016-02-29 15:11:11 +00:00
{
2020-09-16 22:35:24 +00:00
if ( uri = = " " | | uri = = " auto " ) {
2022-05-04 05:44:32 +00:00
auto stateDir = getOr ( params , " state " , settings . nixStateDir ) ;
2016-06-02 11:33:49 +00:00
if ( access ( stateDir . c_str ( ) , R_OK | W_OK ) = = 0 )
2024-04-22 17:32:21 +00:00
return LocalStore : : makeLocalStore ( params ) ;
2016-01-31 09:19:14 +00:00
else if ( pathExists ( settings . nixDaemonSocketFile ) )
2020-09-16 22:35:24 +00:00
return std : : make_shared < UDSRemoteStore > ( params ) ;
2022-06-24 21:35:21 +00:00
# if __linux__
2022-07-15 10:32:29 +00:00
else if ( ! pathExists ( stateDir )
& & params . empty ( )
& & getuid ( ) ! = 0
& & ! getEnv ( " NIX_STORE_DIR " ) . has_value ( )
& & ! getEnv ( " NIX_STATE_DIR " ) . has_value ( ) )
{
2022-06-23 14:29:50 +00:00
/* If /nix doesn't exist, there is no daemon socket, and
we ' re not root , then automatically set up a chroot
store in ~ / . local / share / nix / root . */
auto chrootStore = getDataDir ( ) + " /nix/root " ;
2022-06-29 10:16:51 +00:00
if ( ! pathExists ( chrootStore ) ) {
try {
createDirs ( chrootStore ) ;
} catch ( Error & e ) {
2024-04-22 17:32:21 +00:00
return LocalStore : : makeLocalStore ( params ) ;
2022-06-29 10:16:51 +00:00
}
2024-05-14 00:05:08 +00:00
warn ( " '%s' does not exist, so Lix will use '%s' as a chroot store " , stateDir , chrootStore ) ;
2022-06-29 10:16:51 +00:00
} else
2024-05-14 00:05:08 +00:00
debug ( " '%s' does not exist, so Lix will use '%s' as a chroot store " , stateDir , chrootStore ) ;
2024-05-07 02:54:21 +00:00
Store : : Params chrootStoreParams ;
chrootStoreParams [ " root " ] = chrootStore ;
// FIXME? this ignores *all* store parameters passed to this function?
return LocalStore : : makeLocalStore ( chrootStoreParams ) ;
2022-06-24 21:35:21 +00:00
}
# endif
2016-01-31 09:19:14 +00:00
else
2024-04-22 17:32:21 +00:00
return LocalStore : : makeLocalStore ( params ) ;
2020-09-16 22:35:24 +00:00
} else if ( uri = = " daemon " ) {
return std : : make_shared < UDSRemoteStore > ( params ) ;
} else if ( uri = = " local " ) {
2024-04-22 17:32:21 +00:00
return LocalStore : : makeLocalStore ( params ) ;
2020-09-16 22:35:24 +00:00
} else if ( isNonUriPath ( uri ) ) {
Store : : Params params2 = params ;
params2 [ " root " ] = absPath ( uri ) ;
2024-04-22 17:32:21 +00:00
return LocalStore : : makeLocalStore ( params2 ) ;
2016-09-02 10:39:29 +00:00
} else {
2020-09-16 22:35:24 +00:00
return nullptr ;
2016-01-31 09:19:14 +00:00
}
2016-02-29 15:11:11 +00:00
}
2020-12-05 14:33:16 +00:00
// The `parseURL` function supports both IPv6 URIs as defined in
// RFC2732, but also pure addresses. The latter one is needed here to
// connect to a remote store via SSH (it's possible to do e.g. `ssh root@::1`).
//
// This function now ensures that a usable connection string is available:
// * If the store to be opened is not an SSH store, nothing will be done.
// * If the URL looks like `root@[::1]` (which is allowed by the URL parser and probably
// needed to pass further flags), it
// will be transformed into `root@::1` for SSH (same for `[::1]` -> `::1`).
// * If the URL looks like `root@::1` it will be left as-is.
// * In any other case, the string will be left as-is.
static std : : string extractConnStr ( const std : : string & proto , const std : : string & connStr )
{
if ( proto . rfind ( " ssh " ) ! = std : : string : : npos ) {
std : : smatch result ;
std : : regex v6AddrRegex ( " ^((.*)@)? \\ [(.*) \\ ]$ " ) ;
if ( std : : regex_match ( connStr , result , v6AddrRegex ) ) {
if ( result [ 1 ] . matched ) {
return result . str ( 1 ) + result . str ( 3 ) ;
}
return result . str ( 3 ) ;
}
}
return connStr ;
}
2019-02-21 10:44:25 +00:00
ref < Store > openStore ( const std : : string & uri_ ,
const Store : : Params & extraParams )
2016-04-29 14:26:16 +00:00
{
2019-02-21 10:44:25 +00:00
auto params = extraParams ;
2020-09-11 09:11:05 +00:00
try {
auto parsedUri = parseURL ( uri_ ) ;
params . insert ( parsedUri . query . begin ( ) , parsedUri . query . end ( ) ) ;
2020-12-05 14:33:16 +00:00
auto baseURI = extractConnStr (
parsedUri . scheme ,
parsedUri . authority . value_or ( " " ) + parsedUri . path
) ;
2020-09-11 09:11:05 +00:00
for ( auto implem : * Implementations : : registered ) {
if ( implem . uriSchemes . count ( parsedUri . scheme ) ) {
auto store = implem . create ( parsedUri . scheme , baseURI , params ) ;
if ( store ) {
2023-04-17 15:58:47 +00:00
experimentalFeatureSettings . require ( store - > experimentalFeature ( ) ) ;
2020-09-11 09:11:05 +00:00
store - > init ( ) ;
store - > warnUnknownSettings ( ) ;
return ref < Store > ( store ) ;
}
2020-06-23 15:12:01 +00:00
}
2017-10-24 13:16:18 +00:00
}
2016-01-31 09:19:14 +00:00
}
2020-09-16 12:00:21 +00:00
catch ( BadURL & ) {
2020-09-11 09:11:05 +00:00
auto [ uri , uriParams ] = splitUriAndParams ( uri_ ) ;
params . insert ( uriParams . begin ( ) , uriParams . end ( ) ) ;
2016-02-24 13:48:16 +00:00
2020-09-11 09:11:05 +00:00
if ( auto store = openFromNonUri ( uri , params ) ) {
2018-03-27 16:41:31 +00:00
store - > warnUnknownSettings ( ) ;
2017-04-13 13:55:38 +00:00
return ref < Store > ( store ) ;
}
2016-02-24 13:48:16 +00:00
}
2020-09-11 09:11:05 +00:00
throw Error ( " don't know how to open Nix store '%s' " , uri_ ) ;
2016-02-29 15:11:11 +00:00
}
2016-02-24 13:48:16 +00:00
2016-04-29 11:57:08 +00:00
std : : list < ref < Store > > getDefaultSubstituters ( )
{
2017-07-04 14:26:48 +00:00
static auto stores ( [ ] ( ) {
2016-04-29 11:57:08 +00:00
std : : list < ref < Store > > stores ;
2017-07-04 14:26:48 +00:00
StringSet done ;
2016-04-29 11:57:08 +00:00
2017-07-04 14:26:48 +00:00
auto addStore = [ & ] ( const std : : string & uri ) {
2019-10-09 13:51:52 +00:00
if ( ! done . insert ( uri ) . second ) return ;
2018-02-09 13:36:38 +00:00
try {
stores . push_back ( openStore ( uri ) ) ;
} catch ( Error & e ) {
2020-05-03 14:01:25 +00:00
logWarning ( e . info ( ) ) ;
2018-02-09 13:36:38 +00:00
}
2017-07-04 14:26:48 +00:00
} ;
2016-04-29 11:57:08 +00:00
2017-07-04 14:26:48 +00:00
for ( auto uri : settings . substituters . get ( ) )
addStore ( uri ) ;
2017-03-21 16:59:18 +00:00
2017-07-04 14:34:53 +00:00
stores . sort ( [ ] ( ref < Store > & a , ref < Store > & b ) {
2019-12-17 16:17:53 +00:00
return a - > priority < b - > priority ;
2017-07-04 14:34:53 +00:00
} ) ;
2017-07-04 14:26:48 +00:00
return stores ;
} ( ) ) ;
2016-04-29 11:57:08 +00:00
2017-07-04 14:26:48 +00:00
return stores ;
2016-04-29 11:57:08 +00:00
}
2020-09-09 09:18:12 +00:00
std : : vector < StoreFactory > * Implementations : : registered = 0 ;
2016-04-29 11:57:08 +00:00
2006-11-30 17:43:04 +00:00
}