-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Rehackable components for writing buildbots and test harnesses. -- -- Includes utilities for checking the host platform, running tests, -- capturing output, handling errors, comparing runtimes against a -- baseline, sending mail, running events to a schedule etc. Some of the -- Command functions are just wrappers around shell commands, so be -- careful about passing them weirdly formed arguments. @package buildbox @version 1.5.2.2 -- | A schedule of commands that should be run at a certain time. module BuildBox.Cron.Schedule second, day, hour, minute :: NominalDiffTime -- | When to invoke some event. data When -- | Just keep doing it. Always :: When -- | Don't do it, ever. Never :: When -- | Do it some time after we last started it. Every :: NominalDiffTime -> When -- | Do it some time after it last finished. After :: NominalDiffTime -> When -- | Do it each day at this time. The ''days'' are UTC days, not local -- ones. Daily :: TimeOfDay -> When -- | Modifier to when. data WhenModifier -- | If the event hasn't been invoked before then do it immediately when we -- start the cron process. Immediate :: WhenModifier -- | Wait until after this time before doing it first. WaitUntil :: UTCTime -> WhenModifier type EventName = String -- | Records when an event should start, and when it last ran. data Event Event :: EventName -> When -> Maybe WhenModifier -> Maybe UTCTime -> Maybe UTCTime -> Event -- | A unique name for this event. Used when writing the schedule to a -- file. eventName :: Event -> EventName -- | When to run the command. eventWhen :: Event -> When -- | Modifier to the previous. eventWhenModifier :: Event -> Maybe WhenModifier -- | When the event was last started, if any. eventLastStarted :: Event -> Maybe UTCTime -- | When the event last finished, if any. eventLastEnded :: Event -> Maybe UTCTime -- | Given the current time and a list of events, determine which one -- should be started now. If several events are avaliable then take the -- one with the earliest start time. earliestEventToStartAt :: UTCTime -> [Event] -> Maybe Event -- | Given the current time, decide whether an event could be started. If -- the WhenModifier is Immediate this always returns true. -- The SkipFirst modifier is ignored, as this is handled -- separately. eventCouldStartAt :: UTCTime -> Event -> Bool -- | Map of event names to their details and build commands. data Schedule cmd Schedule :: (Map EventName (Event, cmd)) -> Schedule cmd -- | A nice way to produce a schedule. makeSchedule :: [(EventName, When, Maybe WhenModifier, cmd)] -> Schedule cmd -- | Given an event name, lookup the associated event from a schedule. lookupEventOfSchedule :: EventName -> Schedule cmd -> Maybe Event -- | Given an event name, lookup the associated build command from a -- schedule. lookupCommandOfSchedule :: EventName -> Schedule cmd -> Maybe cmd -- | Given a new version of an event, update any matching event in the -- schedule. If the event not already there then return the original -- schedule. adjustEventOfSchedule :: Event -> Schedule cmd -> Schedule cmd -- | Get the list of events in a schedule, ignoring the build commands. eventsOfSchedule :: Schedule cmd -> [Event] instance Read When instance Show When instance Eq When instance Read WhenModifier instance Show WhenModifier instance Eq WhenModifier instance Read Event instance Show Event instance Eq Event instance Read NominalDiffTime -- | When the output of a command is long, keeping it as a String is -- a bad idea. module BuildBox.Data.Log -- | A sequence of lines, without newline charaters on the end. type Log = Seq Line type Line = ByteString -- | O(1) No logs here. empty :: Log -- | O(1) Check if the log is empty. null :: Log -> Bool -- | O(n) Convert a Log to a String. toString :: Log -> String -- | O(n) Convert a String to a Log. fromString :: String -> Log -- | O(1) Add a Line to the start of a Log. (<|) :: Line -> Log -> Log -- | O(1) Add a Line to the end of a Log. (|>) :: Log -> Line -> Log -- | O(log(min(n1,n2))) Concatenate two Logs. (><) :: Log -> Log -> Log -- | O(n) Take the first m lines from a log firstLines :: Int -> Log -> Log -- | O(n) Take the last m lines from a log lastLines :: Int -> Log -> Log module BuildBox.Data.Dividable class Dividable a divide :: Dividable a => a -> a -> a instance Dividable Float instance Dividable Integer -- | Time utils useful for writing buildbots. module BuildBox.Time -- | Read a time of day string like 17:34:05 in the local time -- zone and convert that to a UTC time of day. Good for parsing command -- line args to buildbots. readLocalTimeOfDayAsUTC :: String -> IO TimeOfDay -- | Get a local time stamp with format YYYYMMDD_HHMMSS. Good for naming -- files with. getStampyTime :: IO String -- | Get the local midnight we've just had as a LocalTime. getMidnightTodayLocal :: IO LocalTime -- | Get the local midnight that we've just had, as a UTCTime. getMidnightTodayUTC :: IO UTCTime -- | Get the local midnight we're about to have as a LocalTime. getMidnightTomorrowLocal :: IO LocalTime -- | Get the local midnight we're about to have as a UTCTime. getMidnightTomorrowUTC :: IO UTCTime -- | Pretty printing utils. module BuildBox.Pretty class Pretty a ppr :: Pretty a => a -> Doc -- | Right justify a doc, padding with a given character. padRc :: Int -> Char -> Doc -> Doc -- | Right justify a string with spaces. padR :: Int -> Doc -> Doc -- | Left justify a string, padding with a given character. padLc :: Int -> Char -> Doc -> Doc -- | Left justify a string with spaces. padL :: Int -> Doc -> Doc -- | Blank text. This is different different from empty because it -- comes out a a newline when used in a vcat. blank :: Doc -- | Pretty print an engineering value, to 4 significant figures. Valid -- range is 10^(-24) (y/yocto) to 10^(+24) (Y/Yotta). Out of range values -- yield Nothing. -- -- examples: -- --
--   liftM render $ pprEngDouble "J" 102400    ==>   Just "1.024MJ"
--   liftM render $ pprEngDouble "s" 0.0000123 ==>   Just "12.30us"
--   
pprEngDouble :: String -> Double -> Maybe Doc -- | Like pprEngDouble but don't display fractional part when the -- value is < 1000. Good for units where fractional values might not -- make sense (like bytes). pprEngInteger :: String -> Integer -> Maybe Doc instance [incoherent] Pretty String instance [incoherent] Pretty a => Pretty [a] instance [incoherent] Pretty UTCTime instance [incoherent] Pretty Integer instance [incoherent] Pretty Int instance [incoherent] Pretty Float instance [incoherent] Pretty Doc -- | The detail is the name of an Aspect seprate from its data. module BuildBox.Aspect.Detail data Detail DetailTimed :: Timed -> Detail DetailUsed :: Used -> Detail DetailSized :: Sized -> Detail -- | Something that takes time to evaluate. data Timed TotalWall :: Timed TotalCpu :: Timed TotalSys :: Timed KernelWall :: Timed KernelCpu :: Timed KernelSys :: Timed -- | Some resource used during execution. data Used HeapMax :: Used HeapAlloc :: Used -- | Some static size of the benchmark that isn't affected during the run. data Sized ExeSize :: Sized instance Eq Timed instance Ord Timed instance Show Timed instance Read Timed instance Enum Timed instance Eq Used instance Ord Used instance Show Used instance Read Used instance Enum Used instance Eq Sized instance Ord Sized instance Show Sized instance Read Sized instance Enum Sized instance Eq Detail instance Ord Detail instance Show Detail instance Read Detail instance Pretty Sized instance Pretty Used instance Pretty Timed module BuildBox.Aspect.Stats -- | Statistics extracted from many-valued data. data Stats a Stats :: a -> a -> a -> Stats a statsMin :: Stats a -> a statsAvg :: Stats a -> a statsMax :: Stats a -> a -- | Make statistics from a list of values. makeStats :: (Real a, Dividable a) => [a] -> Stats a -- | Return True if the predicate matches any of the min, avg, max -- values. predStats :: (a -> Bool) -> Stats a -> Bool -- | Lift a function to each component of a Stats liftStats :: (a -> b) -> Stats a -> Stats b -- | Lift a binary function to each component of a Stats liftStats2 :: (a -> b -> c) -> Stats a -> Stats b -> Stats c instance Read a => Read (Stats a) instance Show a => Show (Stats a) instance Pretty a => Pretty (Stats a) module BuildBox.Aspect.Single -- | A single valued piece of data. data Single a Single :: a -> Single a instance Read a => Read (Single a) instance Show a => Show (Single a) instance Pretty a => Pretty (Single a) instance Eq a => Eq (Single a) instance Num a => Num (Single a) -- | Physical units of measure. module BuildBox.Aspect.Units -- | Seconds of time. data Seconds Seconds :: Double -> Seconds -- | Bytes of data. data Bytes Bytes :: Integer -> Bytes -- | Represents the units used for some thing. data IsUnits a IsSeconds :: IsUnits Seconds IsBytes :: IsUnits Bytes -- | Determine the units used by the elements of some collection, by -- inspecting the elements directly. Returns Nothing when applied -- to empty collections, as they have no units. class HasUnits a b | a -> b hasUnits :: HasUnits a b => a -> Maybe (IsUnits b) -- | A wrapper type used to store data of varying physical units in a -- homogenous collection structure. data WithUnits t WithSeconds :: t Seconds -> WithUnits t WithBytes :: t Bytes -> WithUnits t -- | Helpful wrapper for constructing seconds-valued aspect data. Examples: -- --
--   Time TotalWall `secs` 10  ::  WithUnits (Aspect Single)
--   
secs :: (Single Seconds -> c Single Seconds) -> Double -> WithUnits (c Single) -- | Similar to secs. bytes :: (Single Bytes -> c Single Bytes) -> Integer -> WithUnits (c Single) -- | Apply a function to unit-wrapped data appWithUnits :: (forall units. Real units => t1 units -> b) -> WithUnits t1 -> b -- | Apply a function to unit-wrapped data. liftWithUnits :: (forall units. Real units => t1 units -> t2 units) -> WithUnits t1 -> WithUnits t2 -- | Transform values of each unit type as a group. liftsWithUnits :: (forall units. Real units => [t1 units] -> [t2 units]) -> [WithUnits t1] -> [WithUnits t2] -- | Transform values of each unit type as a group liftsWithUnits2 :: (forall units. Real units => [t1 units] -> [t2 units] -> [t3 units]) -> [WithUnits t1] -> [WithUnits t2] -> [WithUnits t3] -- | Collate some data, while preserving units. class Collatable t collate :: (Collatable t, HasUnits a a) => [t Single a] -> [t [] a] -- | Collate some data. -- --
--   collateWithUnits  [ Time KernelCpu `secs`  5
--                     , Time KernelCpu `secs`  10
--                     , Time TotalWall `secs`  55
--                     , Size ExeSize   `bytes` 100884
--                     , Time TotalWall `secs`  52 ]
--   =>
--                     [ WithSeconds (Time KernelCpu [Seconds 5.0,  Seconds 10.0])
--                     , WithSeconds (Time TotalWall [Seconds 55.0, Seconds 52.0])
--                     , WithBytes   (Size ExeSize [Bytes 1024])]
--   
collateWithUnits :: Collatable c => [WithUnits (c Single)] -> [WithUnits (c [])] instance (Read (t Bytes), Read (t Seconds)) => Read (WithUnits t) instance (Show (t Bytes), Show (t Seconds)) => Show (WithUnits t) instance Read Seconds instance Show Seconds instance Ord Seconds instance Eq Seconds instance Read Bytes instance Show Bytes instance Ord Bytes instance Eq Bytes instance (Pretty (t Bytes), Pretty (t Seconds)) => Pretty (WithUnits t) instance HasUnits a a => HasUnits [a] a instance HasUnits a a => HasUnits (Stats a) a instance HasUnits a a => HasUnits (Single a) a instance HasUnits Bytes Bytes instance HasUnits Seconds Seconds instance Units Bytes instance Units Seconds instance Pretty Bytes instance Num Bytes instance Dividable Bytes instance Real Bytes instance Pretty Seconds instance Num Seconds instance Dividable Seconds instance Real Seconds module BuildBox.Quirk -- | A Quirk is some extended information about a benchmark or test that -- isn't represented by an Aspect. These are singleton pieces of -- data where it doesn't make sense to average them or compute other -- statistics. data Quirk QuirkSucceeded :: Quirk QuirkFailed :: Quirk QuirkExitCode :: ExitCode -> Quirk QuirkTimeout :: Seconds -> Quirk instance Eq Quirk instance Ord Quirk instance Read Quirk instance Show Quirk instance Pretty Quirk module BuildBox.Aspect.Comparison -- | The comparison of two values. data Comparison a -- | Comparison of a recent value with a baseline. Comparison :: a -> a -> Double -> Comparison a comparisonBaseline :: Comparison a -> a comparisonRecent :: Comparison a -> a comparisonSwing :: Comparison a -> Double -- | A new value that doesn't have a baseline. ComparisonNew :: a -> Comparison a comparisonNew :: Comparison a -> a -- | Make a comparison from two values. makeComparison :: Real a => a -> a -> Comparison a -- | Apply a function to the swing of a comparison. appSwing :: a -> (Double -> a) -> Comparison b -> a -- | Comparisons of statistics data StatsComparison a StatsComparison :: (Stats (Comparison a)) -> StatsComparison a -- | Make a comparison of two Stats. makeStatsComparison :: Real a => Stats a -> Stats a -> StatsComparison a -- | Make a ComparisonNew. makeStatsComparisonNew :: Stats a -> StatsComparison a -- | Return True if any of the swings in the StatsComparison -- match the given function. predSwingStatsComparison :: (Double -> Bool) -> StatsComparison a -> Bool instance Read a => Read (Comparison a) instance Show a => Show (Comparison a) instance Read a => Read (StatsComparison a) instance Show a => Show (StatsComparison a) instance Pretty a => Pretty (StatsComparison a) instance Pretty a => Pretty (Comparison a) -- | Some property of the system we can test for. -- -- They have Show instances so we can make nice error messages if -- a check fails. module BuildBox.Build.Testable -- | Some testable property. class Testable prop test :: Testable prop => prop -> Build Bool -- | Testable properties are checkable. If the check returns false then -- throw an error. check :: (Show prop, Testable prop) => prop -> Build () -- | Testable properties are checkable. If the check returns true then -- throw an error. checkFalse :: (Show prop, Testable prop) => prop -> Build () -- | Check some property while printing what we're doing. outCheckOk :: (Show prop, Testable prop) => String -> prop -> Build () -- | Check some property while printing what we're doing. outCheckFalseOk :: (Show prop, Testable prop) => String -> prop -> Build () -- | Directory utils that don't need to be in the Build monad. module BuildBox.IO.Directory -- | Get the names of all files in a directory. This filters out the fake -- files like . and '..' lsFilesIn :: MonadIO m => String -> m [String] -- | Get the names of all the dirs in this one. This filters out the fake -- files like . and '..' lsDirsIn :: MonadIO m => String -> m [String] -- | Get all the files reachable from this directory traceFilesFrom :: FilePath -> IO (Seq FilePath) -- | A gang consisting of a fixed number of threads that can run actions in -- parallel. Good for constructing parallel test frameworks. module BuildBox.Control.Gang -- | Abstract gang of threads. data Gang data GangState -- | Gang is running and starting new actions. GangRunning :: GangState -- | Gang may be running already started actions, but no new ones are being -- started. GangPaused :: GangState -- | Gang is waiting for currently running actions to finish, but not -- starting new ones. GangFlushing :: GangState -- | Gang is finished, all the actions have completed. GangFinished :: GangState -- | Gang was killed, all the threads are dead (or dying). GangKilled :: GangState -- | Fork a new gang to run the given actions. This function returns -- immediately, with the gang executing in the background. Gang state -- starts as GangRunning then transitions to GangFinished. -- To block until all the actions are finished use joinGang. forkGangActions :: Int -> [IO ()] -> IO Gang -- | Block until all actions have finished executing, or the gang is -- killed. joinGang :: Gang -> IO () -- | Pause a gang. Actions that have already been started continue to run, -- but no more will be started until a resumeGang command is -- issued. Gang state changes to GangPaused. pauseGang :: Gang -> IO () -- | Resume a paused gang, which allows it to continue starting new -- actions. Gang state changes to GangRunning. resumeGang :: Gang -> IO () -- | Block until already started actions have completed, but don't start -- any more. Gang state changes to GangFlushing. flushGang :: Gang -> IO () -- | Kill all the threads in a gang. Gang stage changes to -- GangKilled. killGang :: Gang -> IO () -- | Get the state of a gang. getGangState :: Gang -> IO GangState -- | Block until the gang is in the given state. waitForGangState :: Gang -> GangState -> IO () instance Show GangState instance Eq GangState -- | Defines the main Build monad and common utils. module BuildBox.Build -- | The errors we recognise. data BuildError -- | Some generic error ErrorOther :: String -> BuildError -- | Some system command fell over, and it barfed out the given stdout and -- stderr. ErrorSystemCmdFailed :: String -> ExitCode -> Log -> Log -> BuildError buildErrorCmd :: BuildError -> String buildErrorCode :: BuildError -> ExitCode buildErrorStdout :: BuildError -> Log buildErrorStderr :: BuildError -> Log -- | Some miscellanous IO action failed. ErrorIOError :: IOError -> BuildError -- | Some property check was supposed to return the given boolean -- value, but it didn't. ErrorCheckFailed :: Bool -> prop -> BuildError -- | A build command needs the following file to continue. This can be used -- for writing make-like bots. ErrorNeeds :: FilePath -> BuildError -- | Global builder configuration. data BuildState BuildState :: Maybe Handle -> Integer -> Integer -> FilePath -> BuildState -- | Log all system commands executed to this file handle. buildStateLogSystem :: BuildState -> Maybe Handle -- | Uniqueish id for this build process. On POSIX we'd use the PID, but -- that doesn't work on Windows. The id is initialised by the Haskell -- random number generator on startup. buildStateId :: BuildState -> Integer -- | Sequence number for generating fresh file names. buildStateSeq :: BuildState -> Integer -- | Scratch directory for making temp files. buildStateScratchDir :: BuildState -> FilePath -- | The default build config. buildStateDefault :: Integer -> FilePath -> BuildState -- | The builder monad encapsulates and IO action that can fail with an -- error, and also read some global configuration info. type Build a = ErrorT BuildError (StateT BuildState IO) a -- | Run a build command. The first argument is a directory that can be -- used for temporary files (like "/tmp") runBuild :: FilePath -> Build a -> IO (Either BuildError a) -- | Like runBuild but also takes a BuildState. runBuildWithState :: BuildState -> Build a -> IO (Maybe a) -- | Like runBuild, but report whether it succeeded to the console. -- If it succeeded then return Just the result, else Nothing. runBuildPrint :: FilePath -> Build a -> IO (Maybe a) -- | Like runBuildPrint but also takes a BuildState. runBuildPrintWithState :: BuildState -> Build a -> IO (Maybe a) -- | Discard the resulting value of a compuation. Used like -- successfully . runBuild ... successfully :: IO a -> IO () -- | Throw an error in the build monad. throw :: BuildError -> Build a -- | Throw a needs error saying we needs the given file. A catcher could -- then usefully create the file, or defer the compuation until it has -- been created. needs :: FilePath -> Build () -- | Lift an IO action into the build monad. If the action throws any -- exceptions they get caught and turned into ErrorIOError -- exceptions in our Build monad. io :: IO a -> Build a -- | Like when, but with teh monadz. whenM :: Monad m => m Bool -> m () -> m () -- | Print some text to stdout. out :: Pretty a => a -> Build () -- | Print some text to stdout followed by a newline. outLn :: Pretty a => a -> Build () -- | Print a blank line to stdout outBlank :: Build () -- | Print a ----- line to stdout outLine :: Build () -- | Print a ===== line to stdout outLINE :: Build () -- | Log a system command to the handle in our BuildConfig, if -- any. logSystem :: String -> Build () -- | What do build 'bots dream about? module BuildBox.Command.Sleep -- | Sleep for a given number of seconds. sleep :: Int -> Build () -- | Sleep for a given number of milliseconds. msleep :: Int -> Build () -- | Running system commands. On some platforms this may cause the command -- to be executed directly, so shell tricks won't work. The Build -- monad can be made to log commands executed with all versions of -- system by setting buildConfigLogSystem in the -- BuildConfig passed to runBuildPrintWithConfig. -- -- We define a lot of wrappers because executing system commands is the -- bread-and-butter of buildbots, and we usually need all the versions... module BuildBox.Command.System -- | Run a system command, returning its exit code. system :: String -> Build ExitCode -- | Run a successful system command. If the exit code is -- ExitFailure then throw an error in the Build monad. ssystem :: String -> Build () -- | Quietly run a system command, returning its exit code. qsystem :: String -> Build ExitCode -- | Quietly run a successful system command. If the exit code is -- ExitFailure then throw an error in the Build monad. qssystem :: String -> Build () -- | Run a successful system command, returning what it wrote to its -- stdout. If anything was written to stderr then treat -- that as failure. If it fails due to writing to stderr or -- returning ExitFailure then throw an error in the Build -- monad. ssystemOut :: String -> Build String -- | Quietly run a successful system command, returning what it wrote to -- its stdout. If anything was written to stderr then -- treat that as failure. If it fails due to writing to stderr -- or returning ExitFailure then throw an error in the -- Build monad. qssystemOut :: String -> Build String -- | Like systemTeeIO, but in the Build monad. systemTee :: Bool -> String -> String -> Build (ExitCode, String, String) -- | Like systemTeeLogIO, but in the Build monad. systemTeeLog :: Bool -> String -> Log -> Build (ExitCode, Log, Log) -- | Like systemTeeIO, but in the Build monad and throw an -- error if it returns ExitFailure. ssystemTee :: Bool -> String -> String -> Build () -- | Like systemTeeLogIO, but with strings. systemTeeIO :: Bool -> String -> String -> IO (ExitCode, String, String) -- | Run a system command, returning its ExitCode and what was -- written to stdout and stderr. systemTeeLogIO :: Bool -> String -> Log -> IO (ExitCode, Log, Log) -- | Working with the file system. module BuildBox.Command.File -- | Properties of the file system we can test for. data PropFile -- | Some executable is in the current path. HasExecutable :: String -> PropFile -- | Some file exists. HasFile :: FilePath -> PropFile -- | Some directory exists. HasDir :: FilePath -> PropFile -- | Some file is empty. FileEmpty :: FilePath -> PropFile -- | Run a command in a different working directory. Throws an error if the -- directory doesn't exist. inDir :: FilePath -> Build a -> Build a -- | Create a new directory with the given name, run a command within it, -- then change out and recursively delete the directory. Throws an error -- if a directory with the given name already exists. inScratchDir :: FilePath -> Build a -> Build a -- | Delete a dir recursively if it's there, otherwise do nothing. Unlike -- removeDirectoryRecursive, this function does not follow -- symlinks, it just deletes them. clobberDir :: FilePath -> Build () -- | Create a new directory if it isn't already there, or return -- successfully if it is. ensureDir :: FilePath -> Build () -- | Create a temp file, pass it to some command, then delete the file -- after the command finishes. withTempFile :: (FilePath -> Build a) -> Build a -- | Atomically write a file by first writing it to a tmp file then -- renaming it. This prevents concurrent processes from reading -- half-written files. atomicWriteFile :: FilePath -> String -> Build () instance Show PropFile instance Testable PropFile -- | Working with the network. module BuildBox.Command.Network data PropNetwork -- | The given host is reachable with ping. HostReachable :: HostName -> PropNetwork -- | Use wget to check if a web-page is gettable. The page is -- deleted after downloading. UrlGettable :: URL -> PropNetwork instance Show PropNetwork instance Testable PropNetwork -- | Gathering information about the build environment. module BuildBox.Command.Environment -- | The environment consists of the Platform, and some tool -- versions. data Environment Environment :: Platform -> [(String, String)] -> Environment environmentPlatform :: Environment -> Platform environmentVersions :: Environment -> [(String, String)] -- | Get the current environment, including versions of these tools. getEnvironmentWith :: [(String, Build String)] -> Build Environment -- | Generic information about the platform we're running on. data Platform Platform :: String -> String -> String -> String -> String -> Platform platformHostName :: Platform -> String platformHostArch :: Platform -> String platformHostProcessor :: Platform -> String platformHostOS :: Platform -> String platformHostRelease :: Platform -> String -- | Get information about the host platform. getHostPlatform :: Build Platform -- | Get the name of this host, using uname. getHostName :: Build String -- | Get the host architecture, using uname. getHostArch :: Build String -- | Get the host processor name, using uname. getHostProcessor :: Build String -- | Get the host operating system, using uname. getHostOS :: Build String -- | Get the host operating system release, using uname. getHostRelease :: Build String -- | Get the version of this GHC, or throw an error if it can't be found. getVersionGHC :: FilePath -> Build String -- | Get the version of this GCC, or throw an error if it can't be found. getVersionGCC :: FilePath -> Build String instance Show Platform instance Read Platform instance Show Environment instance Read Environment instance Pretty Platform instance Pretty Environment -- | Sending email. We've got baked in support for msmtp, which is -- easy to set up. Adding support for other mailers should be easy. Get -- msmtp here: http://msmtp.sourceforge.net module BuildBox.Command.Mail -- | An email message that we can send. data Mail Mail :: String -> String -> String -> UTCTime -> TimeZone -> String -> String -> Mail mailFrom :: Mail -> String mailTo :: Mail -> String mailSubject :: Mail -> String mailTime :: Mail -> UTCTime mailTimeZone :: Mail -> TimeZone mailMessageId :: Mail -> String mailBody :: Mail -> String -- | An external mailer that can send messages. Also contains mail server -- info if needed. data Mailer -- | Send the mail by writing to the stdin of this command. On many systems -- the command sendmail will be aliased to an appropriate -- wrapper for whatever Mail Transfer Agent (MTA) you have installed. MailerSendmail :: FilePath -> [String] -> Mailer mailerPath :: Mailer -> FilePath mailerExtraFlags :: Mailer -> [String] -- | Send mail via MSMTP, which is a stand-alone SMTP sender. This might be -- be easier to set up if you don't have a real MTA installed. Get it -- from http:msmtp.sourceforge.net/ MailerMSMTP :: FilePath -> Maybe Int -> Mailer mailerPath :: Mailer -> FilePath mailerPort :: Mailer -> Maybe Int -- | Create a mail with a given from, to, subject and body. Fill in the -- date and message id based on the current time. Valid dates and message -- ids are needed to prevent the mail being bounced by spambots. createMailWithCurrentTime :: String -> String -> String -> String -> Build Mail -- | Render an email message as a string. renderMail :: Mail -> Doc -- | Send a mail message. sendMailWithMailer :: Mail -> Mailer -> Build () instance Show Mail instance Show Mailer -- | Querying a darcs repository module BuildBox.Command.Darcs type EmailAddress = String type DarcsPath = String data DarcsPatch DarcsPatch :: LocalTime -> EmailAddress -> Log -> DarcsPatch darcsTimestamp :: DarcsPatch -> LocalTime darcsAuthor :: DarcsPatch -> EmailAddress darcsComment :: DarcsPatch -> Log -- | List all patches in the given repository. If no repository is given, -- the current working directory is used. changes :: Maybe DarcsPath -> Build [DarcsPatch] -- | Retrieve the last N changes from the repository changesN :: Maybe DarcsPath -> Int -> Build [DarcsPatch] -- | Retrieve all patches submitted to the repository after the given time changesAfter :: Maybe DarcsPath -> LocalTime -> Build [DarcsPatch] instance Show DarcsPatch -- | A simple ''cron'' loop. Used for running commands according to a given -- schedule. module BuildBox.Cron -- | Given a schedule of commands, run them when their time is due. Only -- one command is run at a time. If several commands could be started at -- a specific moment, then we take the one with the earliest potential -- start time. If any command throws an error in the Build monad -- then the whole loop does. cronLoop :: Schedule (Build ()) -> Build () -- | An aspect is a piece of data obtained from running a benchmark, like -- its total runtime, heap usage, or executable size. Aspects have -- physical units, so runtime is in seconds, and executable size is in -- bytes. The type system ensures that you can't mess up the units, such -- as by treating executable size as though it was measured in seconds. -- -- Aspects are also parameterised over a carrier constructor, which is -- the collection type used to store the data. For single valued data use -- the Single constructor. For multi valued data use the -- [] (the list constructor). Use this when you have several -- readings for the same benchmark, like runtimes from multiple -- independent runs. Other useful constructors are Stats, -- Comparison and StatsComparison. -- -- Once you have a many-valued aspect, you can use makeAspectStats -- to compute statistics from the data. -- -- Here is a worked example: -- --
--    
--    -- This is our original, single valued data.
--   someData :: [WithUnits (Aspect Single)]
--   someData =  [ Time TotalWall `secs`  100
--               , Time TotalWall `secs`  85
--               , Size ExeSize   `bytes` 1024
--               , Used HeapMax   `bytes` 100000
--               , Used HeapMax   `bytes` 100100]
--   
-- --
--    -- Collate the data, which groups all the readings for the same aspect into a list.
--    -- Note that the carrier constructor is now [].
--   collated  :: [WithUnits (Aspect [])]
--   collated  = collateWithUnits someData
--    ...
--   show collated 
--     =>   [ WithSeconds (Time TotalWall [Seconds 100.0, Seconds 85.0])
--          , WithBytes   (Used HeapMax   [Bytes 100000,  Bytes 100100])
--          , WithBytes   (Size ExeSize   [Bytes 1024])]
--   
-- --
--    -- Extract statistics from the collated data.
--   analysed   :: [WithUnits (Aspect Stats)]
--   analysed   =  map (liftWithUnits makeAspectStats) collated
--    ...
--   show analysed
--     =>   [ WithSeconds (Time TotalWall (Stats {statsMin = Seconds 85.0, statsAvg = Seconds 92.5, statsMax = Seconds 100.0}))
--          , WithBytes   (Used HeapMax   (Stats {statsMin = Bytes 100000, statsAvg = Bytes 100050, statsMax = Bytes 100100}))
--          , WithBytes   (Size ExeSize   (Stats {statsMin = Bytes 1024,   statsAvg = Bytes 1024,   statsMax = Bytes 1024}))]
--   
module BuildBox.Aspect -- | Holds a detail about a benchmark. -- -- The c is the type constructor of the carrier that holds the -- data. -- -- Useful instances for c include Single, `[ ]`, -- Stats, Comparison and StatsComparison. data Aspect c :: (* -> *) units Time :: Timed -> c Seconds -> Aspect c Seconds Size :: Sized -> c Bytes -> Aspect c Bytes Used :: Used -> c Bytes -> Aspect c Bytes -- | Make an aspect from a named detail and data. If the detail doesn't -- match the units of the data then Nothing. makeAspect :: HasUnits (c units) units => Detail -> c units -> Maybe (Aspect c units) -- | Split an aspect into its named detail and data. splitAspect :: Aspect c units -> (Detail, c units) -- | Compute statistics for many-valued aspects. makeAspectStats :: Aspect [] units -> Aspect Stats units -- | Lookup the baseline result for some aspect and produce a comparison. makeAspectComparison :: Real units => [Aspect Stats units] -> Aspect Stats units -> Aspect StatsComparison units -- | Compare lists of aspects. The first argument is the baseline. makeAspectComparisons :: Real units => [Aspect Stats units] -> [Aspect Stats units] -> [Aspect StatsComparison units] -- | Apply a function to the data in an aspect appAspect :: Real units => (c units -> b) -> Aspect c units -> b -- | Apply a function to the data in a wrapped aspect. appAspectWithUnits :: (forall units. Real units => c units -> b) -> WithUnits (Aspect c) -> b -- | Transform the data in an aspect, possibly changing the carrier type. liftAspect :: (c1 units -> c2 units) -> Aspect c1 units -> Aspect c2 units -- | Apply a function to the aspect data, producing a new aspect. If the -- aspect details don't match then error. liftAspect2 :: (c1 units -> c1 units -> c2 units) -> Aspect c1 units -> Aspect c1 units -> Aspect c2 units module BuildBox.Benchmark.BenchResult -- | We include the name of the original benchmark to it's easy to lookup -- the results. If the BenchResult is carrying data derived -- directly by running a benchmark, there will be an element of the -- benchResultRuns for each iteration. On the other hand, If the -- BenchResult is carrying statistics or comparison data there -- should be a single element with an index of 0. This is suggested -- usage, and adhered to by the functions in this module, but not -- required. data BenchResult c BenchResult :: String -> [BenchRunResult c] -> BenchResult c benchResultName :: BenchResult c -> String benchResultRuns :: BenchResult c -> [BenchRunResult c] -- | Holds the result of running a benchmark once. data BenchRunResult c BenchRunResult :: Integer -> [Quirk] -> [WithUnits (Aspect c)] -> BenchRunResult c -- | What iteration this run was. Use 1 for the first ''real'' iteration -- derived by running a program. Use 0 for ''fake'' iterations computed -- by statistics or comparisons. benchRunResultIndex :: BenchRunResult c -> Integer -- | Information about the run that doesn't carry units, eg whether it -- timed out or segfaulted. benchRunResultQuirks :: BenchRunResult c -> [Quirk] -- | Aspects of the benchmark run that carry units and can have statistics -- extracted from them. benchRunResultAspects :: BenchRunResult c -> [WithUnits (Aspect c)] -- | Concatenate the results of all runs. The the resulting -- BenchResult has a single BenchRunResult with an index of -- 0, containing all aspects. concatBenchResult :: BenchResult c1 -> BenchResult c1 -- | Collate the aspects of each run. See collateWithUnits for an -- explanation and example. collateBenchResult :: BenchResult Single -> BenchResult [] -- | Compute statistics from collated aspects of a run. statCollatedBenchResult :: BenchResult [] -> BenchResult Stats -- | Collate the aspects, then compute statistics of a run. statBenchResult :: BenchResult Single -> BenchResult Stats -- | Compute comparisons of benchmark results. Both results must have the -- same benchResultName else error. compareBenchResults :: BenchResult Stats -> BenchResult Stats -> BenchResult StatsComparison -- | Compute comparisons of benchmark result, looking up the baseline -- results from a given list. If there are no matching baseline results -- then this creates a ComparisonNew in the output. compareBenchResultWith :: [BenchResult Stats] -> BenchResult Stats -> BenchResult StatsComparison -- | Compare some baseline results against new results. If there are no -- matching baseline results then this creates a ComparisonNew in -- the output. compareManyBenchResults :: [BenchResult Stats] -> [BenchResult Stats] -> [BenchResult StatsComparison] -- | Return true if any of the aspect data in a result matches a given -- predicate. predBenchResult :: (forall units. Real units => c units -> Bool) -> BenchResult c -> Bool -- | Return true if any of the aspects have swung by more than a given -- fraction since last time. For example, use 0.1 for 10 -- percent. swungBenchResult :: Double -> BenchResult StatsComparison -> Bool -- | Merge lists of BenchResults, preferring results from earlier -- lists. In the output list there is one result for every named -- benchmark in the input. mergeBenchResults :: [[BenchResult c]] -> [BenchResult c] -- | Given a fraction (like 0.1 for 10 percent), split some results into -- three groups: ''winners'', ''losers'' and ''others''. The losers are -- benchmarks had any aspect increase by more than the fraction. Winners -- are non-losers, where any aspect decreased by the fraction. Others are -- not winners or losers. splitBenchResults :: Double -> [BenchResult StatsComparison] -> ([BenchResult StatsComparison], [BenchResult StatsComparison], [BenchResult StatsComparison]) -- | Create a new baseline from original baseline, and recent results. If -- any of the recent results are winners then use them, otherwise use -- results from the old baseline. advanceBenchResults :: Double -> [BenchResult StatsComparison] -> [BenchResult Single] -> [BenchResult Single] -> [BenchResult Single] -- | Apply a function to the aspects of a BenchRunResult appBenchRunResult :: ([BenchRunResult c1] -> b) -> BenchResult c1 -> b -- | Apply a function to the aspects of a BenchRunResult appRunResultAspects :: ([WithUnits (Aspect c1)] -> b) -> BenchRunResult c1 -> b -- | Lift a function to the BenchRunResult in a BenchResult liftBenchRunResult :: ([BenchRunResult c1] -> [BenchRunResult c2]) -> (BenchResult c1 -> BenchResult c2) -- | Lift a binary function to the BenchResults in a -- BenchResult liftBenchRunResult2 :: ([BenchRunResult c1] -> [BenchRunResult c2] -> [BenchRunResult c3]) -> BenchResult c1 -> BenchResult c2 -> BenchResult c3 -- | Lift a function to the aspects of each BenchRunResult. liftToAspectsOfBenchResult :: ([WithUnits (Aspect c1)] -> [WithUnits (Aspect c2)]) -> BenchResult c1 -> BenchResult c2 -- | Lift a binary function to the aspects of each BenchRunResult. liftToAspectsOfBenchResult2 :: ([WithUnits (Aspect c1)] -> [WithUnits (Aspect c2)] -> [WithUnits (Aspect c3)]) -> BenchResult c1 -> BenchResult c2 -> BenchResult c3 -- | Lift a function to the aspects of a BenchRunResult liftRunResultAspects :: ([WithUnits (Aspect c1)] -> [WithUnits (Aspect c2)]) -> BenchRunResult c1 -> BenchRunResult c2 -- | Lift a binary function to the aspects of two BenchRunResults. -- The resulting BenchRunResult gets all the quirks from both. liftRunResultAspects2 :: ([WithUnits (Aspect c1)] -> [WithUnits (Aspect c2)] -> [WithUnits (Aspect c3)]) -> BenchRunResult c1 -> BenchRunResult c2 -> BenchRunResult c3 instance (HasUnits (c Bytes) Bytes, Read (c Bytes), HasUnits (c Seconds) Seconds, Read (c Seconds)) => Read (BenchRunResult c) instance (Show (c Seconds), Show (c Bytes)) => Show (BenchRunResult c) instance (HasUnits (c Bytes) Bytes, Read (c Bytes), HasUnits (c Seconds) Seconds, Read (c Seconds)) => Read (BenchResult c) instance (Show (c Seconds), Show (c Bytes)) => Show (BenchResult c) instance (Pretty (c Seconds), Pretty (c Bytes)) => Pretty (BenchRunResult c) instance (Pretty (c Seconds), Pretty (c Bytes)) => Pretty (BenchResult c) module BuildBox.Reports.BenchResult -- | Produce a human readable report of benchmark results. -- -- If you only want the results within a fractional swing from the -- baseline then pass something like (Just 0.1) as the first -- parameter for a 10% swing, otherwise all results are printed. reportBenchResults :: Maybe Double -> [BenchResult StatsComparison] -> Doc module BuildBox.Benchmark -- | Describes a benchmark that we can run. data Benchmark Benchmark :: String -> Build () -> Build [WithUnits (Aspect Single)] -> Build [WithUnits (Aspect Single)] -> Benchmark -- | A unique name for the benchmark. benchmarkName :: Benchmark -> String -- | Setup command to run before the main benchmark. benchmarkSetup :: Benchmark -> Build () -- | The benchmark command to run. The time taken to run this part is -- automatically measured and added to the overall results. benchmarkCommand :: Benchmark -> Build [WithUnits (Aspect Single)] -- | Check / cleanup command to run after the main benchmark. benchmarkCheck :: Benchmark -> Build [WithUnits (Aspect Single)] -- | Run a command, returning its elapsed time. runTimedCommand :: Build a -> Build (NominalDiffTime, a) -- | Run a benchmark once. runBenchmarkOnce :: Integer -> Benchmark -> Build (BenchRunResult Single) -- | Run a benchmark once, logging activity and timings to the console. outRunBenchmarkOnce :: Integer -> Benchmark -> Build (BenchRunResult Single) -- | Run a benchmark serveral times, logging activity to the console. Also -- lookup prior results and print comparisons during the run. outRunBenchmarkWith :: Int -> [BenchResult Stats] -> Benchmark -> Build (BenchResult Single) module BuildBox.FileFormat.BuildResults -- | A simple build results file format. data BuildResults BuildResults :: UTCTime -> Environment -> [BenchResult Single] -> BuildResults buildResultTime :: BuildResults -> UTCTime buildResultEnvironment :: BuildResults -> Environment buildResultBench :: BuildResults -> [BenchResult Single] -- | Merge some BuildResults. If we have data for a named benchmark in -- multiple BuildResults, then we take the first one in the list. -- The resultTime and environment is taken from the last -- BuildResults, in the list. mergeResults :: [BuildResults] -> BuildResults -- | Take test results from the first BuildResults, except for the -- named one which we take from the second. If the named test is not in -- the second then take it from the first. If it's not anywhere then -- Nothing. acceptResult :: String -> BuildResults -> BuildResults -> Maybe BuildResults -- | Advance benchmark results as per advanceBenchResults. The -- resultTime and environment is taken from the second -- BuildResults. advanceResults :: Double -> BuildResults -> BuildResults -> BuildResults instance Show BuildResults instance Read BuildResults instance Pretty BuildResults module BuildBox