{-# language DataKinds #-}
{-# language ScopedTypeVariables #-}
module System.Nix.ReadonlyStore where
import qualified Data.ByteString as BS
import qualified Data.HashSet as HS
import System.Nix.Hash
import System.Nix.Nar
import System.Nix.StorePath
import Crypto.Hash ( Context
, Digest
, hash
, hashlazy
, hashInit
, hashUpdate
, hashFinalize
, SHA256
)
makeStorePath
:: forall h
. (NamedAlgo h)
=> FilePath
-> ByteString
-> Digest h
-> StorePathName
-> StorePath
makeStorePath :: forall h.
NamedAlgo h =>
FilePath -> ByteString -> Digest h -> StorePathName -> StorePath
makeStorePath FilePath
fp ByteString
ty Digest h
h StorePathName
nm = StorePathHashPart -> StorePathName -> FilePath -> StorePath
StorePath (coerce :: forall a b. Coercible a b => a -> b
coerce ByteString
storeHash) StorePathName
nm FilePath
fp
where
storeHash :: ByteString
storeHash = forall a. HashAlgorithm a => ByteString -> ByteString
mkStorePathHash @h ByteString
s
s :: ByteString
s =
ByteString -> [ByteString] -> ByteString
BS.intercalate ByteString
":" forall a b. (a -> b) -> a -> b
$
ByteString
tyforall a. a -> [a] -> [a]
:forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. ConvertUtf8 a b => a -> b
encodeUtf8
[ forall a. NamedAlgo a => Text
algoName @h
, forall a. BaseEncoding -> Digest a -> Text
encodeDigestWith BaseEncoding
Base16 Digest h
h
, forall a. ToText a => a -> Text
toText FilePath
fp
, coerce :: forall a b. Coercible a b => a -> b
coerce StorePathName
nm
]
makeTextPath
:: FilePath -> StorePathName -> Digest SHA256 -> StorePathSet -> StorePath
makeTextPath :: FilePath
-> StorePathName -> Digest SHA256 -> StorePathSet -> StorePath
makeTextPath FilePath
fp StorePathName
nm Digest SHA256
h StorePathSet
refs = forall h.
NamedAlgo h =>
FilePath -> ByteString -> Digest h -> StorePathName -> StorePath
makeStorePath FilePath
fp ByteString
ty Digest SHA256
h StorePathName
nm
where
ty :: ByteString
ty =
ByteString -> [ByteString] -> ByteString
BS.intercalate ByteString
":" forall a b. (a -> b) -> a -> b
$ ByteString
"text" forall a. a -> [a] -> [a]
: forall a. Ord a => [a] -> [a]
sort (StorePath -> ByteString
storePathToRawFilePath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. HashSet a -> [a]
HS.toList StorePathSet
refs)
makeFixedOutputPath
:: forall hashAlgo
. NamedAlgo hashAlgo
=> FilePath
-> Bool
-> Digest hashAlgo
-> StorePathName
-> StorePath
makeFixedOutputPath :: forall hashAlgo.
NamedAlgo hashAlgo =>
FilePath -> Bool -> Digest hashAlgo -> StorePathName -> StorePath
makeFixedOutputPath FilePath
fp Bool
recursive Digest hashAlgo
h =
if Bool
recursive Bool -> Bool -> Bool
&& (forall a. NamedAlgo a => Text
algoName @hashAlgo) forall a. Eq a => a -> a -> Bool
== Text
"sha256"
then forall h.
NamedAlgo h =>
FilePath -> ByteString -> Digest h -> StorePathName -> StorePath
makeStorePath FilePath
fp ByteString
"source" Digest hashAlgo
h
else forall h.
NamedAlgo h =>
FilePath -> ByteString -> Digest h -> StorePathName -> StorePath
makeStorePath FilePath
fp ByteString
"output:out" Digest SHA256
h'
where
h' :: Digest SHA256
h' =
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
hash @ByteString @SHA256
forall a b. (a -> b) -> a -> b
$ ByteString
"fixed:out:"
forall a. Semigroup a => a -> a -> a
<> forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 (forall a. NamedAlgo a => Text
algoName @hashAlgo)
forall a. Semigroup a => a -> a -> a
<> (if Bool
recursive then ByteString
":r:" else ByteString
":")
forall a. Semigroup a => a -> a -> a
<> forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 (forall a. BaseEncoding -> Digest a -> Text
encodeDigestWith BaseEncoding
Base16 Digest hashAlgo
h)
forall a. Semigroup a => a -> a -> a
<> ByteString
":"
computeStorePathForText
:: FilePath -> StorePathName -> ByteString -> (StorePathSet -> StorePath)
computeStorePathForText :: FilePath
-> StorePathName -> ByteString -> StorePathSet -> StorePath
computeStorePathForText FilePath
fp StorePathName
nm = FilePath
-> StorePathName -> Digest SHA256 -> StorePathSet -> StorePath
makeTextPath FilePath
fp StorePathName
nm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
hash
computeStorePathForPath
:: StorePathName
-> FilePath
-> Bool
-> (FilePath -> Bool)
-> Bool
-> IO StorePath
computeStorePathForPath :: StorePathName
-> FilePath -> Bool -> (FilePath -> Bool) -> Bool -> IO StorePath
computeStorePathForPath StorePathName
name FilePath
pth Bool
recursive FilePath -> Bool
_pathFilter Bool
_repair = do
Digest SHA256
selectedHash <- if Bool
recursive then IO (Digest SHA256)
recursiveContentHash else IO (Digest SHA256)
flatContentHash
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall hashAlgo.
NamedAlgo hashAlgo =>
FilePath -> Bool -> Digest hashAlgo -> StorePathName -> StorePath
makeFixedOutputPath FilePath
"/nix/store" Bool
recursive Digest SHA256
selectedHash StorePathName
name
where
recursiveContentHash :: IO (Digest SHA256)
recursiveContentHash :: IO (Digest SHA256)
recursiveContentHash = forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT StateT (Context SHA256) IO ()
streamNarUpdate (forall a. HashAlgorithm a => Context a
hashInit @SHA256)
streamNarUpdate :: StateT (Context SHA256) IO ()
streamNarUpdate :: StateT (Context SHA256) IO ()
streamNarUpdate = forall (m :: * -> *).
MonadIO m =>
NarEffects IO -> FilePath -> NarSource m
streamNarIO forall (m :: * -> *).
(MonadIO m, MonadFail m, MonadBaseControl IO m) =>
NarEffects m
narEffectsIO FilePath
pth (forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip (forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
Context a -> ba -> Context a
hashUpdate @ByteString @SHA256))
flatContentHash :: IO (Digest SHA256)
flatContentHash :: IO (Digest SHA256)
flatContentHash = forall a. HashAlgorithm a => ByteString -> Digest a
hashlazy forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). NarEffects m -> FilePath -> m ByteString
narReadFile forall (m :: * -> *).
(MonadIO m, MonadFail m, MonadBaseControl IO m) =>
NarEffects m
narEffectsIO FilePath
pth