{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Main where import Control.Monad import qualified Data.ByteString as BS import qualified Data.ByteString.Builder as BSB import qualified Data.ByteString.Lazy as BSL import Data.FileEmbed (embedFile) import Data.Foldable (for_) import qualified Data.List as List import Data.Maybe (isJust) import qualified System.Directory as Dir import System.Environment import System.Exit (die) import System.IO import qualified System.Process as Proc import qualified Graph.Trace.Dot as Dot main :: IO () main = do args <- getArgs let isFlag arg = "--" `List.isPrefixOf` arg (flags, fileArgs) = span isFlag args nexusFlag = "--nexus" `List.elem` flags helpCommand = "--help" `List.elem` flags if helpCommand then putStrLn helpText else do traceFiles <- case fileArgs of [] -> do contents <- Dir.listDirectory =<< Dir.getCurrentDirectory let isTraceFile = (".trace" `List.isSuffixOf`) pure $ filter isTraceFile contents xs -> pure xs for_ traceFiles $ \traceFile -> do logContents <- either (\err -> fail $ "Failed parsing trace file: " <> err) id . Dot.parseLogEntries <$> BSL.readFile traceFile let tree = Dot.buildTree logContents dotFileContent | nexusFlag = Dot.graphToDot (Dot.buildNexus tree) | otherwise = Dot.graphToDot tree fileName = (<> ".html") $ if ".trace" `List.isSuffixOf` traceFile then reverse . drop 6 $ reverse traceFile else traceFile htmlHeader = $(embedFile "extras/header.html") htmlFooter = $(embedFile "extras/footer.html") dotExists <- isJust <$> Dir.findExecutable "dot" unless dotExists $ die "Error! Graphviz is not installed or not accessible" withFile fileName WriteMode $ \h -> do hSetBinaryMode h True hSetBuffering h (BlockBuffering Nothing) BS.hPut h htmlHeader writeSvg h dotFileContent BS.hPut h htmlFooter -- | Invoke @dot@ to produce an svg document and write to the file handle writeSvg :: Handle -> BSB.Builder -> IO () writeSvg htmlFile dotContent = Proc.withCreateProcess (Proc.proc "dot" ["-Tsvg"]) { Proc.std_in = Proc.CreatePipe , Proc.std_out = Proc.CreatePipe } go where go (Just stdIn) (Just stdOut) _ _ = do hSetBinaryMode stdIn True hSetBuffering stdIn (BlockBuffering Nothing) hSetBinaryMode stdOut True hSetBuffering stdOut (BlockBuffering Nothing) _ <- BSB.hPutBuilder stdIn dotContent hClose stdIn svg <- BSL.hGetContents stdOut BSL.hPut htmlFile svg hClose stdOut go _ _ _ _ = pure () helpText :: String helpText = unlines [ "Command line utility for rendering trace files generated by the \ \graph-trace plugin into an interactive HTML document." , "" , "Flags:" , " --nexus Causes two or more identical nodes to be merged into one" ]