Skip to content

Commit 7067c32

Browse files
committed
Implement readonly store path hashing
1 parent b8568a4 commit 7067c32

File tree

4 files changed

+80
-19
lines changed

4 files changed

+80
-19
lines changed

hnix-store-core/hnix-store-core.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ library
2424
, System.Nix.Internal.Hash
2525
, System.Nix.Nar
2626
, System.Nix.Path
27+
, System.Nix.ReadonlyStore
2728
, System.Nix.Store
2829
, System.Nix.Util
2930
build-depends: base >=4.10 && <4.12
31+
, base16-bytestring
3032
, bytestring
3133
, binary
3234
, bytestring
@@ -61,7 +63,7 @@ test-suite format-tests
6163
NarFormat
6264
Hash
6365
hs-source-dirs:
64-
tests
66+
tests
6567
build-depends:
6668
hnix-store-core
6769
, base

hnix-store-core/src/System/Nix/Internal/Hash.hs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,29 @@ Maintainer : Greg Hale <[email protected]>
1212
{-# LANGUAGE ScopedTypeVariables #-}
1313
{-# LANGUAGE TypeApplications #-}
1414
{-# LANGUAGE TypeInType #-}
15+
{-# LANGUAGE OverloadedStrings #-}
1516

1617
module System.Nix.Internal.Hash where
1718

18-
import qualified Crypto.Hash.MD5 as MD5
19-
import qualified Crypto.Hash.SHA1 as SHA1
20-
import qualified Crypto.Hash.SHA256 as SHA256
21-
import qualified Data.ByteString as BS
22-
import qualified Data.ByteString.Char8 as BSC
23-
import Data.Bits (xor)
24-
import qualified Data.ByteString as BS
25-
import qualified Data.ByteString.Lazy as BSL
26-
import qualified Data.Hashable as DataHashable
27-
import Data.Kind (Type)
28-
import Data.List (foldl')
29-
import Data.Proxy (Proxy(Proxy))
30-
import qualified Data.Text as T
31-
import qualified Data.Text.Encoding as T
32-
import qualified Data.Vector as V
33-
import Data.Word (Word8)
19+
import qualified Crypto.Hash.MD5 as MD5
20+
import qualified Crypto.Hash.SHA1 as SHA1
21+
import qualified Crypto.Hash.SHA256 as SHA256
22+
import qualified Data.ByteString as BS
23+
import qualified Data.ByteString.Base16 as Base16
24+
import qualified Data.ByteString.Char8 as BSC
25+
import Data.Bits (xor)
26+
import qualified Data.ByteString as BS
27+
import qualified Data.ByteString.Lazy as BSL
28+
import qualified Data.Hashable as DataHashable
29+
import Data.Kind (Type)
30+
import Data.List (foldl')
31+
import Data.Monoid
32+
import Data.Proxy (Proxy(Proxy))
33+
import Data.Text (Text)
34+
import qualified Data.Text as T
35+
import qualified Data.Text.Encoding as T
36+
import qualified Data.Vector as V
37+
import Data.Word (Word8)
3438
import GHC.TypeLits
3539

3640
-- | A tag for different hashing algorithms
@@ -45,6 +49,18 @@ data HashAlgorithm' n
4549
| Truncated n (HashAlgorithm' n)
4650
deriving (Eq, Show)
4751

52+
class HashAlgoText a where
53+
algoString :: Proxy a -> Text
54+
55+
instance HashAlgoText 'MD5 where
56+
algoString (Proxy :: Proxy 'MD5) = "md5"
57+
58+
instance HashAlgoText 'SHA1 where
59+
algoString (Proxy :: Proxy 'SHA1) = "sha1"
60+
61+
instance HashAlgoText 'SHA256 where
62+
algoString (Proxy :: Proxy 'SHA256) = "sha256"
63+
4864
type HashAlgorithm = HashAlgorithm' Nat
4965

5066
-- | Types with kind @HashAlgorithm@ may be a @HasDigest@ instance
@@ -80,8 +96,11 @@ hashLazy :: forall a.HasDigest a => BSL.ByteString -> Digest a
8096
hashLazy bsl =
8197
finalize $ foldl' (update @a) (initialize @a) (BSL.toChunks bsl)
8298

99+
digestText32 :: forall a. HashAlgoText a => Digest a -> T.Text
100+
digestText32 d = algoString (Proxy :: Proxy a) <> ":" <> printAsBase32 d
83101

84-
102+
digestText16 :: forall a. HashAlgoText a => Digest a -> T.Text
103+
digestText16 (Digest bs) = algoString (Proxy :: Proxy a) <> ":" <> T.decodeUtf8 (Base16.encode bs)
85104

86105
-- | Convert any Digest to a base32-encoded string.
87106
-- This is not used in producing store path hashes

hnix-store-core/src/System/Nix/Path.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ Description : Types and effects for interacting with the Nix store.
33
Maintainer : Shea Levy <[email protected]>
44
-}
55
{-# LANGUAGE DataKinds #-}
6+
{-# LANGUAGE OverloadedStrings #-}
67
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
78
module System.Nix.Path
89
( FilePathPart(..)
910
, PathHashAlgo
1011
, Path(..)
12+
, pathToText
1113
, PathSet
1214
, SubstitutablePathInfo(..)
1315
, ValidPathInfo(..)
@@ -19,12 +21,14 @@ module System.Nix.Path
1921

2022
import System.Nix.Hash (Digest(..),
2123
HashAlgorithm'(Truncated, SHA256))
24+
import System.Nix.Internal.Hash
2225
import qualified Data.ByteString as BS
2326
import qualified Data.ByteString.Char8 as BSC
2427
import Data.Hashable (Hashable (..), hashPtrWithSalt)
2528
import Data.HashMap.Strict (HashMap)
2629
import Data.HashSet (HashSet)
2730
import Data.Map.Strict (Map)
31+
import Data.Monoid
2832
import Data.Text (Text)
2933
import qualified Data.Text as T
3034
import System.IO.Unsafe (unsafeDupablePerformIO)
@@ -46,7 +50,7 @@ newtype PathName = PathName
4650
-- | A regular expression for matching a valid 'PathName'
4751
nameRegex :: Regex
4852
nameRegex =
49-
makeRegex "[a-zA-Z0-9\\+\\-\\_\\?\\=][a-zA-Z0-9\\+\\-\\.\\_\\?\\=]*"
53+
makeRegex ("[a-zA-Z0-9\\+\\-\\_\\?\\=][a-zA-Z0-9\\+\\-\\.\\_\\?\\=]*" :: String)
5054

5155
-- | Construct a 'PathName', assuming the provided contents are valid.
5256
pathName :: Text -> Maybe PathName
@@ -58,6 +62,9 @@ pathName n = case matchTest nameRegex n of
5862
data Path = Path !(Digest PathHashAlgo) !PathName
5963
deriving (Eq, Ord, Show)
6064

65+
pathToText :: Text -> Path -> Text
66+
pathToText storeDir (Path h nm) = storeDir <> "/" <> printAsBase32 h <> "-" <> pathNameContents nm
67+
6168
type PathSet = HashSet Path
6269

6370
-- | Information about substitutes for a 'Path'.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{-# LANGUAGE DataKinds #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
{-# LANGUAGE TypeApplications #-}
4+
5+
module System.Nix.ReadonlyStore where
6+
7+
import Data.ByteString (ByteString)
8+
import Data.ByteString.Base16 as Base16
9+
import qualified Data.HashSet as HS
10+
import Data.Text (Text)
11+
import qualified Data.Text as T
12+
import Data.Text.Encoding
13+
import System.Nix.Internal.Hash
14+
import System.Nix.Path
15+
16+
makeStorePath :: Text -> Text -> Digest 'SHA256 -> Text -> Path
17+
makeStorePath storeDir ty h nm = Path storeHash (PathName nm)
18+
where
19+
s = T.intercalate ":"
20+
[ ty
21+
, digestText16 h
22+
, storeDir
23+
, nm
24+
]
25+
storeHash = truncateDigest $ hash $ encodeUtf8 s
26+
27+
makeTextPath :: Text -> Text -> Digest 'SHA256 -> PathSet -> Path
28+
makeTextPath storeDir nm h refs = makeStorePath storeDir ty h nm
29+
where
30+
ty = T.intercalate ":" ("text" : map (pathToText storeDir) (HS.toList refs))
31+
32+
computeStorePathForText :: Text -> Text -> ByteString -> PathSet -> Path
33+
computeStorePathForText storeDir nm s refs = makeTextPath storeDir nm (hash s) refs

0 commit comments

Comments
 (0)