@@ -3,12 +3,13 @@
4module Data.Tasks.Build
4module Data.Tasks.Build
5 ( Build (..),
5 ( Build (..),
9import Colog
10import Colog
10import Control.GithubCloner
11import Control.GithubCloner
11−import Control.Monad.IO.Class
12+import Control.Monad.Except
12import Control.Monad.IO.Unlift
13import Control.Monad.IO.Unlift
13import Control.Task
14import Control.Task
14import Control.Task.Scheduler
15import Control.Task.Scheduler
@@ -21,6 +22,7 @@ import Data.Submission.Query
21import Data.Tasks.StatusUpdate
22import Data.Tasks.StatusUpdate
22import qualified Data.Text as T
23import qualified Data.Text as T
23import Data.Time.Clock.POSIX
24import Data.Time.Clock.POSIX
25+import qualified Docker.Client as D
24import GHC.Generics
26import GHC.Generics
25import GitHub
27import GitHub
26import Server.Schema
28import Server.Schema
@@ -33,7 +35,7 @@ import UnliftIO.Exception
35 { preProcessShell :: String,
37 { preProcessShell :: String,
36− buildCommand :: String,
38+ dockerFile :: String,
37 owner :: Name Owner,
39 owner :: Name Owner,
38 repoName :: Name Repo,
40 repoName :: Name Repo,
39 sha :: Name Commit
41 sha :: Name Commit
@@ -42,7 +44,7 @@ data Build
43instance Task Build "build-repo" where
45instance Task Build "build-repo" where
45− type TaskMonad Build m = (MonadUnliftIO m, GithubCloner m, StaticPQ m)
47+ type TaskMonad Build m = (MonadUnliftIO m, GithubCloner m, StaticPQ m, HasDockerInfo m)
47 performTask Build {..} =
49 performTask Build {..} =
48 bracket createDir (liftIO . removePathForcibly) $ \dir -> do
50 bracket createDir (liftIO . removePathForcibly) $ \dir -> do
@@ -63,10 +65,38 @@ instance Task Build "build-repo" where
63 scheduleTask erroredTask
65 scheduleTask erroredTask
64 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
66 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
65 ExitSuccess -> do
67 ExitSuccess -> do
66− (buildCode, buildOut, buildErr) <- readProcess . setWorkingDir dir . fromString $ buildCommand
68+ h <- liftIO D.defaultHttpHandler
70+ let opts = D.defaultCreateOpts imageName
71+ runDocker :: forall a m. MonadIO m => D.DockerT IO a -> m a
72+ runDocker = liftIO . D.runDockerT (D.defaultClientOpts {D.baseUrl = dUrl}, h)
73+ imageName = T.pack dir
74+ liftIO $ writeFile (dir <> "/Dockerfile") dockerFile
75+ absDir <- liftIO $ makeAbsolute dir
76+ let waitDockerForever cid =
77+ D.waitContainer cid >>= \case
78+ Left D.GenericDockerError {} -> waitDockerForever cid
80+ dockerRes <- runDocker . runExceptT $ do
81+ ExceptT $ D.buildImageFromDockerfile (D.defaultBuildOpts imageName) absDir
82+ cid <- ExceptT $ D.createContainer opts Nothing
83+ ExceptT $ D.startContainer D.defaultStartOpts cid
84+ buildCode <- ExceptT $ waitDockerForever cid
96+ return (buildCode, buildOut)
67− case buildCode of
97+ case dockerRes of
68− ExitFailure n -> do
98+ Right (ExitFailure n, buildOut) -> do
69− let err = BS.unpack buildErr
99+ let err = BS.unpack buildOut
70 logError . T.pack $
100 logError . T.pack $
71 "test command for repo " <> show fullRepoName <> " at sha "
101 "test command for repo " <> show fullRepoName <> " at sha "
72 <> show sha
102 <> show sha
@@ -76,10 +106,15 @@ instance Task Build "build-repo" where
77 scheduleTask erroredTask
107 scheduleTask erroredTask
78 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
108 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
111+ logError . T.pack $ err
112+ scheduleTask erroredTask
113+ updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
79− ExitSuccess ->
114+ Right (ExitSuccess, buildOut) ->
80− case decode buildOut of
115+ case eitherDecode' (BS.dropWhile (/= '{') buildOut) of
81− Nothing -> do
116+ Left err' -> do
82− let err = BS.unpack buildOut
117+ let err = err' <> " " <> BS.unpack buildOut
83 logError . T.pack $
118 logError . T.pack $
84 "could not decode test result from repo " <> show fullRepoName
119 "could not decode test result from repo " <> show fullRepoName
85 <> " at sha "
120 <> " at sha "
@@ -88,7 +123,7 @@ instance Task Build "build-repo" where
89 scheduleTask erroredTask
124 scheduleTask erroredTask
90 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
125 updateSubmissionStatus fullRepoName sha' (SubmissionFailed err)
91− Just testResult@TestResult {..} -> do
126+ Right testResult@TestResult {..} -> do
92 let total = M.size tests
127 let total = M.size tests
93 passed = M.size . M.filter id $ tests
128 passed = M.size . M.filter id $ tests
94 description = T.pack $ show passed <> "/" <> show total
129 description = T.pack $ show passed <> "/" <> show total
@@ -131,3 +166,6 @@ getTmpDirName = liftIO $ do
131 time :: Integer <- round <$> getPOSIXTime
166 time :: Integer <- round <$> getPOSIXTime
132 i <- randomIO @Int
167 i <- randomIO @Int
133 return $ show time <> "-" <> show i
168 return $ show time <> "-" <> show i
170+class HasDockerInfo m where
171+ getDockerUrl :: m T.Text