Skip to content

Commit 3de47a3

Browse files
committed
Use constant-space encoding and decoding for NARs
1 parent 59e08d4 commit 3de47a3

File tree

8 files changed

+1176
-334
lines changed

8 files changed

+1176
-334
lines changed

default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{ pkgs ? import <nixpkgs> {} }: let
2-
overlay = import ./overlay.nix;
2+
overlay = import ./overlay.nix pkgs.haskell.lib;
33
overrideHaskellPackages = orig: {
44
buildHaskellPackages =
55
orig.buildHaskellPackages.override overrideHaskellPackages;

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: hnix-store-core
2-
version: 0.2.0.0
2+
version: 0.3.0.0
33
synopsis: Core effects for interacting with the Nix store.
44
description:
55
This package contains types and functions needed to describe
@@ -23,6 +23,9 @@ library
2323
, System.Nix.Hash
2424
, System.Nix.Internal.Base32
2525
, System.Nix.Internal.Hash
26+
, System.Nix.Internal.Nar.Parser
27+
, System.Nix.Internal.Nar.Streamer
28+
, System.Nix.Internal.Nar.Effects
2629
, System.Nix.Internal.Signature
2730
, System.Nix.Internal.StorePath
2831
, System.Nix.Nar
@@ -32,17 +35,21 @@ library
3235
, System.Nix.StorePathMetadata
3336
build-depends: base >=4.10 && <5
3437
, attoparsec
38+
, algebraic-graphs >= 0.5 && < 0.6
3539
, base16-bytestring
3640
, bytestring
3741
, binary
3842
, bytestring
43+
, cereal
3944
, containers
4045
, cryptohash-md5
4146
, cryptohash-sha1
4247
, cryptohash-sha256
4348
, directory
4449
, filepath
4550
, hashable
51+
, lifted-base
52+
, monad-control
4653
, mtl
4754
, nix-derivation >= 1.1.1 && <2
4855
, saltine
@@ -83,7 +90,10 @@ test-suite format-tests
8390
, containers
8491
, filepath
8592
, directory
93+
, filepath
94+
, io-streams
8695
, process
96+
, process-extras
8797
, tasty
8898
, tasty-discover
8999
, tasty-golden
@@ -92,4 +102,5 @@ test-suite format-tests
92102
, tasty-quickcheck
93103
, temporary
94104
, text
105+
, unix
95106
default-language: Haskell2010
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{-# LANGUAGE FlexibleContexts #-}
2+
{-# LANGUAGE KindSignatures #-}
3+
{-# LANGUAGE RankNTypes #-}
4+
{-# LANGUAGE ScopedTypeVariables #-}
5+
6+
module System.Nix.Internal.Nar.Effects
7+
( NarEffects(..)
8+
, narEffectsIO
9+
) where
10+
11+
import qualified Control.Exception.Lifted as Lifted
12+
import qualified Control.Monad.Fail as MonadFail
13+
import qualified Control.Monad.IO.Class as IO
14+
import Control.Monad.Trans.Control (MonadBaseControl)
15+
import qualified Data.ByteString as BS
16+
import qualified Data.ByteString.Lazy as BSL
17+
import Data.Int (Int64)
18+
import qualified System.Directory as Directory
19+
import qualified System.Directory as Directory
20+
import qualified System.IO as IO
21+
import System.Posix.Files (createSymbolicLink, fileSize,
22+
getFileStatus, isDirectory,
23+
readSymbolicLink)
24+
25+
data NarEffects (m :: * -> *) = NarEffects {
26+
narReadFile :: FilePath -> m BSL.ByteString
27+
, narWriteFile :: FilePath -> BSL.ByteString -> m ()
28+
, narStreamFile :: FilePath -> m (Maybe BS.ByteString) -> m ()
29+
, narListDir :: FilePath -> m [FilePath]
30+
, narCreateDir :: FilePath -> m ()
31+
, narCreateLink :: FilePath -> FilePath -> m ()
32+
, narGetPerms :: FilePath -> m Directory.Permissions
33+
, narSetPerms :: FilePath -> Directory.Permissions -> m ()
34+
, narIsDir :: FilePath -> m Bool
35+
, narIsSymLink :: FilePath -> m Bool
36+
, narFileSize :: FilePath -> m Int64
37+
, narReadLink :: FilePath -> m FilePath
38+
, narDeleteDir :: FilePath -> m ()
39+
, narDeleteFile :: FilePath -> m ()
40+
}
41+
42+
43+
-- | A particular @NarEffects@ that uses regular POSIX for file manipulation
44+
-- You would replace this with your own @NarEffects@ if you wanted a
45+
-- different backend
46+
narEffectsIO
47+
:: (IO.MonadIO m,
48+
MonadFail.MonadFail m,
49+
MonadBaseControl IO m
50+
) => NarEffects m
51+
narEffectsIO = NarEffects {
52+
narReadFile = IO.liftIO . BSL.readFile
53+
, narWriteFile = \a b -> IO.liftIO $ BSL.writeFile a b
54+
, narStreamFile = streamStringOutIO
55+
, narListDir = IO.liftIO . Directory.listDirectory
56+
, narCreateDir = IO.liftIO . Directory.createDirectory
57+
, narCreateLink = \f t -> IO.liftIO $ createSymbolicLink f t
58+
, narGetPerms = IO.liftIO . Directory.getPermissions
59+
, narSetPerms = \f p -> IO.liftIO $ Directory.setPermissions f p
60+
, narIsDir = \d -> fmap isDirectory $ IO.liftIO (getFileStatus d)
61+
, narIsSymLink = IO.liftIO . Directory.pathIsSymbolicLink
62+
, narFileSize = \n -> fmap (fromIntegral . fileSize) $ IO.liftIO (getFileStatus n)
63+
, narReadLink = IO.liftIO . readSymbolicLink
64+
, narDeleteDir = IO.liftIO . Directory.removeDirectoryRecursive
65+
, narDeleteFile = IO.liftIO . Directory.removeFile
66+
}
67+
68+
69+
-- | This default implementation for @narStreamFile@ requires @IO.MonadIO@
70+
streamStringOutIO
71+
:: forall m
72+
.(IO.MonadIO m,
73+
MonadFail.MonadFail m,
74+
MonadBaseControl IO m
75+
) => FilePath
76+
-> m (Maybe BS.ByteString)
77+
-> m ()
78+
streamStringOutIO f getChunk =
79+
Lifted.bracket
80+
(IO.liftIO (IO.openFile f IO.WriteMode)) (IO.liftIO . IO.hClose) go
81+
`Lifted.catch`
82+
cleanupException
83+
where
84+
go :: IO.Handle -> m ()
85+
go handle = do
86+
chunk <- getChunk
87+
case chunk of
88+
Nothing -> return ()
89+
Just c -> do
90+
IO.liftIO $ BS.hPut handle c
91+
go handle
92+
cleanupException (e :: Lifted.SomeException) = do
93+
IO.liftIO $ Directory.removeFile f
94+
MonadFail.fail $
95+
"Failed to stream string to " ++ f ++ ": " ++ show e

0 commit comments

Comments
 (0)