Skip to content

Commit 7ecef66

Browse files
authored
Merge pull request #13 from sorki/remote
WIP: Remote store
2 parents 2075aae + d5eb32e commit 7ecef66

File tree

16 files changed

+1182
-2
lines changed

16 files changed

+1182
-2
lines changed

cabal.project

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: ./hnix-store-core/*.cabal ./hnix-store-remote/*.cabal

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

+4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ cabal-version: >=1.10
1818

1919
library
2020
exposed-modules: Crypto.Hash.Truncated
21+
, System.Nix.Build
22+
, System.Nix.Derivation
23+
, System.Nix.GC
2124
, System.Nix.Nar
2225
, System.Nix.Path
2326
, System.Nix.Store
27+
, System.Nix.Util
2428
build-depends: base >=4.10 && <4.11
2529
, basement
2630
, bytestring
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{-# LANGUAGE RecordWildCards #-}
2+
{-|
3+
Description : Build related types
4+
Maintainer : srk <[email protected]>
5+
|-}
6+
module System.Nix.Build (
7+
BuildMode(..)
8+
, BuildStatus(..)
9+
, BuildResult(..)
10+
, buildSuccess
11+
) where
12+
13+
import Data.Text (Text)
14+
import Data.HashSet (HashSet)
15+
import System.Nix.Path (Path)
16+
17+
data BuildMode = Normal | Repair | Check
18+
deriving (Eq, Ord, Enum, Show)
19+
20+
data BuildStatus =
21+
Built
22+
| Substituted
23+
| AlreadyValid
24+
| PermanentFailure
25+
| InputRejected
26+
| OutputRejected
27+
| TransientFailure -- possibly transient
28+
| CachedFailure -- no longer used
29+
| TimedOut
30+
| MiscFailure
31+
| DependencyFailed
32+
| LogLimitExceeded
33+
| NotDeterministic
34+
deriving (Eq, Ord, Enum, Show)
35+
36+
37+
-- | Result of the build
38+
data BuildResult = BuildResult
39+
{ -- | build status, MiscFailure should be default
40+
status :: !BuildStatus
41+
, -- | possible build error message
42+
error :: !(Maybe Text)
43+
, -- | How many times this build was performed
44+
timesBuilt :: !Integer
45+
, -- | If timesBuilt > 1, whether some builds did not produce the same result
46+
isNonDeterministic :: !Bool
47+
-- XXX: | startTime stopTime time_t
48+
} deriving (Eq, Ord, Show)
49+
50+
buildSuccess BuildResult{..} = status == Built || status == Substituted || status == AlreadyValid
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{-|
2+
Description : Derivation types
3+
Maintainer : srk <[email protected]>
4+
|-}
5+
6+
module System.Nix.Derivation (
7+
BasicDerivation(..)
8+
) where
9+
10+
11+
import Data.Text (Text)
12+
import Data.HashMap.Strict (HashMap)
13+
import System.Nix.Path
14+
15+
data BasicDerivation = BasicDerivation
16+
{ -- | Derivation outputs
17+
outputs :: !(HashMap Text Path)
18+
, -- | Inputs that are sources
19+
inputSrcs :: !PathSet
20+
, -- | Platform
21+
platform :: !Text
22+
, -- | Path to builder
23+
builder :: !Path
24+
, -- | Arguments
25+
args :: ![Text]
26+
, -- | Environment
27+
env :: ![HashMap Text Text]
28+
} deriving (Eq, Ord, Show)

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

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{-|
2+
Description : Garbage collection actions / options
3+
Maintainer : srk <[email protected]>
4+
|-}
5+
module System.Nix.GC (
6+
Action(..)
7+
, Options(..)
8+
, Result(..)
9+
) where
10+
11+
import System.Nix.Path (PathSet)
12+
13+
{- Garbage collector operation:
14+
- ReturnLive: return the set of paths reachable from
15+
(i.e. in the closure of) the roots.
16+
- ReturnDead: return the set of paths not reachable from
17+
the roots.
18+
- DeleteDead: actually delete the latter set.
19+
- DeleteSpecific: delete the paths listed in
20+
`pathsToDelete', insofar as they are not reachable.
21+
-}
22+
23+
data Action = ReturnLive | ReturnDead | DeleteDead | DeleteSpecific
24+
deriving (Eq, Ord, Enum, Show)
25+
26+
-- | Garbage collector operation options
27+
data Options = Options
28+
{ -- | operation
29+
operation :: !Action
30+
-- | If `ignoreLiveness' is set, then reachability from the roots is
31+
-- ignored (dangerous!). However, the paths must still be
32+
-- unreferenced *within* the store (i.e., there can be no other
33+
-- store paths that depend on them).
34+
, ignoreLiveness :: !Bool
35+
-- | For DeleteSpecific, the paths to delete
36+
, pathsToDelete :: !PathSet
37+
, -- | Stop after at least `maxFreed` bytes have been freed
38+
maxFreed :: !Integer
39+
} deriving (Eq, Ord, Show)
40+
41+
data Result = Result
42+
{ -- | Depending on the action, the GC roots, or the paths that would be or have been deleted
43+
paths :: !PathSet
44+
, -- | For ReturnDead, DeleteDead and DeleteSpecific, the number of bytes that would be or was freed
45+
bytesFreed :: !Integer
46+
} deriving (Eq, Ord, Show)
47+

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

+42-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ module System.Nix.Path
88
( FilePathPart(..)
99
, PathHashAlgo
1010
, Path(..)
11+
, PathSet
1112
, SubstitutablePathInfo(..)
13+
, ValidPathInfo(..)
1214
, PathName(..)
1315
, filePathPart
1416
, pathName
17+
, Roots
1518
) where
1619

1720
import Crypto.Hash (Digest)
@@ -23,6 +26,7 @@ import qualified Data.ByteString.Char8 as BSC
2326
import Data.Hashable (Hashable (..), hashPtrWithSalt)
2427
import Data.HashMap.Strict (HashMap)
2528
import Data.HashSet (HashSet)
29+
import Data.Map.Strict (Map)
2630
import Data.Text (Text)
2731
import qualified Data.Text as T
2832
import System.IO.Unsafe (unsafeDupablePerformIO)
@@ -53,6 +57,7 @@ type PathHashAlgo = Truncated SHA256 20
5357

5458
-- | A path in a store.
5559
data Path = Path !(Digest PathHashAlgo) !PathName
60+
deriving (Eq, Ord, Show)
5661

5762
-- | Wrapper to defined a 'Hashable' instance for 'Digest'.
5863
newtype HashableDigest a = HashableDigest (Digest a)
@@ -67,18 +72,51 @@ instance Hashable Path where
6772
(HashableDigest digest) `hashWithSalt` name
6873

6974

75+
type PathSet = HashSet Path
76+
7077
-- | Information about substitutes for a 'Path'.
7178
data SubstitutablePathInfo = SubstitutablePathInfo
7279
{ -- | The .drv which led to this 'Path'.
7380
deriver :: !(Maybe Path)
7481
, -- | The references of the 'Path'
75-
references :: !(HashSet Path)
82+
references :: !PathSet
7683
, -- | The (likely compressed) size of the download of this 'Path'.
7784
downloadSize :: !Integer
7885
, -- | The size of the uncompressed NAR serialization of this
7986
-- 'Path'.
8087
narSize :: !Integer
81-
}
88+
} deriving (Eq, Ord, Show)
89+
90+
-- | Information about 'Path'.
91+
data ValidPathInfo = ValidPathInfo
92+
{ -- | Path itself
93+
path :: !Path
94+
, -- | The .drv which led to this 'Path'.
95+
deriverVP :: !(Maybe Path)
96+
, -- | NAR hash
97+
narHash :: !Text
98+
, -- | The references of the 'Path'
99+
referencesVP :: !PathSet
100+
, -- | Registration time should be time_t
101+
registrationTime :: !Integer
102+
, -- | The size of the uncompressed NAR serialization of this
103+
-- 'Path'.
104+
narSizeVP :: !Integer
105+
, -- | Whether the path is ultimately trusted, that is, it's a
106+
-- derivation output that was built locally.
107+
ultimate :: !Bool
108+
, -- | Signatures
109+
sigs :: ![Text]
110+
, -- | Content-addressed
111+
-- Store path is computed from a cryptographic hash
112+
-- of the contents of the path, plus some other bits of data like
113+
-- the "name" part of the path.
114+
--
115+
-- ‘ca’ has one of the following forms:
116+
-- * ‘text:sha256:<sha256 hash of file contents>’ (paths by makeTextPath() / addTextToStore())
117+
-- * ‘fixed:<r?>:<ht>:<h>’ (paths by makeFixedOutputPath() / addToStore())
118+
ca :: !Text
119+
} deriving (Eq, Ord, Show)
82120

83121
-- | A valid filename or directory name
84122
newtype FilePathPart = FilePathPart { unFilePathPart :: BSC.ByteString }
@@ -90,3 +128,5 @@ filePathPart :: BSC.ByteString -> Maybe FilePathPart
90128
filePathPart p = case BSC.any (`elem` ['/', '\NUL']) p of
91129
False -> Just $ FilePathPart p
92130
True -> Nothing
131+
132+
type Roots = Map Path Path
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{-|
2+
Description : Utilities for packing stuff
3+
Maintainer : srk <[email protected]>
4+
|-}
5+
module System.Nix.Util where
6+
7+
import Control.Monad
8+
import Data.Binary.Get
9+
import Data.Binary.Put
10+
import qualified Data.ByteString.Lazy as LBS
11+
12+
putInt :: Integral a => a -> Put
13+
putInt = putWord64le . fromIntegral
14+
15+
getInt :: Integral a => Get a
16+
getInt = fromIntegral <$> getWord64le
17+
18+
-- length prefixed string packing with padding to 8 bytes
19+
putByteStringLen :: LBS.ByteString -> Put
20+
putByteStringLen x = do
21+
putInt $ fromIntegral $ len
22+
putLazyByteString x
23+
when (len `mod` 8 /= 0) $
24+
pad $ fromIntegral $ 8 - (len `mod` 8)
25+
where len = LBS.length x
26+
pad x = forM_ (take x $ cycle [0]) putWord8
27+
28+
putByteStrings :: Foldable t => t LBS.ByteString -> Put
29+
putByteStrings xs = do
30+
putInt $ fromIntegral $ length xs
31+
mapM_ putByteStringLen xs
32+
33+
getByteStringLen :: Get LBS.ByteString
34+
getByteStringLen = do
35+
len <- getInt
36+
st <- getLazyByteString len
37+
when (len `mod` 8 /= 0) $ do
38+
pads <- unpad $ fromIntegral $ 8 - (len `mod` 8)
39+
unless (all (==0) pads) $ fail $ "No zeroes" ++ show (st, len, pads)
40+
return st
41+
where unpad x = sequence $ replicate x getWord8
42+
43+
getByteStrings :: Get [LBS.ByteString]
44+
getByteStrings = do
45+
count <- getInt
46+
res <- sequence $ replicate count getByteStringLen
47+
return res
48+

0 commit comments

Comments
 (0)