single BuildResult to rule them all

This commit is contained in:
sorki 2023-12-05 19:32:29 +01:00
parent ee4ad7b07b
commit e6ed8f8069
9 changed files with 89 additions and 162 deletions

View File

@ -7,7 +7,6 @@ module System.Nix.Build
, BuildStatus(..)
, buildSuccess
, BuildResult(..)
, OldBuildResult(..)
) where
import Data.Map (Map)
@ -48,23 +47,21 @@ data BuildStatus =
-- | Result of the build
data BuildResult = BuildResult
{ buildResultStatus :: !BuildStatus
{ buildResultStatus :: BuildStatus
-- ^ Build status, MiscFailure should be the default
, buildResultErrorMessage :: !(Maybe Text)
, buildResultErrorMessage :: Maybe Text
-- ^ Possible build error message
, buildResultTimesBuilt :: !Int
-- ^ How many times this build was performed
, buildResultIsNonDeterministic :: !Bool
-- ^ If timesBuilt > 1, whether some builds did not produce the same result
, buildResultStartTime :: !UTCTime
-- ^ Start time of this build
, buildResultStopTime :: !UTCTime
-- ^ Stop time of this build
, buildResultBuiltOutputs :: !(Maybe (Map OutputName Realisation))
-- ^ Mapping of the output names to @Realisation@s
, buildResultTimesBuilt :: Maybe Int
-- ^ How many times this build was performed (since 1.29)
, buildResultIsNonDeterministic :: Maybe Bool
-- ^ If timesBuilt > 1, whether some builds did not produce the same result (since 1.29)
, buildResultStartTime :: Maybe UTCTime
-- ^ Start time of this build (since 1.29)
, buildResultStopTime :: Maybe UTCTime
-- ^ Stop time of this build (since 1.29)
, buildResultBuiltOutputs :: Maybe (Map OutputName Realisation)
-- ^ Mapping of the output names to @Realisation@s (since 1.28)
-- (paths with additional info and their dependencies)
--
-- Available for protocol version >= 1.28
}
deriving (Eq, Generic, Ord, Show)
@ -75,17 +72,3 @@ buildSuccess x =
, BuildStatus_Substituted
, BuildStatus_AlreadyValid
]
-- | Result of the build, for protocol version <= 1.28
data OldBuildResult = OldBuildResult
{ oldBuildResultStatus :: !BuildStatus
-- ^ Build status, MiscFailure should be the default
, oldBuildResultErrorMessage :: !(Maybe Text)
-- ^ Possible build error message
, oldBuildResultBuiltOutputs :: !(Maybe (Map OutputName Realisation))
-- ^ Mapping of the output names to @Realisation@s
-- (paths with additional info and their dependencies)
--
-- Available for protocol version >= 1.28
}
deriving (Eq, Generic, Ord, Show)

View File

@ -11,7 +11,6 @@ module System.Nix.Store.Remote
, addIndirectRoot
, addTempRoot
, buildPaths
, buildDerivation
, deleteSpecific
, ensurePath
, findRoots
@ -30,6 +29,7 @@ module System.Nix.Store.Remote
, 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
-- * Compat
@ -50,9 +50,8 @@ import Data.Text (Text)
import Data.Word (Word64)
import Network.Socket (Family, SockAddr(SockAddrUnix))
import System.Nix.Nar (NarSource)
import System.Nix.Derivation (Derivation)
import System.Nix.Store.Types (FileIngestionMethod(..), RepairMode(..))
import System.Nix.Build (BuildMode, OldBuildResult)
import System.Nix.Build (BuildMode)
import System.Nix.Hash (NamedAlgo(..), BaseEncoding(Base16), decodeDigestWith)
import System.Nix.StorePath (StoreDir(..), StorePath, StorePathName, StorePathHashPart, InvalidPathError)
import System.Nix.StorePath.Metadata (Metadata(..), StorePathTrust(..))
@ -74,11 +73,9 @@ import qualified System.Nix.StorePath
import System.Nix.Store.Remote.MonadStore (RemoteStoreT, getStoreDir, RemoteStoreError(RemoteStoreError_GetAddrInfoFailed))
import System.Nix.Store.Remote.Client (Run, runStoreSocket, runOp, runOpArgs, runOpArgsIO, simpleOp, simpleOpArgs)
import System.Nix.Store.Remote.Client (buildDerivation)
import System.Nix.Store.Remote.Socket
import System.Nix.Store.Remote.Types
import Data.Serialize (get)
import System.Nix.Store.Remote.Serialize (putDerivation)
import System.Nix.Store.Remote.Serialize.Prim
-- * Compat
@ -222,25 +219,6 @@ buildPaths ps bm = do
putPaths storeDir ps
putInt $ fromEnum bm
buildDerivation
:: StorePath
-> Derivation StorePath Text
-> BuildMode
-> MonadStore OldBuildResult
buildDerivation p drv buildMode = do
storeDir <- getStoreDir
runOpArgs WorkerOp_BuildDerivation $ do
putPath storeDir p
putDerivation storeDir 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 :: Int)
getSocketIncremental get
-- | Delete store paths
deleteSpecific
:: HashSet StorePath -- ^ Paths to delete

