netrium-0.6.0: tool/Visualise.hs
-- |Netrium is Copyright Anthony Waite, Dave Hetwett, Shaun Laurens 2009-2015, and files herein are licensed
-- |under the MIT license, the text of which can be found in license.txt
--
{-# LANGUAGE PatternGuards #-}
module Main where
import Contract
import DecisionTreeSimplify
import Display
import Paths_netrium_demo
import Data.Maybe
import Data.Version
import System.Environment
import System.Exit
import System.Console.GetOpt
import System.IO
import System.Directory
import System.Process
import System.FilePath
import Text.XML.HaXml.XmlContent
data OutputMode = OutputSvg | OutputPng | OutputDot
outputExtension OutputSvg = "svg"
outputExtension OutputPng = "png"
outputExtension OutputDot = "dot"
data Options =
Options
{ optMode :: OutputMode
, optDecisionTree :: Bool
, optStartTime :: Maybe Time
, optDepth :: Maybe Int
, optVersion :: Bool
}
defaultOptions :: Options
defaultOptions =
Options
{ optMode = OutputSvg
, optDecisionTree = False
, optStartTime = Nothing
, optDepth = Nothing
, optVersion = False
}
optDepthDefault :: Int
optDepthDefault = 8
options :: [OptDescr (Options -> Options)]
options =
[ Option [] ["syntax-tree"]
(NoArg (\ opts -> opts { optDecisionTree = False }))
"Generate the contract syntax tree (default mode)"
, Option [] ["decision-tree"]
(NoArg (\ opts -> opts { optDecisionTree = True }))
"Generate the contract decision tree"
, Option [] ["start-time"]
(ReqArg (\ arg opts -> opts {
optStartTime = Just (readArg "start-time" arg)
}) "TIME")
"Contract start time (required in decision tree mode)"
, Option [] ["tree-depth"]
(ReqArg (\ arg opts -> opts {
optDepth = Just (readArg "tree-depth" arg)
}) "NUM")
("Limit the tree depth (decision tree mode default is "
++ show optDepthDefault ++ ")")
, Option [] ["svg"]
(NoArg (\ opts -> opts { optMode = OutputSvg }))
"Output in SVG image format (default format)"
, Option [] ["png"]
(NoArg (\ opts -> opts { optMode = OutputPng }))
"Output in PNG image format"
, Option [] ["dot"]
(NoArg (\ opts -> opts { optMode = OutputDot }))
"Output in DOT graph format"
, Option [] ["version"]
(NoArg (\ opts -> opts { optVersion = True }))
"Print version information"
]
readArg :: Read a => String -> String -> a
readArg optname arg =
case reads arg of
[(v,"")] -> v
_ -> error $ "unrecognised value '" ++ arg
++ "' for option --" ++ optname
main :: IO ()
main =
do
plainArgs <- getArgs
let (optMods, args, errs) = getOpt Permute options plainArgs
let opts = foldl (flip ($)) defaultOptions optMods
case (args, errs) of
_ | optVersion opts -> printVersion
| optDecisionTree opts
, Nothing <- optStartTime opts
-> exit ["In --decision-tree mode, --start-time= is required"]
([contract], []) -> visualise opts contract output
where output = replaceExtension contract
(outputExtension (optMode opts))
([contract, output], []) -> visualise opts contract output
_ -> exit errs
exit :: [String] -> IO ()
exit errs = do
p <- getProgName
let output | null errs = usageInfo usage options
| otherwise = p ++ ": " ++ unlines errs
++ usageInfo usage options
usage = "Usage: " ++ p ++ " <contract.xml> [<output>]\n\nFlags:"
putStrLn output
exitFailure
printVersion :: IO ()
printVersion = do
p <- getProgName
putStrLn $ "netrium-demo " ++ p ++ " version " ++ showVersion version
visualise :: Options -> FilePath -> FilePath -> IO ()
visualise opts contractFile outputFile = do
contract <- fReadXml contractFile
let tree | optDecisionTree opts
, Just startTime <- optStartTime opts
= trimDepth (fromMaybe optDepthDefault (optDepth opts))
$ toTree (decisionTreeSimple startTime contract)
| otherwise
= maybe id trimDepth (optDepth opts)
$ toTree contract
case optMode opts of
OutputDot -> writeFile outputFile (renderDotGraph tree)
_ -> do
tmpdir <- getTemporaryDirectory
(tmpfile, htmp) <- openTempFile tmpdir "contract.dot"
hPutStr htmp (renderDotGraph tree)
hClose htmp
let format = case optMode opts of
OutputSvg -> "-Tsvg"
OutputPng -> "-Tpng"
exitcode <- rawSystem "dot" [format, "-o", outputFile, tmpfile]
removeFile tmpfile
exitWith exitcode