1+ {-# OPTIONS_GHC -Wno-orphans #-}
12{-|
23Description : Representation of Nix store paths.
34-}
@@ -14,6 +15,9 @@ module System.Nix.Internal.StorePath
1415 , StorePathHashPart (.. )
1516 , mkStorePathHashPart
1617 , ContentAddressableAddress (.. )
18+ , contentAddressableAddressBuilder
19+ , contentAddressableAddressParser
20+ , digestBuilder
1721 , NarHashMode (.. )
1822 , -- * Manipulating 'StorePathName'
1923 makeStorePathName
@@ -33,25 +37,33 @@ module System.Nix.Internal.StorePath
3337where
3438
3539import Data.Default.Class (Default (def ))
40+ import Data.Text.Lazy.Builder (Builder )
3641import qualified Relude.Unsafe as Unsafe
42+ import qualified System.Nix.Hash
3743import System.Nix.Internal.Hash
3844import System.Nix.Internal.Base
3945import qualified System.Nix.Internal.Base32 as Nix.Base32
4046
4147import qualified Data.ByteString.Char8 as Bytes.Char8
4248import qualified Data.Char as Char
4349import qualified Data.Text as Text
50+ import qualified Data.Text.Encoding
51+ import qualified Data.Text.Lazy.Builder
4452import Data.Attoparsec.Text.Lazy ( Parser
4553 , (<?>)
4654 )
55+ import qualified Data.Attoparsec.ByteString.Char8
4756import qualified Data.Attoparsec.Text.Lazy as Parser.Text.Lazy
4857import qualified System.FilePath as FilePath
4958import Crypto.Hash ( SHA256
5059 , Digest
5160 , HashAlgorithm
61+ , hash
5262 )
5363
54- import Test.QuickCheck
64+ import Test.QuickCheck (Arbitrary (arbitrary ), listOf , elements )
65+ import Test.QuickCheck.Arbitrary.Generic (GenericArbitrary (.. ))
66+ import Test.QuickCheck.Instances ()
5567
5668-- | A path in a Nix store.
5769--
@@ -116,6 +128,7 @@ mkStorePathHashPart
116128 -> StorePathHashPart
117129mkStorePathHashPart = StorePathHashPart . mkStorePathHash @ hashAlgo
118130
131+ -- TODO(srk): split into its own module + .Builder/.Parser
119132-- | An address for a content-addressable store path, i.e. one whose
120133-- store path hash is purely a function of its contents (as opposed to
121134-- paths that are derivation outputs, whose hashes are a function of
@@ -136,6 +149,66 @@ data ContentAddressableAddress
136149 Fixed ! NarHashMode ! SomeNamedDigest
137150 deriving (Eq , Generic , Ord , Show )
138151
152+ -- TODO(srk): extend to all hash types
153+ instance Arbitrary (Digest SHA256 ) where
154+ arbitrary = hash @ ByteString <$> arbitrary
155+
156+ instance Arbitrary SomeNamedDigest where
157+ arbitrary = SomeDigest @ SHA256 <$> arbitrary
158+
159+ deriving via GenericArbitrary ContentAddressableAddress
160+ instance Arbitrary ContentAddressableAddress
161+
162+ -- | Builder for `ContentAddressableAddress`
163+ contentAddressableAddressBuilder :: ContentAddressableAddress -> Builder
164+ contentAddressableAddressBuilder (Text digest) =
165+ " text:"
166+ <> digestBuilder digest
167+ contentAddressableAddressBuilder (Fixed narHashMode (SomeDigest (digest :: Digest hashAlgo ))) =
168+ " fixed:"
169+ <> (if narHashMode == Recursive then " r:" else mempty )
170+ -- <> Data.Text.Lazy.Builder.fromText (System.Nix.Hash.algoName @hashAlgo)
171+ <> digestBuilder digest
172+
173+ -- | Builder for @Digest@s
174+ digestBuilder :: forall hashAlgo . (NamedAlgo hashAlgo ) => Digest hashAlgo -> Builder
175+ digestBuilder digest =
176+ Data.Text.Lazy.Builder. fromText (System.Nix.Hash. algoName @ hashAlgo )
177+ <> " :"
178+ <> Data.Text.Lazy.Builder. fromText (encodeDigestWith NixBase32 digest)
179+
180+ -- | Parser for content addressable field
181+ contentAddressableAddressParser :: Data.Attoparsec.ByteString.Char8. Parser ContentAddressableAddress
182+ contentAddressableAddressParser = caText <|> caFixed
183+ where
184+ -- | Parser for @text:sha256:<h>@
185+ -- caText :: Parser ContentAddressableAddress
186+ caText = do
187+ _ <- " text:sha256:"
188+ digest <- decodeDigestWith @ SHA256 NixBase32 <$> parseHash
189+ either fail pure $ Text <$> digest
190+
191+ -- | Parser for @fixed:<r?>:<ht>:<h>@
192+ -- caFixed :: Parser ContentAddressableAddress
193+ caFixed = do
194+ _ <- " fixed:"
195+ narHashMode <- (Recursive <$ " r:" ) <|> (RegularFile <$ " " )
196+ digest <- parseTypedDigest
197+ either fail pure $ Fixed narHashMode <$> digest
198+
199+ -- parseTypedDigest :: Parser (Either String SomeNamedDigest)
200+ parseTypedDigest = mkNamedDigest <$> parseHashType <*> parseHash
201+
202+ -- parseHashType :: Parser Text
203+ parseHashType =
204+ Data.Text.Encoding. decodeUtf8
205+ <$> (" sha256" <|> " sha512" <|> " sha1" <|> " md5" ) <* (" :" <|> " -" )
206+
207+ -- parseHash :: Parser Text
208+ parseHash =
209+ Data.Text.Encoding. decodeUtf8
210+ <$> Data.Attoparsec.ByteString.Char8. takeWhile1 (/= ' :' )
211+
139212-- | Schemes for hashing a Nix archive.
140213--
141214-- For backwards-compatibility reasons, there are two different modes
@@ -148,6 +221,9 @@ data NarHashMode
148221 Recursive
149222 deriving (Eq , Enum , Generic , Hashable , Ord , Show )
150223
224+ deriving via GenericArbitrary NarHashMode
225+ instance Arbitrary NarHashMode
226+
151227-- | Reason why a path is not valid
152228data InvalidPathError =
153229 EmptyName
0 commit comments