View File

@ -9,6 +9,7 @@ module System.Nix.Store.Remote.Client
, ourProtoVersion
, doReq
, addToStore
, buildDerivation
, isValidPath
) where
@ -39,6 +40,10 @@ import System.Nix.Store.Remote.Types.WorkerMagic (WorkerMagic(..))
import System.Nix.Store.Remote.Types.WorkerOp (WorkerOp)
import System.Nix.Store.Types (FileIngestionMethod(..), RepairMode(..))
import Data.Text
import System.Nix.Build
import System.Nix.Derivation (Derivation)
simpleOp
:: MonadRemoteStore m
=> WorkerOp
@ -146,6 +151,14 @@ addToStore name source method hashAlgo repair = do
setNarSource source
doReq (AddToStore name method hashAlgo repair)
buildDerivation
:: MonadRemoteStore m
=> StorePath
-> Derivation StorePath Text
-> BuildMode
-> m BuildResult
buildDerivation a b c = doReq (BuildDerivation a b c)
--isValidPath :: MonadIO m => StorePath -> RemoteStoreT StoreConfig m Bool
--isValidPath = doReq . IsValidPath

View File

@ -13,14 +13,13 @@ import Data.Word (Word8, Word32)
import qualified Control.Monad
import qualified Data.Bits
import qualified Data.Bool
import qualified Data.Map
import qualified Data.Set
import qualified Data.Text
import qualified Data.Vector
import System.Nix.Build (BuildMode, BuildStatus)
import System.Nix.Derivation (Derivation(..), DerivationOutput(..))
import System.Nix.Build (BuildMode(..), BuildStatus(..), BuildResult(..), OldBuildResult(..))
import System.Nix.StorePath (StoreDir, StorePath)
import System.Nix.Store.Remote.Serialize.Prim
import System.Nix.Store.Remote.Types
@ -29,7 +28,7 @@ instance Serialize Text where
get = getText
put = putText
-- * BuildResult
-- * Build
instance Serialize BuildMode where
get = getEnum
@ -39,45 +38,6 @@ instance Serialize BuildStatus where
get = getEnum
put = putEnum
instance Serialize BuildResult where
get = do
buildResultStatus <- get
buildResultErrorMessage <-
(\em -> Data.Bool.bool (Just em) Nothing (Data.Text.null em))
<$> get
buildResultTimesBuilt <- getInt
buildResultIsNonDeterministic <- getBool
buildResultStartTime <- getTime
buildResultStopTime <- getTime
buildResultBuiltOutputs <- pure Nothing
pure BuildResult{..}
put BuildResult{..} = do
put buildResultStatus
case buildResultErrorMessage of
Just err -> putText err
Nothing -> putText mempty
putInt buildResultTimesBuilt
putBool buildResultIsNonDeterministic
putTime buildResultStartTime
putTime buildResultStopTime
instance Serialize OldBuildResult where
get = do
oldBuildResultStatus <- get
oldBuildResultErrorMessage <-
(\em -> Data.Bool.bool (Just em) Nothing (Data.Text.null em))
<$> get
oldBuildResultBuiltOutputs <- pure Nothing
pure OldBuildResult{..}
put OldBuildResult{..} = do
put oldBuildResultStatus
case oldBuildResultErrorMessage of
Just err -> putText err
Nothing -> putText mempty
-- * GCAction
--
instance Serialize GCAction where

