@@ -10,7 +10,8 @@ Description : Representation of Nix store paths.
1010
1111module System.Nix.Internal.StorePath
1212 ( -- * Basic store path types
13- StorePath (.. )
13+ StoreDir (.. )
14+ , StorePath (.. )
1415 , StorePathName (.. )
1516 , StorePathSet
1617 , mkStorePathHashPart
@@ -32,7 +33,6 @@ module System.Nix.Internal.StorePath
3233where
3334
3435import qualified Relude.Unsafe as Unsafe
35- import qualified Text.Show
3636import System.Nix.Internal.Hash
3737import System.Nix.Internal.Base
3838import qualified System.Nix.Internal.Base32 as Nix.Base32
@@ -54,10 +54,9 @@ import Crypto.Hash ( SHA256
5454-- From the Nix thesis: A store path is the full path of a store
5555-- object. It has the following anatomy: storeDir/hashPart-name.
5656--
57- -- @storeDir@: The root of the Nix store (e.g. \/nix\/store).
58- --
59- -- See the 'StoreDir' haddocks for details on why we represent this at
60- -- the type level.
57+ -- The store directory is *not* included, and must be known from the
58+ -- context. This matches modern C++ Nix, and also represents the fact
59+ -- that store paths for different store directories cannot be mixed.
6160data StorePath = StorePath
6261 { -- | The 160-bit hash digest reflecting the "address" of the name.
6362 -- Currently, this is a truncated SHA256 hash.
@@ -66,18 +65,13 @@ data StorePath = StorePath
6665 -- this is typically the package name and version (e.g.
6766 -- hello-1.2.3).
6867 storePathName :: ! StorePathName
69- , -- | Root of the store
70- storePathRoot :: ! FilePath
7168 }
72- deriving (Eq , Ord )
69+ deriving (Eq , Ord , Show )
7370
7471instance Hashable StorePath where
7572 hashWithSalt s StorePath {.. } =
7673 s `hashWithSalt` storePathHash `hashWithSalt` storePathName
7774
78- instance Show StorePath where
79- show p = Bytes.Char8. unpack $ storePathToRawFilePath p
80-
8175-- | The name portion of a Nix path.
8276--
8377-- 'unStorePathName' must only contain a-zA-Z0-9+._?=-, can't start
@@ -86,7 +80,7 @@ instance Show StorePath where
8680newtype StorePathName = StorePathName
8781 { -- | Extract the contents of the name.
8882 unStorePathName :: Text
89- } deriving (Eq , Hashable , Ord )
83+ } deriving (Eq , Hashable , Ord , Show )
9084
9185-- | The hash algorithm used for store path hashes.
9286newtype StorePathHashPart = StorePathHashPart ByteString
@@ -161,22 +155,29 @@ validStorePathNameChar c =
161155-- to avoid the dependency.
162156type RawFilePath = ByteString
163157
158+ -- | The path to the store dir
159+ --
160+ -- Many operations need to be parameterized with this, since store paths
161+ -- do not know their own store dir by design.
162+ newtype StoreDir = StoreDir {
163+ unStoreDir :: RawFilePath
164+ } deriving (Eq , Hashable , Ord , Show )
165+
164166-- | Render a 'StorePath' as a 'RawFilePath'.
165- storePathToRawFilePath :: StorePath -> RawFilePath
166- storePathToRawFilePath StorePath {.. } =
167- root <> " /" <> hashPart <> " -" <> name
167+ storePathToRawFilePath :: StoreDir -> StorePath -> RawFilePath
168+ storePathToRawFilePath storeDir StorePath {.. } =
169+ unStoreDir storeDir <> " /" <> hashPart <> " -" <> name
168170 where
169- root = Bytes.Char8. pack storePathRoot
170171 hashPart = encodeUtf8 $ encodeWith NixBase32 $ coerce storePathHash
171172 name = encodeUtf8 $ unStorePathName storePathName
172173
173174-- | Render a 'StorePath' as a 'FilePath'.
174- storePathToFilePath :: StorePath -> FilePath
175- storePathToFilePath = Bytes.Char8. unpack . storePathToRawFilePath
175+ storePathToFilePath :: StoreDir -> StorePath -> FilePath
176+ storePathToFilePath storeDir = Bytes.Char8. unpack . storePathToRawFilePath storeDir
176177
177178-- | Render a 'StorePath' as a 'Text'.
178- storePathToText :: StorePath -> Text
179- storePathToText = toText . Bytes.Char8. unpack . storePathToRawFilePath
179+ storePathToText :: StoreDir -> StorePath -> Text
180+ storePathToText storeDir = toText . Bytes.Char8. unpack . storePathToRawFilePath storeDir
180181
181182-- | Build `narinfo` suffix from `StorePath` which
182183-- can be used to query binary caches.
@@ -186,7 +187,7 @@ storePathToNarInfo StorePath{..} =
186187
187188-- | Parse `StorePath` from `Bytes.Char8.ByteString`, checking
188189-- that store directory matches `expectedRoot`.
189- parsePath :: FilePath -> Bytes.Char8. ByteString -> Either String StorePath
190+ parsePath :: StoreDir -> Bytes.Char8. ByteString -> Either String StorePath
190191parsePath expectedRoot x =
191192 let
192193 (rootDir, fname) = FilePath. splitFileName . Bytes.Char8. unpack $ x
@@ -196,17 +197,20 @@ parsePath expectedRoot x =
196197 -- rootDir' = dropTrailingPathSeparator rootDir
197198 -- cannot use ^^ as it drops multiple slashes /a/b/// -> /a/b
198199 rootDir' = Unsafe. init rootDir
200+ expectedRootS = Bytes.Char8. unpack (unStoreDir expectedRoot)
199201 storeDir =
200- if expectedRoot == rootDir'
202+ if expectedRootS == rootDir'
201203 then pure rootDir'
202- else Left $ " Root store dir mismatch, expected" <> expectedRoot <> " got" <> rootDir'
204+ else Left $ " Root store dir mismatch, expected" <> expectedRootS <> " got" <> rootDir'
203205 in
204- StorePath <$> coerce storeHash <*> name <*> storeDir
206+ either Left ( pure $ StorePath <$> coerce storeHash <*> name) storeDir
205207
206- pathParser :: FilePath -> Parser StorePath
208+ pathParser :: StoreDir -> Parser StorePath
207209pathParser expectedRoot = do
210+ let expectedRootS = Bytes.Char8. unpack (unStoreDir expectedRoot)
211+
208212 _ <-
209- Parser.Text.Lazy. string (toText expectedRoot )
213+ Parser.Text.Lazy. string (toText expectedRootS )
210214 <?> " Store root mismatch" -- e.g. /nix/store
211215
212216 _ <- Parser.Text.Lazy. char ' /'
@@ -232,4 +236,4 @@ pathParser expectedRoot = do
232236 either
233237 fail
234238 pure
235- (StorePath <$> coerce digest <*> name <*> pure expectedRoot )
239+ (StorePath <$> coerce digest <*> name)
0 commit comments