From e103c8e1b5bf9bf47b94e7da443186f5703ce1bb Mon Sep 17 00:00:00 2001 From: stuebinm Date: Fri, 17 Dec 2021 18:21:00 +0100 Subject: simple graphviz visualisation of a repository might be useful to have --- lib/CheckDir.hs | 10 +++++++--- lib/Dirgraph.hs | 22 ++++++++++++++++++++-- walint.cabal | 3 ++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/CheckDir.hs b/lib/CheckDir.hs index 0011857..1cfd753 100644 --- a/lib/CheckDir.hs +++ b/lib/CheckDir.hs @@ -23,7 +23,7 @@ import Data.Map.Strict (mapKeys, (\\)) import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T -import Dirgraph (invertGraph, resultToGraph, +import Dirgraph (graphToDot, invertGraph, resultToGraph, unreachableFrom) import GHC.Generics (Generic) import LintConfig (LintConfig', configMaxLintLevel) @@ -32,6 +32,7 @@ import System.Directory.Extra (doesFileExist) import System.FilePath (splitPath, ()) import qualified System.FilePath as FP import System.FilePath.Posix (takeDirectory) +import Text.Dot (Dot, showDot) import Types (Dep (Local, LocalMap), Hint (Hint), Level (..), hintLevel) import Util (PrettyPrint (prettyprint)) @@ -53,6 +54,7 @@ data DirResult = DirResult -- ^ all dependencies to things outside this repository , dirresultMissingAssets :: [MissingAsset] -- ^ entrypoints of maps which are referred to but missing + , dirresultGraph :: Dot () } deriving (Generic) data MissingDep = MissingDep @@ -96,6 +98,7 @@ instance ToJSON DirResult where [ "missingDeps" .= dirresultDeps res , "missingAssets" .= dirresultMissingAssets res , "mapLints" .= dirresultMaps res + , "exitGraph" .= showDot (dirresultGraph res) ] , "resultText" .= prettyprint (Suggestion, res) , "severity" .= maximumLintLevel res @@ -145,12 +148,12 @@ recursiveCheckDir recursiveCheckDir config prefix root = do maps <- recursiveCheckDir' config prefix [root] mempty + let exitGraph = resultToGraph maps -- maps that don't have (local) ways back to the main entrypoint let nowayback = unreachableFrom root . invertGraph - . resultToGraph - $ maps + $ exitGraph -- inject warnings for maps that have no way back to the entrypoint let maps' = flip mapWithKey maps $ \path res -> @@ -165,6 +168,7 @@ recursiveCheckDir config prefix root = do pure $ DirResult { dirresultDeps = missingDeps root maps' , dirresultMissingAssets = mAssets , dirresultMaps = maps' + , dirresultGraph = graphToDot exitGraph } diff --git a/lib/Dirgraph.hs b/lib/Dirgraph.hs index 0931ea0..b97a644 100644 --- a/lib/Dirgraph.hs +++ b/lib/Dirgraph.hs @@ -1,15 +1,21 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TupleSections #-} -- | Simple directed graphs, for dependency checking module Dirgraph where import CheckMap (MapResult (mapresultDepends)) -import Data.Map.Strict (Map, mapMaybeWithKey, mapWithKey) +import Control.Monad (forM_) +import Data.Functor ((<&>)) +import Data.Map.Strict (Map, mapMaybeWithKey, mapWithKey, + traverseWithKey) import qualified Data.Map.Strict as M import Data.Set (Set, (\\)) import qualified Data.Set as S import Paths (normalise) +import Text.Dot (Dot, (.->.)) +import qualified Text.Dot as D import Types (Dep (LocalMap)) import Witherable (mapMaybe) @@ -47,3 +53,15 @@ reachableFrom entrypoint graph = recursive mempty (S.singleton entrypoint) unreachableFrom :: Ord a => a -> Graph a -> Set a unreachableFrom entrypoint graph = nodes graph \\ reachableFrom entrypoint graph + +graphToDot :: Graph FilePath -> Dot () +graphToDot graph = do + nodes <- traverseWithKey + (\name edges -> D.node [("label",name)] <&> (,edges)) + graph + + forM_ nodes $ \(node, edges) -> + forM_ edges $ \key -> + case M.lookup key nodes of + Just (other,_) -> node .->. other + _ -> pure () diff --git a/walint.cabal b/walint.cabal index 98ba654..c189dda 100644 --- a/walint.cabal +++ b/walint.cabal @@ -54,7 +54,8 @@ library getopt-generics, regex-tdfa, extra, - witherable + witherable, + dotgen -- TODO: move more stuff into lib, these dependencies are silly executable walint -- cgit v1.2.3