View File

@ -61,7 +61,6 @@ module System.Nix.Store.Remote.Serializer
-- * Build
, buildMode
, buildResult
, oldBuildResult
-- * Logger
, LoggerSError(..)
, activityID
@ -129,7 +128,7 @@ import qualified Data.Vector
import Data.Serializer
import System.Nix.Base (BaseEncoding(NixBase32))
import System.Nix.Build (BuildMode, BuildResult(..), OldBuildResult(..))
import System.Nix.Build (BuildMode, BuildResult(..))
import System.Nix.ContentAddress (ContentAddress)
import System.Nix.Derivation (Derivation(..), DerivationOutput(..))
import System.Nix.DerivedPath (DerivedPath, ParseOutputsError)
@ -791,13 +790,25 @@ buildResult
=> NixSerializer r SError BuildResult
buildResult = Serializer
{ getS = do
pv <- Control.Monad.Reader.asks hasProtoVersion
buildResultStatus <- getS enum
buildResultErrorMessage <- getS maybeText
buildResultTimesBuilt <- getS int
buildResultIsNonDeterministic <- getS bool
buildResultStartTime <- getS time
buildResultStopTime <- getS time
pv <- Control.Monad.Reader.asks hasProtoVersion
( buildResultTimesBuilt
, buildResultIsNonDeterministic
, buildResultStartTime
, buildResultStopTime
) <-
if protoVersion_minor pv >= 29
then 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 <$> getS (mapS outputName realisation)
@ -805,44 +816,22 @@ buildResult = Serializer
pure BuildResult{..}
, putS = \BuildResult{..} -> do
pv <- Control.Monad.Reader.asks hasProtoVersion
putS enum buildResultStatus
putS maybeText buildResultErrorMessage
putS int buildResultTimesBuilt
putS bool buildResultIsNonDeterministic
putS time buildResultStartTime
putS time buildResultStopTime
pv <- Control.Monad.Reader.asks hasProtoVersion
if protoVersion_minor pv >= 28
then putS (mapS outputName realisation)
$ Data.Maybe.fromMaybe mempty buildResultBuiltOutputs
else pure ()
}
oldBuildResult
:: ( HasProtoVersion r
, HasStoreDir r
)
=> NixSerializer r SError OldBuildResult
oldBuildResult = Serializer
{ getS = do
oldBuildResultStatus <- getS enum
oldBuildResultErrorMessage <- getS maybeText
pv <- Control.Monad.Reader.asks hasProtoVersion
oldBuildResultBuiltOutputs <-
if protoVersion_minor pv >= 28
then pure <$> getS (mapS outputName realisation)
else pure Nothing
pure OldBuildResult{..}
, putS = \OldBuildResult{..} -> do
putS enum oldBuildResultStatus
putS maybeText oldBuildResultErrorMessage
pv <- Control.Monad.Reader.asks hasProtoVersion
if protoVersion_minor pv >= 28
then putS (mapS outputName realisation)
$ Data.Maybe.fromMaybe mempty oldBuildResultBuiltOutputs
else pure ()
Control.Monad.when (protoVersion_minor pv >= 29) $ 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 outputName realisation)
$ Data.Maybe.fromMaybe mempty buildResultBuiltOutputs
}
where
t0 :: UTCTime
t0 = Data.Time.Clock.POSIX.posixSecondsToUTCTime 0
-- * Logger

View File

