{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module BB8.Types where
import Control.Exception.Base
import Data.Aeson ((.=), (.:), (.:?))
import qualified Data.Aeson as Aeson
import qualified Data.ByteString as BS
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Time.Clock as Time
import qualified Database.SQLite.Simple as SQL
import qualified Database.SQLite.Simple.FromField as SQL
import qualified Database.SQLite.Simple.ToField as SQL
import qualified Database.SQLite.Simple.Ok as SQL
-- * Configuration
data Config = Config
{ configSleepAmount :: Int
, configDBPath :: FilePath
, configWorkDirectory :: FilePath
}
-- * Job-related types
type JobName = T.Text
type JobID = Integer
-- ** User
data User = User
{ userName :: T.Text
, userTeam :: T.Text
} deriving (Eq, Show, Read)
instance Aeson.ToJSON User where
toJSON user = Aeson.object
[ "username" .= userName user
, "userteam" .= userTeam user
]
instance Aeson.FromJSON User where
parseJSON = Aeson.withObject "user" $ \o -> do
userName <- o .: "username"
userTeam <- o .: "userteam"
return User { .. }
-- ** State
data FailureReason
= FailedDuringBuilding Int
| FailedDuringRunning Int
deriving (Eq, Show, Read)
-- | How far along a job is, including a failure state
data JobState
= QueuedState
| FetchingState
| BuildingState
| RunningState
| FinishingState
| DoneState
| FailedState
| DeletedState
deriving (Eq, Show, Read)
isFinished :: Job -> Bool
isFinished Job { jobState = st } =
st == DoneState || st == FailedState || st == DeletedState
instance Aeson.ToJSON JobState where
toJSON QueuedState = Aeson.String "queued"
toJSON FetchingState = Aeson.String "fetching"
toJSON BuildingState = Aeson.String "building"
toJSON RunningState = Aeson.String "running"
toJSON FinishingState = Aeson.String "finishing"
toJSON DoneState = Aeson.String "done"
toJSON FailedState = Aeson.String "failed"
toJSON DeletedState = Aeson.String "deleted"
data InvalidState = InvalidState
deriving (Eq, Show)
instance Exception InvalidState where
instance SQL.FromField JobState where
fromField f = case SQL.fieldData f of
SQL.SQLText "queued" -> return QueuedState
SQL.SQLText "fetching" -> return FetchingState
SQL.SQLText "building" -> return BuildingState
SQL.SQLText "running" -> return RunningState
SQL.SQLText "finishing" -> return FinishingState
SQL.SQLText "done" -> return DoneState
SQL.SQLText "failed" -> return FailedState
SQL.SQLText "deleted" -> return DeletedState
_ -> SQL.Errors [toException InvalidState]
instance SQL.ToField JobState where
toField f = case f of
QueuedState -> SQL.SQLText "queued"
FetchingState -> SQL.SQLText "fetching"
BuildingState -> SQL.SQLText "building"
RunningState -> SQL.SQLText "running"
FinishingState -> SQL.SQLText "finishing"
DoneState -> SQL.SQLText "done"
FailedState -> SQL.SQLText "failed"
DeletedState -> SQL.SQLText "deleted"
-- ** Job
data Job = Job
{ jobName :: T.Text
, jobUser :: User
, jobID :: JobID
, jobState :: JobState
, jobJira :: Maybe T.Text
, jobTag :: Maybe T.Text
} deriving (Eq, Show, Read)
instance Aeson.ToJSON Job where
toJSON job = Aeson.object
[ "name" .= jobName job
, "user" .= jobUser job
, "id" .= jobID job
, "state" .= jobState job
]
instance Aeson.FromJSON Job where
parseJSON = Aeson.withObject "job" $ \o -> do
jobName <- o .: "name"
jobUser <- o .: "user"
let jobID = 0
jobState = FetchingState
jobJira <- o .:? "jira"
jobTag <- o .:? "tag"
return Job { .. }
-- ** Timing Info
data TimingInfo = TimingInfo
{ timingName :: T.Text -- ^ The name of the timing phase
, timingStart :: Time.UTCTime -- ^ The point at which the timing
-- phase started
, timingEnd :: Time.UTCTime -- ^ The point at which the timing
-- phase ended
, timingLength :: Integer -- ^ The total length of the time
} deriving (Eq, Show)
-- | Lines in the output trace are either from stdout or from stderr
data LineSource
= SourceStdout
| SourceStderr
deriving (Eq, Show, Read)
-- | An output line has a timestamp, a source, and the raw text of
-- that line
data OutputLine = OutputLine
{ lineTime :: Time.UTCTime
, lineSource :: LineSource
, lineText :: BS.ByteString
} deriving (Eq, Show, Read)
-- * The values we send the web front-end
data QueueState = QueueState
{ queueJobs :: [Job]
} deriving (Eq, Show, Read)
instance Aeson.ToJSON QueueState where
toJSON queue = Aeson.toJSON (queueJobs queue)
data JobTrace = JobTrace
{ buildTrace :: Maybe BS.ByteString
, runTrace :: Maybe BS.ByteString
} deriving (Eq, Show, Read)
instance Aeson.ToJSON JobTrace where
toJSON trace = Aeson.object
[ "build" .= Aeson.toJSON (fmap T.decodeUtf8 (buildTrace trace))
, "run" .= Aeson.toJSON (fmap T.decodeUtf8 (runTrace trace))
]