aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-02-21 03:02:17 +0100
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-02-21 03:14:16 +0100
commit9f2d5ae570c120f19434f03eb20ab2c3ecf36e0c (patch)
treef8cf8464e404faa077362ac75069849859cf0812
parentfbbd47788b855465773ea951250a281095f4be29 (diff)
add loggingmain
-rw-r--r--abuilder.cabal3
-rw-r--r--app/Main.hs136
2 files changed, 99 insertions, 40 deletions
diff --git a/abuilder.cabal b/abuilder.cabal
index fae0635..8bfc6ad 100644
--- a/abuilder.cabal
+++ b/abuilder.cabal
@@ -23,6 +23,9 @@ executable abuilder
gitlib-libgit2,
hinotify,
mtl,
+ prettyprinter,
+ prettyprinter-ansi-terminal,
+ process,
split,
stm,
string-interpolate,
diff --git a/app/Main.hs b/app/Main.hs
index 07767a6..4f4a35d 100644
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -8,14 +8,15 @@
module Main where
+import Control.Arrow ((***))
import Control.Concurrent
import Control.Concurrent.STM
import Control.Exception
import Control.Monad
import Data.ByteString.Char8 qualified as B
import Data.ByteString.Lazy qualified as LB
-import Data.ByteString.Lazy.UTF8 qualified as LB
-import Data.ByteString.UTF8 qualified as B
+import Data.ByteString.UTF8 qualified as B (fromString, toString)
+import Data.List
import Data.List.Split
import Data.Map.Merge.Strict qualified as M
import Data.Map.Strict qualified as M
@@ -24,8 +25,11 @@ import Data.String
import Data.String.Interpolate (i)
import Data.Tagged
import Data.Text qualified as T
+import Debug.Trace
import Git
import Git.Libgit2
+import Prettyprinter
+import Prettyprinter.Render.Terminal
import System.Directory
import System.Environment
import System.FilePath
@@ -33,7 +37,9 @@ import System.INotify
import System.IO
import System.IO.Temp
import System.IO.Unsafe
+import System.Process (CmdSpec (..))
import System.Process.Typed
+import System.Process.Typed.Internal
import Text.Printf
stateDirectory :: FilePath
@@ -54,6 +60,11 @@ urls =
concurrentBuilders :: Int
concurrentBuilders = 2
+logLevel :: Importance
+logLevel =
+ maybe Info (toEnum . read) $
+ unsafePerformIO (lookupEnv "ABUILDER_LOG_LEVEL")
+
type DesiredOutputs = M.Map JobName CommitHash
type CommitHash = String
@@ -133,13 +144,20 @@ completeBuildJob (BuildJob {jobName, commitHash}) buildJobs =
data Builder = Builder Int
deriving (Show)
-data LogEntry = BuildEntry
- { builder :: Builder,
- buildJob :: BuildJob,
- payload :: LB.ByteString
+data LogEntry = LogEntry
+ { component :: String,
+ importance :: Importance,
+ message :: Doc AnsiStyle
}
deriving (Show)
+data Importance
+ = Error
+ | Info
+ | Warning
+ | Debug
+ deriving (Show, Eq, Ord, Enum)
+
main :: IO ()
main = do
hSetBuffering stderr LineBuffering
@@ -152,15 +170,23 @@ main = do
createDirectoryIfMissing True stateDirectory
setCurrentDirectory stateDirectory
mapM_
- (forkIO . builder logs buildJobsT)
+ (\_ -> forkIO (builder logs buildJobsT))
(map Builder [1 .. concurrentBuilders])
- mapM_ (uncurry (watch inotify desiredOutputsT)) (M.toList urls)
+ mapM_ (uncurry (watch inotify logs desiredOutputsT)) (M.toList urls)
_ <- forkIO (scheduler desiredOutputsT actualOutputsT buildJobsT)
forever do
log <- atomically $ readTQueue logs
case log of
- BuildEntry _ (BuildJob {jobName}) (LB.toString -> payload) ->
- printf "[%s] %s\n" jobName payload
+ LogEntry {component, message, importance} ->
+ when (importance <= logLevel) do
+ let c = case importance of
+ Error -> Red
+ Info -> White
+ Warning -> Yellow
+ Debug -> Black
+ putDoc . annotate (color c) $
+ annotate bold (brackets (pretty component))
+ <+> message <> hardline
scheduler ::
TVar DesiredOutputs ->
@@ -179,8 +205,8 @@ scheduler desiredOutputsT actualOutputsT buildJobsT = do
writeTVar buildJobsT (replaceBuildJobs buildJobs buildJobs')
writeTVar lastDesiredOutputsT (Just desiredOutputs)
-builder :: TQueue LogEntry -> TVar BuildJobs -> Builder -> IO ()
-builder logs buildJobsT builder =
+builder :: TQueue LogEntry -> TVar BuildJobs -> IO ()
+builder logs buildJobsT =
forever
( do
buildJob <- atomically do
@@ -190,18 +216,19 @@ builder logs buildJobsT builder =
writeTVar buildJobsT buildJobs'
pure (fromJust maybeBuildJob)
- build logs builder buildJob
+ build logs buildJob
`catch` ( \(e :: SomeException) -> do
print e
)
)
-build :: TQueue LogEntry -> Builder -> BuildJob -> IO ()
-build logs builder buildJob@(BuildJob {jobName, commitHash}) = do
+build :: TQueue LogEntry -> BuildJob -> IO ()
+build logs (BuildJob {jobName, commitHash}) = do
let url = urls M.! jobName
rev = commitHash
refDir = jobName </> ref
tmpDir = jobName <> "-" <> rev
+ log_ logs jobName Info [printf "building commit %s" rev]
exitCodeT <- newEmptyTMVarIO
_ <-
flip forkFinally (atomically . putTMVar exitCodeT) do
@@ -215,37 +242,29 @@ build logs builder buildJob@(BuildJob {jobName, commitHash}) = do
rev = "#{rev}";
})
|]
- ((B.toString . B.strip . LB.toStrict) -> drv, LB.lines -> err) <-
- readProcess_
- (setWorkingDir tmpDir "nix-instantiate")
- mapM_
- ( atomically
- . writeTQueue logs
- . BuildEntry builder buildJob
- )
- err
- ((B.toString . B.strip . LB.toStrict) -> res, LB.lines -> err) <-
- readProcess_
- ( setWorkingDir
- tmpDir
- (fromString (printf "nix-store --realise '%s'" drv))
- )
- mapM_
- ( atomically
- . writeTQueue logs
- . BuildEntry builder buildJob
- )
- err
+ drv <- sh logs jobName (setWorkingDir tmpDir "nix-instantiate")
+ res <-
+ sh logs jobName . setWorkingDir tmpDir $
+ fromString (printf "nix-store --realise '%s'" drv)
pure res
exitCode <- atomically $ takeTMVar exitCodeT
case exitCode of
- Left e -> throw e
+ Left e -> do
+ log_ logs jobName Error [printf "failed to build commit %s" rev]
+ throw e
Right nixDir -> do
+ log_ logs jobName Info [printf "built commit %s" rev]
createDirectoryIfMissing True jobName
- runProcess_ (fromString (printf "nix-store --add-root '%s' --realise '%s'" refDir nixDir))
+ runProcess_ (fromString (printf ">/dev/null nix-store --add-root '%s' --realise '%s'" refDir nixDir))
-watch :: INotify -> TVar DesiredOutputs -> JobName -> Url -> IO ()
-watch inotify desiredOutputsT jobName url = do
+watch ::
+ INotify ->
+ TQueue LogEntry ->
+ TVar DesiredOutputs ->
+ JobName ->
+ Url ->
+ IO ()
+watch inotify logs desiredOutputsT jobName url = do
let bareFp = url </> "refs/heads"
nonBareFp = url </> ".git/refs/heads"
isBare <- doesDirectoryExist bareFp
@@ -263,6 +282,7 @@ watch inotify desiredOutputsT jobName url = do
_ -> False
when isChange do
updateDesiredOutputs
+ log_ logs jobName Info [printf "watching %s" url]
updateDesiredOutputs
where
updateDesiredOutputs = do
@@ -272,3 +292,39 @@ watch inotify desiredOutputsT jobName url = do
atomically do
desiredOutputs <- readTVar desiredOutputsT
writeTVar desiredOutputsT (M.insert jobName rev desiredOutputs)
+ log_ logs jobName Info [printf "queueing commit %s" rev]
+
+log_ :: TQueue LogEntry -> String -> Importance -> [String] -> IO ()
+log_ logs component importance messages = atomically do
+ mapM_
+ ( writeTQueue logs
+ . LogEntry component importance
+ . pretty
+ )
+ messages
+
+sh ::
+ TQueue LogEntry ->
+ String ->
+ ProcessConfig stdin stdoutIgnored stderrIgnored ->
+ IO String
+sh logs component proc = do
+ log_ logs component Debug $
+ [ printf
+ "+ %s"
+ ( case proc.pcCmdSpec of
+ RawCommand bin args -> intercalate " " (bin : args)
+ ShellCommand s -> s
+ )
+ ]
+ (out, err) <-
+ ( B.toString . B.strip . LB.toStrict
+ *** map (B.toString . B.strip) . B.lines . LB.toStrict
+ )
+ <$> readProcess_ proc
+ log_ logs component Warning err
+ pure out
+
+debug :: Show a => String -> a -> a
+debug s x =
+ trace (printf "%s: %s\n" s (show x)) x