@ -2,6 +2,7 @@ module System.Nix.Store.Remote.Types.StoreReply
( StoreReply(..)
) where
import System.Nix.Build (BuildResult)
import System.Nix.StorePath (HasStoreDir(..), StorePath)
import System.Nix.Store.Remote.Serializer
import System.Nix.Store.Remote.Types.ProtoVersion (HasProtoVersion)
@ -21,6 +22,9 @@ class StoreReply a where
instance StoreReply Bool where
getReplyS = mapPrimE bool
instance StoreReply BuildResult where
getReplyS = mapPrimE buildResult
instance StoreReply StorePath where
getReplyS = mapPrimE storePath

View File

@ -29,7 +29,6 @@ import System.Nix.Build
import System.Nix.StorePath
import System.Nix.StorePath.Metadata
import System.Nix.Store.Remote
import System.Nix.Store.Remote.Client (Run)
import System.Nix.Store.Remote.MonadStore (mapStoreConfig)
import Crypto.Hash (SHA256)

View File

@ -75,21 +75,26 @@ spec = parallel $ do
$ \pv ->
roundtripSReader @TestStoreConfig buildResult (TestStoreConfig sd pv)
. (\x -> x { buildResultBuiltOutputs = Nothing })
. (\x -> x { buildResultTimesBuilt = Nothing
, buildResultIsNonDeterministic = Nothing
, buildResultStartTime = Nothing
, buildResultStopTime = Nothing
}
)
prop "= 1.28"
$ \sd ->
roundtripSReader @TestStoreConfig buildResult (TestStoreConfig 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 @TestStoreConfig buildResult (TestStoreConfig sd pv)
-- prop "OldBuildResult"
-- $ \testStoreConfig ->
-- forAll (arbitrary
-- `suchThat`
-- (restrictProtoVersionBuildResult (hasProtoVersion testStoreConfig)))
-- $ roundtripSReader oldBuildResult testStoreConfig
prop "StorePath" $
roundtripSReader @StoreDir storePath

View File

@ -3,8 +3,9 @@
{-# OPTIONS_GHC -Wno-orphans #-}
module System.Nix.Arbitrary.Build where
import Data.Time (UTCTime)
import Data.Text.Arbitrary ()
import Test.QuickCheck (Arbitrary(..), suchThat)
import Test.QuickCheck (Arbitrary(..), scale, suchThat)
import Test.QuickCheck.Arbitrary.Generic (GenericArbitrary(..))
import System.Nix.Arbitrary.OutputName ()
import System.Nix.Arbitrary.Realisation ()
@ -12,6 +13,8 @@ import System.Nix.Arbitrary.UTCTime ()
import System.Nix.Build
import qualified Data.Time.Clock.POSIX
deriving via GenericArbitrary BuildMode
instance Arbitrary BuildMode
@ -22,20 +25,13 @@ instance Arbitrary BuildResult where
arbitrary = do
buildResultStatus <- arbitrary
buildResultErrorMessage <- arbitrary
buildResultTimesBuilt <- arbitrary
buildResultIsNonDeterministic <- arbitrary
buildResultStartTime <- arbitrary
buildResultStopTime <- arbitrary
buildResultBuiltOutputs <- arbitrary `suchThat` (/= Nothing)
buildResultTimesBuilt <- arbitrary `suchThat` (/= Just 0)
buildResultIsNonDeterministic <- arbitrary `suchThat` (/= Nothing)
buildResultStartTime <- arbitrary `suchThat` (/= Just t0)
buildResultStopTime <- arbitrary `suchThat` (/= Just t0)
buildResultBuiltOutputs <- scale (`div` 10) (arbitrary `suchThat` (/= Nothing))
pure BuildResult{..}
instance Arbitrary OldBuildResult where
arbitrary = do
oldBuildResultStatus <- arbitrary
oldBuildResultErrorMessage <- arbitrary
oldBuildResultBuiltOutputs <- arbitrary `suchThat` (/= Just mempty)
pure OldBuildResult{..}
where
t0 :: UTCTime
t0 = Data.Time.Clock.POSIX.posixSecondsToUTCTime 0