hnix-store-core 0.1.0.0 → 0.2.0.0
raw patch · 18 files changed
+377/−363 lines, 18 filesdep +regex-tdfadep +saltinedep +timedep −regex-tdfa-textnew-uploader
Dependencies added: regex-tdfa, saltine, time
Dependencies removed: regex-tdfa-text
Files
- hnix-store-core.cabal +9/−7
- src/System/Nix/Base32.hs +21/−13
- src/System/Nix/Build.hs +0/−50
- src/System/Nix/Derivation.hs +0/−30
- src/System/Nix/GC.hs +0/−47
- src/System/Nix/Hash.hs +1/−0
- src/System/Nix/Internal/Hash.hs +4/−0
- src/System/Nix/Internal/Signature.hs +29/−0
- src/System/Nix/Internal/StorePath.hs +201/−0
- src/System/Nix/Nar.hs +13/−1
- src/System/Nix/Path.hs +0/−128
- src/System/Nix/ReadonlyStore.hs +16/−18
- src/System/Nix/Signature.hs +9/−0
- src/System/Nix/Store.hs +0/−66
- src/System/Nix/StorePath.hs +23/−0
- src/System/Nix/StorePathMetadata.hs +49/−0
- tests/Hash.hs +2/−2
- tests/NarFormat.hs +0/−1
hnix-store-core.cabal view
@@ -1,5 +1,5 @@ name: hnix-store-core-version: 0.1.0.0+version: 0.2.0.0 synopsis: Core effects for interacting with the Nix store. description: This package contains types and functions needed to describe@@ -18,15 +18,15 @@ library exposed-modules: System.Nix.Base32- , System.Nix.Build- , System.Nix.Derivation- , System.Nix.GC , System.Nix.Hash , System.Nix.Internal.Hash+ , System.Nix.Internal.Signature+ , System.Nix.Internal.StorePath , System.Nix.Nar- , System.Nix.Path , System.Nix.ReadonlyStore- , System.Nix.Store+ , System.Nix.Signature+ , System.Nix.StorePath+ , System.Nix.StorePathMetadata , System.Nix.Util build-depends: base >=4.10 && <5 , base16-bytestring@@ -42,7 +42,9 @@ , hashable , mtl , regex-base- , regex-tdfa-text+ , regex-tdfa >= 1.3.1.0+ , saltine+ , time , text , unix , unordered-containers
src/System/Nix/Base32.hs view
@@ -9,23 +9,31 @@ -- | Encode a 'BS.ByteString' in Nix's base32 encoding encode :: BS.ByteString -> T.Text-encode c = T.pack $ concatMap char32 [nChar - 1, nChar - 2 .. 0]+encode c = T.pack $ map char32 [nChar - 1, nChar - 2 .. 0] where digits32 = V.fromList "0123456789abcdfghijklmnpqrsvwxyz"- -- The base32 encoding is 8/5's as long as the base256 digest. This `+ 1`- -- `- 1` business is a bit odd, but has always been used in C++ since the- -- base32 truncation was added in was first added in- -- d58a11e019813902b6c4547ca61a127938b2cc20.+ -- Each base32 character gives us 5 bits of information, while+ -- each byte gives is 8. Because 'div' rounds down, we need to add+ -- one extra character to the result, and because of that extra 1+ -- we need to subtract one from the number of bits in the+ -- bytestring to cover for the case where the number of bits is+ -- already a factor of 5. Thus, the + 1 outside of the 'div' and+ -- the - 1 inside of it. nChar = fromIntegral $ ((BS.length c * 8 - 1) `div` 5) + 1 - char32 :: Integer -> [Char]- char32 i = [digits32 V.! digitInd]+ byte = BS.index c . fromIntegral++ -- May need to switch to a more efficient calculation at some+ -- point.+ bAsInteger :: Integer+ bAsInteger = sum [fromIntegral (byte j) * (256 ^ j)+ | j <- [0 .. BS.length c - 1]+ ]++ char32 :: Integer -> Char+ char32 i = digits32 V.! digitInd where- byte j = BS.index c (fromIntegral j)- fromIntegral' :: Num b => Integer -> b- fromIntegral' = fromIntegral- digitInd = fromIntegral' $- sum [fromIntegral (byte j) * (256^j)- | j <- [0 .. BS.length c - 1]]+ digitInd = fromIntegral $+ bAsInteger `div` (32^i) `mod` 32
− src/System/Nix/Build.hs
@@ -1,50 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-|-Description : Build related types-Maintainer : srk <srk@48.io>-|-}-module System.Nix.Build (- BuildMode(..)- , BuildStatus(..)- , BuildResult(..)- , buildSuccess- ) where--import Data.Text (Text)-import Data.HashSet (HashSet)-import System.Nix.Path (Path)--data BuildMode = Normal | Repair | Check- deriving (Eq, Ord, Enum, Show)--data BuildStatus =- Built- | Substituted- | AlreadyValid- | PermanentFailure- | InputRejected- | OutputRejected- | TransientFailure -- possibly transient- | CachedFailure -- no longer used- | TimedOut- | MiscFailure- | DependencyFailed- | LogLimitExceeded- | NotDeterministic- deriving (Eq, Ord, Enum, Show)----- | Result of the build-data BuildResult = BuildResult- { -- | build status, MiscFailure should be default- status :: !BuildStatus- , -- | possible build error message- error :: !(Maybe Text)- , -- | How many times this build was performed- timesBuilt :: !Integer- , -- | If timesBuilt > 1, whether some builds did not produce the same result- isNonDeterministic :: !Bool- -- XXX: | startTime stopTime time_t- } deriving (Eq, Ord, Show)--buildSuccess BuildResult{..} = status == Built || status == Substituted || status == AlreadyValid
− src/System/Nix/Derivation.hs
@@ -1,30 +0,0 @@-{-|-Description : Derivation types-Maintainer : srk <srk@48.io>-|-}--module System.Nix.Derivation where---import Data.Text (Text)-import Data.HashMap.Strict (HashMap)-import Data.HashSet (HashSet)-import System.Nix.Path--type OutputName = Text--newtype DerivationInputs = DerivationInputs- { _unDerivationInputs :: HashMap Path (HashSet OutputName)- } deriving (Eq, Ord, Show)--data Derivation = Derivation- { _derivationInputs :: DerivationInputs- , _derivationOutputs :: !(HashMap OutputName Path)- -- | Inputs that are sources- , _derivationInputSrcs :: !PathSet- , _derivationPlatform :: !Text- -- | Path to builder- , _derivationBuilder :: !Path- , _derivationArgs :: ![Text]- , _derivationEnv :: ![HashMap Text Text]- } deriving (Eq, Ord, Show)
− src/System/Nix/GC.hs
@@ -1,47 +0,0 @@-{-|-Description : Garbage collection actions / options-Maintainer : srk <srk@48.io>-|-}-module System.Nix.GC (- Action(..)- , Options(..)- , Result(..)- ) where--import System.Nix.Path (PathSet)--{- Garbage collector operation:- - ReturnLive: return the set of paths reachable from- (i.e. in the closure of) the roots.- - ReturnDead: return the set of paths not reachable from- the roots.- - DeleteDead: actually delete the latter set.- - DeleteSpecific: delete the paths listed in- `pathsToDelete', insofar as they are not reachable.--}--data Action = ReturnLive | ReturnDead | DeleteDead | DeleteSpecific- deriving (Eq, Ord, Enum, Show)---- | Garbage collector operation options-data Options = Options- { -- | operation- operation :: !Action- -- | If `ignoreLiveness' is set, then reachability from the roots is- -- ignored (dangerous!). However, the paths must still be- -- unreferenced *within* the store (i.e., there can be no other- -- store paths that depend on them).- , ignoreLiveness :: !Bool- -- | For DeleteSpecific, the paths to delete- , pathsToDelete :: !PathSet- , -- | Stop after at least `maxFreed` bytes have been freed- maxFreed :: !Integer- } deriving (Eq, Ord, Show)--data Result = Result- { -- | Depending on the action, the GC roots, or the paths that would be or have been deleted- paths :: !PathSet- , -- | For ReturnDead, DeleteDead and DeleteSpecific, the number of bytes that would be or was freed- bytesFreed :: !Integer- } deriving (Eq, Ord, Show)-
src/System/Nix/Hash.hs view
@@ -7,6 +7,7 @@ , HNix.HashAlgorithm(..) , HNix.ValidAlgo(..) , HNix.NamedAlgo(..)+ , HNix.SomeNamedDigest(..) , HNix.hash , HNix.hashLazy
src/System/Nix/Internal/Hash.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ExistentialQuantification #-} module System.Nix.Internal.Hash where @@ -71,6 +72,9 @@ instance NamedAlgo 'SHA256 where algoName = "sha256"++-- | A digest whose 'NamedAlgo' is not known at compile time.+data SomeNamedDigest = forall a . NamedAlgo a => SomeDigest (Digest a) -- | Hash an entire (strict) 'BS.ByteString' as a single call. --
+ src/System/Nix/Internal/Signature.hs view
@@ -0,0 +1,29 @@+{-|+Description : Nix-relevant interfaces to NaCl signatures.+-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module System.Nix.Internal.Signature where++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.Coerce (coerce)+import Crypto.Saltine.Core.Sign (PublicKey)+import Crypto.Saltine.Class (IsEncoding(..))+import qualified Crypto.Saltine.Internal.ByteSizes as NaClSizes++-- | A NaCl signature.+newtype Signature = Signature ByteString deriving (Eq, Ord)++instance IsEncoding Signature where+ decode s+ | BS.length s == NaClSizes.sign = Just (Signature s)+ | otherwise = Nothing+ encode = coerce++-- | A detached NaCl signature attesting to a nix archive's validity.+data NarSignature = NarSignature+ { -- | The public key used to sign the archive.+ publicKey :: PublicKey+ , -- | The archive's signature.+ sig :: Signature+ } deriving (Eq, Ord)
+ src/System/Nix/Internal/StorePath.hs view
@@ -0,0 +1,201 @@+{-|+Description : Representation of Nix store paths.+-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE TypeInType #-} -- Needed for GHC 8.4.4 for some reason+module System.Nix.Internal.StorePath where+import System.Nix.Hash+ ( HashAlgorithm(Truncated, SHA256)+ , Digest+ , encodeBase32+ , SomeNamedDigest+ )+import Text.Regex.Base.RegexLike (makeRegex, matchTest)+import Text.Regex.TDFA.Text (Regex)+import Data.Text (Text)+import Data.Text.Encoding (encodeUtf8)+import GHC.TypeLits (Symbol, KnownSymbol, symbolVal)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BC+import Data.Hashable (Hashable(..))+import Data.HashSet (HashSet)+import Data.Proxy (Proxy(..))++-- | A path in a Nix store.+--+-- From the Nix thesis: A store path is the full path of a store+-- object. It has the following anatomy: storeDir/hashPart-name.+--+-- @storeDir@: The root of the Nix store (e.g. \/nix\/store).+--+-- See the 'StoreDir' haddocks for details on why we represent this at+-- the type level.+data StorePath (storeDir :: StoreDir) = StorePath+ { -- | The 160-bit hash digest reflecting the "address" of the name.+ -- Currently, this is a truncated SHA256 hash.+ storePathHash :: !(Digest StorePathHashAlgo)+ , -- | The (typically human readable) name of the path. For packages+ -- this is typically the package name and version (e.g.+ -- hello-1.2.3).+ storePathName :: !StorePathName+ } deriving (Eq, Ord)++instance Hashable (StorePath storeDir) where+ hashWithSalt s (StorePath {..}) =+ s `hashWithSalt` storePathHash `hashWithSalt` storePathName++-- | The name portion of a Nix path.+--+-- 'unStorePathName' must only contain a-zA-Z0-9+._?=-, can't start+-- with a -, and must have at least one character (i.e. it must match+-- 'storePathNameRegex').+newtype StorePathName = StorePathName+ { -- | Extract the contents of the name.+ unStorePathName :: Text+ } deriving (Eq, Hashable, Ord)++-- | The hash algorithm used for store path hashes.+type StorePathHashAlgo = 'Truncated 20 'SHA256++-- | A set of 'StorePath's.+type StorePathSet storeDir = HashSet (StorePath storeDir)++-- | An address for a content-addressable store path, i.e. one whose+-- store path hash is purely a function of its contents (as opposed to+-- paths that are derivation outputs, whose hashes are a function of+-- the contents of the derivation file instead).+--+-- For backwards-compatibility reasons, the same information is+-- encodable in multiple ways, depending on the method used to add the+-- path to the store. These unfortunately result in separate store+-- paths.+data ContentAddressableAddress+ = -- | The path is a plain file added via makeTextPath or+ -- addTextToStore. It is addressed according to a sha256sum of the+ -- file contents.+ Text !(Digest 'SHA256)+ | -- | The path was added to the store via makeFixedOutputPath or+ -- addToStore. It is addressed according to some hash algorithm+ -- applied to the nar serialization via some 'NarHashMode'.+ Fixed !NarHashMode !SomeNamedDigest++-- | Schemes for hashing a nix archive.+--+-- For backwards-compatibility reasons, there are two different modes+-- here, even though 'Recursive' should be able to cover both.+data NarHashMode+ = -- | Require the nar to represent a non-executable regular file.+ RegularFile+ | -- | Hash an arbitrary nar, including a non-executable regular+ -- file if so desired.+ Recursive++-- | A type-level representation of the root directory of a Nix store.+--+-- The extra complexity of type indices requires justification.+-- Fundamentally, this boils down to the fact that there is little+-- meaningful sense in which 'StorePath's rooted at different+-- directories are of the same type, i.e. there are few if any+-- non-trivial non-contrived functions or data types that could+-- equally well accept 'StorePath's from different stores. In current+-- practice, any real application dealing with Nix stores (including,+-- in particular, the Nix expression language) only operates over one+-- store root and only cares about 'StorePath's belonging to that+-- root. One could imagine a use case that cares about multiple store+-- roots at once (e.g. the normal \/nix\/store along with some private+-- store at \/root\/nix\/store to contain secrets), but in that case+-- distinguishing 'StorePath's that belong to one store or the other+-- is even /more/ critical: Most operations will only be correct over+-- one of the stores or another, and it would be an error to mix and+-- match (e.g. a 'StorePath' in one store could not legitimately refer+-- to one in another).+--+-- As of @5886bc5996537fbf00d1fcfbb29595b8ccc9743e@, the C++ Nix+-- codebase contains 30 separate places where we assert that a given+-- store dir is, in fact, in the store we care about; those run-time+-- assertions could be completely removed if we had stronger types+-- there. Moreover, there are dozens of other cases where input coming+-- from the user, from serializations, etc. is parsed and then+-- required to be in the appropriate store; this case is the+-- equivalent of an existentially quantified version of 'StorePath'+-- and, notably, requiring at runtime that the index matches the+-- ambient store directory we're working in. In every case where a+-- path is treated as a store path, there is exactly one legitimate+-- candidate for the store directory it belongs to.+--+-- It may be instructive to consider the example of "chroot stores".+-- Since Nix 2.0, it has been possible to have a store actually live+-- at one directory (say, $HOME\/nix\/store) with a different+-- effective store directory (say, \/nix\/store). Nix can build into+-- a chroot store by running the builds in a mount namespace where the+-- store is at the effective store directory, can download from a+-- binary cache containing paths for the effective store directory,+-- and can run programs in the store that expect to be living at the+-- effective store directory (via nix run). When viewed as store paths+-- (rather than random files in the filesystem), paths in a chroot+-- store have nothing in common with paths in a non-chroot store that+-- lives in the same directory, and a lot in common with paths in a+-- non-chroot store that lives in the effective store directory of the+-- store in question. Store paths in stores with the same effective+-- store directory share the same hashing scheme, can be copied+-- between each other, etc. Store paths in stores with different+-- effective store directories have no relationship to each other that+-- they don't have to arbitrary other files.+type StoreDir = Symbol++-- | Smart constructor for 'StorePathName' that ensures the underlying+-- content invariant is met.+makeStorePathName :: Text -> Maybe StorePathName+makeStorePathName n = case matchTest storePathNameRegex n of+ True -> Just $ StorePathName n+ False -> Nothing++-- | Regular expression to match valid store path names.+storePathNameRegex :: Regex+storePathNameRegex = makeRegex r+ where+ r :: String+ r = "[a-zA-Z0-9\\+\\-\\_\\?\\=][a-zA-Z0-9\\+\\-\\.\\_\\?\\=]*"++-- | Copied from @RawFilePath@ in the @unix@ package, duplicated here+-- to avoid the dependency.+type RawFilePath = ByteString++-- | Render a 'StorePath' as a 'RawFilePath'.+storePathToRawFilePath+ :: forall storeDir . (KnownStoreDir storeDir)+ => StorePath storeDir+ -> RawFilePath+storePathToRawFilePath (StorePath {..}) = BS.concat+ [ root+ , "/"+ , hashPart+ , "-"+ , name+ ]+ where+ root = storeDirVal @storeDir+ hashPart = encodeUtf8 $ encodeBase32 storePathHash+ name = encodeUtf8 $ unStorePathName storePathName++-- | Get a value-level representation of a 'KnownStoreDir'+storeDirVal :: forall storeDir . (KnownStoreDir storeDir)+ => ByteString+storeDirVal = BC.pack $ symbolVal @storeDir Proxy++-- | A 'StoreDir' whose value is known at compile time.+--+-- A valid instance of 'KnownStoreDir' should represent a valid path,+-- i.e. all "characters" fit into bytes (as determined by the logic of+-- 'BC.pack') and there are no 0 "characters". Currently this is not+-- enforced, but it should be.+type KnownStoreDir = KnownSymbol
src/System/Nix/Nar.hs view
@@ -18,6 +18,8 @@ , localUnpackNar , narEffectsIO , putNar+ , FilePathPart(..)+ , filePathPart ) where import Control.Applicative@@ -42,7 +44,6 @@ import System.Posix.Files (createSymbolicLink, fileSize, getFileStatus, isDirectory, readSymbolicLink) -import System.Nix.Path data NarEffects (m :: * -> *) = NarEffects { narReadFile :: FilePath -> m BSL.ByteString@@ -64,6 +65,17 @@ data Nar = Nar { narFile :: FileSystemObject } deriving (Eq, Show)++-- | A valid filename or directory name+newtype FilePathPart = FilePathPart { unFilePathPart :: BSC.ByteString }+ deriving (Eq, Ord, Show)++-- | Construct FilePathPart from Text by checking that there+-- are no '/' or '\\NUL' characters+filePathPart :: BSC.ByteString -> Maybe FilePathPart+filePathPart p = case BSC.any (`elem` ['/', '\NUL']) p of+ False -> Just $ FilePathPart p+ True -> Nothing -- | A FileSystemObject (FSO) is an anonymous entity that can be NAR archived data FileSystemObject =
− src/System/Nix/Path.hs
@@ -1,128 +0,0 @@-{-|-Description : Types and effects for interacting with the Nix store.-Maintainer : Shea Levy <shea@shealevy.com>--}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-module System.Nix.Path- ( FilePathPart(..)- , PathHashAlgo- , Path(..)- , pathToText- , PathSet- , SubstitutablePathInfo(..)- , ValidPathInfo(..)- , PathName(..)- , filePathPart- , pathName- , Roots- ) where--import System.Nix.Hash (Digest(..),- HashAlgorithm(Truncated, SHA256))-import System.Nix.Internal.Hash-import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BSC-import Data.Hashable (Hashable (..), hashPtrWithSalt)-import Data.HashMap.Strict (HashMap)-import Data.HashSet (HashSet)-import Data.Map.Strict (Map)-import Data.Monoid-import Data.Text (Text)-import qualified Data.Text as T-import System.IO.Unsafe (unsafeDupablePerformIO)-import Text.Regex.Base.RegexLike (makeRegex, matchTest)-import Text.Regex.TDFA.Text (Regex)---- | The hash algorithm used for store path hashes.-type PathHashAlgo = Truncated 20 SHA256----- | The name portion of a Nix path.------ Must be composed of a-z, A-Z, 0-9, +, -, ., _, ?, and =, can't--- start with a ., and must have at least one character.-newtype PathName = PathName- { pathNameContents :: Text -- ^ The contents of the path name- } deriving (Eq, Ord, Show, Hashable)---- | A regular expression for matching a valid 'PathName'-nameRegex :: Regex-nameRegex =- makeRegex ("[a-zA-Z0-9\\+\\-\\_\\?\\=][a-zA-Z0-9\\+\\-\\.\\_\\?\\=]*" :: String)---- | Construct a 'PathName', assuming the provided contents are valid.-pathName :: Text -> Maybe PathName-pathName n = case matchTest nameRegex n of- True -> Just $ PathName n- False -> Nothing---- | A path in a store.-data Path = Path !(Digest PathHashAlgo) !PathName- deriving (Eq, Ord, Show)--pathToText :: Text -> Path -> Text-pathToText storeDir (Path h nm) = storeDir <> "/" <> encodeBase32 h <> "-" <> pathNameContents nm--type PathSet = HashSet Path---- | Information about substitutes for a 'Path'.-data SubstitutablePathInfo = SubstitutablePathInfo- { -- | The .drv which led to this 'Path'.- deriver :: !(Maybe Path)- , -- | The references of the 'Path'- references :: !PathSet- , -- | The (likely compressed) size of the download of this 'Path'.- downloadSize :: !Integer- , -- | The size of the uncompressed NAR serialization of this- -- 'Path'.- narSize :: !Integer- } deriving (Eq, Ord, Show)---- | Information about @Path@-data ValidPathInfo = ValidPathInfo- { -- | Path itself- path :: !Path- , -- | The .drv which led to this 'Path'.- deriverVP :: !(Maybe Path)- , -- | NAR hash- narHash :: !Text- , -- | The references of the 'Path'- referencesVP :: !PathSet- , -- | Registration time should be time_t- registrationTime :: !Integer- , -- | The size of the uncompressed NAR serialization of this- -- 'Path'.- narSizeVP :: !Integer- , -- | Whether the path is ultimately trusted, that is, it's a- -- derivation output that was built locally.- ultimate :: !Bool- , -- | Signatures- sigs :: ![Text]- , -- | Content-addressed- -- Store path is computed from a cryptographic hash- -- of the contents of the path, plus some other bits of data like- -- the "name" part of the path.- --- -- ‘ca’ has one of the following forms:- -- * ‘text:sha256:<sha256 hash of file contents>’ (paths by makeTextPath() / addTextToStore())- -- * ‘fixed:<r?>:<ht>:<h>’ (paths by makeFixedOutputPath() / addToStore())- ca :: !Text- } deriving (Eq, Ord, Show)---- | A valid filename or directory name-newtype FilePathPart = FilePathPart { unFilePathPart :: BSC.ByteString }- deriving (Eq, Ord, Show)---- | Construct FilePathPart from Text by checking that there--- are no '/' or '\\NUL' characters-filePathPart :: BSC.ByteString -> Maybe FilePathPart-filePathPart p = case BSC.any (`elem` ['/', '\NUL']) p of- False -> Just $ FilePathPart p- True -> Nothing--type Roots = Map Path Path--instance Hashable Path where- hashWithSalt s (Path hash name) = s `hashWithSalt` hash `hashWithSalt` name
src/System/Nix/ReadonlyStore.hs view
@@ -1,34 +1,32 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-}-+{-# LANGUAGE ScopedTypeVariables #-} module System.Nix.ReadonlyStore where import Data.ByteString (ByteString)-import Data.ByteString.Base16 as Base16+import qualified Data.ByteString as BS import qualified Data.HashSet as HS-import Data.Text (Text)-import qualified Data.Text as T import Data.Text.Encoding import System.Nix.Hash-import System.Nix.Path+import System.Nix.StorePath -makeStorePath :: Text -> Text -> Digest 'SHA256 -> Text -> Path-makeStorePath storeDir ty h nm = Path storeHash (PathName nm)+makeStorePath :: forall storeDir hashAlgo . (KnownStoreDir storeDir, NamedAlgo hashAlgo) => ByteString -> Digest hashAlgo -> StorePathName -> StorePath storeDir+makeStorePath ty h nm = StorePath storeHash nm where- s = T.intercalate ":"+ s = BS.intercalate ":" [ ty- , algoName @'SHA256- , encodeBase16 h- , storeDir- , nm+ , encodeUtf8 $ algoName @hashAlgo+ , encodeUtf8 $ encodeBase16 h+ , storeDirVal @storeDir+ , encodeUtf8 $ unStorePathName nm ]- storeHash = hash $ encodeUtf8 s+ storeHash = hash s -makeTextPath :: Text -> Text -> Digest 'SHA256 -> PathSet -> Path-makeTextPath storeDir nm h refs = makeStorePath storeDir ty h nm+makeTextPath :: (KnownStoreDir storeDir) => StorePathName -> Digest 'SHA256 -> StorePathSet storeDir -> StorePath storeDir+makeTextPath nm h refs = makeStorePath ty h nm where- ty = T.intercalate ":" ("text" : map (pathToText storeDir) (HS.toList refs))+ ty = BS.intercalate ":" ("text" : map storePathToRawFilePath (HS.toList refs)) -computeStorePathForText :: Text -> Text -> ByteString -> PathSet -> Path-computeStorePathForText storeDir nm s refs = makeTextPath storeDir nm (hash s) refs+computeStorePathForText :: (KnownStoreDir storeDir) => StorePathName -> ByteString -> StorePathSet storeDir -> StorePath storeDir+computeStorePathForText nm s refs = makeTextPath nm (hash s) refs
+ src/System/Nix/Signature.hs view
@@ -0,0 +1,9 @@+{-|+Description : Nix-relevant interfaces to NaCl signatures.+-}+module System.Nix.Signature+ ( Signature+ , NarSignature(..)+ ) where++import System.Nix.Internal.Signature
− src/System/Nix/Store.hs
@@ -1,66 +0,0 @@-{-|-Description : Types and effects for interacting with the Nix store.-Maintainer : Shea Levy <shea@shealevy.com>--}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-module System.Nix.Store- ( PathName, pathNameContents, pathName- , PathHashAlgo, Path(..)- , StoreEffects(..)- , SubstitutablePathInfo(..)- ) where--import qualified Data.ByteString.Lazy as BS-import Data.Text (Text)-import Text.Regex.Base.RegexLike (makeRegex, matchTest)-import Text.Regex.TDFA.Text (Regex)-import Data.Hashable (Hashable(..), hashPtrWithSalt)-import Data.HashSet (HashSet)-import Data.HashMap.Strict (HashMap)-import System.IO.Unsafe (unsafeDupablePerformIO)--import System.Nix.Hash (Digest)-import System.Nix.Path-import System.Nix.Nar----- | Interactions with the Nix store.------ @rootedPath@: A path plus a witness to the fact that the path is--- reachable from a root whose liftime is at least as long as the--- @rootedPath@ reference itself, when the implementation supports--- this.------ @validPath@: A @rootedPath@ plus a witness to the fact that the--- path is valid. On implementations that support temporary roots,--- this implies that the path will remain valid so long as the--- reference is held.------ @m@: The monad the effects operate in.-data StoreEffects rootedPath validPath m =- StoreEffects- { -- | Project out the underlying 'Path' from a 'rootedPath'- fromRootedPath :: !(rootedPath -> Path)- , -- | Project out the underlying 'rootedPath' from a 'validPath'- fromValidPath :: !(validPath -> rootedPath)- , -- | Which of the given paths are valid?- validPaths :: !(HashSet rootedPath -> m (HashSet validPath))- , -- | Get the paths that refer to a given path.- referrers :: !(validPath -> m (HashSet Path))- , -- | Get a root to the 'Path'.- rootedPath :: !(Path -> m rootedPath)- , -- | Get information about substituters of a set of 'Path's- substitutablePathInfos ::- !(HashSet Path -> m (HashMap Path SubstitutablePathInfo))- , -- | Get the currently valid derivers of a 'Path'.- validDerivers :: !(Path -> m (HashSet Path))- , -- | Get the outputs of the derivation at a 'Path'.- derivationOutputs :: !(validPath -> m (HashSet Path))- , -- | Get the output names of the derivation at a 'Path'.- derivationOutputNames :: !(validPath -> m (HashSet Text))- , -- | Get a full 'Path' corresponding to a given 'Digest'.- pathFromHashPart :: !(Digest PathHashAlgo -> m Path)- , -- | Add a non-nar file to the store- addFile :: !(BS.ByteString -> m validPath)- }
+ src/System/Nix/StorePath.hs view
@@ -0,0 +1,23 @@+{-|+Description : Representation of Nix store paths.+-}+module System.Nix.StorePath+ ( -- * Basic store path types+ StorePath(..)+ , StorePathName+ , StorePathSet+ , StorePathHashAlgo+ , StoreDir+ , ContentAddressableAddress(..)+ , NarHashMode(..)+ , -- * Manipulating 'StorePathName'+ makeStorePathName+ , unStorePathName+ , storePathNameRegex+ , -- * Rendering out 'StorePath's+ storePathToRawFilePath+ , storeDirVal+ , KnownStoreDir+ ) where++import System.Nix.Internal.StorePath
+ src/System/Nix/StorePathMetadata.hs view
@@ -0,0 +1,49 @@+{-|+Description : Metadata about Nix store paths.+-}+module System.Nix.StorePathMetadata where++import System.Nix.StorePath (StorePath, StorePathSet, ContentAddressableAddress)+import System.Nix.Hash (SomeNamedDigest)+import Data.Set (Set)+import Data.Time (UTCTime)+import Data.Word (Word64)+import System.Nix.Signature (NarSignature)++-- | Metadata about a 'StorePath' in @storeDir@.+data StorePathMetadata storeDir = StorePathMetadata+ { -- | The path this metadata is about+ path :: !(StorePath storeDir)+ , -- | The path to the derivation file that built this path, if any+ -- and known.+ deriverPath :: !(Maybe (StorePath storeDir))+ , -- TODO should this be optional?+ -- | The hash of the nar serialization of the path.+ narHash :: !SomeNamedDigest+ , -- | The paths that this path directly references+ references :: !(StorePathSet storeDir)+ , -- | When was this path registered valid in the store?+ registrationTime :: !UTCTime+ , -- | The size of the nar serialization of the path, in bytes.+ narBytes :: !(Maybe Word64)+ , -- | How much we trust this path.+ trust :: !StorePathTrust+ , -- | A set of cryptographic attestations of this path's validity.+ --+ -- There is no guarantee from this type alone that these+ -- signatures are valid.+ sigs :: !(Set NarSignature)+ , -- | Whether and how this store path is content-addressable.+ --+ -- There is no guarantee from this type alone that this address+ -- is actually correct for this store path.+ contentAddressableAddress :: !(Maybe ContentAddressableAddress)+ }++-- | How much do we trust the path, based on its provenance?+data StorePathTrust+ = -- | It was built locally and thus ultimately trusted+ BuiltLocally+ | -- | It was built elsewhere (and substituted or similar) and so+ -- is less trusted+ BuiltElsewhere
tests/Hash.hs view
@@ -23,7 +23,7 @@ import Text.Read (readMaybe) import System.Nix.Hash-import System.Nix.Path+import System.Nix.StorePath import NarFormat -- TODO: Move the fixtures into a common module spec_hash :: Spec@@ -45,5 +45,5 @@ let exampleStr = "source:sha256:2bfef67de873c54551d884fdab3055d84d573e654efa79db3" <> "c0d7b98883f9ee3:/nix/store:myfile"- shouldBe (encodeBase32 @PathHashAlgo (hash exampleStr))+ shouldBe (encodeBase32 @StorePathHashAlgo (hash exampleStr)) "xv2iccirbrvklck36f1g7vldn5v58vck"
tests/NarFormat.hs view
@@ -33,7 +33,6 @@ import Text.Read (readMaybe) import System.Nix.Nar-import System.Nix.Path