hnix-store-remote 0.6.0.0 → 0.7.0.0
raw patch · 53 files changed
+6019/−1387 lines, 53 filesdep +QuickCheckdep +aesondep +cerealdep −binarydep −cryptonitedep −nix-derivationdep ~basedep ~hnix-store-coredep ~unixnew-component:exe:build-derivationnew-component:exe:remote-readmePVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, aeson, cereal, concurrency, crypton, data-default-class, dependent-sum, dependent-sum-template, dlist, exceptions, generic-arbitrary, hashable, hnix-store-json, hnix-store-nar, hnix-store-tests, some, transformers, vector
Dependencies removed: binary, cryptonite, nix-derivation, quickcheck-text, relude, tasty, tasty-hspec, tasty-quickcheck
Dependency ranges changed: base, hnix-store-core, unix
API changes (from Hackage documentation)
- System.Nix.Store.Remote: addIndirectRoot :: StorePath -> MonadStore ()
- System.Nix.Store.Remote: addSignatures :: StorePath -> [ByteString] -> MonadStore ()
- System.Nix.Store.Remote: addTempRoot :: StorePath -> MonadStore ()
- System.Nix.Store.Remote: addTextToStore :: Text -> Text -> StorePathSet -> RepairFlag -> MonadStore StorePath
- System.Nix.Store.Remote: addToStore :: forall a. NamedAlgo a => StorePathName -> NarSource MonadStore -> Bool -> RepairFlag -> MonadStore StorePath
- System.Nix.Store.Remote: buildDerivation :: StorePath -> Derivation StorePath Text -> BuildMode -> MonadStore BuildResult
- System.Nix.Store.Remote: buildPaths :: StorePathSet -> BuildMode -> MonadStore ()
- System.Nix.Store.Remote: ensurePath :: StorePath -> MonadStore ()
- System.Nix.Store.Remote: findRoots :: MonadStore (Map ByteString StorePath)
- System.Nix.Store.Remote: isValidPathUncached :: StorePath -> MonadStore Bool
- System.Nix.Store.Remote: optimiseStore :: MonadStore ()
- System.Nix.Store.Remote: queryAllValidPaths :: MonadStore StorePathSet
- System.Nix.Store.Remote: queryDerivationOutputNames :: StorePath -> MonadStore StorePathSet
- System.Nix.Store.Remote: queryDerivationOutputs :: StorePath -> MonadStore StorePathSet
- System.Nix.Store.Remote: queryMissing :: StorePathSet -> MonadStore (StorePathSet, StorePathSet, StorePathSet, Integer, Integer)
- System.Nix.Store.Remote: queryPathFromHashPart :: StorePathHashPart -> MonadStore StorePath
- System.Nix.Store.Remote: queryPathInfoUncached :: StorePath -> MonadStore StorePathMetadata
- System.Nix.Store.Remote: queryReferrers :: StorePath -> MonadStore StorePathSet
- System.Nix.Store.Remote: querySubstitutablePaths :: StorePathSet -> MonadStore StorePathSet
- System.Nix.Store.Remote: queryValidDerivers :: StorePath -> MonadStore StorePathSet
- System.Nix.Store.Remote: queryValidPaths :: StorePathSet -> SubstituteFlag -> MonadStore StorePathSet
- System.Nix.Store.Remote: syncWithGC :: MonadStore ()
- System.Nix.Store.Remote: verifyStore :: CheckFlag -> RepairFlag -> MonadStore Bool
- System.Nix.Store.Remote.Binary: getByteStringLen :: Get ByteString
- System.Nix.Store.Remote.Binary: getByteStrings :: Get [ByteString]
- System.Nix.Store.Remote.Binary: getInt :: Integral a => Get a
- System.Nix.Store.Remote.Binary: getMany :: Get a -> Get [a]
- System.Nix.Store.Remote.Binary: putByteStringLen :: ByteString -> Put
- System.Nix.Store.Remote.Binary: putByteStrings :: Foldable t => t ByteString -> Put
- System.Nix.Store.Remote.Binary: putInt :: Integral a => a -> Put
- System.Nix.Store.Remote.Binary: putMany :: Foldable t => (a -> Put) -> t a -> Put
- System.Nix.Store.Remote.Builders: buildContentAddressableAddress :: ContentAddressableAddress -> Text
- System.Nix.Store.Remote.Logger: Error :: Int -> ByteString -> Logger
- System.Nix.Store.Remote.Logger: Last :: Logger
- System.Nix.Store.Remote.Logger: LogInt :: Int -> Field
- System.Nix.Store.Remote.Logger: LogStr :: ByteString -> Field
- System.Nix.Store.Remote.Logger: Next :: ByteString -> Logger
- System.Nix.Store.Remote.Logger: Read :: Int -> Logger
- System.Nix.Store.Remote.Logger: Result :: ActivityID -> ResultType -> [Field] -> Logger
- System.Nix.Store.Remote.Logger: StartActivity :: ActivityID -> Verbosity -> ActivityType -> ByteString -> [Field] -> ActivityParentID -> Logger
- System.Nix.Store.Remote.Logger: StopActivity :: ActivityID -> Logger
- System.Nix.Store.Remote.Logger: Write :: ByteString -> Logger
- System.Nix.Store.Remote.Logger: data Field
- System.Nix.Store.Remote.Logger: data Logger
- System.Nix.Store.Remote.Parsers: parseContentAddressableAddress :: ByteString -> Either String ContentAddressableAddress
- System.Nix.Store.Remote.Protocol: AddIndirectRoot :: WorkerOp
- System.Nix.Store.Remote.Protocol: AddSignatures :: WorkerOp
- System.Nix.Store.Remote.Protocol: AddTempRoot :: WorkerOp
- System.Nix.Store.Remote.Protocol: AddTextToStore :: WorkerOp
- System.Nix.Store.Remote.Protocol: AddToStore :: WorkerOp
- System.Nix.Store.Remote.Protocol: AddToStoreNar :: WorkerOp
- System.Nix.Store.Remote.Protocol: BuildDerivation :: WorkerOp
- System.Nix.Store.Remote.Protocol: BuildPaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: ClearFailedPaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: CollectGarbage :: WorkerOp
- System.Nix.Store.Remote.Protocol: EnsurePath :: WorkerOp
- System.Nix.Store.Remote.Protocol: FindRoots :: WorkerOp
- System.Nix.Store.Remote.Protocol: HasSubstitutes :: WorkerOp
- System.Nix.Store.Remote.Protocol: IsValidPath :: WorkerOp
- System.Nix.Store.Remote.Protocol: NarFromPath :: WorkerOp
- System.Nix.Store.Remote.Protocol: OptimiseStore :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryAllValidPaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryDerivationOutputNames :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryDerivationOutputs :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryFailedPaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryMissing :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryPathFromHashPart :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryPathInfo :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryReferrers :: WorkerOp
- System.Nix.Store.Remote.Protocol: QuerySubstitutablePathInfo :: WorkerOp
- System.Nix.Store.Remote.Protocol: QuerySubstitutablePathInfos :: WorkerOp
- System.Nix.Store.Remote.Protocol: QuerySubstitutablePaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryValidDerivers :: WorkerOp
- System.Nix.Store.Remote.Protocol: QueryValidPaths :: WorkerOp
- System.Nix.Store.Remote.Protocol: SetOptions :: WorkerOp
- System.Nix.Store.Remote.Protocol: SyncWithGC :: WorkerOp
- System.Nix.Store.Remote.Protocol: VerifyStore :: WorkerOp
- System.Nix.Store.Remote.Protocol: data WorkerOp
- System.Nix.Store.Remote.Protocol: instance GHC.Classes.Eq System.Nix.Store.Remote.Protocol.WorkerOp
- System.Nix.Store.Remote.Protocol: instance GHC.Classes.Ord System.Nix.Store.Remote.Protocol.WorkerOp
- System.Nix.Store.Remote.Protocol: instance GHC.Show.Show System.Nix.Store.Remote.Protocol.WorkerOp
- System.Nix.Store.Remote.Protocol: runOp :: WorkerOp -> MonadStore ()
- System.Nix.Store.Remote.Protocol: runOpArgs :: WorkerOp -> Put -> MonadStore ()
- System.Nix.Store.Remote.Protocol: runOpArgsIO :: WorkerOp -> ((ByteString -> MonadStore ()) -> MonadStore ()) -> MonadStore ()
- System.Nix.Store.Remote.Protocol: runStore :: MonadStore a -> IO (Either String a, [Logger])
- System.Nix.Store.Remote.Protocol: runStoreOpts :: FilePath -> FilePath -> MonadStore a -> IO (Either String a, [Logger])
- System.Nix.Store.Remote.Protocol: runStoreOpts' :: Family -> SockAddr -> FilePath -> MonadStore a -> IO (Either String a, [Logger])
- System.Nix.Store.Remote.Protocol: runStoreOptsTCP :: String -> Int -> FilePath -> MonadStore a -> IO (Either String a, [Logger])
- System.Nix.Store.Remote.Protocol: simpleOp :: WorkerOp -> MonadStore Bool
- System.Nix.Store.Remote.Protocol: simpleOpArgs :: WorkerOp -> Put -> MonadStore Bool
- System.Nix.Store.Remote.Types: Error :: Int -> ByteString -> Logger
- System.Nix.Store.Remote.Types: Last :: Logger
- System.Nix.Store.Remote.Types: LogInt :: Int -> Field
- System.Nix.Store.Remote.Types: LogStr :: ByteString -> Field
- System.Nix.Store.Remote.Types: Next :: ByteString -> Logger
- System.Nix.Store.Remote.Types: Read :: Int -> Logger
- System.Nix.Store.Remote.Types: Result :: ActivityID -> ResultType -> [Field] -> Logger
- System.Nix.Store.Remote.Types: StartActivity :: ActivityID -> Verbosity -> ActivityType -> ByteString -> [Field] -> ActivityParentID -> Logger
- System.Nix.Store.Remote.Types: StopActivity :: ActivityID -> Logger
- System.Nix.Store.Remote.Types: StoreConfig :: FilePath -> Socket -> StoreConfig
- System.Nix.Store.Remote.Types: Write :: ByteString -> Logger
- System.Nix.Store.Remote.Types: [storeDir] :: StoreConfig -> FilePath
- System.Nix.Store.Remote.Types: [storeSocket] :: StoreConfig -> Socket
- System.Nix.Store.Remote.Types: clearData :: MonadStore ()
- System.Nix.Store.Remote.Types: data Field
- System.Nix.Store.Remote.Types: data Logger
- System.Nix.Store.Remote.Types: data StoreConfig
- System.Nix.Store.Remote.Types: flushLog :: MonadStore ()
- System.Nix.Store.Remote.Types: getError :: MonadStore [Logger]
- System.Nix.Store.Remote.Types: getLog :: MonadStore [Logger]
- System.Nix.Store.Remote.Types: getStoreDir :: MonadStore FilePath
- System.Nix.Store.Remote.Types: gotError :: MonadStore Bool
- System.Nix.Store.Remote.Types: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Field
- System.Nix.Store.Remote.Types: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger
- System.Nix.Store.Remote.Types: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Field
- System.Nix.Store.Remote.Types: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger
- System.Nix.Store.Remote.Types: instance GHC.Show.Show System.Nix.Store.Remote.Types.Field
- System.Nix.Store.Remote.Types: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger
- System.Nix.Store.Remote.Types: setData :: ByteString -> MonadStore ()
- System.Nix.Store.Remote.Types: type MonadStore a = ExceptT String (StateT (Maybe ByteString, [Logger]) (ReaderT StoreConfig IO)) a
- System.Nix.Store.Remote.Util: bsToText :: ByteString -> Text
- System.Nix.Store.Remote.Util: bslToText :: ByteString -> Text
- System.Nix.Store.Remote.Util: genericIncremental :: MonadIO m => m (Maybe ByteString) -> Get a -> m a
- System.Nix.Store.Remote.Util: getBool :: Get Bool
- System.Nix.Store.Remote.Util: getBuildResult :: Get BuildResult
- System.Nix.Store.Remote.Util: getEnum :: Enum a => Get a
- System.Nix.Store.Remote.Util: getPath :: FilePath -> Get (Either String StorePath)
- System.Nix.Store.Remote.Util: getPaths :: FilePath -> Get StorePathSet
- System.Nix.Store.Remote.Util: getSocketIncremental :: Get a -> MonadStore a
- System.Nix.Store.Remote.Util: getTime :: Get UTCTime
- System.Nix.Store.Remote.Util: putBool :: Bool -> Put
- System.Nix.Store.Remote.Util: putDerivation :: Derivation StorePath Text -> Put
- System.Nix.Store.Remote.Util: putEnum :: Enum a => a -> Put
- System.Nix.Store.Remote.Util: putPath :: StorePath -> Put
- System.Nix.Store.Remote.Util: putPaths :: StorePathSet -> Put
- System.Nix.Store.Remote.Util: putText :: Text -> Put
- System.Nix.Store.Remote.Util: putTexts :: [Text] -> Put
- System.Nix.Store.Remote.Util: putTime :: UTCTime -> Put
- System.Nix.Store.Remote.Util: sockGet :: Get a -> MonadStore a
- System.Nix.Store.Remote.Util: sockGetBool :: MonadStore Bool
- System.Nix.Store.Remote.Util: sockGetInt :: Integral a => MonadStore a
- System.Nix.Store.Remote.Util: sockGetPath :: MonadStore StorePath
- System.Nix.Store.Remote.Util: sockGetPathMay :: MonadStore (Maybe StorePath)
- System.Nix.Store.Remote.Util: sockGetPaths :: MonadStore StorePathSet
- System.Nix.Store.Remote.Util: sockGetStr :: MonadStore ByteString
- System.Nix.Store.Remote.Util: sockGetStrings :: MonadStore [ByteString]
- System.Nix.Store.Remote.Util: sockPut :: Put -> MonadStore ()
- System.Nix.Store.Remote.Util: textToBS :: Text -> ByteString
- System.Nix.Store.Remote.Util: textToBSL :: Text -> ByteString
+ Data.Serializer: Serializer :: t Get a -> (a -> t PutM ()) -> Serializer t a
+ Data.Serializer: SerializerError_Get :: customGetError -> GetSerializerError customGetError
+ Data.Serializer: SerializerError_GetFail :: String -> GetSerializerError customGetError
+ Data.Serializer: [getS] :: Serializer t a -> t Get a
+ Data.Serializer: [putS] :: Serializer t a -> a -> t PutM ()
+ Data.Serializer: data () => Get a
+ Data.Serializer: data GetSerializerError customGetError
+ Data.Serializer: data () => PutM a
+ Data.Serializer: data Serializer t a
+ Data.Serializer: instance GHC.Classes.Eq customGetError => GHC.Classes.Eq (Data.Serializer.GetSerializerError customGetError)
+ Data.Serializer: instance GHC.Classes.Ord customGetError => GHC.Classes.Ord (Data.Serializer.GetSerializerError customGetError)
+ Data.Serializer: instance GHC.Show.Show customGetError => GHC.Show.Show (Data.Serializer.GetSerializerError customGetError)
+ Data.Serializer: lift2 :: forall a t. MonadTrans t => Get a -> Putter a -> Serializer t a
+ Data.Serializer: liftSerialize :: (Serialize a, MonadTrans t) => Serializer t a
+ Data.Serializer: mapIsoSerializer :: Functor (t Get) => (a -> b) -> (b -> a) -> Serializer t a -> Serializer t b
+ Data.Serializer: mapPrismSerializer :: MonadError eGet (t Get) => (a -> Either eGet b) -> (b -> a) -> Serializer t a -> Serializer t b
+ Data.Serializer: runGetS :: (Monad (t Get), MonadTrans t) => Serializer t a -> (t Get a -> Get b) -> ByteString -> Either String b
+ Data.Serializer: runGetSimple :: SimpleSerializer a -> ByteString -> Either String a
+ Data.Serializer: runPutS :: (Monad (t PutM), MonadTrans t) => Serializer t a -> (t PutM () -> PutM b) -> a -> (b, ByteString)
+ Data.Serializer: runPutSimple :: SimpleSerializer a -> a -> ByteString
+ Data.Serializer: transformGetError :: Either String (Either customGetError b) -> Either (GetSerializerError customGetError) b
+ Data.Serializer: transformPutError :: (Either customPutError (), ByteString) -> Either customPutError ByteString
+ Data.Serializer: tup :: (Applicative (t Get), Monad (t PutM)) => Serializer t a -> Serializer t b -> Serializer t (a, b)
+ Data.Serializer: type SimpleSerializer a = Serializer IdentityT a
+ Data.Serializer.Example: MyGetError_Example :: MyGetError
+ Data.Serializer.Example: MyPutError_NoLongerSupported :: MyPutError
+ Data.Serializer.Example: OpCode_Bool :: OpCode
+ Data.Serializer.Example: OpCode_Int :: OpCode
+ Data.Serializer.Example: [Cmd_Bool] :: Bool -> Cmd Bool
+ Data.Serializer.Example: [Cmd_Int] :: Int8 -> Cmd Int8
+ Data.Serializer.Example: cmdS :: forall t. (MonadTrans t, Monad (t Get), Monad (t PutM)) => Serializer t (Some Cmd)
+ Data.Serializer.Example: cmdSGetError :: Serializer (ExceptT MyGetError) (Some Cmd)
+ Data.Serializer.Example: cmdSGetFail :: (MonadTrans t, MonadFail (t Get), Monad (t PutM)) => Serializer t (Some Cmd)
+ Data.Serializer.Example: cmdSPutError :: Serializer (ExceptT MyPutError) (Some Cmd)
+ Data.Serializer.Example: cmdSPutFail :: (MonadTrans t, MonadFail (t PutM), Monad (t Get)) => Serializer t (Some Cmd)
+ Data.Serializer.Example: cmdSRest :: Serializer (REST Bool e Int) (Some Cmd)
+ Data.Serializer.Example: data Cmd :: Type -> Type
+ Data.Serializer.Example: data MyGetError
+ Data.Serializer.Example: data MyPutError
+ Data.Serializer.Example: data OpCode
+ Data.Serializer.Example: instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance Control.Monad.Trans.Class.MonadTrans (Data.Serializer.Example.REST r e s)
+ Data.Serializer.Example: instance Data.GADT.Internal.GShow Data.Serializer.Example.Cmd
+ Data.Serializer.Example: instance Data.Type.Equality.TestEquality Data.Serializer.Example.Cmd
+ Data.Serializer.Example: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Base.Monad m => Control.Monad.Error.Class.MonadError e (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader r (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState s (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Base.Monad m => GHC.Base.Monad (Data.Serializer.Example.REST r e s m)
+ Data.Serializer.Example: instance GHC.Classes.Eq (Data.Serializer.Example.Cmd a)
+ Data.Serializer.Example: instance GHC.Classes.Eq (Data.Some.Newtype.Some Data.Serializer.Example.Cmd)
+ Data.Serializer.Example: instance GHC.Classes.Eq Data.Serializer.Example.MyGetError
+ Data.Serializer.Example: instance GHC.Classes.Eq Data.Serializer.Example.MyPutError
+ Data.Serializer.Example: instance GHC.Classes.Eq Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance GHC.Classes.Ord Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance GHC.Enum.Bounded Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance GHC.Enum.Enum Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance GHC.Generics.Generic Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance GHC.Show.Show (Data.Serializer.Example.Cmd a)
+ Data.Serializer.Example: instance GHC.Show.Show Data.Serializer.Example.MyGetError
+ Data.Serializer.Example: instance GHC.Show.Show Data.Serializer.Example.MyPutError
+ Data.Serializer.Example: instance GHC.Show.Show Data.Serializer.Example.OpCode
+ Data.Serializer.Example: instance Test.QuickCheck.Arbitrary.Arbitrary (Data.Some.Newtype.Some Data.Serializer.Example.Cmd)
+ Data.Serializer.Example: runG :: Serializer (ExceptT e) a -> ByteString -> Either (GetSerializerError e) a
+ Data.Serializer.Example: runGRest :: Serializer (REST r e s) a -> r -> s -> ByteString -> Either (GetSerializerError e) a
+ Data.Serializer.Example: runP :: Serializer (ExceptT e) a -> a -> Either e ByteString
+ Data.Serializer.Example: runPRest :: Serializer (REST r e s) a -> r -> s -> a -> Either e ByteString
+ System.Nix.Store.Remote: FileIngestionMethod_FileRecursive :: FileIngestionMethod
+ System.Nix.Store.Remote: FileIngestionMethod_Flat :: FileIngestionMethod
+ System.Nix.Store.Remote: RemoteStoreError_GetAddrInfoFailed :: RemoteStoreError
+ System.Nix.Store.Remote: RepairMode_DoRepair :: RepairMode
+ System.Nix.Store.Remote: RepairMode_DontRepair :: RepairMode
+ System.Nix.Store.Remote: appendLog :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => Logger -> m ()
+ System.Nix.Store.Remote: class (MonadIO m, MonadError RemoteStoreError m) => MonadRemoteStore m
+ System.Nix.Store.Remote: clearDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote: clearDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote: clearDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote: data () => FileIngestionMethod
+ System.Nix.Store.Remote: data RemoteStoreError
+ System.Nix.Store.Remote: data RemoteStoreT m a
+ System.Nix.Store.Remote: data () => RepairMode
+ System.Nix.Store.Remote: getConfig :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ProtoStoreConfig
+ System.Nix.Store.Remote: getDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (ByteString -> IO ()))
+ System.Nix.Store.Remote: getDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe Word64)
+ System.Nix.Store.Remote: getDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (Word64 -> IO (Maybe ByteString)))
+ System.Nix.Store.Remote: getProtoVersion :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ProtoVersion
+ System.Nix.Store.Remote: getStoreDir :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m StoreDir
+ System.Nix.Store.Remote: getStoreSocket :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m Socket
+ System.Nix.Store.Remote: justdoit :: Run IO (Bool, Bool)
+ System.Nix.Store.Remote: runDaemon :: forall m a. (MonadIO m, MonadConc m) => WorkerHelper m -> m a -> m a
+ System.Nix.Store.Remote: runDaemonConnection :: forall m a. (MonadIO m, MonadConc m) => WorkerHelper m -> RemoteStoreT m () -> StoreConnection -> m a -> m a
+ System.Nix.Store.Remote: runRemoteStoreT :: Monad m => Socket -> RemoteStoreT m a -> m (Either RemoteStoreError a, DList Logger)
+ System.Nix.Store.Remote: runStoreConnection :: (MonadIO m, MonadMask m) => StoreConnection -> RemoteStoreT m a -> Run m a
+ System.Nix.Store.Remote: runStoreSocket :: (MonadIO m, MonadMask m) => Family -> SockAddr -> RemoteStoreT m a -> Run m a
+ System.Nix.Store.Remote: setDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => (ByteString -> IO ()) -> m ()
+ System.Nix.Store.Remote: setDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => Word64 -> m ()
+ System.Nix.Store.Remote: setDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => (Word64 -> IO (Maybe ByteString)) -> m ()
+ System.Nix.Store.Remote: setNarSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => NarSource IO -> m ()
+ System.Nix.Store.Remote: setProtoVersion :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => ProtoVersion -> m ()
+ System.Nix.Store.Remote: setStoreDir :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => StoreDir -> m ()
+ System.Nix.Store.Remote: takeDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (Word64 -> IO (Maybe ByteString)))
+ System.Nix.Store.Remote: takeNarSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (NarSource IO))
+ System.Nix.Store.Remote: type MonadStore = RemoteStoreT IO
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (Data.Some.Newtype.Some System.Nix.Store.Remote.Types.StoreRequest.StoreRequest)
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Activity.ActivityID
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.GC.GCOptions
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.GC.GCRoot
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.BasicError
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.ErrorInfo
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.Field
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.Logger
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.LoggerOpCode
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Logger.Trace
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.StoreText.StoreText
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.SuccessCodeReply.SuccessCodeReply
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.WorkerMagic.WorkerMagic
+ System.Nix.Store.Remote.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Client: addIndirectRoot :: MonadRemoteStore m => StorePath -> m ()
+ System.Nix.Store.Remote.Client: addSignatures :: MonadRemoteStore m => StorePath -> Set Signature -> m ()
+ System.Nix.Store.Remote.Client: addTempRoot :: MonadRemoteStore m => StorePath -> m ()
+ System.Nix.Store.Remote.Client: addTextToStore :: MonadRemoteStore m => StoreText -> HashSet StorePath -> RepairMode -> m StorePath
+ System.Nix.Store.Remote.Client: addToStore :: MonadRemoteStore m => StorePathName -> NarSource IO -> FileIngestionMethod -> Some HashAlgo -> RepairMode -> m StorePath
+ System.Nix.Store.Remote.Client: addToStoreNar :: MonadRemoteStore m => StorePath -> Metadata StorePath -> RepairMode -> CheckMode -> (Word64 -> IO (Maybe ByteString)) -> m ()
+ System.Nix.Store.Remote.Client: buildDerivation :: MonadRemoteStore m => StorePath -> BuildMode -> m BuildResult
+ System.Nix.Store.Remote.Client: buildPaths :: MonadRemoteStore m => Set DerivedPath -> BuildMode -> m ()
+ System.Nix.Store.Remote.Client: collectGarbage :: MonadRemoteStore m => GCOptions -> m GCResult
+ System.Nix.Store.Remote.Client: ensurePath :: MonadRemoteStore m => StorePath -> m ()
+ System.Nix.Store.Remote.Client: findRoots :: MonadRemoteStore m => m (Map GCRoot StorePath)
+ System.Nix.Store.Remote.Client: isValidPath :: MonadRemoteStore m => StorePath -> m Bool
+ System.Nix.Store.Remote.Client: narFromPath :: MonadRemoteStore m => StorePath -> Word64 -> (ByteString -> IO ()) -> m ()
+ System.Nix.Store.Remote.Client: optimiseStore :: MonadRemoteStore m => m ()
+ System.Nix.Store.Remote.Client: queryAllValidPaths :: MonadRemoteStore m => m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: queryDerivationOutputNames :: MonadRemoteStore m => StorePath -> m (HashSet StorePathName)
+ System.Nix.Store.Remote.Client: queryDerivationOutputs :: MonadRemoteStore m => StorePath -> m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: queryMissing :: MonadRemoteStore m => Set DerivedPath -> m Missing
+ System.Nix.Store.Remote.Client: queryPathFromHashPart :: MonadRemoteStore m => StorePathHashPart -> m StorePath
+ System.Nix.Store.Remote.Client: queryPathInfo :: MonadRemoteStore m => StorePath -> m (Maybe (Metadata StorePath))
+ System.Nix.Store.Remote.Client: queryReferrers :: MonadRemoteStore m => StorePath -> m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: querySubstitutablePaths :: MonadRemoteStore m => HashSet StorePath -> m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: queryValidDerivers :: MonadRemoteStore m => StorePath -> m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: queryValidPaths :: MonadRemoteStore m => HashSet StorePath -> SubstituteMode -> m (HashSet StorePath)
+ System.Nix.Store.Remote.Client: syncWithGC :: MonadRemoteStore m => m ()
+ System.Nix.Store.Remote.Client: verifyStore :: MonadRemoteStore m => CheckMode -> RepairMode -> m Bool
+ System.Nix.Store.Remote.Client.Core: doReq :: forall m a. (MonadIO m, MonadRemoteStore m, StoreReply a, Show a) => StoreRequest a -> m a
+ System.Nix.Store.Remote.Client.Core: greetServer :: MonadRemoteStore m => m ClientHandshakeOutput
+ System.Nix.Store.Remote.Client.Core: type Run m a = m (Either RemoteStoreError a, DList Logger)
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_BuildFailed :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_ClientVersionTooOld :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_DataSourceExhausted :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_DataSourceReadTooLarge :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_DataSourceZeroLengthRead :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_DerivationParse :: String -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_Disconnected :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_Fixme :: String -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_GenericIncrementalFail :: String -> ByteString -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_GenericIncrementalLeftovers :: String -> ByteString -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_GetAddrInfoFailed :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_IOException :: SomeException -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_LoggerError :: Either BasicError ErrorInfo -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_LoggerLeftovers :: String -> ByteString -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_LoggerParserFail :: String -> ByteString -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_NoDataSinkProvided :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_NoDataSinkSizeProvided :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_NoDataSourceProvided :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_NoNarSourceProvided :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_OperationFailed :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_ProtocolMismatch :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_RapairNotSupportedByRemoteStore :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerGet :: SError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerHandshake :: HandshakeSError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerLogger :: LoggerSError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerPut :: SError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerReply :: ReplySError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_SerializerRequest :: RequestSError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_WorkerError :: WorkerError -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_WorkerException :: WorkerException -> RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreError_WorkerMagic2Mismatch :: RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: RemoteStoreState :: ProtoStoreConfig -> DList Logger -> Maybe (Word64 -> IO (Maybe ByteString)) -> Maybe (ByteString -> IO ()) -> Maybe Word64 -> Maybe (NarSource IO) -> RemoteStoreState
+ System.Nix.Store.Remote.MonadStore: WorkerError_InvalidOperation :: Word64 -> WorkerError
+ System.Nix.Store.Remote.MonadStore: WorkerError_NotYetImplemented :: WorkerError
+ System.Nix.Store.Remote.MonadStore: WorkerError_SendClosed :: WorkerError
+ System.Nix.Store.Remote.MonadStore: WorkerError_UnsupportedOperation :: WorkerError
+ System.Nix.Store.Remote.MonadStore: WorkerException_ClientVersionTooOld :: WorkerException
+ System.Nix.Store.Remote.MonadStore: WorkerException_Error :: WorkerError -> WorkerException
+ System.Nix.Store.Remote.MonadStore: WorkerException_ProtocolMismatch :: WorkerException
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateConfig] :: RemoteStoreState -> ProtoStoreConfig
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateLogs] :: RemoteStoreState -> DList Logger
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateMDataSinkSize] :: RemoteStoreState -> Maybe Word64
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateMDataSink] :: RemoteStoreState -> Maybe (ByteString -> IO ())
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateMDataSource] :: RemoteStoreState -> Maybe (Word64 -> IO (Maybe ByteString))
+ System.Nix.Store.Remote.MonadStore: [remoteStoreStateMNarSource] :: RemoteStoreState -> Maybe (NarSource IO)
+ System.Nix.Store.Remote.MonadStore: appendLog :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => Logger -> m ()
+ System.Nix.Store.Remote.MonadStore: class (MonadIO m, MonadError RemoteStoreError m) => MonadRemoteStore m
+ System.Nix.Store.Remote.MonadStore: clearDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote.MonadStore: clearDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote.MonadStore: clearDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ()
+ System.Nix.Store.Remote.MonadStore: data RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: data RemoteStoreState
+ System.Nix.Store.Remote.MonadStore: data RemoteStoreT m a
+ System.Nix.Store.Remote.MonadStore: data WorkerError
+ System.Nix.Store.Remote.MonadStore: data WorkerException
+ System.Nix.Store.Remote.MonadStore: getConfig :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ProtoStoreConfig
+ System.Nix.Store.Remote.MonadStore: getDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (ByteString -> IO ()))
+ System.Nix.Store.Remote.MonadStore: getDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe Word64)
+ System.Nix.Store.Remote.MonadStore: getDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (Word64 -> IO (Maybe ByteString)))
+ System.Nix.Store.Remote.MonadStore: getProtoVersion :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m ProtoVersion
+ System.Nix.Store.Remote.MonadStore: getStoreDir :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m StoreDir
+ System.Nix.Store.Remote.MonadStore: getStoreSocket :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m Socket
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.IO.Class.MonadIO m => System.Nix.Store.Remote.MonadStore.MonadRemoteStore (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance Control.Monad.Trans.Class.MonadTrans System.Nix.Store.Remote.MonadStore.RemoteStoreT
+ System.Nix.Store.Remote.MonadStore: instance GHC.Base.Functor m => GHC.Base.Functor (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance GHC.Base.Monad m => Control.Monad.Error.Class.MonadError System.Nix.Store.Remote.MonadStore.RemoteStoreError (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader Network.Socket.Types.Socket (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance GHC.Base.Monad m => GHC.Base.Applicative (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance GHC.Base.Monad m => GHC.Base.Monad (System.Nix.Store.Remote.MonadStore.RemoteStoreT m)
+ System.Nix.Store.Remote.MonadStore: instance GHC.Classes.Eq System.Nix.Store.Remote.MonadStore.WorkerError
+ System.Nix.Store.Remote.MonadStore: instance GHC.Classes.Eq System.Nix.Store.Remote.MonadStore.WorkerException
+ System.Nix.Store.Remote.MonadStore: instance GHC.Classes.Ord System.Nix.Store.Remote.MonadStore.WorkerError
+ System.Nix.Store.Remote.MonadStore: instance GHC.Classes.Ord System.Nix.Store.Remote.MonadStore.WorkerException
+ System.Nix.Store.Remote.MonadStore: instance GHC.Show.Show System.Nix.Store.Remote.MonadStore.RemoteStoreError
+ System.Nix.Store.Remote.MonadStore: instance GHC.Show.Show System.Nix.Store.Remote.MonadStore.WorkerError
+ System.Nix.Store.Remote.MonadStore: instance GHC.Show.Show System.Nix.Store.Remote.MonadStore.WorkerException
+ System.Nix.Store.Remote.MonadStore: instance System.Nix.Store.Remote.MonadStore.MonadRemoteStore m => System.Nix.Store.Remote.MonadStore.MonadRemoteStore (Control.Monad.Trans.Except.ExceptT System.Nix.Store.Remote.MonadStore.RemoteStoreError m)
+ System.Nix.Store.Remote.MonadStore: instance System.Nix.Store.Remote.MonadStore.MonadRemoteStore m => System.Nix.Store.Remote.MonadStore.MonadRemoteStore (Control.Monad.Trans.Reader.ReaderT r m)
+ System.Nix.Store.Remote.MonadStore: instance System.Nix.Store.Remote.MonadStore.MonadRemoteStore m => System.Nix.Store.Remote.MonadStore.MonadRemoteStore (Control.Monad.Trans.State.Strict.StateT s m)
+ System.Nix.Store.Remote.MonadStore: instance System.Nix.Store.Remote.Types.ProtoVersion.HasProtoVersion System.Nix.Store.Remote.MonadStore.RemoteStoreState
+ System.Nix.Store.Remote.MonadStore: instance System.Nix.StorePath.HasStoreDir System.Nix.Store.Remote.MonadStore.RemoteStoreState
+ System.Nix.Store.Remote.MonadStore: runRemoteStoreT :: Monad m => Socket -> RemoteStoreT m a -> m (Either RemoteStoreError a, DList Logger)
+ System.Nix.Store.Remote.MonadStore: setDataSink :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => (ByteString -> IO ()) -> m ()
+ System.Nix.Store.Remote.MonadStore: setDataSinkSize :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => Word64 -> m ()
+ System.Nix.Store.Remote.MonadStore: setDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => (Word64 -> IO (Maybe ByteString)) -> m ()
+ System.Nix.Store.Remote.MonadStore: setNarSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => NarSource IO -> m ()
+ System.Nix.Store.Remote.MonadStore: setProtoVersion :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => ProtoVersion -> m ()
+ System.Nix.Store.Remote.MonadStore: setStoreDir :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => StoreDir -> m ()
+ System.Nix.Store.Remote.MonadStore: takeDataSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (Word64 -> IO (Maybe ByteString)))
+ System.Nix.Store.Remote.MonadStore: takeNarSource :: (MonadRemoteStore m, MonadTrans t, MonadRemoteStore m', m ~ t m') => m (Maybe (NarSource IO))
+ System.Nix.Store.Remote.Serializer: HandshakeSError_InvalidTrustedFlag :: Word8 -> HandshakeSError
+ System.Nix.Store.Remote.Serializer: HandshakeSError_InvalidWorkerMagic :: Word64 -> HandshakeSError
+ System.Nix.Store.Remote.Serializer: LoggerSError_InvalidOpCode :: Word64 -> LoggerSError
+ System.Nix.Store.Remote.Serializer: LoggerSError_Prim :: SError -> LoggerSError
+ System.Nix.Store.Remote.Serializer: LoggerSError_TooNewForBasicError :: LoggerSError
+ System.Nix.Store.Remote.Serializer: LoggerSError_TooOldForErrorInfo :: LoggerSError
+ System.Nix.Store.Remote.Serializer: LoggerSError_UnknownLogFieldType :: Word8 -> LoggerSError
+ System.Nix.Store.Remote.Serializer: ReplySError_DerivationOutput :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_GCResult :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_Metadata :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_Missing :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_PrimGet :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_PrimPut :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_Realisation :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_RealisationWithId :: SError -> ReplySError
+ System.Nix.Store.Remote.Serializer: ReplySError_UnexpectedFalseOpSuccess :: ReplySError
+ System.Nix.Store.Remote.Serializer: RequestSError_NotYetImplemented :: WorkerOp -> RequestSError
+ System.Nix.Store.Remote.Serializer: RequestSError_PrimGet :: SError -> RequestSError
+ System.Nix.Store.Remote.Serializer: RequestSError_PrimPut :: SError -> RequestSError
+ System.Nix.Store.Remote.Serializer: RequestSError_PrimWorkerOp :: SError -> RequestSError
+ System.Nix.Store.Remote.Serializer: RequestSError_ReservedOp :: WorkerOp -> RequestSError
+ System.Nix.Store.Remote.Serializer: SError :: SError
+ System.Nix.Store.Remote.Serializer: SError_BadPadding :: ByteString -> Int -> [Word8] -> SError
+ System.Nix.Store.Remote.Serializer: SError_ContentAddress :: String -> SError
+ System.Nix.Store.Remote.Serializer: SError_DerivationOutput :: DerivationOutputError -> SError
+ System.Nix.Store.Remote.Serializer: SError_DerivedPath :: ParseOutputsError -> SError
+ System.Nix.Store.Remote.Serializer: SError_Digest :: String -> SError
+ System.Nix.Store.Remote.Serializer: SError_EnumOutOfMaxBound :: Int -> SError
+ System.Nix.Store.Remote.Serializer: SError_EnumOutOfMinBound :: Int -> SError
+ System.Nix.Store.Remote.Serializer: SError_HashAlgo :: String -> SError
+ System.Nix.Store.Remote.Serializer: SError_IllegalBool :: Word64 -> SError
+ System.Nix.Store.Remote.Serializer: SError_InvalidNixBase32 :: SError
+ System.Nix.Store.Remote.Serializer: SError_JSONDecoding :: String -> SError
+ System.Nix.Store.Remote.Serializer: SError_Name :: InvalidNameError -> SError
+ System.Nix.Store.Remote.Serializer: SError_NarHashMustBeSHA256 :: SError
+ System.Nix.Store.Remote.Serializer: SError_NotYetImplemented :: String -> ForPV ProtoVersion -> SError
+ System.Nix.Store.Remote.Serializer: SError_Path :: InvalidPathError -> SError
+ System.Nix.Store.Remote.Serializer: SError_Signature :: String -> SError
+ System.Nix.Store.Remote.Serializer: [badPaddingLen] :: SError -> Int
+ System.Nix.Store.Remote.Serializer: [badPaddingPads] :: SError -> [Word8]
+ System.Nix.Store.Remote.Serializer: [badPaddingStr] :: SError -> ByteString
+ System.Nix.Store.Remote.Serializer: activity :: NixSerializer r LoggerSError Activity
+ System.Nix.Store.Remote.Serializer: activityID :: NixSerializer r LoggerSError ActivityID
+ System.Nix.Store.Remote.Serializer: activityResult :: NixSerializer r LoggerSError ActivityResult
+ System.Nix.Store.Remote.Serializer: basicError :: NixSerializer r LoggerSError BasicError
+ System.Nix.Store.Remote.Serializer: bool :: NixSerializer r SError Bool
+ System.Nix.Store.Remote.Serializer: buildMode :: NixSerializer r SError BuildMode
+ System.Nix.Store.Remote.Serializer: buildResult :: (HasProtoVersion r, HasStoreDir r) => NixSerializer r ReplySError BuildResult
+ System.Nix.Store.Remote.Serializer: byteString :: NixSerializer r SError ByteString
+ System.Nix.Store.Remote.Serializer: data HandshakeSError
+ System.Nix.Store.Remote.Serializer: data LoggerSError
+ System.Nix.Store.Remote.Serializer: data ReplySError
+ System.Nix.Store.Remote.Serializer: data RequestSError
+ System.Nix.Store.Remote.Serializer: data SError
+ System.Nix.Store.Remote.Serializer: derivation :: HasStoreDir r => NixSerializer r SError (Derivation StorePath Text)
+ System.Nix.Store.Remote.Serializer: derivationOutputTyped :: NixSerializer r ReplySError (DerivationOutput OutputName)
+ System.Nix.Store.Remote.Serializer: derivedPath :: (HasProtoVersion r, HasStoreDir r) => NixSerializer r SError DerivedPath
+ System.Nix.Store.Remote.Serializer: digest :: forall a r. HashAlgorithm a => BaseEncoding -> NixSerializer r SError (Digest a)
+ System.Nix.Store.Remote.Serializer: enum :: (Bounded a, Enum a) => NixSerializer r SError a
+ System.Nix.Store.Remote.Serializer: errorInfo :: NixSerializer r LoggerSError ErrorInfo
+ System.Nix.Store.Remote.Serializer: field :: NixSerializer r LoggerSError Field
+ System.Nix.Store.Remote.Serializer: gcResult :: HasStoreDir r => NixSerializer r ReplySError GCResult
+ System.Nix.Store.Remote.Serializer: gcRoot :: NixSerializer r ReplySError GCRoot
+ System.Nix.Store.Remote.Serializer: hashSet :: (Eq a, Hashable a) => NixSerializer r e a -> NixSerializer r e (HashSet a)
+ System.Nix.Store.Remote.Serializer: instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance Control.Monad.Trans.Class.MonadTrans (System.Nix.Store.Remote.Serializer.SerialT r e)
+ System.Nix.Store.Remote.Serializer: instance GHC.Base.Functor m => GHC.Base.Functor (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance GHC.Base.Monad m => Control.Monad.Error.Class.MonadError e (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader r (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance GHC.Base.Monad m => GHC.Base.Applicative (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance GHC.Base.Monad m => GHC.Base.Monad (System.Nix.Store.Remote.Serializer.SerialT r e m)
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq System.Nix.Store.Remote.Serializer.HandshakeSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq System.Nix.Store.Remote.Serializer.LoggerSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq System.Nix.Store.Remote.Serializer.ReplySError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq System.Nix.Store.Remote.Serializer.RequestSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq System.Nix.Store.Remote.Serializer.SError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Eq a => GHC.Classes.Eq (System.Nix.Store.Remote.Serializer.ForPV a)
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord System.Nix.Store.Remote.Serializer.HandshakeSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord System.Nix.Store.Remote.Serializer.LoggerSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord System.Nix.Store.Remote.Serializer.ReplySError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord System.Nix.Store.Remote.Serializer.RequestSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord System.Nix.Store.Remote.Serializer.SError
+ System.Nix.Store.Remote.Serializer: instance GHC.Classes.Ord a => GHC.Classes.Ord (System.Nix.Store.Remote.Serializer.ForPV a)
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic (System.Nix.Store.Remote.Serializer.ForPV a)
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic System.Nix.Store.Remote.Serializer.HandshakeSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic System.Nix.Store.Remote.Serializer.LoggerSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic System.Nix.Store.Remote.Serializer.ReplySError
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic System.Nix.Store.Remote.Serializer.RequestSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Generics.Generic System.Nix.Store.Remote.Serializer.SError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show System.Nix.Store.Remote.Serializer.HandshakeSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show System.Nix.Store.Remote.Serializer.LoggerSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show System.Nix.Store.Remote.Serializer.ReplySError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show System.Nix.Store.Remote.Serializer.RequestSError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show System.Nix.Store.Remote.Serializer.SError
+ System.Nix.Store.Remote.Serializer: instance GHC.Show.Show a => GHC.Show.Show (System.Nix.Store.Remote.Serializer.ForPV a)
+ System.Nix.Store.Remote.Serializer: int :: Integral a => NixSerializer r e a
+ System.Nix.Store.Remote.Serializer: json :: (FromJSON a, ToJSON a) => NixSerializer r SError a
+ System.Nix.Store.Remote.Serializer: list :: NixSerializer r e a -> NixSerializer r e [a]
+ System.Nix.Store.Remote.Serializer: logger :: HasProtoVersion r => NixSerializer r LoggerSError Logger
+ System.Nix.Store.Remote.Serializer: loggerOpCode :: NixSerializer r LoggerSError LoggerOpCode
+ System.Nix.Store.Remote.Serializer: mapErrorS :: (e -> e') -> NixSerializer r e a -> NixSerializer r e' a
+ System.Nix.Store.Remote.Serializer: mapReaderS :: (r' -> r) -> NixSerializer r e a -> NixSerializer r' e a
+ System.Nix.Store.Remote.Serializer: mapS :: Ord k => NixSerializer r e k -> NixSerializer r e v -> NixSerializer r e (Map k v)
+ System.Nix.Store.Remote.Serializer: maybeActivity :: NixSerializer r LoggerSError (Maybe Activity)
+ System.Nix.Store.Remote.Serializer: maybePath :: HasStoreDir r => NixSerializer r SError (Maybe StorePath)
+ System.Nix.Store.Remote.Serializer: maybePathMetadata :: HasStoreDir r => NixSerializer r ReplySError (Maybe (Metadata StorePath))
+ System.Nix.Store.Remote.Serializer: maybeText :: NixSerializer r SError (Maybe Text)
+ System.Nix.Store.Remote.Serializer: missing :: HasStoreDir r => NixSerializer r ReplySError Missing
+ System.Nix.Store.Remote.Serializer: namedDigest :: NixSerializer r SError (DSum HashAlgo Digest)
+ System.Nix.Store.Remote.Serializer: narSignature :: NixSerializer r SError NarSignature
+ System.Nix.Store.Remote.Serializer: noop :: a -> NixSerializer r ReplySError a
+ System.Nix.Store.Remote.Serializer: opSuccess :: NixSerializer r ReplySError SuccessCodeReply
+ System.Nix.Store.Remote.Serializer: outputName :: NixSerializer r SError OutputName
+ System.Nix.Store.Remote.Serializer: pathMetadata :: HasStoreDir r => NixSerializer r SError (Metadata StorePath)
+ System.Nix.Store.Remote.Serializer: protoVersion :: NixSerializer r e ProtoVersion
+ System.Nix.Store.Remote.Serializer: realisation :: NixSerializer r ReplySError Realisation
+ System.Nix.Store.Remote.Serializer: realisationWithId :: NixSerializer r ReplySError RealisationWithId
+ System.Nix.Store.Remote.Serializer: runG :: NixSerializer r e a -> r -> ByteString -> Either (GetSerializerError e) a
+ System.Nix.Store.Remote.Serializer: runP :: NixSerializer r e a -> r -> a -> Either e ByteString
+ System.Nix.Store.Remote.Serializer: runSerialT :: Monad m => r -> SerialT r e m a -> m (Either e a)
+ System.Nix.Store.Remote.Serializer: set :: Ord a => NixSerializer r e a -> NixSerializer r e (Set a)
+ System.Nix.Store.Remote.Serializer: signature :: NixSerializer r SError Signature
+ System.Nix.Store.Remote.Serializer: someHashAlgo :: NixSerializer r SError (Some HashAlgo)
+ System.Nix.Store.Remote.Serializer: storePath :: HasStoreDir r => NixSerializer r SError StorePath
+ System.Nix.Store.Remote.Serializer: storePathHashPart :: NixSerializer r SError StorePathHashPart
+ System.Nix.Store.Remote.Serializer: storePathName :: NixSerializer r SError StorePathName
+ System.Nix.Store.Remote.Serializer: storeRequest :: (HasProtoVersion r, HasStoreDir r) => NixSerializer r RequestSError (Some StoreRequest)
+ System.Nix.Store.Remote.Serializer: storeText :: NixSerializer r SError StoreText
+ System.Nix.Store.Remote.Serializer: text :: NixSerializer r SError Text
+ System.Nix.Store.Remote.Serializer: time :: NixSerializer r e UTCTime
+ System.Nix.Store.Remote.Serializer: trace :: NixSerializer r LoggerSError Trace
+ System.Nix.Store.Remote.Serializer: trustedFlag :: NixSerializer r HandshakeSError (Maybe TrustedFlag)
+ System.Nix.Store.Remote.Serializer: type NixSerializer r e = Serializer (SerialT r e)
+ System.Nix.Store.Remote.Serializer: vector :: Ord a => NixSerializer r e a -> NixSerializer r e (Vector a)
+ System.Nix.Store.Remote.Serializer: verbosity :: NixSerializer r LoggerSError Verbosity
+ System.Nix.Store.Remote.Serializer: workerMagic :: NixSerializer r HandshakeSError WorkerMagic
+ System.Nix.Store.Remote.Serializer: workerOp :: NixSerializer r SError WorkerOp
+ System.Nix.Store.Remote.Server: runProxyDaemon :: forall m a. (MonadIO m, MonadConc m) => WorkerHelper m -> RemoteStoreT m () -> Socket -> m a -> m a
+ System.Nix.Store.Remote.Server: type WorkerHelper m = forall a. (Show a, StoreReply a) => RemoteStoreT m a -> Run m a
+ System.Nix.Store.Remote.Socket: genericIncremental :: (MonadIO m, MonadError RemoteStoreError m, Show a) => m ByteString -> Get a -> m a
+ System.Nix.Store.Remote.Socket: sockGet8 :: MonadRemoteStore m => m ByteString
+ System.Nix.Store.Remote.Socket: sockGetS :: (MonadRemoteStore m, MonadError e m, Show a, Show e) => NixSerializer ProtoStoreConfig e a -> m a
+ System.Nix.Store.Remote.Socket: sockPut :: MonadRemoteStore m => Put -> m ()
+ System.Nix.Store.Remote.Socket: sockPutS :: (MonadRemoteStore m, MonadError e m) => NixSerializer ProtoStoreConfig e a -> a -> m ()
+ System.Nix.Store.Remote.Types.Activity: ActivityID :: Int -> ActivityID
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_BuildLogLine :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_CorruptedPath :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_FileLinked :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_PostBuildLogLine :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_Progress :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_SetExpected :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_SetPhase :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: ActivityResult_UnstrustedPath :: ActivityResult
+ System.Nix.Store.Remote.Types.Activity: Activity_Build :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_BuildWaiting :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_Builds :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_CopyPath :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_CopyPaths :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_FileTransfer :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_OptimiseStore :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_PostBuildHook :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_QueryPathInfo :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_Realise :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_Substitute :: Activity
+ System.Nix.Store.Remote.Types.Activity: Activity_VerifyPaths :: Activity
+ System.Nix.Store.Remote.Types.Activity: [unActivityID] :: ActivityID -> Int
+ System.Nix.Store.Remote.Types.Activity: data Activity
+ System.Nix.Store.Remote.Types.Activity: data ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Activity.ActivityID
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Activity.ActivityID
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Activity.ActivityID
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Show.Show System.Nix.Store.Remote.Types.Activity.Activity
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Show.Show System.Nix.Store.Remote.Types.Activity.ActivityID
+ System.Nix.Store.Remote.Types.Activity: instance GHC.Show.Show System.Nix.Store.Remote.Types.Activity.ActivityResult
+ System.Nix.Store.Remote.Types.Activity: newtype ActivityID
+ System.Nix.Store.Remote.Types.CheckMode: CheckMode_DoCheck :: CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: CheckMode_DontCheck :: CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: data CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.CheckMode: instance GHC.Show.Show System.Nix.Store.Remote.Types.CheckMode.CheckMode
+ System.Nix.Store.Remote.Types.GC: GCAction_DeleteDead :: GCAction
+ System.Nix.Store.Remote.Types.GC: GCAction_DeleteSpecific :: GCAction
+ System.Nix.Store.Remote.Types.GC: GCAction_ReturnDead :: GCAction
+ System.Nix.Store.Remote.Types.GC: GCAction_ReturnLive :: GCAction
+ System.Nix.Store.Remote.Types.GC: GCOptions :: GCAction -> Bool -> HashSet StorePath -> Word64 -> GCOptions
+ System.Nix.Store.Remote.Types.GC: GCResult :: HashSet StorePath -> Word64 -> GCResult
+ System.Nix.Store.Remote.Types.GC: GCRoot_Censored :: GCRoot
+ System.Nix.Store.Remote.Types.GC: GCRoot_Path :: RawFilePath -> GCRoot
+ System.Nix.Store.Remote.Types.GC: [gcOptionsIgnoreLiveness] :: GCOptions -> Bool
+ System.Nix.Store.Remote.Types.GC: [gcOptionsMaxFreed] :: GCOptions -> Word64
+ System.Nix.Store.Remote.Types.GC: [gcOptionsOperation] :: GCOptions -> GCAction
+ System.Nix.Store.Remote.Types.GC: [gcOptionsPathsToDelete] :: GCOptions -> HashSet StorePath
+ System.Nix.Store.Remote.Types.GC: [gcResultBytesFreed] :: GCResult -> Word64
+ System.Nix.Store.Remote.Types.GC: [gcResultDeletedPaths] :: GCResult -> HashSet StorePath
+ System.Nix.Store.Remote.Types.GC: data GCAction
+ System.Nix.Store.Remote.Types.GC: data GCOptions
+ System.Nix.Store.Remote.Types.GC: data GCResult
+ System.Nix.Store.Remote.Types.GC: data GCRoot
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.GC.GCOptions
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.GC.GCRoot
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.GC.GCOptions
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Types.GC: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.GC.GCRoot
+ System.Nix.Store.Remote.Types.GC: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.GC.GCOptions
+ System.Nix.Store.Remote.Types.GC: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Types.GC: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.GC.GCRoot
+ System.Nix.Store.Remote.Types.GC: instance GHC.Show.Show System.Nix.Store.Remote.Types.GC.GCAction
+ System.Nix.Store.Remote.Types.GC: instance GHC.Show.Show System.Nix.Store.Remote.Types.GC.GCOptions
+ System.Nix.Store.Remote.Types.GC: instance GHC.Show.Show System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Types.GC: instance GHC.Show.Show System.Nix.Store.Remote.Types.GC.GCRoot
+ System.Nix.Store.Remote.Types.Handshake: ClientHandshakeInput :: ProtoVersion -> ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: ClientHandshakeOutput :: Maybe Text -> Maybe TrustedFlag -> ProtoVersion -> ProtoVersion -> ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: ServerHandshakeInput :: Text -> ProtoVersion -> Maybe TrustedFlag -> ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: ServerHandshakeOutput :: ProtoVersion -> ProtoVersion -> ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: [clientHandshakeInputOurVersion] :: ClientHandshakeInput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: [clientHandshakeOutputLeastCommonVersion] :: ClientHandshakeOutput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: [clientHandshakeOutputNixVersion] :: ClientHandshakeOutput -> Maybe Text
+ System.Nix.Store.Remote.Types.Handshake: [clientHandshakeOutputServerVersion] :: ClientHandshakeOutput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: [clientHandshakeOutputTrust] :: ClientHandshakeOutput -> Maybe TrustedFlag
+ System.Nix.Store.Remote.Types.Handshake: [serverHandshakeInputNixVersion] :: ServerHandshakeInput -> Text
+ System.Nix.Store.Remote.Types.Handshake: [serverHandshakeInputOurVersion] :: ServerHandshakeInput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: [serverHandshakeInputTrust] :: ServerHandshakeInput -> Maybe TrustedFlag
+ System.Nix.Store.Remote.Types.Handshake: [serverHandshakeOutputClientVersion] :: ServerHandshakeOutput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: [serverHandshakeOutputLeastCommonVersion] :: ServerHandshakeOutput -> ProtoVersion
+ System.Nix.Store.Remote.Types.Handshake: data ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: data ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: data ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: data ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Handshake.ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Handshake.ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Handshake.ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Handshake.ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Handshake.ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Handshake.ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Handshake.ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Handshake.ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Handshake.ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Handshake.ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Handshake.ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Handshake.ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Show.Show System.Nix.Store.Remote.Types.Handshake.ClientHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Show.Show System.Nix.Store.Remote.Types.Handshake.ClientHandshakeOutput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Show.Show System.Nix.Store.Remote.Types.Handshake.ServerHandshakeInput
+ System.Nix.Store.Remote.Types.Handshake: instance GHC.Show.Show System.Nix.Store.Remote.Types.Handshake.ServerHandshakeOutput
+ System.Nix.Store.Remote.Types.Logger: BasicError :: Int -> Text -> BasicError
+ System.Nix.Store.Remote.Types.Logger: ErrorInfo :: Verbosity -> Text -> Maybe Int -> [Trace] -> ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: Field_LogInt :: Int -> Field
+ System.Nix.Store.Remote.Types.Logger: Field_LogStr :: Text -> Field
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Error :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Last :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Next :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Read :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Result :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_StartActivity :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_StopActivity :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: LoggerOpCode_Write :: LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: Logger_Error :: Either BasicError ErrorInfo -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_Last :: Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_Next :: Text -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_Read :: Word64 -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_Result :: ActivityID -> ActivityResult -> [Field] -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_StartActivity :: ActivityID -> Verbosity -> Maybe Activity -> ByteString -> [Field] -> ActivityID -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_StopActivity :: ActivityID -> Logger
+ System.Nix.Store.Remote.Types.Logger: Logger_Write :: ByteString -> Logger
+ System.Nix.Store.Remote.Types.Logger: Trace :: Maybe Int -> Text -> Trace
+ System.Nix.Store.Remote.Types.Logger: [basicErrorExitStatus] :: BasicError -> Int
+ System.Nix.Store.Remote.Types.Logger: [basicErrorMessage] :: BasicError -> Text
+ System.Nix.Store.Remote.Types.Logger: [errorInfoLevel] :: ErrorInfo -> Verbosity
+ System.Nix.Store.Remote.Types.Logger: [errorInfoMessage] :: ErrorInfo -> Text
+ System.Nix.Store.Remote.Types.Logger: [errorInfoPosition] :: ErrorInfo -> Maybe Int
+ System.Nix.Store.Remote.Types.Logger: [errorInfoTraces] :: ErrorInfo -> [Trace]
+ System.Nix.Store.Remote.Types.Logger: [resultActivityID] :: Logger -> ActivityID
+ System.Nix.Store.Remote.Types.Logger: [resultFields] :: Logger -> [Field]
+ System.Nix.Store.Remote.Types.Logger: [resultType] :: Logger -> ActivityResult
+ System.Nix.Store.Remote.Types.Logger: [startActivityFields] :: Logger -> [Field]
+ System.Nix.Store.Remote.Types.Logger: [startActivityID] :: Logger -> ActivityID
+ System.Nix.Store.Remote.Types.Logger: [startActivityParentID] :: Logger -> ActivityID
+ System.Nix.Store.Remote.Types.Logger: [startActivityString] :: Logger -> ByteString
+ System.Nix.Store.Remote.Types.Logger: [startActivityType] :: Logger -> Maybe Activity
+ System.Nix.Store.Remote.Types.Logger: [startActivityVerbosity] :: Logger -> Verbosity
+ System.Nix.Store.Remote.Types.Logger: [stopActivityID] :: Logger -> ActivityID
+ System.Nix.Store.Remote.Types.Logger: [traceHint] :: Trace -> Text
+ System.Nix.Store.Remote.Types.Logger: [tracePosition] :: Trace -> Maybe Int
+ System.Nix.Store.Remote.Types.Logger: data BasicError
+ System.Nix.Store.Remote.Types.Logger: data ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: data Field
+ System.Nix.Store.Remote.Types.Logger: data Logger
+ System.Nix.Store.Remote.Types.Logger: data LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: data Trace
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.BasicError
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.Field
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.Logger
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Logger.Trace
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.BasicError
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.Field
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.Logger
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Logger.Trace
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.BasicError
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.Field
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.Logger
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Logger.Trace
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.BasicError
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.ErrorInfo
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.Field
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.Logger
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.LoggerOpCode
+ System.Nix.Store.Remote.Types.Logger: instance GHC.Show.Show System.Nix.Store.Remote.Types.Logger.Trace
+ System.Nix.Store.Remote.Types.Logger: isError :: Logger -> Bool
+ System.Nix.Store.Remote.Types.Logger: loggerOpCodeToWord64 :: LoggerOpCode -> Word64
+ System.Nix.Store.Remote.Types.Logger: word64ToLoggerOpCode :: Word64 -> Either String LoggerOpCode
+ System.Nix.Store.Remote.Types.NoReply: NoReply :: NoReply
+ System.Nix.Store.Remote.Types.NoReply: data NoReply
+ System.Nix.Store.Remote.Types.NoReply: instance GHC.Show.Show System.Nix.Store.Remote.Types.NoReply.NoReply
+ System.Nix.Store.Remote.Types.ProtoVersion: ProtoVersion :: Word16 -> Word8 -> ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: [protoVersion_major] :: ProtoVersion -> Word16
+ System.Nix.Store.Remote.Types.ProtoVersion: [protoVersion_minor] :: ProtoVersion -> Word8
+ System.Nix.Store.Remote.Types.ProtoVersion: class HasProtoVersion r
+ System.Nix.Store.Remote.Types.ProtoVersion: data ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: hasProtoVersion :: HasProtoVersion r => r -> ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance Data.Default.Class.Default System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance GHC.Show.Show System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.ProtoVersion: instance System.Nix.Store.Remote.Types.ProtoVersion.HasProtoVersion System.Nix.Store.Remote.Types.ProtoVersion.ProtoVersion
+ System.Nix.Store.Remote.Types.Query.Missing: Missing :: HashSet StorePath -> HashSet StorePath -> HashSet StorePath -> Word64 -> Word64 -> Missing
+ System.Nix.Store.Remote.Types.Query.Missing: [missingDownloadSize] :: Missing -> Word64
+ System.Nix.Store.Remote.Types.Query.Missing: [missingNarSize] :: Missing -> Word64
+ System.Nix.Store.Remote.Types.Query.Missing: [missingUnknownPaths] :: Missing -> HashSet StorePath
+ System.Nix.Store.Remote.Types.Query.Missing: [missingWillBuild] :: Missing -> HashSet StorePath
+ System.Nix.Store.Remote.Types.Query.Missing: [missingWillSubstitute] :: Missing -> HashSet StorePath
+ System.Nix.Store.Remote.Types.Query.Missing: data Missing
+ System.Nix.Store.Remote.Types.Query.Missing: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Types.Query.Missing: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Types.Query.Missing: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Types.Query.Missing: instance GHC.Show.Show System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Types.StoreConfig: ProtoStoreConfig :: StoreDir -> ProtoVersion -> ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: StoreConnection_Socket :: StoreSocketPath -> StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: StoreConnection_TCP :: StoreTCP -> StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: StoreSocketPath :: FilePath -> StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: StoreTCP :: String -> Int -> StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: [protoStoreConfigDir] :: ProtoStoreConfig -> StoreDir
+ System.Nix.Store.Remote.Types.StoreConfig: [protoStoreConfigProtoVersion] :: ProtoStoreConfig -> ProtoVersion
+ System.Nix.Store.Remote.Types.StoreConfig: [storeTCPHost] :: StoreTCP -> String
+ System.Nix.Store.Remote.Types.StoreConfig: [storeTCPPort] :: StoreTCP -> Int
+ System.Nix.Store.Remote.Types.StoreConfig: [unStoreSocketPath] :: StoreSocketPath -> FilePath
+ System.Nix.Store.Remote.Types.StoreConfig: class HasStoreSocket r
+ System.Nix.Store.Remote.Types.StoreConfig: data ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: data StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: data StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: hasStoreSocket :: HasStoreSocket r => r -> Socket
+ System.Nix.Store.Remote.Types.StoreConfig: instance Data.Default.Class.Default System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance Data.Default.Class.Default System.Nix.Store.Remote.Types.StoreConfig.StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: instance Data.Default.Class.Default System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance Data.String.IsString System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.StoreConfig.StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.StoreConfig.StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.StoreConfig.StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.StoreConfig.StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.StoreConfig.StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.StoreConfig.StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Show.Show System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Show.Show System.Nix.Store.Remote.Types.StoreConfig.StoreConnection
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Show.Show System.Nix.Store.Remote.Types.StoreConfig.StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreConfig: instance GHC.Show.Show System.Nix.Store.Remote.Types.StoreConfig.StoreTCP
+ System.Nix.Store.Remote.Types.StoreConfig: instance System.Nix.Store.Remote.Types.ProtoVersion.HasProtoVersion System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance System.Nix.Store.Remote.Types.StoreConfig.HasStoreSocket Network.Socket.Types.Socket
+ System.Nix.Store.Remote.Types.StoreConfig: instance System.Nix.StorePath.HasStoreDir System.Nix.Store.Remote.Types.StoreConfig.ProtoStoreConfig
+ System.Nix.Store.Remote.Types.StoreConfig: instance System.Nix.StorePath.HasStoreDir System.Nix.StorePath.StoreDir
+ System.Nix.Store.Remote.Types.StoreConfig: newtype StoreSocketPath
+ System.Nix.Store.Remote.Types.StoreReply: class StoreReply a
+ System.Nix.Store.Remote.Types.StoreReply: getReplyS :: StoreReply a => NixSerializer ProtoStoreConfig ReplySError a
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply (Data.HashSet.Internal.HashSet System.Nix.StorePath.StorePath)
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply (Data.HashSet.Internal.HashSet System.Nix.StorePath.StorePathName)
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply (Data.Map.Internal.Map System.Nix.Store.Remote.Types.GC.GCRoot System.Nix.StorePath.StorePath)
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply (GHC.Maybe.Maybe (System.Nix.StorePath.Metadata.Metadata System.Nix.StorePath.StorePath))
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply GHC.Types.Bool
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.Build.BuildResult
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.Store.Remote.Types.GC.GCResult
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.Store.Remote.Types.NoReply.NoReply
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.Store.Remote.Types.Query.Missing.Missing
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.Store.Remote.Types.SuccessCodeReply.SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreReply: instance System.Nix.Store.Remote.Types.StoreReply.StoreReply System.Nix.StorePath.StorePath
+ System.Nix.Store.Remote.Types.StoreRequest: [AddIndirectRoot] :: StorePath -> StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [AddSignatures] :: StorePath -> Set Signature -> StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [AddTempRoot] :: StorePath -> StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [AddTextToStore] :: StoreText -> HashSet StorePath -> RepairMode -> StoreRequest StorePath
+ System.Nix.Store.Remote.Types.StoreRequest: [AddToStoreNar] :: StorePath -> Metadata StorePath -> RepairMode -> CheckMode -> StoreRequest NoReply
+ System.Nix.Store.Remote.Types.StoreRequest: [AddToStore] :: StorePathName -> FileIngestionMethod -> Some HashAlgo -> RepairMode -> StoreRequest StorePath
+ System.Nix.Store.Remote.Types.StoreRequest: [BuildDerivation] :: StorePath -> Derivation StorePath Text -> BuildMode -> StoreRequest BuildResult
+ System.Nix.Store.Remote.Types.StoreRequest: [BuildPaths] :: Set DerivedPath -> BuildMode -> StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [CollectGarbage] :: GCOptions -> StoreRequest GCResult
+ System.Nix.Store.Remote.Types.StoreRequest: [EnsurePath] :: StorePath -> StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [FindRoots] :: StoreRequest (Map GCRoot StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [IsValidPath] :: StorePath -> StoreRequest Bool
+ System.Nix.Store.Remote.Types.StoreRequest: [NarFromPath] :: StorePath -> StoreRequest NoReply
+ System.Nix.Store.Remote.Types.StoreRequest: [OptimiseStore] :: StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryAllValidPaths] :: StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryDerivationOutputNames] :: StorePath -> StoreRequest (HashSet StorePathName)
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryDerivationOutputs] :: StorePath -> StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryMissing] :: Set DerivedPath -> StoreRequest Missing
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryPathFromHashPart] :: StorePathHashPart -> StoreRequest StorePath
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryPathInfo] :: StorePath -> StoreRequest (Maybe (Metadata StorePath))
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryReferrers] :: StorePath -> StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [QuerySubstitutablePaths] :: HashSet StorePath -> StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryValidDerivers] :: StorePath -> StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [QueryValidPaths] :: HashSet StorePath -> SubstituteMode -> StoreRequest (HashSet StorePath)
+ System.Nix.Store.Remote.Types.StoreRequest: [SyncWithGC] :: StoreRequest SuccessCodeReply
+ System.Nix.Store.Remote.Types.StoreRequest: [VerifyStore] :: CheckMode -> RepairMode -> StoreRequest Bool
+ System.Nix.Store.Remote.Types.StoreRequest: data StoreRequest :: Type -> Type
+ System.Nix.Store.Remote.Types.StoreRequest: instance Data.GADT.Internal.GCompare System.Nix.Store.Remote.Types.StoreRequest.StoreRequest
+ System.Nix.Store.Remote.Types.StoreRequest: instance Data.GADT.Internal.GEq System.Nix.Store.Remote.Types.StoreRequest.StoreRequest
+ System.Nix.Store.Remote.Types.StoreRequest: instance Data.GADT.Internal.GShow System.Nix.Store.Remote.Types.StoreRequest.StoreRequest
+ System.Nix.Store.Remote.Types.StoreRequest: instance GHC.Classes.Eq (Data.Some.Newtype.Some System.Nix.Store.Remote.Types.StoreRequest.StoreRequest)
+ System.Nix.Store.Remote.Types.StoreRequest: instance GHC.Classes.Eq (System.Nix.Store.Remote.Types.StoreRequest.StoreRequest a)
+ System.Nix.Store.Remote.Types.StoreRequest: instance GHC.Show.Show (System.Nix.Store.Remote.Types.StoreRequest.StoreRequest a)
+ System.Nix.Store.Remote.Types.StoreText: StoreText :: StorePathName -> Text -> StoreText
+ System.Nix.Store.Remote.Types.StoreText: [storeTextName] :: StoreText -> StorePathName
+ System.Nix.Store.Remote.Types.StoreText: [storeTextText] :: StoreText -> Text
+ System.Nix.Store.Remote.Types.StoreText: data StoreText
+ System.Nix.Store.Remote.Types.StoreText: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.StoreText.StoreText
+ System.Nix.Store.Remote.Types.StoreText: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.StoreText.StoreText
+ System.Nix.Store.Remote.Types.StoreText: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.StoreText.StoreText
+ System.Nix.Store.Remote.Types.StoreText: instance GHC.Show.Show System.Nix.Store.Remote.Types.StoreText.StoreText
+ System.Nix.Store.Remote.Types.SubstituteMode: SubstituteMode_DoSubstitute :: SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: SubstituteMode_DontSubstitute :: SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: data SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SubstituteMode: instance GHC.Show.Show System.Nix.Store.Remote.Types.SubstituteMode.SubstituteMode
+ System.Nix.Store.Remote.Types.SuccessCodeReply: SuccessCodeReply :: SuccessCodeReply
+ System.Nix.Store.Remote.Types.SuccessCodeReply: data SuccessCodeReply
+ System.Nix.Store.Remote.Types.SuccessCodeReply: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.SuccessCodeReply.SuccessCodeReply
+ System.Nix.Store.Remote.Types.SuccessCodeReply: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.SuccessCodeReply.SuccessCodeReply
+ System.Nix.Store.Remote.Types.SuccessCodeReply: instance GHC.Show.Show System.Nix.Store.Remote.Types.SuccessCodeReply.SuccessCodeReply
+ System.Nix.Store.Remote.Types.TrustedFlag: TrustedFlag_NotTrusted :: TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: TrustedFlag_Trusted :: TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: data TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.TrustedFlag: instance GHC.Show.Show System.Nix.Store.Remote.Types.TrustedFlag.TrustedFlag
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Chatty :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Debug :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Error :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Info :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Notice :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Talkative :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Vomit :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: Verbosity_Warn :: Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: data Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.Verbosity: instance GHC.Show.Show System.Nix.Store.Remote.Types.Verbosity.Verbosity
+ System.Nix.Store.Remote.Types.WorkerMagic: WorkerMagic_One :: WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: WorkerMagic_Two :: WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: data WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.WorkerMagic.WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.WorkerMagic.WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.WorkerMagic.WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: instance GHC.Show.Show System.Nix.Store.Remote.Types.WorkerMagic.WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: word64ToWorkerMagic :: Word64 -> Either String WorkerMagic
+ System.Nix.Store.Remote.Types.WorkerMagic: workerMagicToWord64 :: WorkerMagic -> Word64
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddBuildLog :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddIndirectRoot :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddMultipleToStore :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddSignatures :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddTempRoot :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddTextToStore :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddToStore :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_AddToStoreNar :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_BuildDerivation :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_BuildPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_BuildPathsWithResults :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_ClearFailedPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_CollectGarbage :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_EnsurePath :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_ExportPath :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_FindRoots :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_HasSubstitutes :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_ImportPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_IsValidPath :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_NarFromPath :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_OptimiseStore :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryAllValidPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryDerivationOutputMap :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryDerivationOutputNames :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryDerivationOutputs :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryDeriver :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryFailedPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryMissing :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryPathFromHashPart :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryPathHash :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryPathInfo :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryRealisation :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryReferences :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryReferrers :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QuerySubstitutablePathInfo :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QuerySubstitutablePathInfos :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QuerySubstitutablePaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryValidDerivers :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_QueryValidPaths :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_RegisterDrvOutput :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_Reserved_0__ :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_Reserved_15__ :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_Reserved_17__ :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_Reserved_2__ :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_SetOptions :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_SyncWithGC :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: WorkerOp_VerifyStore :: WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: data WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Classes.Eq System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Classes.Ord System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Enum.Bounded System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Enum.Enum System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Generics.Generic System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Read.Read System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
+ System.Nix.Store.Remote.Types.WorkerOp: instance GHC.Show.Show System.Nix.Store.Remote.Types.WorkerOp.WorkerOp
- System.Nix.Store.Remote: runStore :: MonadStore a -> IO (Either String a, [Logger])
+ System.Nix.Store.Remote: runStore :: (MonadIO m, MonadMask m) => RemoteStoreT m a -> Run m a
- System.Nix.Store.Remote.Logger: processOutput :: MonadStore [Logger]
+ System.Nix.Store.Remote.Logger: processOutput :: MonadRemoteStore m => m ()
Files
- CHANGELOG.md +71/−0
- ChangeLog.md +0/−52
- README.lhs +36/−0
- README.md +13/−5
- app/BuildDerivation.hs +25/−0
- hnix-store-remote.cabal +172/−87
- src/Data/Serializer.hs +214/−0
- src/Data/Serializer/Example.hs +329/−0
- src/System/Nix/Store/Remote.hs +180/−290
- src/System/Nix/Store/Remote/Arbitrary.hs +137/−0
- src/System/Nix/Store/Remote/Binary.hs +0/−52
- src/System/Nix/Store/Remote/Builders.hs +0/−36
- src/System/Nix/Store/Remote/Client.hs +279/−0
- src/System/Nix/Store/Remote/Client/Core.hs +229/−0
- src/System/Nix/Store/Remote/Logger.hs +87/−73
- src/System/Nix/Store/Remote/MonadStore.hs +390/−0
- src/System/Nix/Store/Remote/Parsers.hs +0/−51
- src/System/Nix/Store/Remote/Protocol.hs +0/−215
- src/System/Nix/Store/Remote/Serializer.hs +1567/−0
- src/System/Nix/Store/Remote/Server.hs +365/−0
- src/System/Nix/Store/Remote/Socket.hs +101/−0
- src/System/Nix/Store/Remote/Types.hs +31/−75
- src/System/Nix/Store/Remote/Types/Activity.hs +55/−0
- src/System/Nix/Store/Remote/Types/CheckMode.hs +11/−0
- src/System/Nix/Store/Remote/Types/GC.hs +55/−0
- src/System/Nix/Store/Remote/Types/Handshake.hs +37/−0
- src/System/Nix/Store/Remote/Types/Logger.hs +108/−0
- src/System/Nix/Store/Remote/Types/NoReply.hs +8/−0
- src/System/Nix/Store/Remote/Types/ProtoVersion.hs +27/−0
- src/System/Nix/Store/Remote/Types/Query.hs +5/−0
- src/System/Nix/Store/Remote/Types/Query/Missing.hs +18/−0
- src/System/Nix/Store/Remote/Types/StoreConfig.hs +61/−0
- src/System/Nix/Store/Remote/Types/StoreReply.hs +61/−0
- src/System/Nix/Store/Remote/Types/StoreRequest.hs +202/−0
- src/System/Nix/Store/Remote/Types/StoreText.hs +12/−0
- src/System/Nix/Store/Remote/Types/SubstituteMode.hs +11/−0
- src/System/Nix/Store/Remote/Types/SuccessCodeReply.hs +10/−0
- src/System/Nix/Store/Remote/Types/TrustedFlag.hs +11/−0
- src/System/Nix/Store/Remote/Types/Verbosity.hs +17/−0
- src/System/Nix/Store/Remote/Types/WorkerMagic.hs +27/−0
- src/System/Nix/Store/Remote/Types/WorkerOp.hs +59/−0
- src/System/Nix/Store/Remote/Util.hs +0/−167
- tests-io/DataSink.hs +26/−0
- tests-io/Main.hs +12/−0
- tests-io/NixDaemonSpec.hs +521/−0
- tests-io/SampleNar.hs +89/−0
- tests/Data/SerializerSpec.hs +43/−0
- tests/Driver.hs +1/−9
- tests/EnumSpec.hs +137/−0
- tests/NixDaemon.hs +0/−262
- tests/NixSerializerSpec.hs +169/−0
- tests/Spec.hs +0/−1
- tests/Util.hs +0/−12
+ CHANGELOG.md view
@@ -0,0 +1,71 @@+# [0.7.0.0](https://github.com/haskell-nix/hnix-store/compare/remote-0.6.0.0...remote-0.7.0.0) 2024-07-31++* Changes:+ * `StorePath` no longer carries `storePathRoot` field and we+ have a stand-alone `StoreDir` type instead to be used instead of `FilePath`+ when store root directory is needed as a context.+ Fore `-remote`, this affects `runStoreOpts` and its variants [#216](https://github.com/haskell-nix/hnix-store/pull/216)+ * The old `MonadStore` is now deprecated and aliased to `RemoteStoreT IO`+ * All store operations now use `MonadRemoteStore` typeclass, which `RemoteStoreT` is an instance of+ * Couple of `Bool` parameters switched to enums++* Additions+ * `addToStoreNAR` store operation [#277](https://github.com/haskell-nix/hnix-store/pull/277)+ * `narFromPath` store operation [#279](https://github.com/haskell-nix/hnix-store/pull/279)+ * Initial server-side support with proxy daemon acting as MITM proxy,+ which allows for testing of both sides of the remote store protocol++The library stability is not quite there yet and should be considered experimental.++# [0.6.0.0](https://github.com/haskell-nix/hnix-store/compare/remote-0.5.0.0...remote-0.6.0.0) 2021-06-06++* Changes:+ * `System.Nix.Store.Remote` [#179](https://github.com/haskell-nix/hnix-store/pull/179)+ * `addToStore` no longer accepts `FilePath` as its second argument but uses+ more generic `NarSource` [(NarSource PR)](https://github.com/haskell-nix/hnix-store/pull/177)++# [0.5.0.0](https://github.com/haskell-nix/hnix-store/compare/0.4.3.0...remote-0.5.0.0) 2021-06-11++* Changes:+ * `System.Nix.Store.Remote` [#161](https://github.com/haskell-nix/hnix-store/pull/161)+ * `addToStore`: constraint of `ValidAlgo a` removed in favour of constraint on `cryptonite: HashAlgorithm a` through constraint `NamedAlgo a`.+ * `queryPathFromHashPart`: 1st arg changed from `Digest StorePathHashAlgo` to `StorePathHashPart`, for details: [hnix-store-core 0.5.0.0 ChangeLog](https://hackage.haskell.org/package/hnix-store-core-0.5.0.0/changelog).++# [0.4.3.0](https://github.com/haskell-nix/hnix-store/compare/0.4.2.0...0.4.3.0) 2021-05-30++Nothing (it is tandem `hnix-store-core` fix release)++# [0.4.2.0](https://github.com/haskell-nix/hnix-store/compare/0.4.1.0...0.4.2.0) 2021-03-12++* Additions:+ * Cabal now properly states `tasty-discover` as `build-tool-depends` [#130](https://github.com/haskell-nix/hnix-store/pull/130)+ * added explicit `hie.yml` cradle description for `cabal` to help Haskell Language Server to work with monorepo. [#132](https://github.com/haskell-nix/hnix-store/pull/132)+ * Nix dev env: removed GHC 8.6.5 support, afaik it is not even in Nixpkgs anymore [#136](https://github.com/haskell-nix/hnix-store/pull/136)++# [0.4.1.0](https://github.com/haskell-nix/hnix-store/compare/0.4.0.0...0.4.1.0) 2021-01-16++* `System.Nix.Store.Remote`: module API now re-exports `System.Nix.Store.Remote.Types` API+* Big clean-up of dependencies.++# [0.4.0.0](https://github.com/haskell-nix/hnix-store/compare/0.3.0.0...0.4.0.0) 2020-12-30++* `hnix-store-core` compatibility++# 0.3.0.0 -- 2020-11-29++* Restored most store API functions except `addToStoreNar`+* Added `buildDerivation`++# 0.2.0.0 -- skipped++* `hnix-store-core` release only++# 0.1.0.0 -- 2019-03-18++* First version.++---++`hnix-store-remote` uses [PVP Versioning][1].++[1]: https://pvp.haskell.org
− ChangeLog.md
@@ -1,52 +0,0 @@-# Revision history for hnix-store-remote--## [0.6.0.0](https://github.com/haskell-nix/hnix-store/compare/remote-0.5.0.0...remote-0.6.0.0) 2021-06-06--* Breaking:- * [(link)](https://github.com/haskell-nix/hnix-store/pull/179) `System.Nix.Store.Remote`:- * `addToStore` no longer accepts `FilePath` as its second argument but uses- more generic `NarSource` [(NarSource PR)](https://github.com/haskell-nix/hnix-store/pull/177)--## [0.5.0.0](https://github.com/haskell-nix/hnix-store/compare/0.4.3.0...remote-0.5.0.0) 2021-06-11--* Breaking:- * [(link)](https://github.com/haskell-nix/hnix-store/commit/3b948d112aa9307b0451258f28c7ee5dc86b24c7) `System.Nix.Store.Remote`:- * `addToStore`: constraint of `ValidAlgo a` removed in favour of constraint on `cryptonite: HashAlgorithm a` through constraint `NamedAlgo a`.- * `queryPathFromHashPart`: 1st arg changed from `Digest StorePathHashAlgo` to `StorePathHashPart`, for details: [hnix-store-core 0.5.0.0 ChangeLog](https://hackage.haskell.org/package/hnix-store-core-0.5.0.0/changelog).--## [0.4.3.0](https://github.com/haskell-nix/hnix-store/compare/0.4.2.0...0.4.3.0) 2021-05-30--Nothing (it is tandem `hnix-store-core` fix release)--## [0.4.2.0](https://github.com/haskell-nix/hnix-store/compare/0.4.1.0...0.4.2.0) 2021-03-12--* Additional:-- * [(link)](https://github.com/haskell-nix/hnix-store/commit/5d03ffc43cde9448df05e84838ece70cc83b1b6c) Cabal now properly states `tasty-discover` as `build-tool-depends`.-- * [(link)](https://github.com/haskell-nix/hnix-store/commit/b5ad38573d27e0732d0fadfebd98de1f753b4f07) added explicit `hie.yml` cradle description for `cabal` to help Haskell Language Server to work with monorepo.-- * [(link)](https://github.com/haskell-nix/hnix-store/commit/cf04083aba98ad40d183d1e26251101816cc07ae) Nix dev env: removed GHC 8.6.5 support, afaik it is not even in Nixpkgs anymore.---## [0.4.1.0](https://github.com/haskell-nix/hnix-store/compare/0.4.0.0...0.4.1.0) 2021-01-16--* `System.Nix.Store.Remote`: module API now re-exports `System.Nix.Store.Remote.Types` API-* Big clean-up of dependencies.--## [0.4.0.0](https://github.com/haskell-nix/hnix-store/compare/0.3.0.0...0.4.0.0) 2020-12-30--* `hnix-store-core` compatibility--## 0.3.0.0 -- 2020-11-29--* Restored most store API functions except `addToStoreNar`-* Added `buildDerivation`--## 0.2.0.0 -- skipped--* `hnix-store-core` release only--## 0.1.0.0 -- 2019-03-18--* First version.
+ README.lhs view
@@ -0,0 +1,36 @@+# hnix-store-remote++[Nix] worker protocol implementation for interacting with remote Nix store+via `nix-daemon`.++[Nix]: https://nixos.org/nix++## API++[System.Nix.Store.Remote]: ./src/System/Nix/Store/Remote.hs++## Example++```haskell+{-# LANGUAGE OverloadedStrings #-}++import System.Nix.StorePath (mkStorePathName)+import System.Nix.Store.Remote++main :: IO ()+main = do+ runStore $ do+ syncWithGC+ roots <- findRoots++ res <- case mkStorePathName "hnix-store" of+ Left e -> error (show e)+ Right name ->+ addTextToStore+ (StoreText name "Hello World!")+ mempty+ RepairMode_DontRepair++ pure (roots, res)+ >>= print+```
README.md view
@@ -12,17 +12,25 @@ ## Example ```haskell+{-# LANGUAGE OverloadedStrings #-} -import Control.Monad.IO.Class (liftIO)-import Data.HashSet as HS+import System.Nix.StorePath (mkStorePathName) import System.Nix.Store.Remote +main :: IO () main = do runStore $ do syncWithGC roots <- findRoots- liftIO $ print roots - res <- addTextToStore "hnix-store" "test" (HS.fromList []) False- liftIO $ print res+ res <- case mkStorePathName "hnix-store" of+ Left e -> error (show e)+ Right name ->+ addTextToStore+ (StoreText name "Hello World!")+ mempty+ RepairMode_DontRepair++ pure (roots, res)+ >>= print ```
+ app/BuildDerivation.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE LambdaCase #-}+module Main where++import Data.Default.Class (Default(def))++import qualified Data.Text+import qualified System.Environment+import qualified System.Nix.Build+import qualified System.Nix.StorePath+import qualified System.Nix.Store.Remote++main :: IO ()+main = System.Environment.getArgs >>= \case+ [filename] -> do+ case System.Nix.StorePath.parsePathFromText def (Data.Text.pack filename) of+ Left e -> error $ show e+ Right p -> do+ out <-+ System.Nix.Store.Remote.runStore+ $ System.Nix.Store.Remote.buildDerivation+ p+ System.Nix.Build.BuildMode_Normal+ print out+ _ -> error "No input derivation file"+
hnix-store-remote.cabal view
@@ -1,23 +1,51 @@ cabal-version: 2.2 name: hnix-store-remote-version: 0.6.0.0+version: 0.7.0.0 synopsis: Remote hnix store description: Implementation of the nix store using the daemon protocol. homepage: https://github.com/haskell-nix/hnix-store license: Apache-2.0 license-file: LICENSE-author: Richard Marko+author: Sorki maintainer: srk@48.io-copyright: 2018 Richard Marko+copyright: 2018 Sorki category: Nix build-type: Simple-extra-source-files: ChangeLog.md, README.md+extra-doc-files:+ CHANGELOG.md+extra-source-files:+ README.md+ , README.lhs -Common commons- if impl(ghc >= 8.10)- ghc-options: -Wall -Wunused-packages- else- ghc-options: -Wall+common commons+ ghc-options: -Wall+ default-extensions:+ DataKinds+ , DefaultSignatures+ , DeriveGeneric+ , DeriveDataTypeable+ , DeriveFunctor+ , DeriveFoldable+ , DeriveTraversable+ , DeriveLift+ , DerivingVia+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , RecordWildCards+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeOperators+ , TypeSynonymInstances+ , InstanceSigs+ , KindSignatures+ , MultiParamTypeClasses+ , TupleSections+ , LambdaCase+ , BangPatterns+ , ViewPatterns+ default-language: Haskell2010 flag io-testsuite default:@@ -26,117 +54,174 @@ Enable testsuite, which requires external binaries and Linux namespace support. +flag build-derivation+ default:+ False+ description:+ Build build-derivation executable++flag build-readme+ default:+ False+ description:+ Build README.lhs example+ library import: commons exposed-modules:- System.Nix.Store.Remote- , System.Nix.Store.Remote.Binary- , System.Nix.Store.Remote.Builders+ Data.Serializer+ , Data.Serializer.Example+ , System.Nix.Store.Remote+ , System.Nix.Store.Remote.Arbitrary+ , System.Nix.Store.Remote.Client+ , System.Nix.Store.Remote.Client.Core , System.Nix.Store.Remote.Logger- , System.Nix.Store.Remote.Parsers- , System.Nix.Store.Remote.Protocol+ , System.Nix.Store.Remote.MonadStore+ , System.Nix.Store.Remote.Serializer+ , System.Nix.Store.Remote.Server+ , System.Nix.Store.Remote.Socket , System.Nix.Store.Remote.Types- , System.Nix.Store.Remote.Util+ , System.Nix.Store.Remote.Types.Activity+ , System.Nix.Store.Remote.Types.CheckMode+ , System.Nix.Store.Remote.Types.GC+ , System.Nix.Store.Remote.Types.Handshake+ , System.Nix.Store.Remote.Types.Logger+ , System.Nix.Store.Remote.Types.NoReply+ , System.Nix.Store.Remote.Types.ProtoVersion+ , System.Nix.Store.Remote.Types.Query+ , System.Nix.Store.Remote.Types.Query.Missing+ , System.Nix.Store.Remote.Types.StoreConfig+ , System.Nix.Store.Remote.Types.StoreRequest+ , System.Nix.Store.Remote.Types.StoreReply+ , System.Nix.Store.Remote.Types.StoreText+ , System.Nix.Store.Remote.Types.SubstituteMode+ , System.Nix.Store.Remote.Types.SuccessCodeReply+ , System.Nix.Store.Remote.Types.TrustedFlag+ , System.Nix.Store.Remote.Types.Verbosity+ , System.Nix.Store.Remote.Types.WorkerMagic+ , System.Nix.Store.Remote.Types.WorkerOp build-depends: base >=4.12 && <5- , relude >= 1.0+ , hnix-store-core >= 0.8 && <0.9+ , hnix-store-json >= 0.1+ , hnix-store-nar >= 0.1+ , hnix-store-tests >= 0.1+ , aeson , attoparsec- , binary , bytestring+ , cereal , containers- , cryptonite+ , concurrency+ , crypton+ , data-default-class+ , dependent-sum > 0.7+ , dependent-sum-template >= 0.2.0.1 && < 0.3+-- , directory+ , dlist >= 1.0+ , exceptions+ , generic-arbitrary < 1.1+ , hashable , text , time+ , transformers , network- , nix-derivation >= 1.1.1 && <2 , mtl+ , QuickCheck , unordered-containers- , hnix-store-core >= 0.6 && <0.7- mixins:- base hiding (Prelude)- , relude (Relude as Prelude)- , relude- default-extensions:- OverloadedStrings- , DeriveGeneric- , DeriveDataTypeable- , DeriveFunctor- , DeriveFoldable- , DeriveTraversable- , DeriveLift- , FlexibleContexts- , FlexibleInstances- , StandaloneDeriving- , TypeApplications- , TypeSynonymInstances- , InstanceSigs- , MultiParamTypeClasses- , TupleSections- , LambdaCase- , BangPatterns- , ViewPatterns+ , unix >= 2.7+ , vector hs-source-dirs: src- default-language: Haskell2010 ghc-options: -Wall -test-suite hnix-store-remote-tests- import: commons+executable build-derivation+ if !flag(build-derivation)+ buildable: False+ build-depends:+ base >=4.12 && <5+ , hnix-store-core+ , hnix-store-remote+ , data-default-class+ , text+ default-language: Haskell2010+ main-is: BuildDerivation.hs+ hs-source-dirs: app+ ghc-options: -Wall -threaded -rtsopts "-with-rtsopts -N" - if !flag(io-testsuite)+executable remote-readme+ if !flag(build-readme) buildable: False- ghc-options: -rtsopts -fprof-auto+ build-depends:+ base >=4.12 && <5+ , hnix-store-core+ , hnix-store-remote+ build-tool-depends:+ markdown-unlit:markdown-unlit+ default-language: Haskell2010+ main-is: README.lhs+ ghc-options: -pgmL markdown-unlit -Wall +test-suite remote+ import: commons type: exitcode-stdio-1.0 main-is: Driver.hs- other-modules:- NixDaemon- , Spec- , Util hs-source-dirs: tests+ ghc-options: -Wall -threaded -rtsopts "-with-rtsopts -N"+ other-modules:+ Data.SerializerSpec+ EnumSpec+ NixSerializerSpec build-tool-depends:- tasty-discover:tasty-discover+ hspec-discover:hspec-discover build-depends:- base- , relude- , hnix-store-core >= 0.3+ base >=4.12 && <5+ , hnix-store-core , hnix-store-remote+ , hnix-store-tests+ , bytestring+ , crypton+ , some > 1.0.5 && < 2+ , time+ , hspec+ , QuickCheck++test-suite remote-io+ import: commons++ if !flag(io-testsuite) || os(darwin)+ buildable: False++ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: tests-io+ -- See https://github.com/redneb/hs-linux-namespaces/issues/3+ ghc-options: -rtsopts -fprof-auto "-with-rtsopts -V0"+ other-modules:+ DataSink+ , NixDaemonSpec+ , SampleNar+ build-depends:+ base >=4.12 && <5+ , hnix-store-core+ , hnix-store-nar+ , hnix-store-remote+ , hnix-store-tests+ , bytestring+ , concurrency , containers- , cryptonite+ , crypton+ , data-default-class+ , dependent-sum , directory- , process+ , exceptions , filepath- , hspec-expectations-lifted- , quickcheck-text- , tasty , hspec- , tasty-hspec- , tasty-quickcheck+ , hspec-expectations-lifted , linux-namespaces+ , process+ , some , temporary+ , text+ , time , unix , unordered-containers- mixins:- base hiding (Prelude)- , relude (Relude as Prelude)- , relude- default-extensions:- OverloadedStrings- , DeriveGeneric- , DeriveDataTypeable- , DeriveFunctor- , DeriveFoldable- , DeriveTraversable- , DeriveLift- , FlexibleContexts- , FlexibleInstances- , StandaloneDeriving- , TypeApplications- , TypeSynonymInstances- , InstanceSigs- , MultiParamTypeClasses- , TupleSections- , LambdaCase- , BangPatterns- , ViewPatterns- default-language: Haskell2010
+ src/Data/Serializer.hs view
@@ -0,0 +1,214 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-|+Description : Serializer data type+Copyright : (c) John Ericson, 2023+ Sorki, 2023+Stability : experimental++@Serializer@ ties @Get@ and @PutM@ monads+into a single datatype and allows+transforming both monads with a monad transformer+for adding extra layers like @ExceptT@+(for example when @putS@ can fail due to unsupported+version of a protocol) or @ReaderT@ (when we need+to serialize a data type based differently based+on a protocol version).++See "Data.Serializer.Example"+-}++module Data.Serializer+ (+ -- * Serializer+ Serializer(..)+ -- ** Runners+ , runGetS+ , runPutS+ -- * Simple serializer+ , SimpleSerializer+ -- ** Simple runners+ , runGetSimple+ , runPutSimple+ -- * From Get/Put, Serialize+ , lift2+ , liftSerialize+ -- * Combinators+ , mapIsoSerializer+ , mapPrismSerializer+ , tup+ -- * Utility+ , GetSerializerError(..)+ , transformGetError+ , transformPutError+ -- * Re-exports+ , Get+ , PutM+ ) where++#if !MIN_VERSION_base(4,18,0)+import Control.Applicative (liftA2)+#endif+import Control.Monad.Except (MonadError, throwError)+import Control.Monad.Trans (lift)+import Control.Monad.Trans (MonadTrans)+import Control.Monad.Trans.Identity (IdentityT, runIdentityT)+import Data.ByteString (ByteString)+import Data.Serialize (Serialize)+import Data.Serialize.Get (Get, runGet)+import Data.Serialize.Put (Putter, PutM, runPutM)++import qualified Data.Serialize++-- * Serializer++-- | @Serializer@ ties @Get@ and @PutM@ monads+-- into a single datatype and allows+-- transforming the monads with a monad transformer+-- for e.g. adding @ExceptT@ or @ReaderT@ layers.+data Serializer t a = Serializer+ { getS :: t Get a+ , putS :: a -> t PutM ()+ }++-- ** Runners++-- | Runner for putS of @Serializer@+runPutS+ :: ( Monad (t PutM)+ , MonadTrans t+ )+ => Serializer t a -- ^ Serializer+ -> (t PutM () -> PutM b) -- ^ Tranformer runner+ -> a -- ^ Value to (out)put+ -> (b, ByteString)+runPutS s run a = runPutM $ run $ (putS s) a++-- | Runner for getS of @Serializer@+runGetS+ :: ( Monad (t Get)+ , MonadTrans t+ )+ => Serializer t a -- ^ Serializer+ -> (t Get a -> Get b) -- ^ Tranformer runner+ -> ByteString -- ^ ByteString to parse+ -> Either String b+runGetS s run b = runGet (run (getS s)) b++-- * Simple serializer++-- | Simple @Serializer@+type SimpleSerializer a = Serializer IdentityT a++-- ** Simple runners++-- | Runner for getS of @SimpleSerializer@+runGetSimple+ :: SimpleSerializer a+ -> ByteString+ -> Either String a+runGetSimple s b =+ runGetS s (runIdentityT) b++-- | Runner for putS of @SimpleSerializer@+runPutSimple+ :: SimpleSerializer a+ -> a+ -> ByteString+runPutSimple s =+ snd+ . runPutS s runIdentityT++-- * From Get/Put, Serialize++-- | Lift @Get a@ and @Putter a@ into @Serializer@+lift2+ :: forall a t+ . MonadTrans t+ => Get a+ -> Putter a+ -> Serializer t a+lift2 f g = Serializer+ { getS = lift f+ , putS = lift . g+ }++-- | Lift @Serialize a@ instance into @Serializer@+liftSerialize+ :: ( Serialize a+ , MonadTrans t+ )+ => Serializer t a+liftSerialize =+ lift2+ Data.Serialize.get+ Data.Serialize.put++-- * Combinators++-- | Map over @Serializer@+mapIsoSerializer+ :: Functor (t Get)+ => (a -> b) -- ^ Map over @getS@+ -> (b -> a) -- ^ Map over @putS@+ -> Serializer t a+ -> Serializer t b+mapIsoSerializer f g s = Serializer+ { getS = f <$> getS s+ , putS = putS s . g+ }++-- | Map over @Serializer@ where @getS@+-- can return @Either@+mapPrismSerializer+ :: MonadError eGet (t Get)+ => (a -> Either eGet b) -- ^ Map over @getS@+ -> (b -> a) -- ^ Map over @putS@+ -> Serializer t a+ -> Serializer t b+mapPrismSerializer f g s = Serializer+ { getS = either throwError pure . f =<< getS s+ , putS = putS s . g+ }++-- | Tuple combinator+tup+ :: ( Applicative (t Get)+ , Monad (t PutM)+ )+ => Serializer t a+ -> Serializer t b+ -> Serializer t (a, b)+tup a b = Serializer+ { getS = liftA2 (,) (getS a) (getS b)+ , putS = \(x, y) -> do+ putS a x+ putS b y+ }++-- * Utilities++-- | Wrapper for both GetS errors+--+-- * the one that occurs when @fail@ is called+-- * custom one when @ExceptT@ is used+data GetSerializerError customGetError+ = SerializerError_GetFail String+ | SerializerError_Get customGetError+ deriving (Eq, Ord, Show)++-- | Helper for transforming nested Eithers+-- into @GetSerializerError@ wrapper+transformGetError+ :: Either String (Either customGetError b)+ -> Either (GetSerializerError customGetError) b+transformGetError = \case+ Left stringyRunGetError -> Left (SerializerError_GetFail stringyRunGetError)+ Right (Left myGetError) -> Left (SerializerError_Get myGetError)+ Right (Right res) -> Right res++-- | Helper for transforming @runPutM@ result+transformPutError+ :: (Either customPutError (), ByteString)+ -> Either customPutError ByteString+transformPutError (e, r) = either Left (pure $ Right r) e
+ src/Data/Serializer/Example.hs view
@@ -0,0 +1,329 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Data.Serializer.Example+ (+ -- * Simple protocol+ OpCode(..)+ , Cmd(..)+ -- * Cmd Serializer+ , cmdS+ -- * Runners+ , runG+ , runP+ -- * Custom errors+ , MyGetError(..)+ , MyPutError(..)+ -- ** Erroring variants of cmdS+ -- *** putS with throwError and MyPutError+ , cmdSPutError+ -- *** getS with throwError and MyGetError+ , cmdSGetError+ -- *** getS with fail+ , cmdSGetFail+ -- *** putS with fail+ , cmdSPutFail+ -- * Elaborate+ , cmdSRest+ , runGRest+ , runPRest+ ) where++import Control.Monad.Except (MonadError, throwError)+import Control.Monad.Reader (MonadReader, ask)+import Control.Monad.State (MonadState)+import Control.Monad.Trans (MonadTrans, lift)+import Control.Monad.Trans.Reader (ReaderT, runReaderT)+import Control.Monad.Trans.Except (ExceptT, runExceptT)+import Control.Monad.Trans.State (StateT, runStateT)+import Data.Bifunctor (first, second)+import Data.ByteString (ByteString)+import Data.Int (Int8)+import Data.GADT.Show (GShow(..), defaultGshowsPrec)+import Data.Kind (Type)+import Data.Type.Equality (TestEquality(..), (:~:)(Refl))+import Data.Serialize.Get (Get, getInt8)+import Data.Serialize.Put (Putter, PutM, putInt8)+import Data.Serializer+ ( Serializer(..)+ , GetSerializerError+ , runGetS+ , runPutS+ , transformGetError+ , transformPutError+ )+import Data.Some (Some(..))+import GHC.Generics (Generic)++import Test.QuickCheck (Arbitrary(..), oneof)++-- * Simple protocol++-- | OpCode used to differentiate between operations+data OpCode = OpCode_Int | OpCode_Bool+ deriving (Bounded, Eq, Enum, Generic, Ord, Show)++-- | Protocol operations+data Cmd :: Type -> Type where+ Cmd_Int :: Int8 -> Cmd Int8+ Cmd_Bool :: Bool -> Cmd Bool++deriving instance Eq (Cmd a)+deriving instance Show (Cmd a)++instance GShow Cmd where+ gshowsPrec = defaultGshowsPrec++instance TestEquality Cmd where+ testEquality (Cmd_Int _) (Cmd_Int _) = Just Refl+ testEquality (Cmd_Bool _) (Cmd_Bool _) = Just Refl+ testEquality _ _ = Nothing++-- constructors only+-- import Data.GADT.Compare+-- instance GEq Cmd where+-- geq = testEquality++instance {-# OVERLAPPING #-} Eq (Some Cmd) where+ Some (Cmd_Int a) == Some (Cmd_Int b) = a == b+ Some (Cmd_Bool a) == Some (Cmd_Bool b) = a == b+ _ == _ = False++instance Arbitrary (Some Cmd) where+ arbitrary = oneof+ [ Some . Cmd_Int <$> arbitrary+ , Some . Cmd_Bool <$> arbitrary+ ]++-- | @OpCode@ @Serializer@+opcode :: MonadTrans t => Serializer t OpCode+opcode = Serializer+ { getS = lift getEnum+ , putS = lift . putEnum+ }++-- * Cmd Serializer++-- | @Cmd@ @Serializer@+cmdS+ :: forall t . ( MonadTrans t+ , Monad (t Get)+ , Monad (t PutM)+ )+ => Serializer t (Some Cmd)+cmdS = Serializer+ { getS = getS opcode >>= \case+ OpCode_Int -> Some . Cmd_Int <$> lift getInt8+ OpCode_Bool -> Some . Cmd_Bool <$> lift getBool+ , putS = \case+ Some (Cmd_Int i) -> putS opcode OpCode_Int >> lift (putInt8 i)+ Some (Cmd_Bool b) -> putS opcode OpCode_Bool >> lift (putBool b)+ }++-- * Runners++-- | @runGetS@ specialized to @ExceptT e@+runG+ :: Serializer (ExceptT e) a+ -> ByteString+ -> Either (GetSerializerError e) a+runG s =+ transformGetError+ . runGetS s runExceptT++-- | @runPutS@ specialized to @ExceptT e@+runP+ :: Serializer (ExceptT e) a+ -> a+ -> Either e ByteString+runP s =+ (\(e, r) -> either Left (pure $ Right r) e)+ . runPutS s runExceptT++-- * Custom errors++data MyGetError+ = MyGetError_Example+ deriving (Eq, Show)++data MyPutError+ = MyPutError_NoLongerSupported -- no longer supported protocol version+ deriving (Eq, Show)++-- ** Erroring variants of cmdS++-- *** putS with throwError and MyPutError++cmdSPutError :: Serializer (ExceptT MyPutError) (Some Cmd)+cmdSPutError = Serializer+ { getS = getS cmdS+ , putS = \case+ Some (Cmd_Int i) -> putS opcode OpCode_Int >> lift (putInt8 i)+ Some (Cmd_Bool _b) -> throwError MyPutError_NoLongerSupported+ }++-- *** getS with throwError and MyGetError++cmdSGetError :: Serializer (ExceptT MyGetError) (Some Cmd)+cmdSGetError = Serializer+ { getS = getS opcode >>= \case+ OpCode_Int -> Some . Cmd_Int <$> lift getInt8+ OpCode_Bool -> throwError MyGetError_Example+ , putS = putS cmdS+ }++-- *** getS with fail++cmdSGetFail+ :: ( MonadTrans t+ , MonadFail (t Get)+ , Monad (t PutM)+ )+ => Serializer t (Some Cmd)+cmdSGetFail = Serializer+ { getS = getS opcode >>= \case+ OpCode_Int -> Some . Cmd_Int <$> lift getInt8+ OpCode_Bool -> fail "no parse"+ , putS = putS cmdS+ }++-- *** putS with fail++-- | Unused as PutM doesn't have @MonadFail@+-- >>> serializerPutFail = cmdPutFail @(ExceptT MyGetError)+-- No instance for (MonadFail PutM)+-- as expected+cmdSPutFail+ :: ( MonadTrans t+ , MonadFail (t PutM)+ , Monad (t Get)+ )+ => Serializer t (Some Cmd)+cmdSPutFail = Serializer+ { getS = getS cmdS+ , putS = \case+ Some (Cmd_Int i) -> putS opcode OpCode_Int >> lift (putInt8 i)+ Some (Cmd_Bool _b) -> fail "can't"+ }++-- * Elaborate++-- | Transformer for @Serializer@+newtype REST r e s m a = REST+ { _unREST :: ExceptT e (StateT s (ReaderT r m)) a }+ deriving+ ( Applicative+ , Functor+ , Monad+ , MonadError e+ , MonadReader r+ , MonadState s+ , MonadFail+ )++instance MonadTrans (REST r e s) where+ lift = REST . lift . lift . lift++-- | Runner for @REST@+restRunner+ :: Monad m+ => r+ -> s+ -> REST r e s m a+ -> m ((Either e a), s)+restRunner r s =+ (`runReaderT` r)+ . (`runStateT` s)+ . runExceptT+ . _unREST++runGRest+ :: Serializer (REST r e s) a+ -> r+ -> s+ -> ByteString+ -> Either (GetSerializerError e) a+runGRest serializer r s =+ transformGetError+ . second fst+ . runGetS+ serializer+ (restRunner r s)++runPRest+ :: Serializer (REST r e s) a+ -> r+ -> s+ -> a+ -> Either e ByteString+runPRest serializer r s =+ transformPutError+ . first fst+ . runPutS+ serializer+ (restRunner r s)++cmdSRest+ :: Serializer (REST Bool e Int) (Some Cmd)+cmdSRest = Serializer+ { getS = getS opcode >>= \case+ OpCode_Int -> do+ isTrue <- ask+ if isTrue+ then Some . Cmd_Int . (+1) <$> lift getInt8+ else Some . Cmd_Int <$> lift getInt8+ OpCode_Bool -> Some . Cmd_Bool <$> lift getBool+ , putS = \case+ Some (Cmd_Int i) -> do+ putS opcode OpCode_Int+ isTrue <- ask+ if isTrue+ then lift (putInt8 (i - 1))+ else lift (putInt8 i)+ Some (Cmd_Bool b) -> putS opcode OpCode_Bool >> lift (putBool b)+ }++-- Primitives helpers++getInt :: Integral a => Get a+getInt = fromIntegral <$> getInt8++putInt :: Integral a => Putter a+putInt = putInt8 . fromIntegral++-- | Deserialize @Bool@ from integer+getBool :: Get Bool+getBool = (getInt :: Get Int8) >>= \case+ 0 -> pure False+ 1 -> pure True+ x -> fail $ "illegal bool value " ++ show x++-- | Serialize @Bool@ into integer+putBool :: Putter Bool+putBool True = putInt (1 :: Int8)+putBool False = putInt (0 :: Int8)++-- | Utility toEnum version checking bounds using Bounded class+toEnumCheckBounds+ :: forall a+ . ( Bounded a+ , Enum a+ )+ => Int+ -> Either String a+toEnumCheckBounds = \case+ x | x < fromEnum (minBound @a) -> Left $ "enum out of min bound " ++ show x+ x | x > fromEnum (maxBound @a) -> Left $ "enum out of max bound " ++ show x+ x | otherwise -> Right $ toEnum x++-- | Deserialize @Enum@ to integer+getEnum+ :: ( Bounded a+ , Enum a+ )+ => Get a+getEnum =+ toEnumCheckBounds <$> getInt+ >>= either fail pure++-- | Serialize @Enum@ to integer+putEnum :: Enum a => Putter a+putEnum = putInt . fromEnum
src/System/Nix/Store/Remote.hs view
@@ -1,309 +1,199 @@-{-# language AllowAmbiguousTypes #-}-{-# language KindSignatures #-}-{-# language RankNTypes #-}-{-# language ScopedTypeVariables #-}-{-# language DataKinds #-}-{-# language RecordWildCards #-}-{-# language LiberalTypeSynonyms #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-} module System.Nix.Store.Remote- ( addToStore- , addTextToStore- , addSignatures- , addIndirectRoot- , addTempRoot- , buildPaths- , buildDerivation- , ensurePath- , findRoots- , isValidPathUncached- , queryValidPaths- , queryAllValidPaths- , querySubstitutablePaths- , queryPathInfoUncached- , queryReferrers- , queryValidDerivers- , queryDerivationOutputs- , queryDerivationOutputNames- , queryPathFromHashPart- , queryMissing- , optimiseStore- , runStore- , syncWithGC- , verifyStore+ ( module System.Nix.Store.Types+ , module System.Nix.Store.Remote.Client+ , module System.Nix.Store.Remote.MonadStore , module System.Nix.Store.Remote.Types- )-where--import Prelude hiding ( putText )-import qualified Data.ByteString.Lazy as BSL+ -- * Compat+ , MonadStore+ -- * Runners+ , runStore+ , runStoreConnection+ , runStoreSocket+ -- ** Daemon+ , runDaemon+ , runDaemonConnection+ , justdoit+ ) where -import Nix.Derivation ( Derivation )-import System.Nix.Build ( BuildMode- , BuildResult- )-import System.Nix.Hash ( NamedAlgo(..)- , SomeNamedDigest(..)- , BaseEncoding(NixBase32)- , decodeDigestWith- )-import System.Nix.StorePath ( StorePath- , StorePathName- , StorePathSet- , StorePathHashPart- )-import System.Nix.StorePathMetadata ( StorePathMetadata(..)- , StorePathTrust(..)- )-import System.Nix.Internal.Base ( encodeWith )+import Control.Monad.Catch (MonadMask)+import Control.Monad.Conc.Class (MonadConc)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Default.Class (Default(def))+import Network.Socket (Family, SockAddr(SockAddrUnix))+import System.Nix.Store.Types (FileIngestionMethod(..), RepairMode(..))+import System.Nix.Store.Remote.MonadStore+ ( runRemoteStoreT+ , MonadRemoteStore(..)+ , RemoteStoreT+ , RemoteStoreError(RemoteStoreError_GetAddrInfoFailed))+import System.Nix.Store.Remote.Client+import System.Nix.Store.Remote.Server (WorkerHelper, runProxyDaemon)+import System.Nix.Store.Remote.Types -import qualified Data.Binary.Put-import qualified Data.Map.Strict-import qualified Data.Set+import qualified Control.Monad.Catch+import qualified Network.Socket+-- see TODO bellow+--import qualified System.Directory +-- wip justdoit+import System.Nix.StorePath (StorePath) import qualified System.Nix.StorePath-import qualified System.Nix.Store.Remote.Parsers -import System.Nix.Store.Remote.Binary-import System.Nix.Store.Remote.Types-import System.Nix.Store.Remote.Protocol-import System.Nix.Store.Remote.Util-import Crypto.Hash ( SHA256 )-import System.Nix.Nar ( NarSource )--type RepairFlag = Bool-type CheckFlag = Bool-type SubstituteFlag = Bool---- | Pack `Nar` and add it to the store.-addToStore- :: forall a- . (NamedAlgo a)- => StorePathName -- ^ Name part of the newly created `StorePath`- -> NarSource MonadStore -- ^ provide nar stream- -> Bool -- ^ Add target directory recursively- -> RepairFlag -- ^ Only used by local store backend- -> MonadStore StorePath-addToStore name source recursive _repair = do- runOpArgsIO AddToStore $ \yield -> do- yield $ toStrict $ Data.Binary.Put.runPut $ do- putText $ System.Nix.StorePath.unStorePathName name- putBool $ not $ System.Nix.Hash.algoName @a == "sha256" && recursive- putBool recursive- putText $ System.Nix.Hash.algoName @a- source yield- sockGetPath---- | Add text to store.------ Reference accepts repair but only uses it--- to throw error in case of remote talking to nix-daemon.-addTextToStore- :: Text -- ^ Name of the text- -> Text -- ^ Actual text to add- -> StorePathSet -- ^ Set of `StorePath`s that the added text references- -> RepairFlag -- ^ Repair flag, must be `False` in case of remote backend- -> MonadStore StorePath-addTextToStore name text references' repair = do- when repair- $ error "repairing is not supported when building through the Nix daemon"- runOpArgs AddTextToStore $ do- putText name- putText text- putPaths references'- sockGetPath--addSignatures :: StorePath -> [BSL.ByteString] -> MonadStore ()-addSignatures p signatures = do- void $ simpleOpArgs AddSignatures $ do- putPath p- putByteStrings signatures--addIndirectRoot :: StorePath -> MonadStore ()-addIndirectRoot pn = do- void $ simpleOpArgs AddIndirectRoot $ putPath pn---- | Add temporary garbage collector root.------ This root is removed as soon as the client exits.-addTempRoot :: StorePath -> MonadStore ()-addTempRoot pn = do- void $ simpleOpArgs AddTempRoot $ putPath pn---- | Build paths if they are an actual derivations.------ If derivation output paths are already valid, do nothing.-buildPaths :: StorePathSet -> BuildMode -> MonadStore ()-buildPaths ps bm = do- void $ simpleOpArgs BuildPaths $ do- putPaths ps- putInt $ fromEnum bm--buildDerivation- :: StorePath- -> Derivation StorePath Text- -> BuildMode- -> MonadStore BuildResult-buildDerivation p drv buildMode = do- runOpArgs BuildDerivation $ do- putPath p- putDerivation drv- putEnum buildMode- -- XXX: reason for this is unknown- -- but without it protocol just hangs waiting for- -- more data. Needs investigation.- -- Intentionally the only warning that should pop-up.- putInt (0 :: Integer)-- getSocketIncremental getBuildResult--ensurePath :: StorePath -> MonadStore ()-ensurePath pn = do- void $ simpleOpArgs EnsurePath $ putPath pn---- | Find garbage collector roots.-findRoots :: MonadStore (Map BSL.ByteString StorePath)-findRoots = do- runOp FindRoots- sd <- getStoreDir- res <-- getSocketIncremental- $ getMany- $ (,)- <$> (fromStrict <$> getByteStringLen)- <*> getPath sd-- r <- catRights res- pure $ Data.Map.Strict.fromList r- where- catRights :: [(a, Either String b)] -> MonadStore [(a, b)]- catRights = mapM ex-- ex :: (a, Either [Char] b) -> MonadStore (a, b)- ex (x , Right y) = pure (x, y)- ex (_x, Left e ) = error $ "Unable to decode root: " <> fromString e--isValidPathUncached :: StorePath -> MonadStore Bool-isValidPathUncached p = do- simpleOpArgs IsValidPath $ putPath p---- | Query valid paths from set, optionally try to use substitutes.-queryValidPaths- :: StorePathSet -- ^ Set of `StorePath`s to query- -> SubstituteFlag -- ^ Try substituting missing paths when `True`- -> MonadStore StorePathSet-queryValidPaths ps substitute = do- runOpArgs QueryValidPaths $ do- putPaths ps- putBool substitute- sockGetPaths--queryAllValidPaths :: MonadStore StorePathSet-queryAllValidPaths = do- runOp QueryAllValidPaths- sockGetPaths--querySubstitutablePaths :: StorePathSet -> MonadStore StorePathSet-querySubstitutablePaths ps = do- runOpArgs QuerySubstitutablePaths $ putPaths ps- sockGetPaths--queryPathInfoUncached :: StorePath -> MonadStore StorePathMetadata-queryPathInfoUncached path = do- runOpArgs QueryPathInfo $ do- putPath path-- valid <- sockGetBool- unless valid $ error "Path is not valid"-- deriverPath <- sockGetPathMay-- narHashText <- decodeUtf8 <$> sockGetStr- let- narHash =- case- decodeDigestWith @SHA256 NixBase32 narHashText- of- Left e -> error $ fromString e- Right x -> SomeDigest x-- references <- sockGetPaths- registrationTime <- sockGet getTime- narBytes <- Just <$> sockGetInt- ultimate <- sockGetBool-- _sigStrings <- fmap bsToText <$> sockGetStrings- caString <- sockGetStr-- let- -- XXX: signatures need pubkey from config- sigs = Data.Set.empty-- contentAddressableAddress =- case- System.Nix.Store.Remote.Parsers.parseContentAddressableAddress caString- of- Left e -> error $ fromString e- Right x -> Just x-- trust = if ultimate then BuiltLocally else BuiltElsewhere+-- * Compat - pure $ StorePathMetadata{..}+type MonadStore = RemoteStoreT IO -queryReferrers :: StorePath -> MonadStore StorePathSet-queryReferrers p = do- runOpArgs QueryReferrers $ putPath p- sockGetPaths+-- * Runners -queryValidDerivers :: StorePath -> MonadStore StorePathSet-queryValidDerivers p = do- runOpArgs QueryValidDerivers $ putPath p- sockGetPaths+runStore+ :: ( MonadIO m+ , MonadMask m+ )+ => RemoteStoreT m a+ -> Run m a+runStore = runStoreConnection def -queryDerivationOutputs :: StorePath -> MonadStore StorePathSet-queryDerivationOutputs p = do- runOpArgs QueryDerivationOutputs $ putPath p- sockGetPaths+runStoreConnection+ :: ( MonadIO m+ , MonadMask m+ )+ => StoreConnection+ -> RemoteStoreT m a+ -> Run m a+runStoreConnection sc k =+ connectionToSocket sc+ >>= \case+ Left e -> pure (Left e, mempty)+ Right (fam, sock) -> runStoreSocket fam sock k -queryDerivationOutputNames :: StorePath -> MonadStore StorePathSet-queryDerivationOutputNames p = do- runOpArgs QueryDerivationOutputNames $ putPath p- sockGetPaths+runStoreSocket+ :: ( MonadIO m+ , MonadMask m+ )+ => Family+ -> SockAddr+ -> RemoteStoreT m a+ -> Run m a+runStoreSocket sockFamily sockAddr code =+ Control.Monad.Catch.bracket+ (liftIO open)+ (liftIO . Network.Socket.close . hasStoreSocket)+ (\s -> runRemoteStoreT s $ greetServer >> code)+ where+ open = do+ soc <-+ Network.Socket.socket+ sockFamily+ Network.Socket.Stream+ Network.Socket.defaultProtocol+ Network.Socket.connect soc sockAddr+ pure soc -queryPathFromHashPart :: StorePathHashPart -> MonadStore StorePath-queryPathFromHashPart storePathHash = do- runOpArgs QueryPathFromHashPart- $ putByteStringLen- $ encodeUtf8 (encodeWith NixBase32 $ coerce storePathHash)- sockGetPath+justdoit :: Run IO (Bool, Bool)+justdoit = do+ runDaemonConnection runStore (pure ()) (StoreConnection_Socket "/tmp/dsock") $+ runStoreConnection (StoreConnection_Socket "/tmp/dsock")+ $ do+ a <- isValidPath pth+ b <- isValidPath pth+ pure (a, b)+ where+ pth :: StorePath+ pth =+ either (error . show) id+ $ System.Nix.StorePath.parsePathFromText+ def+ "/nix/store/yyznqbwam67cmp7zfwk0rkgmi9yqsdsm-hnix-store-core-0.8.0.0" -queryMissing- :: StorePathSet- -> MonadStore- ( StorePathSet-- Paths that will be built- , StorePathSet -- Paths that have substitutes- , StorePathSet -- Unknown paths- , Integer -- Download size- , Integer -- Nar size?- )-queryMissing ps = do- runOpArgs QueryMissing $ putPaths ps+runDaemon+ :: forall m a+ . ( MonadIO m+ , MonadConc m+ )+ => WorkerHelper m+ -> m a+ -> m a+runDaemon workerHelper =+ runDaemonConnection+ workerHelper+ (pure ())+ def - willBuild <- sockGetPaths- willSubstitute <- sockGetPaths- unknown <- sockGetPaths- downloadSize' <- sockGetInt- narSize' <- sockGetInt- pure (willBuild, willSubstitute, unknown, downloadSize', narSize')+-- | Run an emulated nix daemon using given @StoreConnection@+-- the deamon will close when the continuation returns.+runDaemonConnection+ :: forall m a+ . ( MonadIO m+ , MonadConc m+ )+ => WorkerHelper m+ -> RemoteStoreT m ()+ -> StoreConnection+ -> m a+ -> m a+runDaemonConnection workerHelper postGreet sc k =+ connectionToSocket sc+ >>= \case+ Left e -> error $ show e+ Right (fam, sock) -> runDaemonSocket workerHelper postGreet fam sock k -optimiseStore :: MonadStore ()-optimiseStore = void $ simpleOp OptimiseStore+-- | Run an emulated nix daemon using given @StoreConnection@+-- the deamon will close when the continuation returns.+runDaemonSocket+ :: forall m a+ . ( MonadIO m+ , MonadConc m+ )+ => WorkerHelper m+ -> RemoteStoreT m ()+ -> Family+ -> SockAddr+ -> m a+ -> m a+runDaemonSocket workerHelper postGreet sockFamily sockAddr k =+ Control.Monad.Catch.bracket+ (liftIO+ $ Network.Socket.socket+ sockFamily+ Network.Socket.Stream+ Network.Socket.defaultProtocol+ )+ (\lsock -> liftIO $ Network.Socket.close lsock)+ $ \lsock -> do+ -- TODO: the: (\lsock -> liftIO $ Network.Socket.close lsock *> System.Directory.removeFile f)+ -- branch should really be (and even removeFile is currently omitted)+ -- a file lock followed by unlink *before* bind rather than after close. If+ -- the program crashes (or loses power or something) then a stale unix+ -- socket will stick around and prevent the daemon from starting. using a+ -- lock file instead means only one "copy" of the daemon can hold the lock,+ -- and can safely unlink the socket before binding no matter how shutdown+ -- occured. -syncWithGC :: MonadStore ()-syncWithGC = void $ simpleOp SyncWithGC+ -- set up the listening socket+ liftIO $ Network.Socket.bind lsock sockAddr+ runProxyDaemon workerHelper postGreet lsock k --- returns True on errors-verifyStore :: CheckFlag -> RepairFlag -> MonadStore Bool-verifyStore check repair = simpleOpArgs VerifyStore $ do- putBool check- putBool repair+connectionToSocket+ :: MonadIO m+ => StoreConnection+ -> m (Either RemoteStoreError (Family, SockAddr))+connectionToSocket (StoreConnection_Socket (StoreSocketPath f)) =+ pure $ pure+ ( Network.Socket.AF_UNIX+ , SockAddrUnix f+ )+connectionToSocket (StoreConnection_TCP StoreTCP{..}) = do+ addrInfo <- liftIO $ Network.Socket.getAddrInfo+ (Just Network.Socket.defaultHints)+ (Just storeTCPHost)+ (Just $ show storeTCPPort)+ case addrInfo of+ (sockAddr:_) ->+ pure $ pure+ ( Network.Socket.addrFamily sockAddr+ , Network.Socket.addrAddress sockAddr+ )+ _ -> pure (Left RemoteStoreError_GetAddrInfoFailed)
+ src/System/Nix/Store/Remote/Arbitrary.hs view
@@ -0,0 +1,137 @@+-- due to recent generic-arbitrary+{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}+{-# OPTIONS_GHC -Wno-orphans #-}+module System.Nix.Store.Remote.Arbitrary where++import Data.Some (Some(Some))+import System.Nix.Arbitrary ()+import System.Nix.Store.Types (RepairMode(..))+import System.Nix.Store.Remote.Types++import Test.QuickCheck (Arbitrary(..), oneof, suchThat)+import Test.QuickCheck.Arbitrary.Generic (GenericArbitrary(..))++deriving via GenericArbitrary CheckMode+ instance Arbitrary CheckMode++deriving via GenericArbitrary SubstituteMode+ instance Arbitrary SubstituteMode++deriving via GenericArbitrary ProtoStoreConfig+ instance Arbitrary ProtoStoreConfig++deriving via GenericArbitrary ProtoVersion+ instance Arbitrary ProtoVersion++deriving via GenericArbitrary StoreText+ instance Arbitrary StoreText++-- * Logger++deriving via GenericArbitrary Activity+ instance Arbitrary Activity++deriving via GenericArbitrary ActivityID+ instance Arbitrary ActivityID++deriving via GenericArbitrary ActivityResult+ instance Arbitrary ActivityResult++deriving via GenericArbitrary Field+ instance Arbitrary Field++instance Arbitrary Trace where+ arbitrary = do+ -- we encode 0 position as Nothing+ tracePosition <- arbitrary `suchThat` (/= Just 0)+ traceHint <- arbitrary++ pure Trace{..}++deriving via GenericArbitrary BasicError+ instance Arbitrary BasicError++instance Arbitrary ErrorInfo where+ arbitrary = do+ errorInfoLevel <- arbitrary+ errorInfoMessage <- arbitrary+ -- we encode 0 position as Nothing+ errorInfoPosition <- arbitrary `suchThat` (/= Just 0)+ errorInfoTraces <- arbitrary++ pure ErrorInfo{..}++deriving via GenericArbitrary LoggerOpCode+ instance Arbitrary LoggerOpCode++deriving via GenericArbitrary Logger+ instance Arbitrary Logger++deriving via GenericArbitrary Verbosity+ instance Arbitrary Verbosity++-- * GC++deriving via GenericArbitrary GCAction+ instance Arbitrary GCAction++deriving via GenericArbitrary GCOptions+ instance Arbitrary GCOptions++-- * Handshake++deriving via GenericArbitrary WorkerMagic+ instance Arbitrary WorkerMagic++deriving via GenericArbitrary TrustedFlag+ instance Arbitrary TrustedFlag++-- * Worker protocol++deriving via GenericArbitrary WorkerOp+ instance Arbitrary WorkerOp++-- ** Request++instance Arbitrary (Some StoreRequest) where+ arbitrary = oneof+ [ Some <$> (AddToStore <$> arbitrary <*> arbitrary <*> arbitrary <*> pure RepairMode_DontRepair)+ , Some <$> (AddTextToStore <$> arbitrary <*> arbitrary <*> pure RepairMode_DontRepair)+ , Some <$> (AddSignatures <$> arbitrary <*> arbitrary)+ , Some . AddIndirectRoot <$> arbitrary+ , Some . AddTempRoot <$> arbitrary+ , Some <$> (BuildPaths <$> arbitrary <*> arbitrary)+ , Some <$> (BuildDerivation <$> arbitrary <*> arbitrary <*> arbitrary)+ , Some . CollectGarbage <$> arbitrary+ , Some . EnsurePath <$> arbitrary+ , pure $ Some FindRoots+ , Some . IsValidPath <$> arbitrary+ , Some . NarFromPath <$> arbitrary+ , Some <$> (QueryValidPaths <$> arbitrary <*> arbitrary)+ , pure $ Some QueryAllValidPaths+ , Some . QuerySubstitutablePaths <$> arbitrary+ , Some . QueryPathInfo <$> arbitrary+ , Some . QueryReferrers <$> arbitrary+ , Some . QueryValidDerivers <$> arbitrary+ , Some . QueryDerivationOutputs <$> arbitrary+ , Some . QueryDerivationOutputNames <$> arbitrary+ , Some . QueryPathFromHashPart <$> arbitrary+ , Some . QueryMissing <$> arbitrary+ , pure $ Some OptimiseStore+ , pure $ Some SyncWithGC+ , Some <$> (VerifyStore <$> arbitrary <*> arbitrary)+ ]++-- ** Reply++deriving via GenericArbitrary SuccessCodeReply+ instance Arbitrary SuccessCodeReply++deriving via GenericArbitrary GCResult+ instance Arbitrary GCResult++deriving via GenericArbitrary GCRoot+ instance Arbitrary GCRoot++deriving via GenericArbitrary Missing+ instance Arbitrary Missing
− src/System/Nix/Store/Remote/Binary.hs
@@ -1,52 +0,0 @@-{-|-Description : Utilities for packing stuff-Maintainer : srk <srk@48.io>-|-}-module System.Nix.Store.Remote.Binary where--import Data.Binary.Get-import Data.Binary.Put-import qualified Data.ByteString.Lazy as BSL--putInt :: Integral a => a -> Put-putInt = putWord64le . fromIntegral--getInt :: Integral a => Get a-getInt = fromIntegral <$> getWord64le--putMany :: Foldable t => (a -> Put) -> t a -> Put-putMany printer xs = do- putInt (length xs)- mapM_ printer xs--getMany :: Get a -> Get [a]-getMany parser = do- count <- getInt- replicateM count parser---- length prefixed string packing with padding to 8 bytes-putByteStringLen :: BSL.ByteString -> Put-putByteStringLen x = do- putInt len- putLazyByteString x- when (len `mod` 8 /= 0) $ pad $ 8 - (len `mod` 8)- where- len :: Int- len = fromIntegral $ BSL.length x- pad count = replicateM_ count (putWord8 0)--putByteStrings :: Foldable t => t BSL.ByteString -> Put-putByteStrings = putMany putByteStringLen--getByteStringLen :: Get ByteString-getByteStringLen = do- len <- getInt- st <- getLazyByteString len- when (len `mod` 8 /= 0) $ do- pads <- unpad $ fromIntegral $ 8 - (len `mod` 8)- unless (all (== 0) pads) $ fail $ "No zeroes" <> show (st, len, pads)- pure $ toStrict st- where unpad x = replicateM x getWord8--getByteStrings :: Get [ByteString]-getByteStrings = getMany getByteStringLen
− src/System/Nix/Store/Remote/Builders.hs
@@ -1,36 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ScopedTypeVariables #-}-{-# language RankNTypes #-}--module System.Nix.Store.Remote.Builders- ( buildContentAddressableAddress- )-where--import qualified Data.Text.Lazy as TL-import Crypto.Hash ( Digest )-import System.Nix.StorePath ( ContentAddressableAddress(..)- )--import Data.Text.Lazy.Builder ( Builder )-import qualified Data.Text.Lazy.Builder as TL--import System.Nix.Hash---- | Marshall `ContentAddressableAddress` to `Text`--- in form suitable for remote protocol usage.-buildContentAddressableAddress :: ContentAddressableAddress -> TL.Text-buildContentAddressableAddress =- TL.toLazyText . contentAddressableAddressBuilder--contentAddressableAddressBuilder :: ContentAddressableAddress -> Builder-contentAddressableAddressBuilder (Text digest) =- "text:" <> digestBuilder digest-contentAddressableAddressBuilder (Fixed _narHashMode (SomeDigest (digest :: Digest hashAlgo))) =- "fixed:"- <> TL.fromText (System.Nix.Hash.algoName @hashAlgo)- <> digestBuilder digest--digestBuilder :: Digest a -> Builder-digestBuilder =- TL.fromText . encodeDigestWith NixBase32
+ src/System/Nix/Store/Remote/Client.hs view
@@ -0,0 +1,279 @@+module System.Nix.Store.Remote.Client+ ( addToStore+ , addToStoreNar+ , addTextToStore+ , addSignatures+ , addTempRoot+ , addIndirectRoot+ , buildPaths+ , buildDerivation+ , collectGarbage+ , ensurePath+ , findRoots+ , isValidPath+ , narFromPath+ , queryValidPaths+ , queryAllValidPaths+ , querySubstitutablePaths+ , queryPathInfo+ , queryReferrers+ , queryValidDerivers+ , queryDerivationOutputs+ , queryDerivationOutputNames+ , queryPathFromHashPart+ , queryMissing+ , optimiseStore+ , syncWithGC+ , verifyStore+ , module System.Nix.Store.Remote.Client.Core+ ) where++import Control.Monad (void, when)+import Control.Monad.Except (throwError)+import Data.ByteString (ByteString)+import Data.HashSet (HashSet)+import Data.Map (Map)+import Data.Set (Set)+import Data.Some (Some)+import Data.Word (Word64)++import System.Nix.Build (BuildMode, BuildResult)+import System.Nix.DerivedPath (DerivedPath)+import System.Nix.Hash (HashAlgo(..))+import System.Nix.Nar (NarSource)+import System.Nix.Signature (Signature)+import System.Nix.StorePath (StorePath, StorePathHashPart, StorePathName)+import System.Nix.StorePath.Metadata (Metadata)+import System.Nix.Store.Remote.MonadStore+import System.Nix.Store.Remote.Types.GC (GCOptions, GCResult, GCRoot)+import System.Nix.Store.Remote.Types.CheckMode (CheckMode)+import System.Nix.Store.Remote.Types.Query.Missing (Missing)+import System.Nix.Store.Remote.Types.StoreRequest (StoreRequest(..))+import System.Nix.Store.Remote.Types.StoreText (StoreText)+import System.Nix.Store.Remote.Types.SubstituteMode (SubstituteMode)+import System.Nix.Store.Remote.Client.Core+import System.Nix.Store.Types (FileIngestionMethod(..), RepairMode(..))++import qualified Control.Monad.IO.Class+import qualified Data.Attoparsec.Text+import qualified Data.Text.IO+import qualified System.Nix.Derivation+import qualified System.Nix.StorePath++-- | Add `NarSource` to the store+addToStore+ :: MonadRemoteStore m+ => StorePathName -- ^ Name part of the newly created `StorePath`+ -> NarSource IO -- ^ Provide nar stream+ -> FileIngestionMethod -- ^ Add target directory recursively+ -> Some HashAlgo -- ^+ -> RepairMode -- ^ Only used by local store backend+ -> m StorePath+addToStore name source method hashAlgo repair = do+ Control.Monad.when+ (repair == RepairMode_DoRepair)+ $ throwError RemoteStoreError_RapairNotSupportedByRemoteStore++ setNarSource source+ doReq (AddToStore name method hashAlgo repair)++addToStoreNar+ :: MonadRemoteStore m+ => StorePath+ -> Metadata StorePath+ -> RepairMode+ -> CheckMode+ -> (Word64 -> IO(Maybe ByteString))+ -> m ()+addToStoreNar path metadata repair checkSigs source = do+ setDataSource source+ void $ doReq (AddToStoreNar path metadata repair checkSigs)+ pure ()++-- | Add @StoreText@ to the store+-- Reference accepts repair but only uses it+-- to throw error in case of remote talking to nix-daemon.+addTextToStore+ :: MonadRemoteStore m+ => StoreText+ -> HashSet StorePath -- ^ Set of `StorePath`s that the added text references+ -> RepairMode -- ^ Repair mode, must be `RepairMode_DontRepair` for remote backend+ -- (only valid for local store)+ -> m StorePath+addTextToStore stext references repair = do+ Control.Monad.when+ (repair == RepairMode_DoRepair)+ $ throwError RemoteStoreError_RapairNotSupportedByRemoteStore++ doReq (AddTextToStore stext references repair)++-- | Add @Signature@s to a store path+addSignatures+ :: MonadRemoteStore m+ => StorePath+ -> Set Signature+ -> m ()+addSignatures p signatures = (void . doReq) (AddSignatures p signatures)++-- | Add temporary garbage collector root.+--+-- This root is removed as soon as the client exits.+addTempRoot+ :: MonadRemoteStore m+ => StorePath+ -> m ()+addTempRoot = void . doReq . AddTempRoot++-- | Add indirect garbage collector root.+addIndirectRoot+ :: MonadRemoteStore m+ => StorePath+ -> m ()+addIndirectRoot = void . doReq . AddIndirectRoot++-- | Build a derivation available at @StorePath@+buildDerivation+ :: MonadRemoteStore m+ => StorePath+ -> BuildMode+ -> m BuildResult+buildDerivation sp mode = do+ sd <- getStoreDir+ drvContents <-+ Control.Monad.IO.Class.liftIO+ $ Data.Text.IO.readFile+ $ System.Nix.StorePath.storePathToFilePath sd sp+ case Data.Attoparsec.Text.parseOnly+ (System.Nix.Derivation.parseDerivation sd) drvContents of+ Left e -> throwError $ RemoteStoreError_DerivationParse e+ Right drv -> doReq (BuildDerivation sp drv mode)++-- | Build paths if they are an actual derivations.+--+-- If derivation output paths are already valid, do nothing.+buildPaths+ :: MonadRemoteStore m+ => Set DerivedPath+ -> BuildMode+ -> m ()+buildPaths a b = (void . doReq) (BuildPaths a b)++collectGarbage+ :: MonadRemoteStore m+ => GCOptions+ -> m GCResult+collectGarbage = doReq . CollectGarbage++ensurePath+ :: MonadRemoteStore m+ => StorePath+ -> m ()+ensurePath = void . doReq . EnsurePath++-- | Find garbage collector roots.+findRoots+ :: MonadRemoteStore m+ => m (Map GCRoot StorePath)+findRoots = doReq FindRoots++isValidPath+ :: MonadRemoteStore m+ => StorePath+ -> m Bool+isValidPath = doReq . IsValidPath++-- | Download a NAR file.+narFromPath+ :: MonadRemoteStore m+ => StorePath -- ^ Path to generate a NAR for+ -> Word64 -- ^ Byte length of NAR+ -> (ByteString -> IO()) -- ^ Data sink where NAR bytes will be written+ -> m ()+narFromPath path narSize sink = do+ setDataSink sink+ setDataSinkSize narSize+ void $ doReq (NarFromPath path)++-- | Query valid paths from a set,+-- optionally try to use substitutes+queryValidPaths+ :: MonadRemoteStore m+ => HashSet StorePath+ -- ^ Set of @StorePath@s to query+ -> SubstituteMode+ -- ^ Try substituting missing paths when @SubstituteMode_DoSubstitute@+ -> m (HashSet StorePath)+queryValidPaths a b = doReq (QueryValidPaths a b)++-- | Query all valid paths+queryAllValidPaths+ :: MonadRemoteStore m+ => m (HashSet StorePath)+queryAllValidPaths = doReq QueryAllValidPaths++-- | Query a set of paths substituable from caches+querySubstitutablePaths+ :: MonadRemoteStore m+ => HashSet StorePath+ -> m (HashSet StorePath)+querySubstitutablePaths = doReq . QuerySubstitutablePaths++-- | Query path metadata+queryPathInfo+ :: MonadRemoteStore m+ => StorePath+ -> m (Maybe (Metadata StorePath))+queryPathInfo = doReq . QueryPathInfo++queryReferrers+ :: MonadRemoteStore m+ => StorePath+ -> m (HashSet StorePath)+queryReferrers = doReq . QueryReferrers++queryValidDerivers+ :: MonadRemoteStore m+ => StorePath+ -> m (HashSet StorePath)+queryValidDerivers = doReq . QueryValidDerivers++queryDerivationOutputs+ :: MonadRemoteStore m+ => StorePath+ -> m (HashSet StorePath)+queryDerivationOutputs = doReq . QueryDerivationOutputs++queryDerivationOutputNames+ :: MonadRemoteStore m+ => StorePath+ -> m (HashSet StorePathName)+queryDerivationOutputNames = doReq . QueryDerivationOutputNames++queryPathFromHashPart+ :: MonadRemoteStore m+ => StorePathHashPart+ -> m StorePath+queryPathFromHashPart = doReq . QueryPathFromHashPart++queryMissing+ :: MonadRemoteStore m+ => Set DerivedPath+ -> m Missing+queryMissing = doReq . QueryMissing++optimiseStore+ :: MonadRemoteStore m+ => m ()+optimiseStore = (void . doReq) OptimiseStore++syncWithGC+ :: MonadRemoteStore m+ => m ()+syncWithGC = (void . doReq) SyncWithGC++verifyStore+ :: MonadRemoteStore m+ => CheckMode+ -> RepairMode+ -> m Bool+verifyStore check repair = doReq (VerifyStore check repair)
+ src/System/Nix/Store/Remote/Client/Core.hs view
@@ -0,0 +1,229 @@+module System.Nix.Store.Remote.Client.Core+ ( Run+ , greetServer+ , doReq+ ) where++import Control.Monad (unless, when)+import Control.Monad.Except (throwError)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.ByteString (ByteString)+import Data.DList (DList)+import Data.Some (Some(Some))+import Data.Word (Word64)+import Network.Socket (Socket)+import System.Nix.Nar (NarSource)+import System.Nix.StorePath.Metadata (Metadata(..))+import System.Nix.Store.Remote.Logger (processOutput)+import System.Nix.Store.Remote.MonadStore+ ( MonadRemoteStore(..)+ , RemoteStoreError(..)+ )+import System.Nix.Store.Remote.Socket (sockPutS, sockGetS)+import System.Nix.Store.Remote.Serializer+ ( bool+ , int+ , mapErrorS+ , protoVersion+ , storeRequest+ , text+ , trustedFlag+ , workerMagic+ )+import System.Nix.Store.Remote.Types.Handshake (ClientHandshakeOutput(..))+import System.Nix.Store.Remote.Types.Logger (Logger)+import System.Nix.Store.Remote.Types.NoReply (NoReply(..))+import System.Nix.Store.Remote.Types.ProtoVersion (ProtoVersion(..))+import System.Nix.Store.Remote.Types.StoreRequest (StoreRequest(..))+import System.Nix.Store.Remote.Types.StoreReply (StoreReply(..))+import System.Nix.Store.Remote.Types.WorkerMagic (WorkerMagic(..))++import qualified Data.ByteString+import qualified Network.Socket.ByteString++type Run m a = m (Either RemoteStoreError a, DList Logger)++-- | Perform @StoreRequest@+doReq+ :: forall m a+ . ( MonadIO m+ , MonadRemoteStore m+ , StoreReply a+ , Show a+ )+ => StoreRequest a+ -> m a+doReq = \case+ x -> do+ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerRequest+ storeRequest+ )+ (Some x)++ case x of+ AddToStore {} -> do++ ms <- takeNarSource+ case ms of+ Just (stream :: NarSource IO) -> do+ soc <- getStoreSocket+ liftIO+ $ stream+ $ Network.Socket.ByteString.sendAll soc+ Nothing ->+ throwError+ RemoteStoreError_NoNarSourceProvided+ processOutput+ processReply++ AddToStoreNar _ meta _ _ -> do+ let narBytes = maybe 0 id $ metadataNarBytes meta+ maybeDataSource <- takeDataSource+ soc <- getStoreSocket+ case maybeDataSource of+ Nothing ->+ if narBytes == 0 then writeFramedSource (const (pure Nothing)) soc 0+ else throwError RemoteStoreError_NoDataSourceProvided+ Just dataSource -> do+ writeFramedSource dataSource soc narBytes+ processOutput+ pure NoReply++ NarFromPath _ -> do+ maybeSink <- getDataSink+ sink <- case maybeSink of+ Nothing -> throwError RemoteStoreError_NoDataSinkProvided+ Just sink -> pure sink+ clearDataSink+ maybeNarSize <- getDataSinkSize+ narSize <- case maybeNarSize of+ Nothing -> throwError RemoteStoreError_NoDataSinkSizeProvided+ Just narSize -> pure narSize+ clearDataSinkSize+ soc <- getStoreSocket+ processOutput+ copyToSink sink narSize soc+ pure NoReply++ _ -> do+ processOutput+ processReply++ where+ processReply = sockGetS+ (mapErrorS RemoteStoreError_SerializerReply+ $ getReplyS @a+ )++copyToSink+ :: forall m+ . ( MonadIO m+ , MonadRemoteStore m+ )+ => (ByteString -> IO()) -- ^ data sink+ -> Word64 -- ^ byte length to read+ -> Socket+ -> m ()+copyToSink sink remainingBytes soc =+ when (remainingBytes > 0) $ do+ let chunkSize = 16384+ bytesToRead = min chunkSize remainingBytes+ bytes <- liftIO $ Network.Socket.ByteString.recv soc (fromIntegral bytesToRead)+ liftIO $ sink bytes+ let nextRemainingBytes = remainingBytes - (fromIntegral . Data.ByteString.length) bytes+ copyToSink sink nextRemainingBytes soc++writeFramedSource+ :: forall m+ . ( MonadIO m+ , MonadRemoteStore m+ )+ => (Word64 -> IO(Maybe ByteString))+ -> Socket+ -> Word64+ -> m ()+writeFramedSource dataSource soc remainingBytes = do+ let chunkSize = 16384+ maybeBytes <- liftIO $ dataSource chunkSize+ case maybeBytes of+ Nothing -> do+ unless (remainingBytes == 0) $ throwError RemoteStoreError_DataSourceExhausted+ let eof :: Word64 = 0+ sockPutS int eof+ Just bytes -> do+ let bytesInChunk = fromIntegral $ Data.ByteString.length bytes+ when (bytesInChunk > chunkSize || bytesInChunk > remainingBytes) $ throwError RemoteStoreError_DataSourceReadTooLarge+ when (bytesInChunk == 0) $ throwError RemoteStoreError_DataSourceZeroLengthRead+ sockPutS int bytesInChunk+ liftIO+ $ Network.Socket.ByteString.sendAll soc bytes+ let nextRemainingBytes = remainingBytes - bytesInChunk+ writeFramedSource dataSource soc nextRemainingBytes++greetServer+ :: MonadRemoteStore m+ => m ClientHandshakeOutput+greetServer = do+ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerHandshake+ workerMagic+ )+ WorkerMagic_One++ magic <-+ sockGetS+ $ mapErrorS+ RemoteStoreError_SerializerHandshake+ workerMagic++ unless+ (magic == WorkerMagic_Two)+ $ throwError RemoteStoreError_WorkerMagic2Mismatch++ daemonVersion <- sockGetS protoVersion++ when (daemonVersion < ProtoVersion 1 10)+ $ throwError RemoteStoreError_ClientVersionTooOld++ pv <- getProtoVersion+ sockPutS protoVersion pv++ let leastCommonVersion = min daemonVersion pv++ when (leastCommonVersion >= ProtoVersion 1 14)+ $ sockPutS int (0 :: Int) -- affinity, obsolete++ when (leastCommonVersion >= ProtoVersion 1 11) $ do+ sockPutS+ (mapErrorS RemoteStoreError_SerializerPut bool)+ False -- reserveSpace, obsolete++ daemonNixVersion <- if leastCommonVersion >= ProtoVersion 1 33+ then do+ -- If we were buffering I/O, we would flush the output here.+ txtVer <-+ sockGetS+ $ mapErrorS+ RemoteStoreError_SerializerGet+ text+ pure $ Just txtVer+ else pure Nothing++ remoteTrustsUs <- if leastCommonVersion >= ProtoVersion 1 35+ then do+ sockGetS+ $ mapErrorS RemoteStoreError_SerializerHandshake trustedFlag+ else pure Nothing++ setProtoVersion leastCommonVersion+ processOutput++ pure ClientHandshakeOutput+ { clientHandshakeOutputNixVersion = daemonNixVersion+ , clientHandshakeOutputTrust = remoteTrustsUs+ , clientHandshakeOutputLeastCommonVersion = leastCommonVersion+ , clientHandshakeOutputServerVersion = daemonVersion+ }
src/System/Nix/Store/Remote/Logger.hs view
@@ -1,86 +1,100 @@-{-# language RankNTypes #-}- module System.Nix.Store.Remote.Logger- ( Logger(..)- , Field(..)- , processOutput- )-where+ ( processOutput+ ) where +import Control.Monad.Except (throwError)+import Control.Monad.IO.Class (liftIO)+import Data.ByteString (ByteString)+import Data.Serialize (Result(..))+import System.Nix.Store.Remote.Serializer (LoggerSError, logger, runSerialT)+import System.Nix.Store.Remote.Socket (sockGet8)+import System.Nix.Store.Remote.MonadStore (MonadRemoteStore, RemoteStoreError(..), appendLog, getDataSource, getDataSink, getStoreSocket, getProtoVersion)+import System.Nix.Store.Remote.Types.Logger (Logger(..))+import System.Nix.Store.Remote.Types.ProtoVersion (ProtoVersion) -import Prelude hiding ( Last )-import Control.Monad.Except ( throwError )-import Data.Binary.Get+import qualified Control.Monad+import qualified Data.Serialize.Get+import qualified Data.Serializer+import qualified Network.Socket.ByteString -import Network.Socket.ByteString ( recv )+processOutput+ :: MonadRemoteStore m+ => m ()+processOutput = do+ protoVersion <- getProtoVersion+ sockGet8 >>= go . (decoder protoVersion)+ where+ decoder+ :: ProtoVersion+ -> ByteString+ -> Result (Either LoggerSError Logger)+ decoder protoVersion =+ Data.Serialize.Get.runGetPartial+ (runSerialT protoVersion $ Data.Serializer.getS logger) -import System.Nix.Store.Remote.Binary-import System.Nix.Store.Remote.Types-import System.Nix.Store.Remote.Util+ go+ :: MonadRemoteStore m+ => Result (Either LoggerSError Logger)+ -> m ()+ go (Done ectrl leftover) = do+ let loop = do+ protoVersion <- getProtoVersion+ sockGet8 >>= go . (decoder protoVersion) + Control.Monad.unless (leftover == mempty) $+ throwError+ $ RemoteStoreError_LoggerLeftovers+ (show ectrl)+ leftover -controlParser :: Get Logger-controlParser = do- ctrl <- getInt- case (ctrl :: Int) of- 0x6f6c6d67 -> Next <$> getByteStringLen- 0x64617461 -> Read <$> getInt- 0x64617416 -> Write <$> getByteStringLen- 0x616c7473 -> pure Last- 0x63787470 -> flip Error <$> getByteStringLen- <*> getInt- 0x53545254 -> StartActivity <$> getInt- <*> getInt- <*> getInt- <*> getByteStringLen- <*> getFields- <*> getInt- 0x53544f50 -> StopActivity <$> getInt- 0x52534c54 -> Result <$> getInt- <*> getInt- <*> getFields- x -> fail $ "Invalid control message received:" <> show x+ case ectrl of+ Left e -> throwError $ RemoteStoreError_SerializerLogger e+ Right ctrl -> do+ case ctrl of+ -- These two terminate the logger loop+ Logger_Error e -> throwError $ RemoteStoreError_LoggerError e+ Logger_Last -> appendLog Logger_Last -processOutput :: MonadStore [Logger]-processOutput = go decoder- where- decoder = runGetIncremental controlParser- go :: Decoder Logger -> MonadStore [Logger]- go (Done _leftover _consumed ctrl) = do- case ctrl of- e@(Error _ _) -> pure [e]- Last -> pure [Last]- Read _n -> do- (mdata, _) <- get- case mdata of- Nothing -> throwError "No data to read provided"- Just part -> do- -- XXX: we should check/assert part size against n of (Read n)- sockPut $ putByteStringLen part- clearData+ -- Read data from source+ Logger_Read size -> do+ mSource <- getDataSource+ case mSource of+ Nothing ->+ throwError RemoteStoreError_NoDataSourceProvided+ Just source -> do+ mChunk <- liftIO $ source size+ case mChunk of+ Nothing -> throwError RemoteStoreError_DataSourceExhausted+ Just chunk -> do+ sock <- getStoreSocket+ liftIO $ Network.Socket.ByteString.sendAll sock chunk - go decoder+ loop - -- we should probably handle Read here as well- x -> do- next <- go decoder- pure $ x : next- go (Partial k) = do- soc <- asks storeSocket- chunk <- liftIO (Just <$> recv soc 8)- go (k chunk)+ -- Write data to sink+ Logger_Write out -> do+ mSink <- getDataSink+ case mSink of+ Nothing ->+ throwError RemoteStoreError_NoDataSinkProvided+ Just sink -> do+ liftIO $ sink out - go (Fail _leftover _consumed msg) = error $ fromString msg+ loop -getFields :: Get [Field]-getFields = do- cnt <- getInt- replicateM cnt getField+ -- Following we just append and loop+ -- but listed here explicitely for posterity+ x@(Logger_Next _) -> appendLog x >> loop+ x@(Logger_StartActivity {}) -> appendLog x >> loop+ x@(Logger_StopActivity {}) -> appendLog x >> loop+ x@(Logger_Result {}) -> appendLog x >> loop -getField :: Get Field-getField = do- typ <- getInt- case (typ :: Int) of- 0 -> LogInt <$> getInt- 1 -> LogStr <$> getByteStringLen- x -> fail $ "Unknown log type: " <> show x+ go (Partial k) = do+ chunk <- sockGet8+ go (k chunk)++ go (Fail msg leftover) =+ throwError+ $ RemoteStoreError_LoggerParserFail+ msg+ leftover
+ src/System/Nix/Store/Remote/MonadStore.hs view
@@ -0,0 +1,390 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module System.Nix.Store.Remote.MonadStore+ ( RemoteStoreState(..)+ , RemoteStoreError(..)+ , WorkerError(..)+ , WorkerException(..)+ , RemoteStoreT+ , runRemoteStoreT+ , MonadRemoteStore(..)+ ) where++import Control.Exception (SomeException)+import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)+import Control.Monad.Except (MonadError)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Reader (MonadReader, ask)+import Control.Monad.State.Strict (get, gets, modify)+import Control.Monad.Trans (MonadTrans, lift)+import Control.Monad.Trans.State.Strict (StateT, runStateT)+import Control.Monad.Trans.Except (ExceptT, runExceptT)+import Control.Monad.Trans.Reader (ReaderT, runReaderT)+import Data.ByteString (ByteString)+import Data.Default.Class (Default(def))+import Data.DList (DList)+import Data.Word (Word64)+import Network.Socket (Socket)+import System.Nix.Nar (NarSource)+import System.Nix.StorePath (HasStoreDir(..), StoreDir)+import System.Nix.Store.Remote.Serializer (HandshakeSError, LoggerSError, RequestSError, ReplySError, SError)+import System.Nix.Store.Remote.Types.Logger (Logger, BasicError, ErrorInfo)+import System.Nix.Store.Remote.Types.ProtoVersion (HasProtoVersion(..), ProtoVersion)+import System.Nix.Store.Remote.Types.StoreConfig (ProtoStoreConfig(..))++import qualified Data.DList++data RemoteStoreState = RemoteStoreState {+ remoteStoreStateConfig :: ProtoStoreConfig+ , remoteStoreStateLogs :: DList Logger+ , remoteStoreStateMDataSource :: Maybe (Word64 -> IO (Maybe ByteString))+ -- ^ Source for @Logger_Read@, this will be called repeatedly+ -- as the daemon requests chunks of size @Word64@.+ -- If the function returns Nothing and daemon tries to read more+ -- data an error is thrown.+ -- Used by @AddToStoreNar@ and @ImportPaths@ operations.+ , remoteStoreStateMDataSink :: Maybe (ByteString -> IO ())+ -- ^ Sink for @Logger_Write@, called repeatedly by the daemon+ -- to dump us some data. Used by @ExportPath@ operation.+ , remoteStoreStateMDataSinkSize :: Maybe Word64+ -- ^ Byte length to be written to the sink, for NarForPath+ , remoteStoreStateMNarSource :: Maybe (NarSource IO)+ }++instance HasStoreDir RemoteStoreState where+ hasStoreDir = hasStoreDir . remoteStoreStateConfig++instance HasProtoVersion RemoteStoreState where+ hasProtoVersion = hasProtoVersion . remoteStoreStateConfig++data RemoteStoreError+ = RemoteStoreError_Fixme String+ | RemoteStoreError_BuildFailed+ | RemoteStoreError_ClientVersionTooOld+ | RemoteStoreError_DerivationParse String+ | RemoteStoreError_Disconnected+ | RemoteStoreError_GetAddrInfoFailed+ | RemoteStoreError_GenericIncrementalLeftovers String ByteString -- when there are bytes left over after genericIncremental parser is done, (Done x leftover), first param is show x+ | RemoteStoreError_GenericIncrementalFail String ByteString -- when genericIncremental parser returns ((Fail msg leftover) :: Result)+ | RemoteStoreError_SerializerGet SError+ | RemoteStoreError_SerializerHandshake HandshakeSError+ | RemoteStoreError_SerializerLogger LoggerSError+ | RemoteStoreError_SerializerPut SError+ | RemoteStoreError_SerializerRequest RequestSError+ | RemoteStoreError_SerializerReply ReplySError+ | RemoteStoreError_IOException SomeException+ | RemoteStoreError_LoggerError (Either BasicError ErrorInfo)+ | RemoteStoreError_LoggerLeftovers String ByteString -- when there are bytes left over after incremental logger parser is done, (Done x leftover), first param is show x+ | RemoteStoreError_LoggerParserFail String ByteString -- when incremental parser returns ((Fail msg leftover) :: Result)+ | RemoteStoreError_NoDataSourceProvided -- remoteStoreStateMDataSource is required but it is Nothing+ | RemoteStoreError_DataSourceExhausted -- remoteStoreStateMDataSource returned Nothing but more data was requested+ | RemoteStoreError_DataSourceZeroLengthRead -- remoteStoreStateMDataSource returned a zero length ByteString+ | RemoteStoreError_DataSourceReadTooLarge -- remoteStoreStateMDataSource returned a ByteString larger than the chunk size requested or the remaining bytes+ | RemoteStoreError_NoDataSinkProvided -- remoteStoreStateMDataSink is required but it is Nothing+ | RemoteStoreError_NoDataSinkSizeProvided -- remoteStoreStateMDataSinkSize is required but it is Nothing+ | RemoteStoreError_NoNarSourceProvided+ | RemoteStoreError_OperationFailed+ | RemoteStoreError_ProtocolMismatch+ | RemoteStoreError_RapairNotSupportedByRemoteStore -- "repairing is not supported when building through the Nix daemon"+ | RemoteStoreError_WorkerMagic2Mismatch+ | RemoteStoreError_WorkerError WorkerError+ -- bad / redundant+ | RemoteStoreError_WorkerException WorkerException+ deriving Show++-- | fatal error in worker interaction which should disconnect client.+data WorkerException+ = WorkerException_ClientVersionTooOld+ | WorkerException_ProtocolMismatch+ | WorkerException_Error WorkerError+ -- ^ allowed error outside allowed worker state+-- | WorkerException_DecodingError DecodingError+-- | WorkerException_BuildFailed StorePath+ deriving (Eq, Ord, Show)++-- | Non-fatal (to server) errors in worker interaction+data WorkerError+ = WorkerError_SendClosed+ | WorkerError_InvalidOperation Word64+ | WorkerError_NotYetImplemented+ | WorkerError_UnsupportedOperation+ deriving (Eq, Ord, Show)++newtype RemoteStoreT m a = RemoteStoreT+ { _unRemoteStoreT+ :: ExceptT RemoteStoreError+ (StateT RemoteStoreState+ (ReaderT Socket m)) a+ }+ deriving+ ( Functor+ , Applicative+ , Monad+ , MonadReader Socket+ --, MonadState StoreState -- Avoid making the internal state explicit+ , MonadError RemoteStoreError+ , MonadCatch+ , MonadMask+ , MonadThrow+ , MonadIO+ )++instance MonadTrans RemoteStoreT where+ lift = RemoteStoreT . lift . lift . lift++-- | Runner for @RemoteStoreT@+runRemoteStoreT+ :: Monad m+ => Socket+ -> RemoteStoreT m a+ -> m (Either RemoteStoreError a, DList Logger)+runRemoteStoreT sock =+ fmap (\(res, RemoteStoreState{..}) -> (res, remoteStoreStateLogs))+ . (`runReaderT` sock)+ . (`runStateT` emptyState)+ . runExceptT+ . _unRemoteStoreT+ where+ emptyState = RemoteStoreState+ { remoteStoreStateConfig = def+ , remoteStoreStateLogs = mempty+ , remoteStoreStateMDataSource = Nothing+ , remoteStoreStateMDataSink = Nothing+ , remoteStoreStateMDataSinkSize = Nothing+ , remoteStoreStateMNarSource = Nothing+ }++class ( MonadIO m+ , MonadError RemoteStoreError m+ )+ => MonadRemoteStore m where++ appendLog :: Logger -> m ()+ default appendLog+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => Logger+ -> m ()+ appendLog = lift . appendLog++ getConfig :: m ProtoStoreConfig+ default getConfig+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m ProtoStoreConfig+ getConfig = lift getConfig++ getStoreDir :: m StoreDir+ default getStoreDir+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m StoreDir+ getStoreDir = lift getStoreDir++ setStoreDir :: StoreDir -> m ()+ default setStoreDir+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => StoreDir+ -> m ()+ setStoreDir = lift . setStoreDir++ -- | Get @ProtoVersion@ from state+ getProtoVersion :: m ProtoVersion+ default getProtoVersion+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m ProtoVersion+ getProtoVersion = lift getProtoVersion++ setProtoVersion :: ProtoVersion -> m ()+ default setProtoVersion+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => ProtoVersion+ -> m ()+ setProtoVersion = lift . setProtoVersion++ getStoreSocket :: m Socket+ default getStoreSocket+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m Socket+ getStoreSocket = lift getStoreSocket++ setNarSource :: NarSource IO -> m ()+ default setNarSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => NarSource IO+ -> m ()+ setNarSource x = lift (setNarSource x)++ takeNarSource :: m (Maybe (NarSource IO))+ default takeNarSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m (Maybe (NarSource IO))+ takeNarSource = lift takeNarSource++ setDataSource :: (Word64 -> IO (Maybe ByteString)) -> m ()+ default setDataSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => (Word64 -> IO (Maybe ByteString))+ -> m ()+ setDataSource x = lift (setDataSource x)++ takeDataSource :: m (Maybe (Word64 -> IO (Maybe ByteString)))+ default takeDataSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m (Maybe (Word64 -> IO (Maybe ByteString)))+ takeDataSource = lift takeDataSource++ getDataSource :: m (Maybe (Word64 -> IO (Maybe ByteString)))+ default getDataSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m (Maybe (Word64 -> IO (Maybe ByteString)))+ getDataSource = lift getDataSource++ clearDataSource :: m ()+ default clearDataSource+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m ()+ clearDataSource = lift clearDataSource++ setDataSink :: (ByteString -> IO ()) -> m ()+ default setDataSink+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => (ByteString -> IO ())+ -> m ()+ setDataSink x = lift (setDataSink x)++ getDataSink :: m (Maybe (ByteString -> IO ()))+ default getDataSink+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m (Maybe (ByteString -> IO ()))+ getDataSink = lift getDataSink++ clearDataSink :: m ()+ default clearDataSink+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m ()+ clearDataSink = lift clearDataSink++ setDataSinkSize :: Word64 -> m ()+ default setDataSinkSize+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => Word64+ -> m ()+ setDataSinkSize x = lift (setDataSinkSize x)++ getDataSinkSize :: m (Maybe Word64)+ default getDataSinkSize+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m (Maybe Word64)+ getDataSinkSize = lift getDataSinkSize++ clearDataSinkSize :: m ()+ default clearDataSinkSize+ :: ( MonadTrans t+ , MonadRemoteStore m'+ , m ~ t m'+ )+ => m ()+ clearDataSinkSize = lift clearDataSinkSize++instance MonadRemoteStore m => MonadRemoteStore (StateT s m)+instance MonadRemoteStore m => MonadRemoteStore (ReaderT r m)+instance MonadRemoteStore m => MonadRemoteStore (ExceptT RemoteStoreError m)++instance MonadIO m => MonadRemoteStore (RemoteStoreT m) where++ getConfig = RemoteStoreT $ gets remoteStoreStateConfig+ getProtoVersion = RemoteStoreT $ gets hasProtoVersion+ setProtoVersion pv =+ RemoteStoreT $ modify $ \s ->+ s { remoteStoreStateConfig =+ (remoteStoreStateConfig s) { protoStoreConfigProtoVersion = pv }+ }+ getStoreDir = RemoteStoreT $ gets hasStoreDir+ setStoreDir sd =+ RemoteStoreT $ modify $ \s ->+ s { remoteStoreStateConfig =+ (remoteStoreStateConfig s) { protoStoreConfigDir = sd }+ }++ getStoreSocket = RemoteStoreT ask++ appendLog x =+ RemoteStoreT+ $ modify+ $ \s -> s { remoteStoreStateLogs = remoteStoreStateLogs s `Data.DList.snoc` x }++ setDataSource x = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSource = pure x }+ getDataSource = RemoteStoreT (gets remoteStoreStateMDataSource)+ clearDataSource = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSource = Nothing }++ takeDataSource = RemoteStoreT $ do+ x <- remoteStoreStateMDataSource <$> get+ modify $ \s -> s { remoteStoreStateMDataSource = Nothing }+ pure x++ setDataSink x = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSink = pure x }+ getDataSink = RemoteStoreT (gets remoteStoreStateMDataSink)+ clearDataSink = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSink = Nothing }++ setDataSinkSize x = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSinkSize = pure x }+ getDataSinkSize = RemoteStoreT (gets remoteStoreStateMDataSinkSize)+ clearDataSinkSize = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMDataSinkSize = Nothing }++ setNarSource x = RemoteStoreT $ modify $ \s -> s { remoteStoreStateMNarSource = pure x }+ takeNarSource = RemoteStoreT $ do+ x <- remoteStoreStateMNarSource <$> get+ modify $ \s -> s { remoteStoreStateMNarSource = Nothing }+ pure x
− src/System/Nix/Store/Remote/Parsers.hs
@@ -1,51 +0,0 @@-{-# language AllowAmbiguousTypes #-}-{-# language ScopedTypeVariables #-}-{-# language RankNTypes #-}-{-# language DataKinds #-}--module System.Nix.Store.Remote.Parsers- ( parseContentAddressableAddress- )-where--import Data.Attoparsec.ByteString.Char8-import System.Nix.Hash-import System.Nix.StorePath ( ContentAddressableAddress(..)- , NarHashMode(..)- )-import Crypto.Hash ( SHA256 )---- | Parse `ContentAddressableAddress` from `ByteString`-parseContentAddressableAddress- :: ByteString -> Either String ContentAddressableAddress-parseContentAddressableAddress =- Data.Attoparsec.ByteString.Char8.parseOnly contentAddressableAddressParser---- | Parser for content addressable field-contentAddressableAddressParser :: Parser ContentAddressableAddress-contentAddressableAddressParser = caText <|> caFixed---- | Parser for @text:sha256:<h>@-caText :: Parser ContentAddressableAddress-caText = do- _ <- "text:sha256:"- digest <- decodeDigestWith @SHA256 NixBase32 <$> parseHash- either fail pure $ Text <$> digest---- | Parser for @fixed:<r?>:<ht>:<h>@-caFixed :: Parser ContentAddressableAddress-caFixed = do- _ <- "fixed:"- narHashMode <- (Recursive <$ "r:") <|> (RegularFile <$ "")- digest <- parseTypedDigest- either fail pure $ Fixed narHashMode <$> digest--parseTypedDigest :: Parser (Either String SomeNamedDigest)-parseTypedDigest = mkNamedDigest <$> parseHashType <*> parseHash--parseHashType :: Parser Text-parseHashType =- decodeUtf8 <$> ("sha256" <|> "sha512" <|> "sha1" <|> "md5") <* (":" <|> "-")--parseHash :: Parser Text-parseHash = decodeUtf8 <$> takeWhile1 (/= ':')
− src/System/Nix/Store/Remote/Protocol.hs
@@ -1,215 +0,0 @@-{-# language DataKinds #-}-{-# language ScopedTypeVariables #-}-{-# LANGUAGE LambdaCase #-}-module System.Nix.Store.Remote.Protocol- ( WorkerOp(..)- , simpleOp- , simpleOpArgs- , runOp- , runOpArgs- , runOpArgsIO- , runStore- , runStoreOpts- , runStoreOptsTCP- , runStoreOpts'- )-where--import qualified Relude.Unsafe as Unsafe--import Control.Exception ( bracket )-import Control.Monad.Except--import Data.Binary.Get-import Data.Binary.Put-import qualified Data.ByteString-import qualified Data.ByteString.Char8--import Network.Socket ( SockAddr(SockAddrUnix) )-import qualified Network.Socket as S-import Network.Socket.ByteString ( recv- , sendAll- )--import System.Nix.Store.Remote.Binary-import System.Nix.Store.Remote.Logger-import System.Nix.Store.Remote.Types-import System.Nix.Store.Remote.Util---protoVersion :: Int-protoVersion = 0x115--- major protoVersion & 0xFF00--- minor .. & 0x00FF--workerMagic1 :: Int-workerMagic1 = 0x6e697863-workerMagic2 :: Int-workerMagic2 = 0x6478696f--defaultSockPath :: String-defaultSockPath = "/nix/var/nix/daemon-socket/socket"--data WorkerOp =- IsValidPath- | HasSubstitutes- | QueryReferrers- | AddToStore- | AddTextToStore- | BuildPaths- | EnsurePath- | AddTempRoot- | AddIndirectRoot- | SyncWithGC- | FindRoots- | SetOptions- | CollectGarbage- | QuerySubstitutablePathInfo- | QueryDerivationOutputs- | QueryAllValidPaths- | QueryFailedPaths- | ClearFailedPaths- | QueryPathInfo- | QueryDerivationOutputNames- | QueryPathFromHashPart- | QuerySubstitutablePathInfos- | QueryValidPaths- | QuerySubstitutablePaths- | QueryValidDerivers- | OptimiseStore- | VerifyStore- | BuildDerivation- | AddSignatures- | NarFromPath- | AddToStoreNar- | QueryMissing- deriving (Eq, Ord, Show)--opNum :: WorkerOp -> Int-opNum IsValidPath = 1-opNum HasSubstitutes = 3-opNum QueryReferrers = 6-opNum AddToStore = 7-opNum AddTextToStore = 8-opNum BuildPaths = 9-opNum EnsurePath = 10-opNum AddTempRoot = 11-opNum AddIndirectRoot = 12-opNum SyncWithGC = 13-opNum FindRoots = 14-opNum SetOptions = 19-opNum CollectGarbage = 20-opNum QuerySubstitutablePathInfo = 21-opNum QueryDerivationOutputs = 22-opNum QueryAllValidPaths = 23-opNum QueryFailedPaths = 24-opNum ClearFailedPaths = 25-opNum QueryPathInfo = 26-opNum QueryDerivationOutputNames = 28-opNum QueryPathFromHashPart = 29-opNum QuerySubstitutablePathInfos = 30-opNum QueryValidPaths = 31-opNum QuerySubstitutablePaths = 32-opNum QueryValidDerivers = 33-opNum OptimiseStore = 34-opNum VerifyStore = 35-opNum BuildDerivation = 36-opNum AddSignatures = 37-opNum NarFromPath = 38-opNum AddToStoreNar = 39-opNum QueryMissing = 40---simpleOp :: WorkerOp -> MonadStore Bool-simpleOp op = simpleOpArgs op pass--simpleOpArgs :: WorkerOp -> Put -> MonadStore Bool-simpleOpArgs op args = do- runOpArgs op args- err <- gotError- bool- sockGetBool- (do- Error _num msg <- Unsafe.head <$> getError- throwError $ Data.ByteString.Char8.unpack msg- )- err--runOp :: WorkerOp -> MonadStore ()-runOp op = runOpArgs op pass--runOpArgs :: WorkerOp -> Put -> MonadStore ()-runOpArgs op args =- runOpArgsIO- op- (\encode -> encode $ toStrict $ runPut args)--runOpArgsIO- :: WorkerOp- -> ((Data.ByteString.ByteString -> MonadStore ()) -> MonadStore ())- -> MonadStore ()-runOpArgsIO op encoder = do-- sockPut $ putInt $ opNum op-- soc <- asks storeSocket- encoder (liftIO . sendAll soc)-- out <- processOutput- modify (\(a, b) -> (a, b <> out))- err <- gotError- when err $ do- Error _num msg <- Unsafe.head <$> getError- throwError $ Data.ByteString.Char8.unpack msg--runStore :: MonadStore a -> IO (Either String a, [Logger])-runStore = runStoreOpts defaultSockPath "/nix/store"--runStoreOpts- :: FilePath -> FilePath -> MonadStore a -> IO (Either String a, [Logger])-runStoreOpts path = runStoreOpts' S.AF_UNIX (SockAddrUnix path)--runStoreOptsTCP- :: String -> Int -> FilePath -> MonadStore a -> IO (Either String a, [Logger])-runStoreOptsTCP host port storeRootDir code = do- S.getAddrInfo (Just S.defaultHints) (Just host) (Just $ show port) >>= \case- (sockAddr:_) -> runStoreOpts' (S.addrFamily sockAddr) (S.addrAddress sockAddr) storeRootDir code- _ -> pure (Left "Couldn't resolve host and port with getAddrInfo.", [])--runStoreOpts'- :: S.Family -> S.SockAddr -> FilePath -> MonadStore a -> IO (Either String a, [Logger])-runStoreOpts' sockFamily sockAddr storeRootDir code =- bracket open (S.close . storeSocket) run-- where- open = do- soc <- S.socket sockFamily S.Stream 0- S.connect soc sockAddr- pure StoreConfig- { storeSocket = soc- , storeDir = storeRootDir- }-- greet = do- sockPut $ putInt workerMagic1- soc <- asks storeSocket- vermagic <- liftIO $ recv soc 16- let- (magic2, _daemonProtoVersion) =- flip runGet (fromStrict vermagic)- $ (,)- <$> (getInt :: Get Int)- <*> (getInt :: Get Int)- unless (magic2 == workerMagic2) $ error "Worker magic 2 mismatch"-- sockPut $ putInt protoVersion -- clientVersion- sockPut $ putInt (0 :: Int) -- affinity- sockPut $ putInt (0 :: Int) -- obsolete reserveSpace-- processOutput-- run sock =- fmap (\(res, (_data, logs)) -> (res, logs))- $ (`runReaderT` sock)- $ (`runStateT` (Nothing, []))- $ runExceptT (greet >> code)
+ src/System/Nix/Store/Remote/Serializer.hs view
@@ -0,0 +1,1567 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-|+Description : NixSerializer+Copyright : (c) John Ericson, 2023+ Sorki, 2023+|-}++module System.Nix.Store.Remote.Serializer+ (+ -- * NixSerializer+ NixSerializer+ , mapReaderS+ , mapErrorS+ -- * Errors+ , SError(..)+ -- ** Runners+ , runSerialT+ , runG+ , runP+ -- * Primitives+ , int+ , bool+ , byteString+ , enum+ , text+ , maybeText+ -- * UTCTime+ , time+ -- * Combinators+ , list+ , set+ , hashSet+ , mapS+ , vector+ , json+ -- * ProtoVersion+ , protoVersion+ -- * StorePath+ , storePath+ , maybePath+ , storePathHashPart+ , storePathName+ -- * Metadata+ , pathMetadata+ -- * OutputName+ , outputName+ -- * Signatures+ , signature+ , narSignature+ -- * Some HashAlgo+ , someHashAlgo+ -- * Digest+ , digest+ -- * DSum HashAlgo Digest+ , namedDigest+ -- * Derivation+ , derivation+ -- * Derivation+ , derivedPath+ -- * Build+ , buildMode+ -- * Logger+ , LoggerSError(..)+ , activityID+ , maybeActivity+ , activity+ , activityResult+ , field+ , trace+ , basicError+ , errorInfo+ , loggerOpCode+ , logger+ , verbosity+ -- * Handshake+ , HandshakeSError(..)+ , workerMagic+ , trustedFlag+ -- * Worker protocol+ , storeText+ , workerOp+ -- ** Request+ , RequestSError(..)+ , storeRequest+ -- ** Reply+ , ReplySError(..)+ , opSuccess+ , noop+ -- *** Realisation+ , derivationOutputTyped+ , realisation+ , realisationWithId+ -- *** BuildResult+ , buildResult+ -- *** GCResult+ , gcResult+ -- *** GCResult+ , gcRoot+ -- *** Missing+ , missing+ -- *** Maybe (Metadata StorePath)+ , maybePathMetadata+ ) where++import Control.Monad.Except (MonadError, throwError, )+import Control.Monad.Reader (MonadReader)+import Control.Monad.Trans (MonadTrans, lift)+import Control.Monad.Trans.Reader (ReaderT, runReaderT, withReaderT)+import Control.Monad.Trans.Except (ExceptT, mapExceptT, runExceptT, withExceptT)+import Crypto.Hash (Digest, HashAlgorithm, SHA256)+import Data.Aeson (FromJSON, ToJSON)+import Data.ByteString (ByteString)+import Data.Dependent.Sum (DSum((:=>)))+import Data.Fixed (Uni)+import Data.Hashable (Hashable)+import Data.HashSet (HashSet)+import Data.Map (Map)+import Data.Serializer+import Data.Set (Set)+import Data.Some (Some(Some))+import Data.Text (Text)+import Data.Text.Lazy.Builder (Builder)+import Data.Time (NominalDiffTime, UTCTime)+import Data.Vector (Vector)+import Data.Word (Word8, Word32, Word64)+import GHC.Generics (Generic)+import System.Nix.Base (BaseEncoding(Base16, NixBase32))+import System.Nix.Build (BuildMode, BuildResult(..))+import System.Nix.ContentAddress (ContentAddress)+import System.Nix.Derivation (Derivation(..), DerivationOutput(..))+import System.Nix.DerivedPath (DerivedPath(..), ParseOutputsError)+import System.Nix.Hash (HashAlgo(..))+import System.Nix.JSON ()+import System.Nix.OutputName (OutputName)+import System.Nix.Realisation (DerivationOutputError, Realisation(..), RealisationWithId(..))+import System.Nix.Signature (Signature, NarSignature)+import System.Nix.Store.Types (FileIngestionMethod(..), RepairMode(..))+import System.Nix.StorePath (HasStoreDir(..), InvalidNameError, InvalidPathError, StorePath, StorePathHashPart, StorePathName)+import System.Nix.StorePath.Metadata (Metadata(..), StorePathTrust(..))+import System.Nix.Store.Remote.Types++import qualified Control.Monad+import qualified Control.Monad.Reader+import qualified Data.Aeson+import qualified Data.Attoparsec.Text+import qualified Data.Bifunctor+import qualified Data.Bits+import qualified Data.ByteString+import qualified Data.ByteString.Char8+import qualified Data.ByteString.Lazy+import qualified Data.Coerce+import qualified Data.HashSet+import qualified Data.Map.Strict+import qualified Data.Maybe+import qualified Data.Serialize.Get+import qualified Data.Serialize.Put+import qualified Data.Set+import qualified Data.Some+import qualified Data.Text+import qualified Data.Text.Encoding+import qualified Data.Text.Lazy+import qualified Data.Text.Lazy.Builder+import qualified Data.Time.Clock.POSIX+import qualified Data.Vector+import qualified System.Nix.Base+import qualified System.Nix.ContentAddress+import qualified System.Nix.DerivedPath+import qualified System.Nix.Hash+import qualified System.Nix.OutputName+import qualified System.Nix.Realisation+import qualified System.Nix.Signature+import qualified System.Nix.StorePath++-- | Transformer for @Serializer@+newtype SerialT r e m a = SerialT+ { _unSerialT :: ExceptT e (ReaderT r m) a }+ deriving+ ( Applicative+ , Functor+ , Monad+ , MonadError e+ , MonadReader r+ , MonadFail+ )++instance MonadTrans (SerialT r e) where+ lift = SerialT . lift . lift++-- | Runner for @SerialT@+runSerialT+ :: Monad m+ => r+ -> SerialT r e m a+ -> m (Either e a)+runSerialT r =+ (`runReaderT` r)+ . runExceptT+ . _unSerialT++mapErrorST+ :: Functor m+ => (e -> e')+ -> SerialT r e m a+ -> SerialT r e' m a+mapErrorST f =+ SerialT+ . withExceptT f+ . _unSerialT++mapErrorS+ :: (e -> e')+ -> NixSerializer r e a+ -> NixSerializer r e' a+mapErrorS f s = Serializer+ { getS = mapErrorST f $ getS s+ , putS = mapErrorST f . putS s+ }++mapReaderST+ :: Functor m+ => (r' -> r)+ -> SerialT r e m a+ -> SerialT r' e m a+mapReaderST f =+ SerialT+ . (mapExceptT . withReaderT) f+ . _unSerialT++mapReaderS+ :: (r' -> r)+ -> NixSerializer r e a+ -> NixSerializer r' e a+mapReaderS f s = Serializer+ { getS = mapReaderST f $ getS s+ , putS = mapReaderST f . putS s+ }++-- * NixSerializer++type NixSerializer r e = Serializer (SerialT r e)++-- * Errors++data SError+ = SError+ | SError_BadPadding+ { badPaddingStr :: ByteString+ , badPaddingLen :: Int+ , badPaddingPads :: [Word8]+ }+ | SError_ContentAddress String+ | SError_DerivedPath ParseOutputsError+ | SError_DerivationOutput DerivationOutputError+ | SError_Digest String+ | SError_EnumOutOfMinBound Int+ | SError_EnumOutOfMaxBound Int+ | SError_HashAlgo String+ | SError_IllegalBool Word64+ | SError_InvalidNixBase32+ | SError_JSONDecoding String+ | SError_NarHashMustBeSHA256+ | SError_NotYetImplemented String (ForPV ProtoVersion)+ | SError_Name InvalidNameError+ | SError_Path InvalidPathError+ | SError_Signature String+ deriving (Eq, Ord, Generic, Show)++data ForPV a+ = ForPV_Newer a+ | ForPV_Older a+ deriving (Eq, Ord, Generic, Show)++-- ** Runners++runG+ :: NixSerializer r e a+ -> r+ -> ByteString+ -> Either (GetSerializerError e) a+runG serializer r =+ transformGetError+ . runGetS+ serializer+ (runSerialT r)++runP+ :: NixSerializer r e a+ -> r+ -> a+ -> Either e ByteString+runP serializer r =+ transformPutError+ . runPutS+ serializer+ (runSerialT r)++-- * Primitives++int :: Integral a => NixSerializer r e a+int = Serializer+ { getS = fromIntegral <$> lift Data.Serialize.Get.getWord64le+ , putS = lift . Data.Serialize.Put.putWord64le . fromIntegral+ }++bool :: NixSerializer r SError Bool+bool = Serializer+ { getS = getS (int @Word64) >>= \case+ 0 -> pure False+ 1 -> pure True+ x -> throwError $ SError_IllegalBool x+ , putS = \case+ False -> putS (int @Word8) 0+ True -> putS (int @Word8) 1+ }++byteString :: NixSerializer r SError ByteString+byteString = Serializer+ { getS = do+ len <- getS int+ st <- lift $ Data.Serialize.Get.getByteString len+ Control.Monad.when (len `mod` 8 /= 0) $ do+ pads <- unpad $ fromIntegral $ 8 - (len `mod` 8)+ Control.Monad.unless+ (all (== 0) pads)+ $ throwError+ $ SError_BadPadding st len pads+ pure st+ , putS = \x -> do+ let len = Data.ByteString.length x+ putS int len+ lift $ Data.Serialize.Put.putByteString x+ Control.Monad.when+ (len `mod` 8 /= 0)+ $ pad $ 8 - (len `mod` 8)+ }+ where+ unpad count =+ Control.Monad.replicateM+ count+ (lift Data.Serialize.Get.getWord8)+ pad count =+ Control.Monad.replicateM_+ count+ (lift $ Data.Serialize.Put.putWord8 0)++-- | Utility toEnum version checking bounds using Bounded class+toEnumCheckBoundsM+ :: forall a m+ . ( Bounded a+ , Enum a+ , MonadError SError m+ )+ => Int+ -> m a+toEnumCheckBoundsM = \case+ x | x < fromEnum (minBound @a) -> throwError $ SError_EnumOutOfMinBound x+ x | x > fromEnum (maxBound @a) -> throwError $ SError_EnumOutOfMaxBound x+ x | otherwise -> pure $ toEnum x++enum+ :: ( Bounded a+ , Enum a+ )+ => NixSerializer r SError a+enum = Serializer+ { getS = getS int >>= toEnumCheckBoundsM+ , putS = putS int . fromEnum+ }++text :: NixSerializer r SError Text+text = mapIsoSerializer+ Data.Text.Encoding.decodeUtf8+ Data.Text.Encoding.encodeUtf8+ byteString++-- TODO Parser Builder+_textBuilder :: NixSerializer r SError Builder+_textBuilder = Serializer+ { getS = Data.Text.Lazy.Builder.fromText <$> getS text+ , putS = putS text . Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText+ }++maybeText :: NixSerializer r SError (Maybe Text)+maybeText = mapIsoSerializer+ (\case+ t | Data.Text.null t -> Nothing+ t | otherwise -> Just t+ )+ (Data.Maybe.fromMaybe mempty)+ text++-- * UTCTime++time :: NixSerializer r e UTCTime+time = Serializer+ { getS =+ Data.Time.Clock.POSIX.posixSecondsToUTCTime+ . toPicoSeconds+ <$> getS int+ , putS =+ putS int+ . fromPicoSeconds+ . Data.Time.Clock.POSIX.utcTimeToPOSIXSeconds+ }+ where+ -- fancy (*10^12), from Int to Uni to Pico(seconds)+ toPicoSeconds :: Int -> NominalDiffTime+ toPicoSeconds n = realToFrac (toEnum n :: Uni)++ -- fancy (`div`10^12), from Pico to Uni to Int+ fromPicoSeconds :: NominalDiffTime -> Int+ fromPicoSeconds = (fromEnum :: Uni -> Int) . realToFrac++-- * Combinators++list+ :: NixSerializer r e a+ -> NixSerializer r e [a]+list s = Serializer+ { getS = do+ count <- getS int+ Control.Monad.replicateM count (getS s)+ , putS = \xs -> do+ putS int (length xs)+ mapM_ (putS s) xs+ }++set+ :: Ord a+ => NixSerializer r e a+ -> NixSerializer r e (Set a)+set =+ mapIsoSerializer+ Data.Set.fromList+ Data.Set.toList+ . list++hashSet+ :: ( Eq a+ , Hashable a+ )+ => NixSerializer r e a+ -> NixSerializer r e (HashSet a)+hashSet =+ mapIsoSerializer+ Data.HashSet.fromList+ Data.HashSet.toList+ . list++mapS+ :: Ord k+ => NixSerializer r e k+ -> NixSerializer r e v+ -> NixSerializer r e (Map k v)+mapS k v =+ mapIsoSerializer+ Data.Map.Strict.fromList+ Data.Map.Strict.toList+ $ list+ $ tup k v++vector+ :: Ord a+ => NixSerializer r e a+ -> NixSerializer r e (Vector a)+vector =+ mapIsoSerializer+ Data.Vector.fromList+ Data.Vector.toList+ . list++json+ :: ( FromJSON a+ , ToJSON a+ )+ => NixSerializer r SError a+json =+ mapPrismSerializer+ ( Data.Bifunctor.first SError_JSONDecoding+ . Data.Aeson.eitherDecode+ )+ Data.Aeson.encode+ $ mapIsoSerializer+ Data.ByteString.Lazy.fromStrict+ Data.ByteString.Lazy.toStrict+ byteString++-- * ProtoVersion++-- protoVersion_major & 0xFF00+-- protoVersion_minor & 0x00FF+protoVersion :: NixSerializer r e ProtoVersion+protoVersion = Serializer+ { getS = do+ v <- getS (int @Word32)+ pure ProtoVersion+ { protoVersion_major = fromIntegral $ Data.Bits.shiftR v 8+ , protoVersion_minor = fromIntegral $ v Data.Bits..&. 0x00FF+ }+ , putS = \p ->+ putS (int @Word32)+ $ ((Data.Bits.shiftL (fromIntegral $ protoVersion_major p :: Word32) 8)+ Data.Bits..|. fromIntegral (protoVersion_minor p))+ }++-- * StorePath++storePath :: HasStoreDir r => NixSerializer r SError StorePath+storePath = Serializer+ { getS = do+ sd <- Control.Monad.Reader.asks hasStoreDir+ System.Nix.StorePath.parsePath sd <$> getS byteString+ >>=+ either+ (throwError . SError_Path)+ pure+ , putS = \p -> do+ sd <- Control.Monad.Reader.asks hasStoreDir+ putS+ byteString+ $ System.Nix.StorePath.storePathToRawFilePath sd p+ }++maybePath+ :: HasStoreDir r+ => NixSerializer r SError (Maybe StorePath)+maybePath = Serializer+ { getS = do+ getS maybeText >>= \case+ Nothing -> pure Nothing+ Just t -> do+ sd <- Control.Monad.Reader.asks hasStoreDir+ either+ (throwError . SError_Path)+ (pure . pure)+ $ System.Nix.StorePath.parsePathFromText sd t++ , putS = \case+ Nothing -> putS maybeText Nothing+ Just p -> do+ sd <- Control.Monad.Reader.asks hasStoreDir+ putS text $ System.Nix.StorePath.storePathToText sd p+ }++storePathHashPart :: NixSerializer r SError StorePathHashPart+storePathHashPart =+ mapIsoSerializer+ System.Nix.StorePath.unsafeMakeStorePathHashPart+ System.Nix.StorePath.unStorePathHashPart+ $ mapPrismSerializer+ (Data.Bifunctor.first (pure SError_InvalidNixBase32)+ . System.Nix.Base.decodeWith NixBase32)+ (System.Nix.Base.encodeWith NixBase32)+ text++storePathName :: NixSerializer r SError StorePathName+storePathName =+ mapPrismSerializer+ (Data.Bifunctor.first SError_Name+ . System.Nix.StorePath.mkStorePathName)+ System.Nix.StorePath.unStorePathName+ text++pathMetadata+ :: HasStoreDir r+ => NixSerializer r SError (Metadata StorePath)+pathMetadata = Serializer+ { getS = do+ metadataDeriverPath <- getS maybePath++ digest' <- getS $ digest Base16+ let metadataNarHash = System.Nix.Hash.HashAlgo_SHA256 :=> digest'++ metadataReferences <- getS $ hashSet storePath+ metadataRegistrationTime <- getS time+ metadataNarBytes <-+ (\case+ 0 -> Nothing+ size -> Just size+ ) <$> getS int+ metadataTrust <- getS storePathTrust++ metadataSigs <- getS $ set narSignature+ metadataContentAddress <- getS maybeContentAddress++ pure $ Metadata{..}++ , putS = \Metadata{..} -> do+ putS maybePath metadataDeriverPath++ let putNarHash+ :: DSum HashAlgo Digest+ -> SerialT r SError PutM ()+ putNarHash = \case+ System.Nix.Hash.HashAlgo_SHA256 :=> d+ -> putS (digest @SHA256 Base16) d+ _ -> throwError SError_NarHashMustBeSHA256++ putNarHash metadataNarHash++ putS (hashSet storePath) metadataReferences+ putS time metadataRegistrationTime+ putS int $ Data.Maybe.fromMaybe 0 metadataNarBytes+ putS storePathTrust metadataTrust+ putS (set narSignature) metadataSigs+ putS maybeContentAddress metadataContentAddress+ }+ where+ maybeContentAddress+ :: NixSerializer r SError (Maybe ContentAddress)+ maybeContentAddress =+ mapPrismSerializer+ (maybe+ (pure Nothing)+ $ Data.Bifunctor.bimap+ SError_ContentAddress+ Just+ . System.Nix.ContentAddress.parseContentAddress+ )+ (fmap System.Nix.ContentAddress.buildContentAddress)+ maybeText++ storePathTrust+ :: NixSerializer r SError StorePathTrust+ storePathTrust =+ mapIsoSerializer+ (\case False -> BuiltElsewhere; True -> BuiltLocally)+ (\case BuiltElsewhere -> False; BuiltLocally -> True)+ bool++-- * OutputName++outputName :: NixSerializer r SError OutputName+outputName =+ mapPrismSerializer+ (Data.Bifunctor.first SError_Name+ . System.Nix.OutputName.mkOutputName)+ System.Nix.OutputName.unOutputName+ text++-- * Signatures++signature+ :: NixSerializer r SError Signature+signature =+ mapPrismSerializer+ (Data.Bifunctor.first SError_Signature+ . Data.Attoparsec.Text.parseOnly+ System.Nix.Signature.signatureParser)+ (System.Nix.Signature.signatureToText)+ text++narSignature+ :: NixSerializer r SError NarSignature+narSignature =+ mapPrismSerializer+ (Data.Bifunctor.first SError_Signature+ . Data.Attoparsec.Text.parseOnly+ System.Nix.Signature.narSignatureParser)+ (System.Nix.Signature.narSignatureToText)+ text++-- * Some HashAlgo++someHashAlgo :: NixSerializer r SError (Some HashAlgo)+someHashAlgo =+ mapPrismSerializer+ (Data.Bifunctor.first SError_HashAlgo+ . System.Nix.Hash.textToAlgo)+ (Data.Some.foldSome System.Nix.Hash.algoToText)+ text++-- * Digest++digest+ :: forall a r+ . HashAlgorithm a+ => BaseEncoding+ -> NixSerializer r SError (Digest a)+digest base =+ mapIsoSerializer+ Data.Coerce.coerce+ Data.Coerce.coerce+ $ mapPrismSerializer+ (Data.Bifunctor.first SError_Digest+ . System.Nix.Hash.decodeDigestWith @a base)+ (System.Nix.Hash.encodeDigestWith base)+ $ text++-- * DSum HashAlgo Digest++namedDigest :: NixSerializer r SError (DSum HashAlgo Digest)+namedDigest = Serializer+ { getS = do+ sriHash <- getS text+ let (sriName, _h) = Data.Text.breakOn (Data.Text.singleton '-') sriHash+ -- bit hacky since mkNamedDigest does the check+ -- that the expected matches but we don't know+ -- what we expect here (i.e. handle each HashAlgo)+ case System.Nix.Hash.mkNamedDigest sriName sriHash of+ Left e -> throwError $ SError_Digest e+ Right x -> pure x+ -- TODO: we also lack a builder for SRI hashes+ -- , putS = putS textBuilder . System.Nix.Hash.algoDigestBuilder+ , putS = \(algo :=> d) -> do+ putS text+ $ System.Nix.Hash.algoToText algo+ <> (Data.Text.singleton '-')+ <> System.Nix.Hash.encodeDigestWith NixBase32 d+ }++derivationOutput+ :: HasStoreDir r+ => NixSerializer r SError (DerivationOutput StorePath Text)+derivationOutput = Serializer+ { getS = do+ path <- getS storePath+ hashAlgo <- getS text+ hash <- getS text+ pure DerivationOutput{..}+ , putS = \DerivationOutput{..} -> do+ putS storePath path+ putS text hashAlgo+ putS text hash+ }++-- * Derivation++derivation+ :: HasStoreDir r+ => NixSerializer r SError (Derivation StorePath Text)+derivation = Serializer+ { getS = do+ outputs <- getS (mapS text derivationOutput)+ -- Our type is Derivation, but in Nix+ -- the type sent over the wire is BasicDerivation+ -- which omits inputDrvs+ inputDrvs <- pure mempty+ inputSrcs <- getS (set storePath)++ platform <- getS text+ builder <- getS text+ args <- getS (vector text)+ env <- getS (mapS text text)+ pure Derivation{..}+ , putS = \Derivation{..} -> do+ putS (mapS text derivationOutput) outputs+ putS (set storePath) inputSrcs+ putS text platform+ putS text builder+ putS (vector text) args+ putS (mapS text text) env+ }++-- * DerivedPath++derivedPathNew+ :: HasStoreDir r+ => NixSerializer r SError DerivedPath+derivedPathNew = Serializer+ { getS = do+ root <- Control.Monad.Reader.asks hasStoreDir+ p <- getS text+ case System.Nix.DerivedPath.parseDerivedPath root p of+ Left err -> throwError $ SError_DerivedPath err+ Right x -> pure x+ , putS = \d -> do+ root <- Control.Monad.Reader.asks hasStoreDir+ putS text (System.Nix.DerivedPath.derivedPathToText root d)+ }++derivedPath+ :: ( HasProtoVersion r+ , HasStoreDir r+ )+ => NixSerializer r SError DerivedPath+derivedPath = Serializer+ { getS = do+ pv <- Control.Monad.Reader.asks hasProtoVersion+ if pv < ProtoVersion 1 30+ then DerivedPath_Opaque <$> getS storePath+ else getS derivedPathNew+ , putS = \d -> do+ pv <- Control.Monad.Reader.asks hasProtoVersion+ if pv < ProtoVersion 1 30+ then case d of+ DerivedPath_Opaque p -> putS storePath p+ _ -> throwError+ $ SError_NotYetImplemented+ "DerivedPath_Built"+ (ForPV_Older pv)+ else putS derivedPathNew d+ }++-- * Build++buildMode :: NixSerializer r SError BuildMode+buildMode = enum++-- * Logger++data LoggerSError+ = LoggerSError_Prim SError+ | LoggerSError_InvalidOpCode Word64+ | LoggerSError_TooOldForErrorInfo+ | LoggerSError_TooNewForBasicError+ | LoggerSError_UnknownLogFieldType Word8+ deriving (Eq, Ord, Generic, Show)++mapPrimE+ :: Functor m+ => SerialT r SError m a+ -> SerialT r LoggerSError m a+mapPrimE = mapErrorST LoggerSError_Prim++maybeActivity :: NixSerializer r LoggerSError (Maybe Activity)+maybeActivity = Serializer+ { getS = getS (int @Int) >>= \case+ 0 -> pure Nothing+ x -> mapPrimE $ toEnumCheckBoundsM (x - 100) >>= pure . Just+ , putS = \case+ Nothing -> putS (int @Int) 0+ Just act -> putS activity act+ }++activity :: NixSerializer r LoggerSError Activity+activity = Serializer+ { getS = mapPrimE $ getS int >>= toEnumCheckBoundsM . (+(-100))+ , putS = putS int . (+100) . fromEnum+ }++activityID :: NixSerializer r LoggerSError ActivityID+activityID = mapIsoSerializer ActivityID unActivityID int++activityResult :: NixSerializer r LoggerSError ActivityResult+activityResult = Serializer+ { getS = mapPrimE $ getS int >>= toEnumCheckBoundsM . (+(-100))+ , putS = putS int . (+100) . fromEnum+ }++field :: NixSerializer r LoggerSError Field+field = Serializer+ { getS = getS (int @Word8) >>= \case+ 0 -> Field_LogInt <$> getS int+ 1 -> Field_LogStr <$> mapPrimE (getS text)+ x -> throwError $ LoggerSError_UnknownLogFieldType x+ , putS = \case+ Field_LogInt x -> putS int (0 :: Word8) >> putS int x+ Field_LogStr x -> putS int (1 :: Word8) >> mapPrimE (putS text x)+ }++trace :: NixSerializer r LoggerSError Trace+trace = Serializer+ { getS = do+ tracePosition <- (\case 0 -> Nothing; x -> Just x) <$> getS (int @Int)+ traceHint <- mapPrimE $ getS text+ pure Trace{..}+ , putS = \Trace{..} -> do+ putS int $ Data.Maybe.fromMaybe 0 tracePosition+ mapPrimE $ putS text traceHint+ }++basicError :: NixSerializer r LoggerSError BasicError+basicError = Serializer+ { getS = do+ basicErrorMessage <- mapPrimE $ getS text+ basicErrorExitStatus <- getS int+ pure BasicError{..}++ , putS = \BasicError{..} -> do+ mapPrimE $ putS text basicErrorMessage+ putS int basicErrorExitStatus+ }++errorInfo :: NixSerializer r LoggerSError ErrorInfo+errorInfo = Serializer+ { getS = do+ etyp <- mapPrimE $ getS text+ Control.Monad.unless (etyp == Data.Text.pack "Error")+ $ fail+ $ "get ErrorInfo: received unknown error type" ++ show etyp+ errorInfoLevel <- getS verbosity+ _name <- mapPrimE $ getS text -- removed error name+ errorInfoMessage <- mapPrimE $ getS text+ errorInfoPosition <- (\case 0 -> Nothing; x -> Just x) <$> getS int+ errorInfoTraces <- getS (list trace)+ pure ErrorInfo{..}++ , putS = \ErrorInfo{..} -> do+ mapPrimE $ do+ putS text $ Data.Text.pack "Error"+ putS verbosity errorInfoLevel+ mapPrimE $ do+ putS text $ Data.Text.pack "Error" -- removed error name+ putS text errorInfoMessage+ putS int $ Data.Maybe.fromMaybe 0 errorInfoPosition+ putS (list trace) errorInfoTraces+ }++loggerOpCode :: NixSerializer r LoggerSError LoggerOpCode+loggerOpCode = Serializer+ { getS = do+ c <- getS int+ either+ (pure $ throwError (LoggerSError_InvalidOpCode c))+ pure+ $ word64ToLoggerOpCode c+ , putS = putS int . loggerOpCodeToWord64+ }++logger+ :: HasProtoVersion r+ => NixSerializer r LoggerSError Logger+logger = Serializer+ { getS = getS loggerOpCode >>= \case+ LoggerOpCode_Next ->+ mapPrimE $+ Logger_Next <$> getS text++ LoggerOpCode_Read ->+ Logger_Read <$> getS int++ LoggerOpCode_Write ->+ mapPrimE $+ Logger_Write <$> getS byteString++ LoggerOpCode_Last ->+ pure Logger_Last++ LoggerOpCode_Error -> do+ pv <- Control.Monad.Reader.asks hasProtoVersion+ Logger_Error <$>+ if protoVersion_minor pv >= 26+ then Right <$> getS errorInfo+ else Left <$> getS basicError++ LoggerOpCode_StartActivity -> do+ startActivityID <- getS activityID+ startActivityVerbosity <- getS verbosity+ startActivityType <- getS maybeActivity+ startActivityString <- mapPrimE $ getS byteString+ startActivityFields <- getS (list field)+ startActivityParentID <- getS activityID+ pure Logger_StartActivity{..}++ LoggerOpCode_StopActivity -> do+ stopActivityID <- getS activityID+ pure Logger_StopActivity{..}++ LoggerOpCode_Result -> do+ resultActivityID <- getS activityID+ resultType <- getS activityResult+ resultFields <- getS (list field)+ pure Logger_Result {..}++ , putS = \case+ Logger_Next s -> do+ putS loggerOpCode LoggerOpCode_Next+ mapPrimE $ putS text s++ Logger_Read i -> do+ putS loggerOpCode LoggerOpCode_Read+ putS int i++ Logger_Write s -> do+ putS loggerOpCode LoggerOpCode_Write+ mapPrimE $ putS byteString s++ Logger_Last ->+ putS loggerOpCode LoggerOpCode_Last++ Logger_Error basicOrInfo -> do+ putS loggerOpCode LoggerOpCode_Error++ minor <- protoVersion_minor <$> Control.Monad.Reader.asks hasProtoVersion++ case basicOrInfo of+ Left _ | minor >= 26 -> throwError $ LoggerSError_TooNewForBasicError+ Left e | otherwise -> putS basicError e+ Right _ | minor < 26 -> throwError $ LoggerSError_TooOldForErrorInfo+ Right e -> putS errorInfo e++ Logger_StartActivity{..} -> do+ putS loggerOpCode LoggerOpCode_StartActivity+ putS activityID startActivityID+ putS verbosity startActivityVerbosity+ putS maybeActivity startActivityType+ mapPrimE $+ putS byteString startActivityString+ putS (list field) startActivityFields+ putS activityID startActivityParentID++ Logger_StopActivity{..} -> do+ putS loggerOpCode LoggerOpCode_StopActivity+ putS activityID stopActivityID++ Logger_Result{..} -> do+ putS loggerOpCode LoggerOpCode_Result+ putS activityID resultActivityID+ putS activityResult resultType+ putS (list field) resultFields+ }++verbosity :: NixSerializer r LoggerSError Verbosity+verbosity = Serializer+ { getS = mapPrimE $ getS enum+ , putS = mapPrimE . putS enum+ }++-- * Handshake++data HandshakeSError+ = HandshakeSError_InvalidWorkerMagic Word64+ | HandshakeSError_InvalidTrustedFlag Word8+ deriving (Eq, Ord, Generic, Show)++workerMagic :: NixSerializer r HandshakeSError WorkerMagic+workerMagic = Serializer+ { getS = do+ c <- getS int+ either+ (pure $ throwError (HandshakeSError_InvalidWorkerMagic c))+ pure+ $ word64ToWorkerMagic c+ , putS = putS int . workerMagicToWord64+ }++trustedFlag :: NixSerializer r HandshakeSError (Maybe TrustedFlag)+trustedFlag = Serializer+ { getS = do+ n :: Word8 <- getS int+ case n of+ 0 -> return $ Nothing+ 1 -> return $ Just TrustedFlag_Trusted+ 2 -> return $ Just TrustedFlag_NotTrusted+ _ -> throwError (HandshakeSError_InvalidTrustedFlag n)+ , putS = \n -> putS int $ case n of+ Nothing -> 0 :: Word8+ Just TrustedFlag_Trusted -> 1+ Just TrustedFlag_NotTrusted -> 2+ }++-- * Worker protocol++storeText :: NixSerializer r SError StoreText+storeText = Serializer+ { getS = do+ storeTextName <- getS storePathName+ storeTextText <- getS text+ pure StoreText{..}+ , putS = \StoreText{..} -> do+ putS storePathName storeTextName+ putS text storeTextText+ }++workerOp :: NixSerializer r SError WorkerOp+workerOp = enum++-- * Request++data RequestSError+ = RequestSError_NotYetImplemented WorkerOp+ | RequestSError_ReservedOp WorkerOp+ | RequestSError_PrimGet SError+ | RequestSError_PrimPut SError+ | RequestSError_PrimWorkerOp SError+ deriving (Eq, Ord, Generic, Show)++storeRequest+ :: ( HasProtoVersion r+ , HasStoreDir r+ )+ => NixSerializer r RequestSError (Some StoreRequest)+storeRequest = Serializer+ { getS = mapErrorST RequestSError_PrimWorkerOp (getS workerOp) >>= \case+ WorkerOp_AddToStore -> mapGetE $ do+ pathName <- getS storePathName+ _fixed <- getS bool -- obsolete+ recursive <- getS enum+ hashAlgo <- getS someHashAlgo++ -- not supported by ProtoVersion < 1.25+ let repair = RepairMode_DontRepair++ pure $ Some (AddToStore pathName recursive hashAlgo repair)++ WorkerOp_AddToStoreNar -> mapGetE $ do+ storePath' <- getS storePath+ metadata <- getS pathMetadata+ repair <- getS bool+ let repairMode = if repair then RepairMode_DoRepair else RepairMode_DontRepair+ dontCheckSigs <- getS bool+ let checkSigs = if dontCheckSigs then CheckMode_DontCheck else CheckMode_DoCheck++ pure $ Some (AddToStoreNar storePath' metadata repairMode checkSigs)++ WorkerOp_AddTextToStore -> mapGetE $ do+ txt <- getS storeText+ paths <- getS (hashSet storePath)+ let repair = RepairMode_DontRepair+ pure $ Some (AddTextToStore txt paths repair)++ WorkerOp_AddSignatures -> mapGetE $ do+ path <- getS storePath+ signatures <- getS (set signature)+ pure $ Some (AddSignatures path signatures)++ WorkerOp_AddIndirectRoot -> mapGetE $ do+ Some . AddIndirectRoot <$> getS storePath++ WorkerOp_AddTempRoot -> mapGetE $ do+ Some . AddTempRoot <$> getS storePath++ WorkerOp_BuildPaths -> mapGetE $ do+ derived <- getS (set derivedPath)+ buildMode' <- getS buildMode+ pure $ Some (BuildPaths derived buildMode')++ WorkerOp_BuildDerivation -> mapGetE $ do+ path <- getS storePath+ drv <- getS derivation+ buildMode' <- getS buildMode+ pure $ Some (BuildDerivation path drv buildMode')++ WorkerOp_CollectGarbage -> mapGetE $ do+ gcOptionsOperation <- getS enum+ gcOptionsPathsToDelete <- getS (hashSet storePath)+ gcOptionsIgnoreLiveness <- getS bool+ gcOptionsMaxFreed <- getS int+ -- obsolete fields+ Control.Monad.forM_ [0..(2 :: Word8)]+ $ pure $ getS (int @Word8)+ pure $ Some (CollectGarbage GCOptions{..})++ WorkerOp_EnsurePath -> mapGetE $ do+ Some . EnsurePath <$> getS storePath++ WorkerOp_FindRoots -> mapGetE $ do+ pure $ Some FindRoots++ WorkerOp_IsValidPath -> mapGetE $ do+ Some . IsValidPath <$> getS storePath++ WorkerOp_NarFromPath -> mapGetE $ do+ Some . NarFromPath <$> getS storePath++ WorkerOp_QueryValidPaths -> mapGetE $ do+ paths <- getS (hashSet storePath)+ substituteMode <- getS enum+ pure $ Some (QueryValidPaths paths substituteMode)++ WorkerOp_QueryAllValidPaths -> mapGetE $ do+ pure $ Some QueryAllValidPaths++ WorkerOp_QuerySubstitutablePaths -> mapGetE $ do+ Some . QuerySubstitutablePaths <$> getS (hashSet storePath)++ WorkerOp_QueryPathInfo -> mapGetE $ do+ Some . QueryPathInfo <$> getS storePath++ WorkerOp_QueryReferrers -> mapGetE $ do+ Some . QueryReferrers <$> getS storePath++ WorkerOp_QueryValidDerivers -> mapGetE $ do+ Some . QueryValidDerivers <$> getS storePath++ WorkerOp_QueryDerivationOutputs -> mapGetE $ do+ Some . QueryDerivationOutputs <$> getS storePath++ WorkerOp_QueryDerivationOutputNames -> mapGetE $ do+ Some . QueryDerivationOutputNames <$> getS storePath++ WorkerOp_QueryPathFromHashPart -> mapGetE $ do+ Some . QueryPathFromHashPart <$> getS storePathHashPart++ WorkerOp_QueryMissing -> mapGetE $ do+ Some . QueryMissing <$> getS (set derivedPath)++ WorkerOp_OptimiseStore -> mapGetE $ do+ pure $ Some OptimiseStore++ WorkerOp_SyncWithGC -> mapGetE $ do+ pure $ Some SyncWithGC++ WorkerOp_VerifyStore -> mapGetE $ do+ checkMode <- getS enum+ repairMode <- getS enum++ pure $ Some (VerifyStore checkMode repairMode)++ w@WorkerOp_Reserved_0__ -> reserved w+ w@WorkerOp_Reserved_2__ -> reserved w+ w@WorkerOp_Reserved_15__ -> reserved w+ w@WorkerOp_Reserved_17__ -> reserved w++ w@WorkerOp_AddBuildLog -> notYet w+ w@WorkerOp_AddMultipleToStore -> notYet w+ w@WorkerOp_BuildPathsWithResults -> notYet w+ w@WorkerOp_ClearFailedPaths -> notYet w+ w@WorkerOp_ExportPath -> notYet w+ w@WorkerOp_HasSubstitutes -> notYet w+ w@WorkerOp_ImportPaths -> notYet w+ w@WorkerOp_QueryDerivationOutputMap -> notYet w+ w@WorkerOp_QueryDeriver -> notYet w+ w@WorkerOp_QueryFailedPaths -> notYet w+ w@WorkerOp_QueryPathHash -> notYet w+ w@WorkerOp_QueryRealisation -> notYet w+ w@WorkerOp_QuerySubstitutablePathInfo -> notYet w+ w@WorkerOp_QuerySubstitutablePathInfos -> notYet w+ w@WorkerOp_QueryReferences -> notYet w+ w@WorkerOp_RegisterDrvOutput -> notYet w+ w@WorkerOp_SetOptions -> notYet w++ , putS = \case+ Some (AddToStore pathName recursive hashAlgo _repair) -> mapPutE $ do+ putS workerOp WorkerOp_AddToStore++ putS storePathName pathName+ -- obsolete fixed+ putS bool+ $ not+ $ hashAlgo == Some HashAlgo_SHA256+ && (recursive == FileIngestionMethod_FileRecursive)++ putS bool (recursive == FileIngestionMethod_FileRecursive)+ putS someHashAlgo hashAlgo++ Some (AddToStoreNar storePath' metadata repair checkSigs) -> mapPutE $ do+ putS workerOp WorkerOp_AddToStoreNar++ putS storePath storePath'+ putS pathMetadata metadata+ putS bool $ repair == RepairMode_DoRepair+ putS bool $ checkSigs == CheckMode_DontCheck++ Some (AddTextToStore txt paths _repair) -> mapPutE $ do+ putS workerOp WorkerOp_AddTextToStore++ putS storeText txt+ putS (hashSet storePath) paths++ Some (AddSignatures path signatures) -> mapPutE $ do+ putS workerOp WorkerOp_AddSignatures++ putS storePath path+ putS (set signature) signatures++ Some (AddIndirectRoot path) -> mapPutE $ do+ putS workerOp WorkerOp_AddIndirectRoot+ putS storePath path++ Some (AddTempRoot path) -> mapPutE $ do+ putS workerOp WorkerOp_AddTempRoot+ putS storePath path++ Some (BuildPaths derived buildMode') -> mapPutE $ do+ putS workerOp WorkerOp_BuildPaths++ putS (set derivedPath) derived+ putS buildMode buildMode'++ Some (BuildDerivation path drv buildMode') -> mapPutE $ do+ putS workerOp WorkerOp_BuildDerivation++ putS storePath path+ putS derivation drv+ putS buildMode buildMode'++ Some (CollectGarbage GCOptions{..}) -> mapPutE $ do+ putS workerOp WorkerOp_CollectGarbage++ putS enum gcOptionsOperation+ putS (hashSet storePath) gcOptionsPathsToDelete+ putS bool gcOptionsIgnoreLiveness+ putS int gcOptionsMaxFreed+ -- obsolete fields+ Control.Monad.forM_ [0..(2 :: Word8)]+ $ pure $ putS int (0 :: Word8)++ Some (EnsurePath path) -> mapPutE $ do+ putS workerOp WorkerOp_EnsurePath+ putS storePath path++ Some FindRoots -> mapPutE $ do+ putS workerOp WorkerOp_FindRoots++ Some (IsValidPath path) -> mapPutE $ do+ putS workerOp WorkerOp_IsValidPath+ putS storePath path++ Some (NarFromPath path) -> mapPutE $ do+ putS workerOp WorkerOp_NarFromPath+ putS storePath path++ Some (QueryValidPaths paths substituteMode) -> mapPutE $ do+ putS workerOp WorkerOp_QueryValidPaths++ putS (hashSet storePath) paths+ putS enum substituteMode++ Some QueryAllValidPaths -> mapPutE $ do+ putS workerOp WorkerOp_QueryAllValidPaths++ Some (QuerySubstitutablePaths paths) -> mapPutE $ do+ putS workerOp WorkerOp_QuerySubstitutablePaths+ putS (hashSet storePath) paths++ Some (QueryPathInfo path) -> mapPutE $ do+ putS workerOp WorkerOp_QueryPathInfo+ putS storePath path++ Some (QueryReferrers path) -> mapPutE $ do+ putS workerOp WorkerOp_QueryReferrers+ putS storePath path++ Some (QueryValidDerivers path) -> mapPutE $ do+ putS workerOp WorkerOp_QueryValidDerivers+ putS storePath path++ Some (QueryDerivationOutputs path) -> mapPutE $ do+ putS workerOp WorkerOp_QueryDerivationOutputs+ putS storePath path++ Some (QueryDerivationOutputNames path) -> mapPutE $ do+ putS workerOp WorkerOp_QueryDerivationOutputNames+ putS storePath path++ Some (QueryPathFromHashPart pathHashPart) -> mapPutE $ do+ putS workerOp WorkerOp_QueryPathFromHashPart+ putS storePathHashPart pathHashPart++ Some (QueryMissing derived) -> mapPutE $ do+ putS workerOp WorkerOp_QueryMissing+ putS (set derivedPath) derived++ Some OptimiseStore -> mapPutE $ do+ putS workerOp WorkerOp_OptimiseStore++ Some SyncWithGC -> mapPutE $ do+ putS workerOp WorkerOp_SyncWithGC++ Some (VerifyStore checkMode repairMode) -> mapPutE $ do+ putS workerOp WorkerOp_VerifyStore+ putS enum checkMode+ putS enum repairMode+ }+ where+ mapGetE+ :: Functor m+ => SerialT r SError m a+ -> SerialT r RequestSError m a+ mapGetE = mapErrorST RequestSError_PrimGet++ mapPutE+ :: Functor m+ => SerialT r SError m a+ -> SerialT r RequestSError m a+ mapPutE = mapErrorST RequestSError_PrimPut++ notYet+ :: MonadError RequestSError m+ => WorkerOp+ -> m a+ notYet = throwError . RequestSError_NotYetImplemented++ reserved+ :: MonadError RequestSError m+ => WorkerOp+ -> m a+ reserved = throwError . RequestSError_ReservedOp++-- ** Reply++data ReplySError+ = ReplySError_PrimGet SError+ | ReplySError_PrimPut SError+ | ReplySError_DerivationOutput SError+ | ReplySError_GCResult SError+ | ReplySError_Metadata SError+ | ReplySError_Missing SError+ | ReplySError_Realisation SError+ | ReplySError_RealisationWithId SError+ | ReplySError_UnexpectedFalseOpSuccess+ deriving (Eq, Ord, Generic, Show)++mapGetER+ :: Functor m+ => SerialT r SError m a+ -> SerialT r ReplySError m a+mapGetER = mapErrorST ReplySError_PrimGet++mapPutER+ :: Functor m+ => SerialT r SError m a+ -> SerialT r ReplySError m a+mapPutER = mapErrorST ReplySError_PrimPut++-- | Parse a bool returned at the end of simple operations.+-- This is always 1 (@True@) so we assert that it really is so.+-- Errors for these operations are indicated via @Logger_Error@.+opSuccess :: NixSerializer r ReplySError SuccessCodeReply+opSuccess = Serializer+ { getS = do+ retCode <- mapGetER $ getS bool+ Control.Monad.unless+ (retCode == True)+ $ throwError ReplySError_UnexpectedFalseOpSuccess+ pure SuccessCodeReply+ , putS = \_ -> mapPutER $ putS bool True+ }++noop :: a -> NixSerializer r ReplySError a+noop ret = Serializer+ { getS = pure ret+ , putS = \_ -> pure ()+ }++-- *** Realisation++derivationOutputTyped :: NixSerializer r ReplySError (System.Nix.Realisation.DerivationOutput OutputName)+derivationOutputTyped = mapErrorS ReplySError_DerivationOutput $+ mapPrismSerializer+ ( Data.Bifunctor.first SError_DerivationOutput+ . System.Nix.Realisation.derivationOutputParser+ System.Nix.OutputName.mkOutputName+ )+ ( Data.Text.Lazy.toStrict+ . Data.Text.Lazy.Builder.toLazyText+ . System.Nix.Realisation.derivationOutputBuilder+ System.Nix.OutputName.unOutputName+ )+ text++realisation :: NixSerializer r ReplySError Realisation+realisation = mapErrorS ReplySError_Realisation json++realisationWithId :: NixSerializer r ReplySError RealisationWithId+realisationWithId = mapErrorS ReplySError_RealisationWithId json++-- *** BuildResult++buildResult+ :: ( HasProtoVersion r+ , HasStoreDir r+ )+ => NixSerializer r ReplySError BuildResult+buildResult = Serializer+ { getS = do+ pv <- Control.Monad.Reader.asks hasProtoVersion++ buildResultStatus <- mapGetER $ getS enum+ buildResultErrorMessage <- mapGetER $ getS maybeText++ ( buildResultTimesBuilt+ , buildResultIsNonDeterministic+ , buildResultStartTime+ , buildResultStopTime+ ) <-+ if protoVersion_minor pv >= 29+ then mapGetER $ do+ tb <- (\case 0 -> Nothing; x -> Just x) <$> getS int+ nondet <- getS bool+ start <- (\case x | x == t0 -> Nothing; x -> Just x) <$> getS time+ end <- (\case x | x == t0 -> Nothing; x -> Just x) <$> getS time+ pure $ (tb, pure nondet, start, end)+ else pure $ (Nothing, Nothing, Nothing, Nothing)++ buildResultBuiltOutputs <-+ if protoVersion_minor pv >= 28+ then+ pure+ . Data.Map.Strict.fromList+ . map (\(_, RealisationWithId (a, b)) -> (a, b))+ . Data.Map.Strict.toList+ <$> getS (mapS derivationOutputTyped realisationWithId)+ else pure Nothing+ pure BuildResult{..}++ , putS = \BuildResult{..} -> do+ pv <- Control.Monad.Reader.asks hasProtoVersion++ mapPutER $ putS enum buildResultStatus+ mapPutER $ putS maybeText buildResultErrorMessage+ Control.Monad.when (protoVersion_minor pv >= 29) $ mapPutER $ do+ putS int $ Data.Maybe.fromMaybe 0 buildResultTimesBuilt+ putS bool $ Data.Maybe.fromMaybe False buildResultIsNonDeterministic+ putS time $ Data.Maybe.fromMaybe t0 buildResultStartTime+ putS time $ Data.Maybe.fromMaybe t0 buildResultStopTime+ Control.Monad.when (protoVersion_minor pv >= 28)+ $ putS (mapS derivationOutputTyped realisationWithId)+ $ Data.Map.Strict.fromList+ $ map (\(a, b) -> (a, RealisationWithId (a, b)))+ $ Data.Map.Strict.toList+ $ Data.Maybe.fromMaybe mempty buildResultBuiltOutputs+ }+ where+ t0 :: UTCTime+ t0 = Data.Time.Clock.POSIX.posixSecondsToUTCTime 0++-- *** GCResult++gcResult+ :: HasStoreDir r+ => NixSerializer r ReplySError GCResult+gcResult = mapErrorS ReplySError_GCResult $ Serializer+ { getS = do+ gcResultDeletedPaths <- getS (hashSet storePath)+ gcResultBytesFreed <- getS int+ Control.Monad.void $ getS (int @Word64) -- obsolete+ pure GCResult{..}+ , putS = \GCResult{..} -> do+ putS (hashSet storePath) gcResultDeletedPaths+ putS int gcResultBytesFreed+ putS (int @Word64) 0 -- obsolete+ }++-- *** GCRoot++gcRoot :: NixSerializer r ReplySError GCRoot+gcRoot = Serializer+ { getS = mapGetER $ do+ getS byteString >>= \case+ p | p == censored -> pure GCRoot_Censored+ p -> pure (GCRoot_Path p)+ , putS = mapPutER . putS byteString . \case+ GCRoot_Censored -> censored+ GCRoot_Path p -> p+ }+ where censored = Data.ByteString.Char8.pack "{censored}"++-- *** Missing++missing+ :: HasStoreDir r+ => NixSerializer r ReplySError Missing+missing = mapErrorS ReplySError_Missing $ Serializer+ { getS = do+ missingWillBuild <- getS (hashSet storePath)+ missingWillSubstitute <- getS (hashSet storePath)+ missingUnknownPaths <- getS (hashSet storePath)+ missingDownloadSize <- getS int+ missingNarSize <- getS int++ pure Missing{..}+ , putS = \Missing{..} -> do+ putS (hashSet storePath) missingWillBuild+ putS (hashSet storePath) missingWillSubstitute+ putS (hashSet storePath) missingUnknownPaths+ putS int missingDownloadSize+ putS int missingNarSize+ }++-- *** Maybe (Metadata StorePath)++maybePathMetadata+ :: HasStoreDir r+ => NixSerializer r ReplySError (Maybe (Metadata StorePath))+maybePathMetadata = mapErrorS ReplySError_Metadata $ Serializer+ { getS = do+ valid <- getS bool+ if valid+ then pure <$> getS pathMetadata+ else pure Nothing+ , putS = \case+ Nothing -> putS bool False+ Just pm -> putS bool True >> putS pathMetadata pm+ }
+ src/System/Nix/Store/Remote/Server.hs view
@@ -0,0 +1,365 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}+module System.Nix.Store.Remote.Server+ ( runProxyDaemon+ , WorkerHelper+ )+ where++import Control.Concurrent.Classy.Async+import Control.Monad (join, void, when)+import Control.Monad.Conc.Class (MonadConc)+import Control.Monad.Except (MonadError, throwError)+import Control.Monad.Trans (lift)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Default.Class (Default(def))+import Data.Foldable (traverse_)+import Data.IORef (IORef, atomicModifyIORef, newIORef)+import Data.Text (Text)+import Data.Void (Void, absurd)+import Data.Word (Word32)+import Network.Socket (Socket, accept, close, listen, maxListenQueue)+import System.Nix.Nar (NarSource)+import System.Nix.Store.Remote.Client (Run, doReq)+import System.Nix.Store.Remote.Serializer (LoggerSError, mapErrorS, storeRequest, workerMagic, protoVersion, int, logger, text, trustedFlag)+import System.Nix.Store.Remote.Socket+import System.Nix.Store.Remote.Types.StoreRequest as R+import System.Nix.Store.Remote.Types.StoreReply+import System.Nix.Store.Remote.Types.ProtoVersion (ProtoVersion(..))+import System.Nix.Store.Remote.Types.Logger (BasicError(..), ErrorInfo, Logger(..))+import System.Nix.Store.Remote.MonadStore (MonadRemoteStore(..), WorkerError(..), WorkerException(..), RemoteStoreError(..), RemoteStoreT, runRemoteStoreT)+import System.Nix.Store.Remote.Types.Handshake (ServerHandshakeInput(..), ServerHandshakeOutput(..))+import System.Nix.Store.Remote.Types.WorkerMagic (WorkerMagic(..))+import qualified Data.Some+import qualified Data.Text+import qualified Data.Text.IO+import qualified System.Timeout+import qualified Network.Socket.ByteString++type WorkerHelper m+ = forall a+ . ( Show a+ , StoreReply a+ )+ => RemoteStoreT m a+ -> Run m a++chatty :: Bool+chatty = False++dbg :: MonadIO m => Text -> m ()+dbg = when chatty . liftIO . Data.Text.IO.putStrLn++-- | Run an emulated nix daemon on given socket address.+-- The deamon will close when the continuation returns.+runProxyDaemon+ :: forall m a+ . ( MonadIO m+ , MonadConc m+ )+ => WorkerHelper m+ -> RemoteStoreT m ()+ -> Socket+ -> m a+ -> m a+runProxyDaemon workerHelper postGreet lsock k = do+ liftIO $ listen lsock maxListenQueue++ dbg "listening"++ let listener :: m Void+ listener = do+ (sock, _) <- liftIO $ accept lsock+ dbg "accepting"++ -- TODO: this, but without the space leak+ fmap fst+ $ concurrently listener+ $ processConnection workerHelper postGreet sock++ either absurd id <$> race listener k++-- | "main loop" of the daemon for a single connection.+--+-- this function should take care to not throw errors from client connections.+processConnection+ :: forall m+ . MonadIO m+ => WorkerHelper m+ -> RemoteStoreT m ()+ -> Socket+ -> m ()+processConnection workerHelper postGreet sock = do+ ~() <- void $ runRemoteStoreT sock $ do++ ServerHandshakeOutput{..}+ <- greet+ ServerHandshakeInput+ { serverHandshakeInputNixVersion = "nixVersion (hnix-store-remote)"+ , serverHandshakeInputOurVersion = def+ , serverHandshakeInputTrust = Nothing+ }++ setProtoVersion serverHandshakeOutputLeastCommonVersion++ tunnelLogger <- liftIO $ newTunnelLogger+ -- Send startup error messages to the client.+ startWork tunnelLogger++ -- TODO: do we need auth at all? probably?+ -- If we can't accept clientVersion, then throw an error *here* (not above).+ --authHook(*store);+ stopWork tunnelLogger++ -- so we can set store dir+ postGreet++ let perform+ :: ( Show a+ , StoreReply a+ )+ => StoreRequest a+ -> RemoteStoreT m ()+ perform req = do++ special <- case req of+ AddToStore {} -> do+ -- This is a hack (but a pretty neat and fast one!)+ -- it should parse nad stream NAR instead+ let proxyNarSource :: NarSource IO+ proxyNarSource f =+ liftIO+ (System.Timeout.timeout+ 1000000+ (Network.Socket.ByteString.recv sock 8)+ )+ >>= \case+ Nothing -> pure ()+ Just x -> f x >> proxyNarSource f++ pure $ setNarSource proxyNarSource+ _ -> pure $ pure ()++ res <-+ bracketLogger+ tunnelLogger+ $ lift+ $ workerHelper+ $ special >> doReq req++ case fst res of+ Left e -> throwError e+ Right reply ->+ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerReply+ $ getReplyS+ )+ reply++ -- Process client requests.+ let loop = do+ someReq <-+ sockGetS+ $ mapErrorS+ RemoteStoreError_SerializerRequest+ storeRequest++ -- have to be explicit here+ -- because otherwise GHC can't conjure Show a, StoreReply a+ -- out of thin air+ () <- Data.Some.withSome someReq $ \case+ r@AddToStore {} -> perform r+ r@AddToStoreNar {} -> perform r+ r@AddTextToStore {} -> perform r+ r@AddSignatures {} -> perform r+ r@AddTempRoot {} -> perform r+ r@AddIndirectRoot {} -> perform r+ r@BuildDerivation {} -> perform r+ r@BuildPaths {} -> perform r+ r@CollectGarbage {} -> perform r+ r@EnsurePath {} -> perform r+ r@FindRoots {} -> perform r+ r@IsValidPath {} -> perform r+ r@NarFromPath {} -> perform r+ r@QueryValidPaths {} -> perform r+ r@QueryAllValidPaths {} -> perform r+ r@QuerySubstitutablePaths {} -> perform r+ r@QueryPathInfo {} -> perform r+ r@QueryReferrers {} -> perform r+ r@QueryValidDerivers {} -> perform r+ r@QueryDerivationOutputs {} -> perform r+ r@QueryDerivationOutputNames {} -> perform r+ r@QueryPathFromHashPart {} -> perform r+ r@QueryMissing {} -> perform r+ r@OptimiseStore {} -> perform r+ r@SyncWithGC {} -> perform r+ r@VerifyStore {} -> perform r+ loop+ loop++ dbg "daemon connection done"+ liftIO $ close sock++ where+ -- Exchange the greeting.+ greet+ :: MonadIO m+ => ServerHandshakeInput+ -> RemoteStoreT m ServerHandshakeOutput+ greet ServerHandshakeInput{..} = do+ magic <-+ sockGetS+ $ mapErrorS+ RemoteStoreError_SerializerHandshake+ workerMagic++ when (magic /= WorkerMagic_One)+ $ throwError+ $ RemoteStoreError_WorkerException+ WorkerException_ProtocolMismatch++ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerHandshake+ workerMagic+ )+ WorkerMagic_Two++ sockPutS protoVersion serverHandshakeInputOurVersion++ clientVersion <- sockGetS protoVersion++ let leastCommonVersion = min clientVersion serverHandshakeInputOurVersion++ when (clientVersion < ProtoVersion 1 10)+ $ throwError+ $ RemoteStoreError_WorkerException+ WorkerException_ClientVersionTooOld++ when (clientVersion >= ProtoVersion 1 14) $ do+ x :: Word32 <- sockGetS int+ when (x /= 0) $ do+ -- Obsolete CPU affinity.+ _ :: Word32 <- sockGetS int+ pure ()++ when (clientVersion >= ProtoVersion 1 11) $ do+ _ :: Word32 <- sockGetS int -- obsolete reserveSpace+ pure ()++ when (clientVersion >= ProtoVersion 1 33) $ do+ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerPut+ text+ )+ serverHandshakeInputNixVersion++ when (clientVersion >= ProtoVersion 1 35) $ do+ sockPutS+ (mapErrorS+ RemoteStoreError_SerializerHandshake+ trustedFlag+ )+ serverHandshakeInputTrust++ pure ServerHandshakeOutput+ { serverHandshakeOutputLeastCommonVersion = leastCommonVersion+ , serverHandshakeOutputClientVersion = clientVersion+ }++{-# WARNING _unimplemented "not yet implemented" #-}+_unimplemented :: RemoteStoreError+_unimplemented = RemoteStoreError_WorkerException $ WorkerException_Error $ WorkerError_NotYetImplemented++bracketLogger+ :: MonadRemoteStore m+ => TunnelLogger+ -> m a+ -> m a+bracketLogger tunnelLogger m = do+ startWork tunnelLogger+ a <- m+ stopWork tunnelLogger+ pure a++---++data TunnelLogger = TunnelLogger+ { _tunnelLogger_state :: IORef TunnelLoggerState+ }++data TunnelLoggerState = TunnelLoggerState+ { _tunnelLoggerState_canSendStderr :: Bool+ , _tunnelLoggerState_pendingMsgs :: [Logger]+ }++newTunnelLogger :: IO TunnelLogger+newTunnelLogger = TunnelLogger <$> newIORef (TunnelLoggerState False [])++enqueueMsg+ :: ( MonadRemoteStore m+ , MonadError LoggerSError m+ )+ => TunnelLogger+ -> Logger+ -> m ()+enqueueMsg x l = updateLogger x $ \st@(TunnelLoggerState c p) -> case c of+ True -> (st, sockPutS logger l)+ False -> (TunnelLoggerState c (l:p), pure ())++_log+ :: ( MonadRemoteStore m+ , MonadError LoggerSError m+ )+ => TunnelLogger+ -> Text+ -> m ()+_log l s = enqueueMsg l (Logger_Next s)++startWork+ :: MonadRemoteStore m+ => TunnelLogger+ -> m ()+startWork x = updateLogger x $ \(TunnelLoggerState _ p) -> (,)+ (TunnelLoggerState True []) $+ (traverse_ (sockPutS logger') $ reverse p)+ where logger' = mapErrorS RemoteStoreError_SerializerLogger logger++stopWork+ :: MonadRemoteStore m+ => TunnelLogger+ -> m ()+stopWork x = updateLogger x $ \_ -> (,)+ (TunnelLoggerState False [])+ (sockPutS (mapErrorS RemoteStoreError_SerializerLogger logger) Logger_Last)++-- | Stop sending logging and report an error.+--+-- Returns true if the the session was in a state that allowed the error to be+-- sent.+--+-- Unlike 'stopWork', this function may be called at any time to (try) to end a+-- session with an error.+_stopWorkOnError+ :: MonadRemoteStore m+ => TunnelLogger+ -> ErrorInfo+ -> m Bool+_stopWorkOnError x ex = updateLogger x $ \st ->+ case _tunnelLoggerState_canSendStderr st of+ False -> (st, pure False)+ True -> (,) (TunnelLoggerState False []) $ do+ getProtoVersion >>= \pv -> if protoVersion_minor pv >= 26+ then sockPutS logger' (Logger_Error (Right ex))+ else sockPutS logger' (Logger_Error (Left (BasicError 0 (Data.Text.pack $ show ex))))+ pure True+ where logger' = mapErrorS RemoteStoreError_SerializerLogger logger++updateLogger+ :: MonadRemoteStore m+ => TunnelLogger+ -> (TunnelLoggerState -> (TunnelLoggerState, m a))+ -> m a+updateLogger x = join . liftIO . atomicModifyIORef (_tunnelLogger_state x)
+ src/System/Nix/Store/Remote/Socket.hs view
@@ -0,0 +1,101 @@+module System.Nix.Store.Remote.Socket where++import Control.Monad.Except (MonadError, throwError)+import Control.Monad.IO.Class (MonadIO(..))+import Data.ByteString (ByteString)+import Data.Serialize.Get (Get, Result(..))+import Data.Serialize.Put (Put, runPut)+import Network.Socket.ByteString (recv, sendAll)+import System.Nix.Store.Remote.MonadStore (MonadRemoteStore(..), RemoteStoreError(..))+import System.Nix.Store.Remote.Serializer (NixSerializer, runP, runSerialT)+import System.Nix.Store.Remote.Types (ProtoStoreConfig)++import qualified Control.Exception+import qualified Data.ByteString+import qualified Data.Serializer+import qualified Data.Serialize.Get++genericIncremental+ :: ( MonadIO m+ , MonadError RemoteStoreError m+ , Show a+ )+ => m ByteString+ -> Get a+ -> m a+genericIncremental getsome parser = do+ getsome >>= go . decoder+ where+ decoder = Data.Serialize.Get.runGetPartial parser+ go (Done x leftover) | leftover /= mempty =+ throwError+ $ RemoteStoreError_GenericIncrementalLeftovers+ (show x)+ leftover++ go (Done x _leftover) = pure x++ go (Partial k) = do+ chunk <- getsome+ go (k chunk)++ go (Fail msg leftover) =+ throwError+ $ RemoteStoreError_GenericIncrementalFail+ msg+ leftover++sockGet8+ :: MonadRemoteStore m+ => m ByteString+sockGet8 = do+ soc <- getStoreSocket+ eresult <- liftIO $ Control.Exception.try $ recv soc 8+ case eresult of+ Left e ->+ throwError $ RemoteStoreError_IOException e++ Right result | Data.ByteString.length result == 0 ->+ throwError RemoteStoreError_Disconnected++ Right result | otherwise ->+ pure result++sockPut+ :: MonadRemoteStore m+ => Put+ -> m ()+sockPut p = do+ soc <- getStoreSocket+ liftIO $ sendAll soc $ runPut p++sockPutS+ :: ( MonadRemoteStore m+ , MonadError e m+ )+ => NixSerializer ProtoStoreConfig e a+ -> a+ -> m ()+sockPutS s a = do+ cfg <- getConfig+ sock <- getStoreSocket+ case runP s cfg a of+ Right x -> liftIO $ sendAll sock x+ Left e -> throwError e++sockGetS+ :: ( MonadRemoteStore m+ , MonadError e m+ , Show a+ , Show e+ )+ => NixSerializer ProtoStoreConfig e a+ -> m a+sockGetS s = do+ cfg <- getConfig+ res <- genericIncremental sockGet8+ $ runSerialT cfg $ Data.Serializer.getS s++ case res of+ Right x -> pure x+ Left e -> throwError e
src/System/Nix/Store/Remote/Types.hs view
@@ -1,77 +1,33 @@-{-# language DataKinds #-}-{-# language KindSignatures #-}-{-# language ScopedTypeVariables #-} module System.Nix.Store.Remote.Types- ( MonadStore- , StoreConfig(..)- , Logger(..)- , Field(..)- , getStoreDir- , getLog- , flushLog- , gotError- , getError- , setData- , clearData- )-where---import qualified Data.ByteString.Lazy as BSL-import Network.Socket ( Socket )--data StoreConfig = StoreConfig- { storeDir :: FilePath- , storeSocket :: Socket- }--type MonadStore a- = ExceptT- String- (StateT (Maybe BSL.ByteString, [Logger]) (ReaderT StoreConfig IO))- a--type ActivityID = Int-type ActivityParentID = Int-type ActivityType = Int-type Verbosity = Int-type ResultType = Int--data Field = LogStr ByteString | LogInt Int- deriving (Eq, Ord, Show)--data Logger =- Next ByteString- | Read Int -- data needed from source- | Write ByteString -- data for sink- | Last- | Error Int ByteString- | StartActivity ActivityID Verbosity ActivityType ByteString [Field] ActivityParentID- | StopActivity ActivityID- | Result ActivityID ResultType [Field]- deriving (Eq, Ord, Show)--isError :: Logger -> Bool-isError (Error _ _) = True-isError _ = False--gotError :: MonadStore Bool-gotError = gets (any isError . snd)--getError :: MonadStore [Logger]-getError = gets (filter isError . snd)--getLog :: MonadStore [Logger]-getLog = gets snd--flushLog :: MonadStore ()-flushLog = modify (\(a, _b) -> (a, []))--setData :: BSL.ByteString -> MonadStore ()-setData x = modify (\(_, b) -> (Just x, b))--clearData :: MonadStore ()-clearData = modify (\(_, b) -> (Nothing, b))+ ( module System.Nix.Store.Remote.Types.Activity+ , module System.Nix.Store.Remote.Types.GC+ , module System.Nix.Store.Remote.Types.CheckMode+ , module System.Nix.Store.Remote.Types.Logger+ , module System.Nix.Store.Remote.Types.ProtoVersion+ , module System.Nix.Store.Remote.Types.Query+ , module System.Nix.Store.Remote.Types.StoreConfig+ , module System.Nix.Store.Remote.Types.StoreRequest+ , module System.Nix.Store.Remote.Types.StoreText+ , module System.Nix.Store.Remote.Types.SubstituteMode+ , module System.Nix.Store.Remote.Types.SuccessCodeReply+ , module System.Nix.Store.Remote.Types.TrustedFlag+ , module System.Nix.Store.Remote.Types.Verbosity+ , module System.Nix.Store.Remote.Types.WorkerMagic+ , module System.Nix.Store.Remote.Types.WorkerOp+ ) where -getStoreDir :: MonadStore FilePath-getStoreDir = asks storeDir+import System.Nix.Store.Remote.Types.Activity+import System.Nix.Store.Remote.Types.GC+import System.Nix.Store.Remote.Types.CheckMode+import System.Nix.Store.Remote.Types.Logger+import System.Nix.Store.Remote.Types.ProtoVersion+import System.Nix.Store.Remote.Types.Query+import System.Nix.Store.Remote.Types.StoreConfig+import System.Nix.Store.Remote.Types.StoreRequest+import System.Nix.Store.Remote.Types.StoreText+import System.Nix.Store.Remote.Types.SubstituteMode+import System.Nix.Store.Remote.Types.SuccessCodeReply+import System.Nix.Store.Remote.Types.TrustedFlag+import System.Nix.Store.Remote.Types.Verbosity+import System.Nix.Store.Remote.Types.WorkerMagic+import System.Nix.Store.Remote.Types.WorkerOp
+ src/System/Nix/Store/Remote/Types/Activity.hs view
@@ -0,0 +1,55 @@+module System.Nix.Store.Remote.Types.Activity+ ( Activity(..)+ , ActivityID(..)+ , ActivityResult(..)+ ) where++import GHC.Generics++-- | Type of the activity+--+-- We don't have Activity_Unknown here+-- as we can do @Maybe Activity@ and @Nothing@+-- corresponding to Unknown (which has 0 value)+--+-- Rest of the values are offset by @(+100)@+-- on the wire, i.e.:+--+-- * @Activity_CopyPath = 100@+-- * @Activity_BuildWaiting = 111@+data Activity+ = Activity_CopyPath+ | Activity_FileTransfer+ | Activity_Realise+ | Activity_CopyPaths+ | Activity_Builds+ | Activity_Build+ | Activity_OptimiseStore+ | Activity_VerifyPaths+ | Activity_Substitute+ | Activity_QueryPathInfo+ | Activity_PostBuildHook+ | Activity_BuildWaiting+ deriving (Bounded, Eq, Enum, Generic, Ord, Show)++-- | Numeric ID of the activity+newtype ActivityID = ActivityID { unActivityID :: Int }+ deriving (Eq, Generic, Ord, Show)++-- | Result of some activity+--+-- The values are offset by @(+100)@+-- on the wire, i.e.:+--+-- * @ActivityResult_FileLinked = 100@+-- * @ActivityResult_PostBuildLogLine = 107@+data ActivityResult+ = ActivityResult_FileLinked+ | ActivityResult_BuildLogLine+ | ActivityResult_UnstrustedPath+ | ActivityResult_CorruptedPath+ | ActivityResult_SetPhase+ | ActivityResult_Progress+ | ActivityResult_SetExpected+ | ActivityResult_PostBuildLogLine+ deriving (Bounded, Eq, Enum, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/CheckMode.hs view
@@ -0,0 +1,11 @@+module System.Nix.Store.Remote.Types.CheckMode+ ( CheckMode(..)+ ) where++import GHC.Generics++-- | Check mode, used by @verifyStore@+data CheckMode+ = CheckMode_DoCheck+ | CheckMode_DontCheck+ deriving (Bounded, Eq, Generic, Enum, Ord, Show)
+ src/System/Nix/Store/Remote/Types/GC.hs view
@@ -0,0 +1,55 @@+{-|+Description : Garbage collection actions / options+Maintainer : srk <srk@48.io>+|-}+module System.Nix.Store.Remote.Types.GC (+ GCAction(..)+ , GCOptions(..)+ , GCResult(..)+ , GCRoot(..)+ ) where++import Data.HashSet (HashSet)+import Data.Word (Word64)+import GHC.Generics (Generic)+import System.Nix.StorePath (StorePath)+import System.Posix.ByteString (RawFilePath)++-- | Garbage collection action+data GCAction+ = GCAction_ReturnLive -- ^ Return the set of paths reachable from roots (closure)+ | GCAction_ReturnDead -- ^ Return unreachable paths+ | GCAction_DeleteDead -- ^ Delete unreachable paths+ | GCAction_DeleteSpecific -- ^ Delete specified paths+ deriving (Bounded, Eq, Enum, Generic, Ord, Show)++-- | Garbage collector operation options+data GCOptions = GCOptions+ { -- | Operation+ gcOptionsOperation :: GCAction+ -- | If set, then reachability from the roots is ignored (unused)+ , gcOptionsIgnoreLiveness :: Bool+ -- | Paths to delete for @GCAction_DeleteSpecific@+ , gcOptionsPathsToDelete :: HashSet StorePath+ -- | Stop after `gcOptions_maxFreed` bytes have been freed+ , gcOptionsMaxFreed :: Word64+ } deriving (Eq, Generic, Ord, Show)++-- | Result of the garbage collection operation+data GCResult = GCResult+ { -- | Depending on the action, the GC roots,+ -- or the paths that would be or have been deleted+ gcResultDeletedPaths :: HashSet StorePath+ -- | The number of bytes that would be or was freed for+ --+ -- - @GCAction_ReturnDead@+ -- - @GCAction_DeleteDead@+ -- - @GCAction_DeleteSpecific@+ , gcResultBytesFreed :: Word64+ } deriving (Eq, Generic, Ord, Show)++-- | Used as a part of the result of @FindRoots@ operation+data GCRoot+ = GCRoot_Censored -- ^ Source path is censored since the user is not trusted+ | GCRoot_Path RawFilePath -- ^ Raw source path+ deriving (Eq, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/Handshake.hs view
@@ -0,0 +1,37 @@+module System.Nix.Store.Remote.Types.Handshake+ ( ClientHandshakeInput(..)+ , ClientHandshakeOutput(..)+ , ServerHandshakeInput(..)+ , ServerHandshakeOutput(..)+ ) where++import Data.Text (Text)+import GHC.Generics (Generic)+import System.Nix.Store.Remote.Types.ProtoVersion (ProtoVersion)+import System.Nix.Store.Remote.Types.TrustedFlag (TrustedFlag)++-- | Data sent by the client during initial protocol handshake+data ClientHandshakeInput = ClientHandshakeInput+ { clientHandshakeInputOurVersion :: ProtoVersion -- ^ Our protocol version (that we advertise to the server)+ } deriving (Eq, Generic, Ord, Show)++-- | Data received by the client via initial protocol handshake+data ClientHandshakeOutput = ClientHandshakeOutput+ { clientHandshakeOutputNixVersion :: Maybe Text -- ^ Textual version, since 1.33+ , clientHandshakeOutputTrust :: Maybe TrustedFlag -- ^ Whether remote side trusts us+ , clientHandshakeOutputLeastCommonVersion :: ProtoVersion -- ^ Minimum protocol version supported by both sides+ , clientHandshakeOutputServerVersion :: ProtoVersion -- ^ Protocol version supported by the server+ } deriving (Eq, Generic, Ord, Show)++-- | Data sent by the server during initial protocol handshake+data ServerHandshakeInput = ServerHandshakeInput+ { serverHandshakeInputNixVersion :: Text -- ^ Textual version, since 1.33+ , serverHandshakeInputOurVersion :: ProtoVersion -- ^ Our protocol version (that we advertise to the client)+ , serverHandshakeInputTrust :: Maybe TrustedFlag -- ^ Whether client should trusts us+ } deriving (Eq, Generic, Ord, Show)++-- | Data received by the server during initial protocol handshake+data ServerHandshakeOutput = ServerHandshakeOutput+ { serverHandshakeOutputLeastCommonVersion :: ProtoVersion -- ^ Minimum protocol version supported by both sides+ , serverHandshakeOutputClientVersion :: ProtoVersion -- ^ Protocol version supported by the client+ } deriving (Eq, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/Logger.hs view
@@ -0,0 +1,108 @@+module System.Nix.Store.Remote.Types.Logger+ ( Field(..)+ , Trace(..)+ , BasicError(..)+ , ErrorInfo(..)+ , Logger(..)+ , LoggerOpCode(..)+ , loggerOpCodeToWord64+ , word64ToLoggerOpCode+ , isError+ ) where++import Data.ByteString (ByteString)+import Data.Text (Text)+import Data.Word (Word64)+import GHC.Generics+import System.Nix.Store.Remote.Types.Activity (Activity, ActivityID, ActivityResult)+import System.Nix.Store.Remote.Types.Verbosity (Verbosity)++data Field+ = Field_LogStr Text+ | Field_LogInt Int+ deriving (Eq, Generic, Ord, Show)++-- | Error trace+data Trace = Trace+ { tracePosition :: Maybe Int -- Error position, Nix always writes 0 here+ , traceHint :: Text+ }+ deriving (Eq, Generic, Ord, Show)++data BasicError = BasicError+ { basicErrorExitStatus :: Int+ , basicErrorMessage :: Text+ }+ deriving (Eq, Generic, Ord, Show)++-- | Extended error info+-- available for protoVersion_minor >= 26+data ErrorInfo = ErrorInfo+ { errorInfoLevel :: Verbosity+ , errorInfoMessage :: Text+ , errorInfoPosition :: Maybe Int -- Error position, Nix always writes 0 here+ , errorInfoTraces :: [Trace]+ }+ deriving (Eq, Generic, Ord, Show)++data LoggerOpCode+ = LoggerOpCode_Next+ | LoggerOpCode_Read+ | LoggerOpCode_Write+ | LoggerOpCode_Last+ | LoggerOpCode_Error+ | LoggerOpCode_StartActivity+ | LoggerOpCode_StopActivity+ | LoggerOpCode_Result+ deriving (Eq, Generic, Ord, Show)++loggerOpCodeToWord64 :: LoggerOpCode -> Word64+loggerOpCodeToWord64 = \case+ LoggerOpCode_Next -> 0x6f6c6d67+ LoggerOpCode_Read -> 0x64617461+ LoggerOpCode_Write -> 0x64617416+ LoggerOpCode_Last -> 0x616c7473+ LoggerOpCode_Error -> 0x63787470+ LoggerOpCode_StartActivity -> 0x53545254+ LoggerOpCode_StopActivity -> 0x53544f50+ LoggerOpCode_Result -> 0x52534c54++word64ToLoggerOpCode :: Word64 -> Either String LoggerOpCode+word64ToLoggerOpCode = \case+ 0x6f6c6d67 -> Right LoggerOpCode_Next+ 0x64617461 -> Right LoggerOpCode_Read+ 0x64617416 -> Right LoggerOpCode_Write+ 0x616c7473 -> Right LoggerOpCode_Last+ 0x63787470 -> Right LoggerOpCode_Error+ 0x53545254 -> Right LoggerOpCode_StartActivity+ 0x53544f50 -> Right LoggerOpCode_StopActivity+ 0x52534c54 -> Right LoggerOpCode_Result+ x -> Left $ "Invalid LoggerOpCode: " ++ show x++data Logger+ = Logger_Next Text+ | Logger_Read Word64 -- data needed from source+ | Logger_Write ByteString -- data for sink+ | Logger_Last+ | Logger_Error (Either BasicError ErrorInfo)+ | Logger_StartActivity+ { startActivityID :: ActivityID+ , startActivityVerbosity :: Verbosity+ , startActivityType :: Maybe Activity+ , startActivityString :: ByteString+ , startActivityFields :: [Field]+ , startActivityParentID :: ActivityID+ }+ | Logger_StopActivity+ { stopActivityID :: ActivityID+ }+ | Logger_Result+ { resultActivityID :: ActivityID+ , resultType :: ActivityResult+ , resultFields :: [Field]+ }+ deriving (Eq, Generic, Ord, Show)++isError :: Logger -> Bool+isError Logger_Error {} = True+isError _ = False
+ src/System/Nix/Store/Remote/Types/NoReply.hs view
@@ -0,0 +1,8 @@+module System.Nix.Store.Remote.Types.NoReply+ ( NoReply(..)+ ) where++-- | Reply type for the case where the server does not reply+data NoReply = NoReply+ deriving (Show)+
+ src/System/Nix/Store/Remote/Types/ProtoVersion.hs view
@@ -0,0 +1,27 @@+module System.Nix.Store.Remote.Types.ProtoVersion+ ( ProtoVersion(..)+ , HasProtoVersion(..)+ ) where++import Data.Default.Class (Default(def))+import Data.Word (Word8, Word16)+import GHC.Generics (Generic)++data ProtoVersion = ProtoVersion+ { protoVersion_major :: Word16+ , protoVersion_minor :: Word8+ }+ deriving (Eq, Generic, Ord, Show)++-- | The protocol version we support+instance Default ProtoVersion where+ def = ProtoVersion+ { protoVersion_major = 1+ , protoVersion_minor = 24+ }++class HasProtoVersion r where+ hasProtoVersion :: r -> ProtoVersion++instance HasProtoVersion ProtoVersion where+ hasProtoVersion = id
+ src/System/Nix/Store/Remote/Types/Query.hs view
@@ -0,0 +1,5 @@+module System.Nix.Store.Remote.Types.Query+ ( module System.Nix.Store.Remote.Types.Query.Missing+ ) where++import System.Nix.Store.Remote.Types.Query.Missing
+ src/System/Nix/Store/Remote/Types/Query/Missing.hs view
@@ -0,0 +1,18 @@+module System.Nix.Store.Remote.Types.Query.Missing+ ( Missing(..)+ ) where++import Data.HashSet (HashSet)+import Data.Word (Word64)+import GHC.Generics (Generic)+import System.Nix.StorePath (StorePath)++-- | Result of @QueryMissing@ @StoreRequest@+data Missing = Missing+ { missingWillBuild :: HashSet StorePath -- ^ Paths that will be built+ , missingWillSubstitute :: HashSet StorePath -- ^ Paths that can be substituted from cache+ , missingUnknownPaths :: HashSet StorePath -- ^ Path w/o any information+ , missingDownloadSize :: Word64 -- ^ Total size of packed NARs to download+ , missingNarSize :: Word64 -- ^ Total size of NARs after unpacking+ }+ deriving (Eq, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/StoreConfig.hs view
@@ -0,0 +1,61 @@+{-# OPTIONS_GHC -Wno-orphans #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module System.Nix.Store.Remote.Types.StoreConfig+ ( ProtoStoreConfig(..)+ , StoreSocketPath(..)+ , StoreTCP(..)+ , StoreConnection(..)+ , HasStoreSocket(..)+ ) where++import Data.Default.Class (Default(def))+import Data.String (IsString)+import GHC.Generics (Generic)+import Network.Socket (Socket)+import System.Nix.StorePath (HasStoreDir(..), StoreDir)+import System.Nix.Store.Remote.Types.ProtoVersion (HasProtoVersion(..), ProtoVersion)++class HasStoreSocket r where+ hasStoreSocket :: r -> Socket++instance HasStoreSocket Socket where+ hasStoreSocket = id++data ProtoStoreConfig = ProtoStoreConfig+ { protoStoreConfigDir :: StoreDir+ , protoStoreConfigProtoVersion :: ProtoVersion+ } deriving (Eq, Generic, Ord, Show)++instance Default ProtoStoreConfig where+ def = ProtoStoreConfig def def++instance HasStoreDir StoreDir where+ hasStoreDir = id++instance HasStoreDir ProtoStoreConfig where+ hasStoreDir = protoStoreConfigDir++instance HasProtoVersion ProtoStoreConfig where+ hasProtoVersion = protoStoreConfigProtoVersion++newtype StoreSocketPath = StoreSocketPath+ { unStoreSocketPath :: FilePath+ }+ deriving newtype (IsString)+ deriving stock (Eq, Generic, Ord, Show)++instance Default StoreSocketPath where+ def = StoreSocketPath "/nix/var/nix/daemon-socket/socket"++data StoreTCP = StoreTCP+ { storeTCPHost :: String+ , storeTCPPort :: Int+ } deriving (Eq, Generic, Ord, Show)++data StoreConnection+ = StoreConnection_Socket StoreSocketPath+ | StoreConnection_TCP StoreTCP+ deriving (Eq, Generic, Ord, Show)++instance Default StoreConnection where+ def = StoreConnection_Socket def
+ src/System/Nix/Store/Remote/Types/StoreReply.hs view
@@ -0,0 +1,61 @@+module System.Nix.Store.Remote.Types.StoreReply+ ( StoreReply(..)+ ) where++import Data.HashSet (HashSet)+import Data.Map (Map)+import System.Nix.Build (BuildResult)+import System.Nix.StorePath (StorePath, StorePathName)+import System.Nix.StorePath.Metadata (Metadata)+import System.Nix.Store.Remote.Serializer+import System.Nix.Store.Remote.Types.NoReply (NoReply(..))+import System.Nix.Store.Remote.Types.SuccessCodeReply (SuccessCodeReply)+import System.Nix.Store.Remote.Types.GC (GCResult, GCRoot)+import System.Nix.Store.Remote.Types.Query.Missing (Missing)+import System.Nix.Store.Remote.Types.StoreConfig (ProtoStoreConfig)++-- | Get @NixSerializer@ for some type @a@+-- This could also be generalized for every type+-- we have a serializer for but we mostly need+-- this for replies and it would make look serializers+-- quite hodor, like @a <- getS get; b <- getS get@+class StoreReply a where+ getReplyS :: NixSerializer ProtoStoreConfig ReplySError a++instance StoreReply SuccessCodeReply where+ getReplyS = opSuccess++instance StoreReply NoReply where+ getReplyS = noop NoReply++instance StoreReply Bool where+ getReplyS = mapPrimE bool++instance StoreReply BuildResult where+ getReplyS = buildResult++instance StoreReply GCResult where+ getReplyS = gcResult++instance StoreReply (Map GCRoot StorePath) where+ getReplyS = mapS gcRoot (mapPrimE storePath)++instance StoreReply Missing where+ getReplyS = missing++instance StoreReply (Maybe (Metadata StorePath)) where+ getReplyS = maybePathMetadata++instance StoreReply StorePath where+ getReplyS = mapPrimE storePath++instance StoreReply (HashSet StorePath) where+ getReplyS = mapPrimE (hashSet storePath)++instance StoreReply (HashSet StorePathName) where+ getReplyS = mapPrimE (hashSet storePathName)++mapPrimE+ :: NixSerializer r SError a+ -> NixSerializer r ReplySError a+mapPrimE = mapErrorS ReplySError_PrimGet
+ src/System/Nix/Store/Remote/Types/StoreRequest.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TemplateHaskell #-}++module System.Nix.Store.Remote.Types.StoreRequest+ ( StoreRequest(..)+ ) where++import Data.GADT.Compare.TH (deriveGEq, deriveGCompare)+import Data.GADT.Show.TH (deriveGShow)+import Data.HashSet (HashSet)+import Data.Kind (Type)+import Data.Map (Map)+import Data.Set (Set)+import Data.Text (Text)+import Data.Some (Some(Some))++import System.Nix.Build (BuildMode, BuildResult)+import System.Nix.Derivation (Derivation)+import System.Nix.DerivedPath (DerivedPath)+import System.Nix.Hash (HashAlgo)+import System.Nix.Signature (Signature)+import System.Nix.Store.Types (FileIngestionMethod, RepairMode)+import System.Nix.StorePath (StorePath, StorePathName, StorePathHashPart)+import System.Nix.StorePath.Metadata (Metadata)+import System.Nix.Store.Remote.Types.GC (GCOptions, GCResult, GCRoot)+import System.Nix.Store.Remote.Types.CheckMode (CheckMode)+import System.Nix.Store.Remote.Types.NoReply (NoReply)+import System.Nix.Store.Remote.Types.Query.Missing (Missing)+import System.Nix.Store.Remote.Types.StoreText (StoreText)+import System.Nix.Store.Remote.Types.SubstituteMode (SubstituteMode)+import System.Nix.Store.Remote.Types.SuccessCodeReply (SuccessCodeReply)++data StoreRequest :: Type -> Type where+ -- | Add @NarSource@ to the store.+ AddToStore+ :: StorePathName -- ^ Name part of the newly created @StorePath@+ -> FileIngestionMethod -- ^ Add target directory recursively+ -> Some HashAlgo -- ^ Nar hashing algorithm+ -> RepairMode -- ^ Only used by local store backend+ -> StoreRequest StorePath++ -- | Add a NAR with Metadata to the store.+ AddToStoreNar+ :: StorePath+ -> Metadata StorePath+ -> RepairMode+ -> CheckMode -- ^ Whether to check signatures+ -> StoreRequest NoReply++ -- | Add text to store.+ --+ -- Reference accepts repair but only uses it+ -- to throw error in case of remote talking to nix-daemon.+ AddTextToStore+ :: StoreText+ -> HashSet StorePath -- ^ Set of @StorePath@s that the added text references+ -> RepairMode -- ^ Repair mode, must be @RepairMode_DontRepair@ in case of remote backend+ -> StoreRequest StorePath++ AddSignatures+ :: StorePath+ -> Set Signature+ -> StoreRequest SuccessCodeReply++ AddIndirectRoot+ :: StorePath+ -> StoreRequest SuccessCodeReply++ -- | Add temporary garbage collector root.+ --+ -- This root is removed as soon as the client exits.+ AddTempRoot+ :: StorePath+ -> StoreRequest SuccessCodeReply++ -- | Build paths if they are an actual derivations.+ --+ -- If derivation output paths are already valid, do nothing.+ BuildPaths+ :: Set DerivedPath+ -> BuildMode+ -> StoreRequest SuccessCodeReply++ BuildDerivation+ :: StorePath+ -> Derivation StorePath Text+ -> BuildMode+ -> StoreRequest BuildResult++ CollectGarbage+ :: GCOptions+ -> StoreRequest GCResult++ EnsurePath+ :: StorePath+ -> StoreRequest SuccessCodeReply++ -- | Find garbage collector roots.+ FindRoots+ :: StoreRequest (Map GCRoot StorePath)++ IsValidPath+ :: StorePath+ -> StoreRequest Bool++ -- | Fetch a NAR from the server+ NarFromPath+ :: StorePath+ -> StoreRequest NoReply++ -- | Query valid paths from set, optionally try to use substitutes.+ QueryValidPaths+ :: HashSet StorePath+ -- ^ Set of @StorePath@s to query+ -> SubstituteMode+ -- ^ Try substituting missing paths when @SubstituteMode_DoSubstitute@+ -> StoreRequest (HashSet StorePath)++ QueryAllValidPaths+ :: StoreRequest (HashSet StorePath)++ QuerySubstitutablePaths+ :: HashSet StorePath+ -> StoreRequest (HashSet StorePath)++ QueryPathInfo+ :: StorePath+ -> StoreRequest (Maybe (Metadata StorePath))++ QueryReferrers+ :: StorePath+ -> StoreRequest (HashSet StorePath)++ QueryValidDerivers+ :: StorePath+ -> StoreRequest (HashSet StorePath)++ QueryDerivationOutputs+ :: StorePath+ -> StoreRequest (HashSet StorePath)++ QueryDerivationOutputNames+ :: StorePath+ -> StoreRequest (HashSet StorePathName)++ QueryPathFromHashPart+ :: StorePathHashPart+ -> StoreRequest StorePath++ QueryMissing+ :: Set DerivedPath+ -> StoreRequest Missing++ OptimiseStore+ :: StoreRequest SuccessCodeReply++ SyncWithGC+ :: StoreRequest SuccessCodeReply++ -- returns True on errors+ VerifyStore+ :: CheckMode+ -> RepairMode+ -> StoreRequest Bool++deriving instance Eq (StoreRequest a)+deriving instance Show (StoreRequest a)++deriveGEq ''StoreRequest+deriveGCompare ''StoreRequest+deriveGShow ''StoreRequest++instance {-# OVERLAPPING #-} Eq (Some StoreRequest) where+ Some (AddToStore a b c d) == Some (AddToStore a' b' c' d') = (a, b, c, d) == (a', b', c', d')+ Some (AddToStoreNar a b c d) == Some (AddToStoreNar a' b' c' d') = (a, b, c, d) == (a', b', c', d')+ Some (AddTextToStore a b c) == Some (AddTextToStore a' b' c') = (a, b, c) == (a', b', c')+ Some (AddSignatures a b) == Some (AddSignatures a' b') = (a, b) == (a', b')+ Some (AddIndirectRoot a) == Some (AddIndirectRoot a') = a == a'+ Some (AddTempRoot a) == Some (AddTempRoot a') = a == a'+ Some (BuildPaths a b) == Some (BuildPaths a' b') = (a, b) == (a', b')+ Some (BuildDerivation a b c) == Some (BuildDerivation a' b' c') = (a, b, c) == (a', b', c')+ Some (CollectGarbage a) == Some (CollectGarbage a') = a == a'+ Some (EnsurePath a) == Some (EnsurePath a') = a == a'+ Some (FindRoots) == Some (FindRoots) = True+ Some (IsValidPath a) == Some (IsValidPath a') = a == a'+ Some (NarFromPath a) == Some (NarFromPath a') = a == a'+ Some (QueryValidPaths a b) == Some (QueryValidPaths a' b') = (a, b) == (a', b')+ Some QueryAllValidPaths == Some QueryAllValidPaths = True+ Some (QuerySubstitutablePaths a) == Some (QuerySubstitutablePaths a') = a == a'+ Some (QueryPathInfo a) == Some (QueryPathInfo a') = a == a'+ Some (QueryReferrers a) == Some (QueryReferrers a') = a == a'+ Some (QueryValidDerivers a) == Some (QueryValidDerivers a') = a == a'+ Some (QueryDerivationOutputs a) == Some (QueryDerivationOutputs a') = a == a'+ Some (QueryDerivationOutputNames a) == Some (QueryDerivationOutputNames a') = a == a'+ Some (QueryPathFromHashPart a) == Some (QueryPathFromHashPart a') = a == a'+ Some (QueryMissing a) == Some (QueryMissing a') = a == a'+ Some OptimiseStore == Some OptimiseStore = True+ Some SyncWithGC == Some SyncWithGC = True+ Some (VerifyStore a b) == Some (VerifyStore a' b') = (a, b) == (a', b')++ _ == _ = False
+ src/System/Nix/Store/Remote/Types/StoreText.hs view
@@ -0,0 +1,12 @@+module System.Nix.Store.Remote.Types.StoreText+ ( StoreText(..)+ ) where++import Data.Text (Text)+import GHC.Generics (Generic)+import System.Nix.StorePath (StorePathName)++data StoreText = StoreText+ { storeTextName :: StorePathName+ , storeTextText :: Text+ } deriving (Eq, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/SubstituteMode.hs view
@@ -0,0 +1,11 @@+module System.Nix.Store.Remote.Types.SubstituteMode+ ( SubstituteMode(..)+ ) where++import GHC.Generics++-- | Path substitution mode, used by @queryValidPaths@+data SubstituteMode+ = SubstituteMode_DoSubstitute+ | SubstituteMode_DontSubstitute+ deriving (Bounded, Eq, Generic, Enum, Ord, Show)
+ src/System/Nix/Store/Remote/Types/SuccessCodeReply.hs view
@@ -0,0 +1,10 @@+module System.Nix.Store.Remote.Types.SuccessCodeReply+ ( SuccessCodeReply(..)+ ) where++import GHC.Generics (Generic)++-- | Reply that checks an int success return value+data SuccessCodeReply = SuccessCodeReply+ deriving (Eq, Show, Generic)+
+ src/System/Nix/Store/Remote/Types/TrustedFlag.hs view
@@ -0,0 +1,11 @@+module System.Nix.Store.Remote.Types.TrustedFlag+ ( TrustedFlag(..)+ ) where++import GHC.Generics (Generic)++-- | Whether remote side trust us+data TrustedFlag+ = TrustedFlag_Trusted+ | TrustedFlag_NotTrusted+ deriving (Bounded, Eq, Generic, Enum, Ord, Show)
+ src/System/Nix/Store/Remote/Types/Verbosity.hs view
@@ -0,0 +1,17 @@+module System.Nix.Store.Remote.Types.Verbosity+ ( Verbosity(..)+ ) where++import GHC.Generics++-- | Logging verbosity+data Verbosity+ = Verbosity_Error+ | Verbosity_Warn+ | Verbosity_Notice+ | Verbosity_Info+ | Verbosity_Talkative+ | Verbosity_Chatty+ | Verbosity_Debug+ | Verbosity_Vomit+ deriving (Bounded, Eq, Enum, Generic, Ord, Show)
+ src/System/Nix/Store/Remote/Types/WorkerMagic.hs view
@@ -0,0 +1,27 @@+module System.Nix.Store.Remote.Types.WorkerMagic+ ( WorkerMagic(..)+ , workerMagicToWord64+ , word64ToWorkerMagic+ ) where++import Data.Word (Word64)+import GHC.Generics (Generic)++-- | WorkerMagic+--+-- Magic numbers exchange during handshake+data WorkerMagic+ = WorkerMagic_One+ | WorkerMagic_Two+ deriving (Eq, Generic, Ord, Show)++workerMagicToWord64 :: WorkerMagic -> Word64+workerMagicToWord64 = \case+ WorkerMagic_One -> 0x6e697863+ WorkerMagic_Two -> 0x6478696f++word64ToWorkerMagic :: Word64 -> Either String WorkerMagic+word64ToWorkerMagic = \case+ 0x6e697863 -> Right WorkerMagic_One+ 0x6478696f -> Right WorkerMagic_Two+ x -> Left $ "Invalid WorkerMagic: " ++ show x
+ src/System/Nix/Store/Remote/Types/WorkerOp.hs view
@@ -0,0 +1,59 @@+module System.Nix.Store.Remote.Types.WorkerOp + ( WorkerOp(..)+ ) where++import GHC.Generics (Generic)++-- | Worker opcode+--+-- This type has gaps filled in so that the GHC builtin+-- Enum instance lands on the right values.+data WorkerOp+ = WorkerOp_Reserved_0__ -- 0+ | WorkerOp_IsValidPath -- 1+ | WorkerOp_Reserved_2__ -- 2+ | WorkerOp_HasSubstitutes -- 3+ | WorkerOp_QueryPathHash -- 4 // obsolete+ | WorkerOp_QueryReferences -- 5 // obsolete+ | WorkerOp_QueryReferrers -- 6+ | WorkerOp_AddToStore -- 7+ | WorkerOp_AddTextToStore -- 8 // obsolete since 1.25, Nix 3.0. Use wopAddToStore+ | WorkerOp_BuildPaths -- 9+ | WorkerOp_EnsurePath -- 10 0xa+ | WorkerOp_AddTempRoot -- 11 0xb+ | WorkerOp_AddIndirectRoot -- 12 0xc+ | WorkerOp_SyncWithGC -- 13 0xd+ | WorkerOp_FindRoots -- 14 0xe+ | WorkerOp_Reserved_15__ -- 15 0xf+ | WorkerOp_ExportPath -- 16 0x10 // obsolete+ | WorkerOp_Reserved_17__ -- 17 0x11+ | WorkerOp_QueryDeriver -- 18 0x12 // obsolete+ | WorkerOp_SetOptions -- 19 0x13+ | WorkerOp_CollectGarbage -- 20 0x14+ | WorkerOp_QuerySubstitutablePathInfo -- 21 0x15+ | WorkerOp_QueryDerivationOutputs -- 22 0x16 // obsolete+ | WorkerOp_QueryAllValidPaths -- 23 0x17+ | WorkerOp_QueryFailedPaths -- 24 0x18+ | WorkerOp_ClearFailedPaths -- 25 0x19+ | WorkerOp_QueryPathInfo -- 26 0x1a+ | WorkerOp_ImportPaths -- 27 0x1b // obsolete+ | WorkerOp_QueryDerivationOutputNames -- 28 0x1c // obsolete+ | WorkerOp_QueryPathFromHashPart -- 29 0x1d+ | WorkerOp_QuerySubstitutablePathInfos -- 30 0x1e+ | WorkerOp_QueryValidPaths -- 31 0x1f+ | WorkerOp_QuerySubstitutablePaths -- 32 0x20+ | WorkerOp_QueryValidDerivers -- 33 0x21+ | WorkerOp_OptimiseStore -- 34 0x22+ | WorkerOp_VerifyStore -- 35 0x23+ | WorkerOp_BuildDerivation -- 36 0x24+ | WorkerOp_AddSignatures -- 37 0x25+ | WorkerOp_NarFromPath -- 38 0x26+ | WorkerOp_AddToStoreNar -- 39 0x27+ | WorkerOp_QueryMissing -- 40 0x28+ | WorkerOp_QueryDerivationOutputMap -- 41 0x29+ | WorkerOp_RegisterDrvOutput -- 42 0x2a+ | WorkerOp_QueryRealisation -- 43 0x2b+ | WorkerOp_AddMultipleToStore -- 44 0x2c+ | WorkerOp_AddBuildLog -- 45 0x2d+ | WorkerOp_BuildPathsWithResults -- 46 0x2e+ deriving (Bounded, Eq, Enum, Generic, Ord, Show, Read)
− src/System/Nix/Store/Remote/Util.hs
@@ -1,167 +0,0 @@-{-# language RecordWildCards #-}-module System.Nix.Store.Remote.Util where--import Prelude hiding ( putText )-import Control.Monad.Except--import Data.Binary.Get-import Data.Binary.Put-import qualified Data.Text.Lazy.Encoding as TL-import Data.Time-import Data.Time.Clock.POSIX-import qualified Data.ByteString.Char8 as BSC-import qualified Data.ByteString.Lazy as BSL--import Network.Socket.ByteString ( recv- , sendAll- )--import Nix.Derivation--import System.Nix.Build-import System.Nix.StorePath-import System.Nix.Store.Remote.Binary-import System.Nix.Store.Remote.Types--import qualified Data.HashSet-import qualified Data.Map--genericIncremental :: (MonadIO m) => m (Maybe ByteString) -> Get a -> m a-genericIncremental getsome parser = go decoder- where- decoder = runGetIncremental parser- go (Done _leftover _consumed x ) = pure x- go (Partial k ) = do- chunk <- getsome- go (k chunk)- go (Fail _leftover _consumed msg) = error $ fromString msg--getSocketIncremental :: Get a -> MonadStore a-getSocketIncremental = genericIncremental sockGet8- where- sockGet8 :: MonadStore (Maybe BSC.ByteString)- sockGet8 = do- soc <- asks storeSocket- liftIO $ Just <$> recv soc 8--sockPut :: Put -> MonadStore ()-sockPut p = do- soc <- asks storeSocket- liftIO $ sendAll soc $ toStrict $ runPut p--sockGet :: Get a -> MonadStore a-sockGet = getSocketIncremental--sockGetInt :: Integral a => MonadStore a-sockGetInt = getSocketIncremental getInt--sockGetBool :: MonadStore Bool-sockGetBool = (== (1 :: Int)) <$> sockGetInt--sockGetStr :: MonadStore ByteString-sockGetStr = getSocketIncremental getByteStringLen--sockGetStrings :: MonadStore [ByteString]-sockGetStrings = getSocketIncremental getByteStrings--sockGetPath :: MonadStore StorePath-sockGetPath = do- sd <- getStoreDir- pth <- getSocketIncremental (getPath sd)- either- throwError- pure- pth--sockGetPathMay :: MonadStore (Maybe StorePath)-sockGetPathMay = do- sd <- getStoreDir- pth <- getSocketIncremental (getPath sd)- pure $- either- (const Nothing)- Just- pth--sockGetPaths :: MonadStore StorePathSet-sockGetPaths = do- sd <- getStoreDir- getSocketIncremental (getPaths sd)--bsToText :: ByteString -> Text-bsToText = decodeUtf8--textToBS :: Text -> ByteString-textToBS = encodeUtf8--bslToText :: BSL.ByteString -> Text-bslToText = toText . TL.decodeUtf8--textToBSL :: Text -> BSL.ByteString-textToBSL = TL.encodeUtf8 . toLText--putText :: Text -> Put-putText = putByteStringLen . textToBSL--putTexts :: [Text] -> Put-putTexts = putByteStrings . fmap textToBSL--getPath :: FilePath -> Get (Either String StorePath)-getPath sd = parsePath sd <$> getByteStringLen--getPaths :: FilePath -> Get StorePathSet-getPaths sd =- Data.HashSet.fromList . rights . fmap (parsePath sd) <$> getByteStrings--putPath :: StorePath -> Put-putPath = putByteStringLen . fromStrict . storePathToRawFilePath--putPaths :: StorePathSet -> Put-putPaths = putByteStrings . Data.HashSet.toList . Data.HashSet.map- (fromStrict . storePathToRawFilePath)--putBool :: Bool -> Put-putBool True = putInt (1 :: Int)-putBool False = putInt (0 :: Int)--getBool :: Get Bool-getBool = (== 1) <$> (getInt :: Get Int)--putEnum :: (Enum a) => a -> Put-putEnum = putInt . fromEnum--getEnum :: (Enum a) => Get a-getEnum = toEnum <$> getInt--putTime :: UTCTime -> Put-putTime = (putInt :: Int -> Put) . round . utcTimeToPOSIXSeconds--getTime :: Get UTCTime-getTime = posixSecondsToUTCTime <$> getEnum--getBuildResult :: Get BuildResult-getBuildResult =- BuildResult- <$> getEnum- <*> (Just . bsToText <$> getByteStringLen)- <*> getInt- <*> getBool- <*> getTime- <*> getTime--putDerivation :: Derivation StorePath Text -> Put-putDerivation Derivation{..} = do- flip putMany (Data.Map.toList outputs)- $ \(outputName, DerivationOutput{..}) -> do- putText outputName- putPath path- putText hashAlgo- putText hash-- putMany putPath inputSrcs- putText platform- putText builder- putMany putText args-- flip putMany (Data.Map.toList env)- $ \(a1, a2) -> putText a1 *> putText a2
+ tests-io/DataSink.hs view
@@ -0,0 +1,26 @@+module DataSink++( DataSink(..)+, dataSinkResult+, dataSinkWriter+, newDataSink+)++where++import Data.ByteString (ByteString)++import Control.Monad.ST+import Data.STRef++-- | Basic data sink for testing+newtype DataSink = DataSink (STRef RealWorld ByteString)++newDataSink :: IO DataSink+newDataSink = DataSink <$> (stToIO . newSTRef) mempty++dataSinkWriter :: DataSink -> (ByteString -> IO())+dataSinkWriter (DataSink stref) chunk = stToIO (modifySTRef stref (chunk <>))++dataSinkResult :: DataSink -> IO ByteString+dataSinkResult (DataSink stref) = (stToIO . readSTRef) stref
+ tests-io/Main.hs view
@@ -0,0 +1,12 @@+module Main where++import qualified Test.Hspec+import qualified NixDaemonSpec++-- we run remote tests in+-- Linux namespaces to avoid interacting with systems store+main :: IO ()+main = do+ NixDaemonSpec.enterNamespaces+ Test.Hspec.hspec+ NixDaemonSpec.spec
+ tests-io/NixDaemonSpec.hs view
@@ -0,0 +1,521 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NamedFieldPuns #-}++module NixDaemonSpec+ ( enterNamespaces+ , spec+ ) where++import Control.Exception (catch, SomeException)+import Control.Monad (forM_, unless, void)+import Control.Monad.Catch (MonadMask)+import Control.Monad.Conc.Class (MonadConc)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Crypto.Hash (SHA256)+import Data.Some (Some(Some))+import Data.Text (Text)+import Test.Hspec (ActionWith, Spec, SpecWith, around, describe, context)+import Test.Hspec.Expectations.Lifted+import Test.Hspec.Nix (forceRight)+import System.FilePath ((</>))+import System.Linux.Namespaces (Namespace(..), GroupMapping(..), UserMapping(..))+import System.Nix.Hash (HashAlgo(HashAlgo_SHA256))+import System.Nix.Build (BuildMode(..))+import System.Nix.DerivedPath (DerivedPath(..))+import System.Nix.StorePath (StoreDir(..), StorePath)+import System.Nix.StorePath.Metadata (Metadata(..))+import System.Nix.Store.Remote+import System.Nix.Store.Remote.Server (WorkerHelper)+import System.Process (CreateProcess(..), ProcessHandle)+import qualified Control.Concurrent+import qualified Control.Exception+import qualified Data.ByteString.Char8+import qualified Data.Either+import qualified Data.HashSet+import qualified Data.Map+import qualified Data.Set+import qualified Data.Text+import qualified Data.Text.Encoding+import qualified DataSink+import qualified SampleNar+import qualified System.Directory+import qualified System.Environment+import qualified System.IO.Temp+import qualified System.Linux.Namespaces+import qualified System.Nix.StorePath+import qualified System.Nix.Nar+import qualified System.Posix.User+import qualified System.Process+import qualified Test.Hspec++createProcessEnv+ :: FilePath+ -> CreateProcess+ -> IO ProcessHandle+createProcessEnv fp cp = do+ mPath <- System.Environment.lookupEnv "PATH"++ (_, _, _, ph) <-+ System.Process.createProcess cp+ { cwd = Just fp+ , env = Just $ mockedEnv mPath fp+ }+ pure ph++mockedEnv+ :: Maybe String+ -> FilePath+ -> [(String, FilePath)]+mockedEnv mEnvPath fp =+ [ ("NIX_STORE_DIR" , fp </> "store")+ , ("NIX_LOCALSTATE_DIR", fp </> "var")+ , ("NIX_LOG_DIR" , fp </> "var" </> "log")+ , ("NIX_STATE_DIR" , fp </> "var" </> "nix")+ , ("NIX_CONF_DIR" , fp </> "etc")+ , ("HOME" , fp </> "home")+-- , ("NIX_REMOTE", "daemon")+ ] <> foldMap (\x -> [("PATH", x)]) mEnvPath++waitSocket+ :: FilePath+ -> Int+ -> IO ()+waitSocket _ 0 = fail "No socket"+waitSocket fp x = do+ ex <- System.Directory.doesFileExist fp+ unless ex $ do+ Control.Concurrent.threadDelay 100000+ waitSocket fp (x - 1)++writeConf :: FilePath -> IO ()+writeConf fp =+ writeFile fp $ unlines+ [ "build-users-group = "+ , "trusted-users = root"+ , "allowed-users = *"+ , "fsync-metadata = false"+ ]++{-+ - we run in user namespace as root but groups are failed+ - => build-users-group has to be empty but we still+ - get an error (maybe older nix-daemon)+ -+uid=0(root) gid=65534(nobody) groups=65534(nobody)++drwxr-xr-x 3 0 65534 60 Nov 29 05:53 store++accepted connection from pid 22959, user root (trusted)+error: changing ownership of path '/run/user/1000/test-nix-store-06b0d249e5616122/store': Invalid argument+-}++startDaemon+ :: FilePath -- ^ Temporary directory+ -> IO (ProcessHandle, StoreConnection)+startDaemon fp = do+ writeConf (fp </> "etc" </> "nix.conf")+ procHandle <-+ createProcessEnv+ fp+ $ System.Process.proc "nix-daemon" mempty++ waitSocket sockFp 30+ pure ( procHandle+ , StoreConnection_Socket+ $ StoreSocketPath sockFp+ )+ where+ sockFp = fp </> "var/nix/daemon-socket/socket"++enterNamespaces :: IO ()+enterNamespaces = do+ uid <- System.Posix.User.getEffectiveUserID+ gid <- System.Posix.User.getEffectiveGroupID++ System.Linux.Namespaces.unshare+ [User, Network, Mount]++ -- fmap our (parent) uid to root+ System.Linux.Namespaces.writeUserMappings+ Nothing+ [ UserMapping+ 0 -- inside namespace+ uid -- outside namespace+ 1 --range+ ]++ -- fmap our (parent) gid to root group+ System.Linux.Namespaces.writeGroupMappings+ Nothing+ [ GroupMapping 0 gid 1 ]+ True++withNixDaemon'+ :: (FilePath -> StoreDir -> StoreConnection -> IO a)+ -> IO a+withNixDaemon' action =+ System.IO.Temp.withSystemTempDirectory "test-nix-store" $ \path -> do++ mapM_ (System.Directory.createDirectory . snd)+ (filter+ ((/= "NIX_REMOTE") . fst)+ $ mockedEnv Nothing path)++ ini <-+ createProcessEnv+ path+ $ System.Process.shell+ -- see long note above @startDaemon@+ "nix-store --init 2>&1 | grep -v 'error: changing ownership'"++ void $ System.Process.waitForProcess ini++ writeFile (path </> "dummy") "Hello World"++ System.Directory.setCurrentDirectory path+ let storeDir =+ StoreDir+ $ Data.ByteString.Char8.pack+ $ path </> "store"++ Control.Exception.bracket+ (startDaemon path)+ (System.Process.terminateProcess . fst)+ (action path storeDir . snd)++withNixDaemon+ :: ( MonadIO m+ , MonadMask m+ )+ => ((RemoteStoreT m a -> Run m a) -> IO a)+ -> IO a+withNixDaemon action =+ withNixDaemon' $ \_tmpPath storeDir storeConn ->+ action $ \(mstore :: RemoteStoreT m a) ->+ runStoreConnection storeConn+ ( setStoreDir storeDir+ >> mstore+ )++withManInTheMiddleNixDaemon+ :: forall m a+ . ( MonadIO m+ , MonadMask m+ , MonadConc m+ )+ => ((RemoteStoreT m a -> Run m a) -> IO a)+ -> IO a+withManInTheMiddleNixDaemon action =+ withNixDaemon' $ \tmpPath storeDir storeConn ->+ let+ sockFp2 = tmpPath </> "var/nix/daemon-socket/socket2"+ storeConn2 = StoreConnection_Socket $ StoreSocketPath sockFp2++ handler :: WorkerHelper m+ handler =+ runStoreConnection storeConn+ . (setStoreDir storeDir >>)++ in action $ \(mstore :: RemoteStoreT m a) ->+ runDaemonConnection handler+ (setStoreDir storeDir)+ storeConn2+ $ runStoreConnection storeConn2+ ( setStoreDir storeDir+ >> mstore+ )++checks+ :: ( Show a+ , Show b+ )+ => IO (a, b)+ -> (a -> Bool)+ -> IO ()+checks action check =+ action >>= (`Test.Hspec.shouldSatisfy` (check . fst))++it+ :: (Show a, Show b, Monad m)+ => String+ -> m c+ -> (a -> Bool)+ -> SpecWith (m () -> IO (a, b))+it name action check =+ Test.Hspec.it name $ \run -> run (void $ action) `checks` check++itRights+ :: ( Show a+ , Show b+ , Show c+ , Monad m+ )+ => String+ -> m d+ -> SpecWith (m () -> IO (Either a b, c))+itRights name action = it name action Data.Either.isRight++itLefts+ :: ( Show a+ , Show b+ , Show c+ , Monad m+ )+ => String+ -> m d+ -> SpecWith (m () -> IO (Either a b, c))+itLefts name action = it name action Data.Either.isLeft++sampleText :: Text+sampleText = "test"++withPath+ :: MonadRemoteStore m+ => (StorePath -> m a)+ -> m a+withPath action = do+ path <-+ addTextToStore+ (StoreText+ (forceRight $ System.Nix.StorePath.mkStorePathName "hnix-store")+ sampleText+ )+ mempty+ RepairMode_DontRepair+ action path++-- | dummy path, adds <tmp>/dummy with "Hello World" contents+dummy :: MonadRemoteStore m => m StorePath+dummy = do+ addToStore+ (forceRight $ System.Nix.StorePath.mkStorePathName "dummy")+ (System.Nix.Nar.dumpPath "dummy")+ FileIngestionMethod_Flat+ (Some HashAlgo_SHA256)+ RepairMode_DontRepair++invalidPath :: StorePath+invalidPath =+ let name = forceRight $ System.Nix.StorePath.mkStorePathName "invalid"+ in System.Nix.StorePath.unsafeMakeStorePath+ (System.Nix.StorePath.mkStorePathHashPart+ @SHA256+ "invalid")+ name++_withBuilder+ :: MonadRemoteStore m+ => (StorePath -> m a)+ -> m a+_withBuilder action = do+ path <-+ addTextToStore+ (StoreText+ (forceRight $ System.Nix.StorePath.mkStorePathName "builder")+ builderSh+ )+ mempty+ RepairMode_DontRepair+ action path++builderSh :: Text+builderSh = "declare -xpexport > $out"++spec :: Spec+spec = do+ describe "Remote store protocol" $ do+ describe "Direct"+ $ makeProtoSpec+ withNixDaemon+ SpecFlavor_Direct+ describe "MITM"+ $ makeProtoSpec+ withManInTheMiddleNixDaemon+ SpecFlavor_MITM++data SpecFlavor+ = SpecFlavor_Direct+ | SpecFlavor_MITM+ deriving (Eq, Ord, Show)++makeProtoSpec+ :: (ActionWith+ (RemoteStoreT IO () -> Run IO ())+ -> IO ()+ )+ -> SpecFlavor+ -> Spec+makeProtoSpec f flavor = around f $ do++ context "syncWithGC" $+ itRights "syncs with garbage collector" syncWithGC++ context "verifyStore" $ do+ itRights "check=False repair=False" $+ verifyStore+ CheckMode_DontCheck+ RepairMode_DontRepair+ `shouldReturn` False++ itRights "check=True repair=False" $+ verifyStore+ CheckMode_DoCheck+ RepairMode_DontRepair+ `shouldReturn` False++ --privileged+ itRights "check=True repair=True" $+ verifyStore+ CheckMode_DoCheck+ RepairMode_DoRepair+ `shouldReturn` False++ context "addTextToStore" $+ itRights "adds text to store" $ withPath pure++ context "isValidPath" $ do+ itRights "validates path" $ withPath $ \path -> do+ isValidPath path `shouldReturn` True++ itLefts "fails on invalid path" $ do+ setStoreDir (StoreDir "/asdf")+ isValidPath invalidPath++ context "queryAllValidPaths" $ do+ itRights "empty query" queryAllValidPaths+ itRights "non-empty query" $ withPath $ \path ->+ queryAllValidPaths `shouldReturn` Data.HashSet.fromList [path]++ context "queryPathInfo" $+ itRights "queries path info" $ withPath $ \path -> do+ meta <- queryPathInfo path+ (metadataReferences <$> meta) `shouldBe` (Just mempty)++ context "ensurePath" $+ itRights "simple ensure" $ withPath ensurePath++ context "addTempRoot" $+ itRights "simple addition" $ withPath addTempRoot++ context "addIndirectRoot" $+ itRights "simple addition" $ withPath addIndirectRoot++ let toDerivedPathSet p = Data.Set.fromList [DerivedPath_Opaque p]++ context "buildPaths" $ do+ itRights "build Normal" $ withPath $ \path -> do+ buildPaths (toDerivedPathSet path) BuildMode_Normal++ itRights "build Check" $ withPath $ \path -> do+ buildPaths (toDerivedPathSet path) BuildMode_Check++ itLefts "build Repair" $ withPath $ \path -> do+ buildPaths (toDerivedPathSet path) BuildMode_Repair++ context "roots" $ context "findRoots" $ do+ itRights "empty roots" (findRoots `shouldReturn` mempty)++ itRights "path added as a temp root" $ withPath $ \_ -> do+ let expectRoots =+ if flavor == SpecFlavor_MITM+ then 0 -- nested client closes its connection so temp root gets removed+ else 1+ roots <- findRoots+ roots `shouldSatisfy` ((== expectRoots) . Data.Map.size)++ itRights "indirect root" $ withPath $ \path -> do+ let expectRoots =+ if flavor == SpecFlavor_MITM+ then 1 -- nested client closes its connection so temp root gets removed+ else 2+ addIndirectRoot path+ roots <- findRoots+ roots `shouldSatisfy` ((== expectRoots) . Data.Map.size)++ context "optimiseStore" $ itRights "optimises" optimiseStore++ context "queryMissing" $+ itRights "queries" $ withPath $ \path -> do+ queryMissing (toDerivedPathSet path)+ `shouldReturn`+ Missing+ { missingWillBuild = mempty+ , missingWillSubstitute = mempty+ , missingUnknownPaths = mempty+ , missingDownloadSize = 0+ , missingNarSize = 0+ }++ context "addToStore" $+ itRights "adds file to store" $ do+ fp <-+ liftIO+ $ System.IO.Temp.writeSystemTempFile+ "addition"+ "yolo"++ addToStore+ (forceRight $ System.Nix.StorePath.mkStorePathName "tmp-addition")+ (System.Nix.Nar.dumpPath fp)+ FileIngestionMethod_Flat+ (Some HashAlgo_SHA256)+ RepairMode_DontRepair++ context "with dummy" $ do+ itRights "adds dummy" dummy++ itRights "valid dummy" $ do+ path <- dummy+ isValidPath path `shouldReturn` True++ context "collectGarbage" $ do+ itRights "deletes a specific path from the store" $ withPath $ \path -> do+ -- clear temp gc roots so the delete works. restarting the nix daemon should also do this...+ storeDir <- getStoreDir+ let tempRootsDir = Data.Text.unpack $ mconcat [ Data.Text.Encoding.decodeUtf8 (unStoreDir storeDir), "/../var/nix/temproots/" ]+ liftIO $ do+ tempRootList <-+ System.Directory.listDirectory tempRootsDir+ forM_ tempRootList $ \entry -> do+ System.Directory.removeFile+ $ mconcat [ tempRootsDir, "/", entry ]+ -- for MITM, the temp root will get deleted+ -- by the daemon as our nested client exists+ -- but the listDirectory might still see it+ -- causing TOC/TOU flakiness+ `catch` (\(_e :: SomeException) -> pure ())++ GCResult{..} <-+ collectGarbage+ GCOptions+ { gcOptionsOperation = GCAction_DeleteSpecific+ , gcOptionsIgnoreLiveness = False+ , gcOptionsPathsToDelete = Data.HashSet.fromList [path]+ , gcOptionsMaxFreed = maxBound+ }+ gcResultDeletedPaths `shouldBe` Data.HashSet.fromList [path]+ gcResultBytesFreed `shouldBe` 4++ context "addToStoreNar" $ do+ itRights "adds nar file" $ do+ unless (flavor == SpecFlavor_MITM) $ do+ sampleNar@SampleNar.SampleNar{..} <- liftIO SampleNar.sampleNar0+ dataSource <- liftIO $ SampleNar.buildDataSource sampleNar+ addToStoreNar sampleNar_storePath sampleNar_metadata RepairMode_DontRepair CheckMode_DontCheck dataSource++ meta <- queryPathInfo sampleNar_storePath+ (metadataDeriverPath =<< meta) `shouldBe` metadataDeriverPath sampleNar_metadata++ context "narFromPath" $ do+ itRights "downloads nar file" $ do+ unless (flavor == SpecFlavor_MITM) $ do+ withPath $ \path -> do+ maybeMetadata <- queryPathInfo path+ case maybeMetadata of+ Just Metadata{metadataNarBytes=Just narBytes} -> do+ dataSink <- liftIO DataSink.newDataSink+ narFromPath path narBytes (DataSink.dataSinkWriter dataSink)+ narData <- liftIO $ DataSink.dataSinkResult dataSink+ expectedNarData <- liftIO $ SampleNar.encodeNar (Data.Text.Encoding.encodeUtf8 sampleText)+ narData `shouldBe` expectedNarData+ _ -> expectationFailure "missing metadata or narBytes"
+ tests-io/SampleNar.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NamedFieldPuns #-}++module SampleNar++( SampleNar(..)+, buildDataSource+, sampleNar0+, encodeNar+)++where++import Crypto.Hash ( Digest, SHA256, hashInit, hashUpdate, hashFinalize )+import Data.ByteString (ByteString)+import Data.Dependent.Sum (DSum((:=>)))+import Data.Time.Calendar.OrdinalDate (fromOrdinalDate)+import Data.Time.Clock (UTCTime(..))+import System.Nix.Hash (HashAlgo(HashAlgo_SHA256))+import System.Nix.StorePath (StorePath, parsePath)+import System.Nix.StorePath.Metadata (Metadata(..), StorePathTrust(..))++import Control.Monad.ST+import Data.Default.Class+import Data.STRef+import Data.Word++import qualified Data.ByteString+import qualified System.Nix.Nar++-- | Sample data for an AddToStoreNar operation+data SampleNar+ = SampleNar+ { sampleNar_fileData :: !ByteString -- ^ Contents of the file to be put in the store+ , sampleNar_narData :: !ByteString -- ^ The file data serialized as a NAR+ , sampleNar_storePath :: !StorePath+ , sampleNar_metadata :: !(Metadata StorePath)+ }++sampleNar0 :: IO SampleNar+sampleNar0 = do+ let sampleNar_fileData = "hello"+ sampleNar_narData <- encodeNar sampleNar_fileData+ let sampleNar_metadata = Metadata+ { metadataDeriverPath = Just $ forceParsePath "/nix/store/g2mxdrkwr1hck4y5479dww7m56d1x81v-hello-2.12.1.drv"+ , metadataNarHash = sha256 sampleNar_narData+ , metadataReferences = mempty+ , metadataRegistrationTime = UTCTime (fromOrdinalDate 1980 1) 0+ , metadataNarBytes = Just ((fromIntegral . Data.ByteString.length) sampleNar_narData)+ , metadataTrust = BuiltElsewhere+ , metadataSigs = mempty+ , metadataContentAddress = Nothing+ }+ sampleNar_storePath = forceParsePath "/nix/store/00000lj3clbkc0aqvjjzfa6slp4zdvlj-hello-2.12.1"+ pure SampleNar{..}++buildDataSource :: SampleNar -> IO(Word64 -> IO (Maybe ByteString))+buildDataSource SampleNar{sampleNar_narData} = dataSourceFromByteString sampleNar_narData++dataSourceFromByteString :: ByteString -> IO (Word64 -> IO(Maybe ByteString))+dataSourceFromByteString bs = do+ posRef <- stToIO $ newSTRef (0::Word64)+ let len = fromIntegral $ Data.ByteString.length bs+ outFn chunkSize = do+ pos <- stToIO $ readSTRef posRef+ if pos >= len then pure Nothing+ else do+ let bs' = Data.ByteString.drop (fromIntegral pos) bs+ bs'' = Data.ByteString.take (fromIntegral chunkSize) bs'+ takenLen = fromIntegral $ Data.ByteString.length bs''+ stToIO $ modifySTRef posRef (takenLen +)+ pure $ Just bs''+ pure outFn++forceParsePath :: ByteString -> StorePath+forceParsePath path = case parsePath def path of+ Left err -> error $ mconcat [ "forceParsePath failed: ", show err ]+ Right x -> x+sha256 :: ByteString -> DSum HashAlgo Digest+sha256 bs = HashAlgo_SHA256 :=> hashFinalize (hashUpdate (hashInit @SHA256) bs)++encodeNar :: ByteString -> IO ByteString+encodeNar bytes = do+ ref <- stToIO $ newSTRef mempty+ let accumFn chunk = do+ stToIO $ modifySTRef ref (<> chunk)+ System.Nix.Nar.dumpString bytes accumFn+ stToIO $ readSTRef ref+
+ tests/Data/SerializerSpec.hs view
@@ -0,0 +1,43 @@+module Data.SerializerSpec (spec) where++import Data.Some+import Data.Serializer+import Data.Serializer.Example++import Test.Hspec (Spec, describe, it, shouldBe)+import Test.Hspec.QuickCheck (prop)++spec :: Spec+spec = describe "Serializer" $ do+ prop "Roundtrips GADT protocol" $ \someCmd ->+ (runG cmdS+ <$> (runP cmdS someCmd))+ `shouldBe`+ ((pure $ pure someCmd) ::+ Either MyPutError+ (Either (GetSerializerError MyGetError)+ (Some Cmd)))++ it "Handles putS error" $+ runP cmdSPutError (Some (Cmd_Bool True))+ `shouldBe`+ Left MyPutError_NoLongerSupported++ it "Handles getS error" $+ runG cmdSGetError (runPutSimple cmdS (Some (Cmd_Bool True)))+ `shouldBe`+ Left (SerializerError_Get MyGetError_Example)++ it "Handles getS fail" $+ runG cmdSGetFail (runPutSimple cmdS (Some (Cmd_Bool True)))+ `shouldBe`+ Left (SerializerError_GetFail @MyGetError "Failed reading: no parse\nEmpty call stack\n")++ prop "Roundtrips elaborate example" $ \someCmd readerBool ->+ (runGRest cmdSRest readerBool 0+ <$> (runPRest cmdSRest readerBool 0 someCmd))+ `shouldBe`+ ((pure $ pure $ someCmd) ::+ Either MyPutError+ (Either (GetSerializerError MyGetError)+ (Some Cmd)))
tests/Driver.hs view
@@ -1,9 +1,1 @@-import NixDaemon-import qualified Spec---- we run remote tests in--- Linux namespaces to avoid interacting with systems store-main :: IO ()-main = do- enterNamespaces- Spec.main+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ tests/EnumSpec.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE OverloadedStrings #-}++module EnumSpec (spec) where++import Test.Hspec (SpecWith, Spec, describe, it, shouldBe)++import Data.ByteString (ByteString)+import Data.Word (Word64)+import System.Nix.Build (BuildMode(..), BuildStatus(..))+import System.Nix.Store.Remote.Serializer + ( activity+ , activityResult+ , enum+ , int+ , loggerOpCode+ , runP+ , LoggerSError+ , NixSerializer+ , SError+ )+import System.Nix.Store.Remote.Types++spec :: Spec+spec = do+ let+ itE+ :: ( Bounded a+ , Enum a+ , Show a+ )+ => String+ -> a+ -> Word64+ -> SpecWith ()+ itE name constr value =+ it name+ $ ((runP enum () constr) :: Either SError ByteString)+ `shouldBe`+ (runP (int @Word64) () value)++ itE'+ :: Show a+ => NixSerializer () LoggerSError a+ -> String+ -> a+ -> Word64+ -> SpecWith ()+ itE' s name constr value =+ it name+ $ ((runP s () constr) :: Either LoggerSError ByteString)+ `shouldBe`+ (runP (int @Word64) () (value))++ describe "Enums" $ do+ describe "BuildMode enum order matches Nix" $ do+ itE "Normal" BuildMode_Normal 0+ itE "Repair" BuildMode_Repair 1+ itE "Check" BuildMode_Check 2++ describe "BuildStatus enum order matches Nix" $ do+ itE "Built" BuildStatus_Built 0+ itE "Substituted" BuildStatus_Substituted 1+ itE "AlreadyValid" BuildStatus_AlreadyValid 2+ itE "PermanentFailure" BuildStatus_PermanentFailure 3+ itE "InputRejected" BuildStatus_InputRejected 4+ itE "OutputRejected" BuildStatus_OutputRejected 5+ itE "TransientFailure" BuildStatus_TransientFailure 6+ itE "CachedFailure" BuildStatus_CachedFailure 7+ itE "TimedOut" BuildStatus_TimedOut 8+ itE "MiscFailure" BuildStatus_MiscFailure 9+ itE "DependencyFailed" BuildStatus_DependencyFailed 10+ itE "LogLimitExceeded" BuildStatus_LogLimitExceeded 11+ itE "NotDeterministic" BuildStatus_NotDeterministic 12+ itE "ResolvesToAlreadyValid" BuildStatus_ResolvesToAlreadyValid 13+ itE "NoSubstituters" BuildStatus_NoSubstituters 14++ describe "GCAction enum order matches Nix" $ do+ itE "ReturnLive" GCAction_ReturnLive 0+ itE "ReturnDead" GCAction_ReturnDead 1+ itE "DeleteDead" GCAction_DeleteDead 2+ itE "DeleteSpecific" GCAction_DeleteSpecific 3++ describe "Logger" $ do+ let itA = itE' activity+ describe "Activity enum order matches Nix" $ do+ itA "CopyPath" Activity_CopyPath 100+ itA "FileTransfer" Activity_FileTransfer 101+ itA "Realise" Activity_Realise 102+ itA "CopyPaths" Activity_CopyPaths 103+ itA "Builds" Activity_Builds 104+ itA "Build" Activity_Build 105+ itA "OptimiseStore" Activity_OptimiseStore 106+ itA "VerifyPaths" Activity_VerifyPaths 107+ itA "Substitute" Activity_Substitute 108+ itA "QueryPathInfo" Activity_QueryPathInfo 109+ itA "PostBuildHook" Activity_PostBuildHook 110+ itA "BuildWaiting" Activity_BuildWaiting 111++ let itR = itE' activityResult+ describe "ActivityResult enum order matches Nix" $ do+ itR "FileLinked" ActivityResult_FileLinked 100+ itR "BuildLogLine" ActivityResult_BuildLogLine 101+ itR "UnstrustedPath" ActivityResult_UnstrustedPath 102+ itR "CorruptedPath" ActivityResult_CorruptedPath 103+ itR "SetPhase" ActivityResult_SetPhase 104+ itR "Progress" ActivityResult_Progress 105+ itR "SetExpected" ActivityResult_SetExpected 106+ itR "PostBuildLogLine" ActivityResult_PostBuildLogLine 107+++ let itL = itE' loggerOpCode+ describe "LoggerOpCode matches Nix" $ do+ itL "Next" LoggerOpCode_Next 0x6f6c6d67+ itL "Read" LoggerOpCode_Read 0x64617461+ itL "Write" LoggerOpCode_Write 0x64617416+ itL "Last" LoggerOpCode_Last 0x616c7473+ itL "Error" LoggerOpCode_Error 0x63787470+ itL "StartActivity" LoggerOpCode_StartActivity 0x53545254+ itL "StopActivity" LoggerOpCode_StopActivity 0x53544f50+ itL "Result" LoggerOpCode_Result 0x52534c54++ describe "Verbosity enum order matches Nix" $ do+ itE "Error" Verbosity_Error 0+ itE "Warn" Verbosity_Warn 1+ itE "Notice" Verbosity_Notice 2+ itE "Info" Verbosity_Info 3+ itE "Talkative" Verbosity_Talkative 4+ itE "Chatty" Verbosity_Chatty 5+ itE "Debug" Verbosity_Debug 6+ itE "Vomit" Verbosity_Vomit 7++ describe "WorkerOp enum order matches Nix" $ do+ itE "IsValidPath" WorkerOp_IsValidPath 1+ itE "BuildPathsWithResults" WorkerOp_BuildPathsWithResults 46+++
− tests/NixDaemon.hs
@@ -1,262 +0,0 @@-{-# language DataKinds #-}-{-# language ScopedTypeVariables #-}--module NixDaemon where--import qualified System.Environment as Env-import Control.Exception ( bracket )-import Control.Concurrent ( threadDelay )-import qualified Data.HashSet as HS-import qualified Data.Map.Strict as M-import System.Directory-import System.IO.Temp-import qualified System.Process as P-import System.Posix.User as U-import System.Linux.Namespaces as NS-import Test.Hspec ( Spec- , describe- , context- )-import qualified Test.Hspec as Hspec-import Test.Hspec.Expectations.Lifted--import System.FilePath--import System.Nix.Build-import System.Nix.StorePath-import System.Nix.Store.Remote-import System.Nix.Store.Remote.Protocol--import Crypto.Hash ( SHA256 )-import System.Nix.Nar ( dumpPath )--createProcessEnv :: FilePath -> String -> [String] -> IO P.ProcessHandle-createProcessEnv fp proc args = do- mPath <- Env.lookupEnv "PATH"-- (_, _, _, ph) <-- P.createProcess (P.proc proc args)- { P.cwd = Just fp- , P.env = Just $ mockedEnv mPath fp- }- pure ph--mockedEnv :: Maybe String -> FilePath -> [(String, FilePath)]-mockedEnv mEnvPath fp = (fp </>) <<$>>- [ ("NIX_STORE_DIR" , "store")- , ("NIX_LOCALSTATE_DIR", "var")- , ("NIX_LOG_DIR" , "var" </> "log")- , ("NIX_STATE_DIR" , "var" </> "nix")- , ("NIX_CONF_DIR" , "etc")- , ("HOME" , "home")--- , ("NIX_REMOTE", "daemon")- ] <> foldMap (\x -> [("PATH", x)]) mEnvPath--waitSocket :: FilePath -> Int -> IO ()-waitSocket _ 0 = fail "No socket"-waitSocket fp x = do- ex <- doesFileExist fp- bool- (threadDelay 100000 >> waitSocket fp (x - 1))- pass- ex--writeConf :: FilePath -> IO ()-writeConf fp =- writeFileText fp $ unlines- [ "build-users-group = "- , "trusted-users = root"- , "allowed-users = *"- , "fsync-metadata = false"- ]--{-- - we run in user namespace as root but groups are failed- - => build-users-group has to be empty but we still- - get an error (maybe older nix-daemon)- --uid=0(root) gid=65534(nobody) groups=65534(nobody)--drwxr-xr-x 3 0 65534 60 Nov 29 05:53 store--accepted connection from pid 22959, user root (trusted)-error: changing ownership of path '/run/user/1000/test-nix-store-06b0d249e5616122/store': Invalid argument--}--startDaemon- :: FilePath- -> IO (P.ProcessHandle, MonadStore a -> IO (Either String a, [Logger]))-startDaemon fp = do- writeConf (fp </> "etc" </> "nix.conf")- p <- createProcessEnv fp "nix-daemon" []- waitSocket sockFp 30- pure (p, runStoreOpts sockFp (fp </> "store"))- where- sockFp = fp </> "var/nix/daemon-socket/socket"--enterNamespaces :: IO ()-enterNamespaces = do- uid <- getEffectiveUserID- gid <- getEffectiveGroupID-- unshare [User, Network, Mount]- -- fmap our (parent) uid to root- writeUserMappings Nothing [UserMapping 0 uid 1]- -- fmap our (parent) gid to root group- writeGroupMappings Nothing [GroupMapping 0 gid 1] True--withNixDaemon- :: ((MonadStore a -> IO (Either String a, [Logger])) -> IO a) -> IO a-withNixDaemon action =- withSystemTempDirectory "test-nix-store" $ \path -> do-- mapM_ (createDirectory . snd)- (filter ((/= "NIX_REMOTE") . fst) $ mockedEnv Nothing path)-- ini <- createProcessEnv path "nix-store" ["--init"]- void $ P.waitForProcess ini-- writeFile (path </> "dummy") "Hello World"-- setCurrentDirectory path-- bracket (startDaemon path)- (P.terminateProcess . fst)- (action . snd)--checks :: (Show a, Show b) => IO (a, b) -> (a -> Bool) -> IO ()-checks action check = action >>= (`Hspec.shouldSatisfy` (check . fst))--it- :: (Show a, Show b, Monad m)- => String- -> m c- -> (a -> Bool)- -> Hspec.SpecWith (m () -> IO (a, b))-it name action check =- Hspec.it name $ \run -> run (action >> pass) `checks` check--itRights- :: (Show a, Show b, Show c, Monad m)- => String- -> m d- -> Hspec.SpecWith (m () -> IO (Either a b, c))-itRights name action = it name action isRight--itLefts- :: (Show a, Show b, Show c, Monad m)- => String- -> m d- -> Hspec.SpecWith (m () -> IO (Either a b, c))-itLefts name action = it name action isLeft--withPath :: (StorePath -> MonadStore a) -> MonadStore a-withPath action = do- path <- addTextToStore "hnix-store" "test" (HS.fromList []) False- action path---- | dummy path, adds <tmp>/dummpy with "Hello World" contents-dummy :: MonadStore StorePath-dummy = do- let Right n = makeStorePathName "dummy"- addToStore @SHA256 n (dumpPath "dummy") False False--invalidPath :: StorePath-invalidPath =- let Right n = makeStorePathName "invalid"- in StorePath (mkStorePathHashPart "invalid") n "no_such_root"--withBuilder :: (StorePath -> MonadStore a) -> MonadStore a-withBuilder action = do- path <- addTextToStore "builder" builderSh (HS.fromList []) False- action path--builderSh :: Text-builderSh = "declare -xpexport > $out"--spec_protocol :: Spec-spec_protocol = Hspec.around withNixDaemon $-- describe "store" $ do-- context "syncWithGC" $- itRights "syncs with garbage collector" syncWithGC-- context "verifyStore" $ do- itRights "check=False repair=False" $- verifyStore False False `shouldReturn` False-- itRights "check=True repair=False" $- verifyStore True False `shouldReturn` False-- --privileged- itRights "check=True repair=True" $- verifyStore True True `shouldReturn` False-- context "addTextToStore" $- itRights "adds text to store" $ withPath pure-- context "isValidPathUncached" $ do- itRights "validates path" $ withPath $ \path -> do- liftIO $ print path- isValidPathUncached path `shouldReturn` True- itLefts "fails on invalid path" $ isValidPathUncached invalidPath-- context "queryAllValidPaths" $ do- itRights "empty query" queryAllValidPaths- itRights "non-empty query" $ withPath $ \path ->- queryAllValidPaths `shouldReturn` HS.fromList [path]-- context "queryPathInfoUncached" $- itRights "queries path info" $ withPath queryPathInfoUncached-- context "ensurePath" $- itRights "simple ensure" $ withPath ensurePath-- context "addTempRoot" $- itRights "simple addition" $ withPath addTempRoot-- context "addIndirectRoot" $- itRights "simple addition" $ withPath addIndirectRoot-- context "buildPaths" $ do- itRights "build Normal" $ withPath $ \path -> do- let pathSet = HS.fromList [path]- buildPaths pathSet Normal-- itRights "build Check" $ withPath $ \path -> do- let pathSet = HS.fromList [path]- buildPaths pathSet Check-- itLefts "build Repair" $ withPath $ \path -> do- let pathSet = HS.fromList [path]- buildPaths pathSet Repair-- context "roots" $ context "findRoots" $ do- itRights "empty roots" (findRoots `shouldReturn` M.empty)-- itRights "path added as a temp root" $ withPath $ \_ -> do- roots <- findRoots- roots `shouldSatisfy` ((== 1) . M.size)-- context "optimiseStore" $ itRights "optimises" optimiseStore-- context "queryMissing" $- itRights "queries" $ withPath $ \path -> do- let pathSet = HS.fromList [path]- queryMissing pathSet `shouldReturn` (HS.empty, HS.empty, HS.empty, 0, 0)-- context "addToStore" $- itRights "adds file to store" $ do- fp <- liftIO $ writeSystemTempFile "addition" "lal"- let Right n = makeStorePathName "tmp-addition"- res <- addToStore @SHA256 n (dumpPath fp) False False- liftIO $ print res-- context "with dummy" $ do- itRights "adds dummy" dummy-- itRights "valid dummy" $ do- path <- dummy- liftIO $ print path- isValidPathUncached path `shouldReturn` True
+ tests/NixSerializerSpec.hs view
@@ -0,0 +1,169 @@+{-# LANGUAGE OverloadedStrings #-}++module NixSerializerSpec (spec) where++import Crypto.Hash (MD5, SHA1, SHA256, SHA512)+import Data.Some (Some(Some))+import Data.Time (UTCTime)+import Test.Hspec (Expectation, Spec, describe, parallel, shouldBe)+import Test.Hspec.QuickCheck (prop)+import Test.QuickCheck (Gen, arbitrary, forAll, suchThat)++import System.Nix.Arbitrary ()+import System.Nix.Derivation (Derivation(inputDrvs))+import System.Nix.Build (BuildResult(..))+import System.Nix.StorePath (StoreDir)+import System.Nix.Store.Remote.Arbitrary ()+import System.Nix.Store.Remote.Serializer+import System.Nix.Store.Remote.Types.Logger (Logger(..))+import System.Nix.Store.Remote.Types.ProtoVersion (HasProtoVersion(..), ProtoVersion(..))+import System.Nix.Store.Remote.Types.StoreConfig (ProtoStoreConfig(..))+import System.Nix.Store.Remote.Types.StoreRequest (StoreRequest(..))++-- | Test for roundtrip using @NixSerializer@+roundtripSReader+ :: forall r e a+ . ( Eq a+ , Show a+ , Eq e+ , Show e+ )+ => NixSerializer r e a+ -> r+ -> a+ -> Expectation+roundtripSReader serializer readerVal a =+ (runG serializer readerVal+ <$> runP serializer readerVal a)+ `shouldBe` (pure $ pure a)++roundtripS+ :: ( Eq a+ , Show a+ , Eq e+ , Show e+ )+ => NixSerializer () e a+ -> a+ -> Expectation+roundtripS serializer = roundtripSReader serializer ()++spec :: Spec+spec = parallel $ do+ describe "Prim" $ do+ prop "Int" $ roundtripS @Int @() int+ prop "Bool" $ roundtripS bool+ prop "ByteString" $ roundtripS byteString+ prop "Text" $ roundtripS text+ prop "Maybe Text" $ roundtripS maybeText+ prop "UTCTime" $ roundtripS @UTCTime @() time++ describe "Combinators" $ do+ prop "list" $ roundtripS @[Int] @() (list int)+ prop "set" $ roundtripS (set byteString)+ prop "hashSet" $ roundtripS (hashSet byteString)+ prop "mapS" $ roundtripS (mapS (int @Int) byteString)++ describe "Complex" $ do+ prop "DSum HashAlgo Digest" $ roundtripS namedDigest++ describe "BuildResult" $ do+ prop "< 1.28"+ $ \sd -> forAll (arbitrary `suchThat` ((< 28) . protoVersion_minor))+ $ \pv ->+ roundtripSReader @ProtoStoreConfig buildResult (ProtoStoreConfig sd pv)+ . (\x -> x { buildResultBuiltOutputs = Nothing })+ . (\x -> x { buildResultTimesBuilt = Nothing+ , buildResultIsNonDeterministic = Nothing+ , buildResultStartTime = Nothing+ , buildResultStopTime = Nothing+ }+ )+ prop "= 1.28"+ $ \sd ->+ roundtripSReader @ProtoStoreConfig buildResult (ProtoStoreConfig sd (ProtoVersion 1 28))+ . (\x -> x { buildResultTimesBuilt = Nothing+ , buildResultIsNonDeterministic = Nothing+ , buildResultStartTime = Nothing+ , buildResultStopTime = Nothing+ }+ )+ prop "> 1.28"+ $ \sd -> forAll (arbitrary `suchThat` ((> 28) . protoVersion_minor))+ $ \pv ->+ roundtripSReader @ProtoStoreConfig buildResult (ProtoStoreConfig sd pv)++ prop "StorePath" $+ roundtripSReader @StoreDir storePath++ prop "StorePathHashPart" $+ roundtripS storePathHashPart++ prop "StorePathName" $+ roundtripS storePathName++ prop "Metadata (StorePath)" $+ roundtripSReader @StoreDir pathMetadata++ prop "Some HashAlgo" $+ roundtripS someHashAlgo++ describe "Digest" $ do+ prop "MD5" $ roundtripS . digest @MD5+ prop "SHA1" $ roundtripS . digest @SHA1+ prop "SHA256" $ roundtripS . digest @SHA256+ prop "SHA512" $ roundtripS . digest @SHA512++ prop "Derivation" $ \sd ->+ roundtripSReader @StoreDir derivation sd+ . (\drv -> drv { inputDrvs = mempty })++ prop "ProtoVersion" $ roundtripS @ProtoVersion @() protoVersion++ describe "Logger" $ do+ prop "ActivityID" $ roundtripS activityID+ prop "Maybe Activity" $ roundtripS maybeActivity+ prop "ActivityResult" $ roundtripS activityResult+ prop "Field" $ roundtripS field+ prop "Trace" $ roundtripS trace+ prop "BasicError" $ roundtripS basicError+ prop "ErrorInfo" $ roundtripS errorInfo+ prop "LoggerOpCode" $ roundtripS loggerOpCode+ prop "Verbosity" $ roundtripS verbosity+ prop "Logger"+ $ forAll (arbitrary :: Gen ProtoVersion)+ $ \pv ->+ forAll (arbitrary `suchThat` errorInfoIf (protoVersion_minor pv >= 26))+ $ roundtripSReader logger pv++ describe "Handshake" $ do+ prop "WorkerMagic" $ roundtripS workerMagic+ prop "TrustedFlag" $ roundtripS trustedFlag++ describe "Worker protocol" $ do+ prop "WorkerOp" $ roundtripS workerOp+ prop "StoreText" $ roundtripS storeText++ prop "StoreRequest"+ $ \testStoreConfig ->+ forAll (arbitrary `suchThat` (restrictProtoVersion (hasProtoVersion testStoreConfig)))+ $ roundtripSReader @ProtoStoreConfig storeRequest testStoreConfig++ describe "StoreReply" $ do+ prop "()" $ roundtripS opSuccess+ prop "GCResult" $ roundtripSReader @StoreDir gcResult+ prop "GCRoot" $ roundtripS gcRoot+ prop "Missing" $ roundtripSReader @StoreDir missing+ prop "Maybe (Metadata StorePath)" $ roundtripSReader @StoreDir maybePathMetadata++restrictProtoVersion :: ProtoVersion -> Some StoreRequest -> Bool+restrictProtoVersion v (Some (BuildPaths _ _)) | v < ProtoVersion 1 30 = False+restrictProtoVersion _ (Some (BuildDerivation _ drv _)) = inputDrvs drv == mempty+restrictProtoVersion v (Some (QueryMissing _)) | v < ProtoVersion 1 30 = False+restrictProtoVersion _ _ = True++errorInfoIf :: Bool -> Logger -> Bool+errorInfoIf True (Logger_Error (Right _)) = True+errorInfoIf False (Logger_Error (Left _)) = True+errorInfoIf _ (Logger_Error _) = False+errorInfoIf _ _ = True
− tests/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF tasty-discover -optF --generated-module=Spec #-}
− tests/Util.hs
@@ -1,12 +0,0 @@--module Util where--import Data.Text.Arbitrary ()-import System.Nix.Store.Remote.Util-import Test.Tasty.QuickCheck--prop_TextToBSLRoundtrip :: Text -> Property-prop_TextToBSLRoundtrip x = bslToText (textToBSL x) === x--prop_TextToBSRoundtrip :: Text -> Property-prop_TextToBSRoundtrip x = bsToText (textToBS x) === x