haskell-import-graph (empty) → 1.0.0
raw patch · 7 files changed
+187/−0 lines, 7 filesdep +basedep +classy-preludedep +ghcsetup-changed
Dependencies added: base, classy-prelude, ghc, graphviz, haskell-import-graph, process, text, transformers
Files
- LICENSE +20/−0
- Setup.hs +2/−0
- exec/Main.hs +6/−0
- haskell-import-graph.cabal +51/−0
- lib/System/ImportGraph/AppMain.hs +45/−0
- lib/System/ImportGraph/GetIface.hs +20/−0
- lib/System/ImportGraph/ModuleCluster.hs +43/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 ncaq++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ exec/Main.hs view
@@ -0,0 +1,6 @@+module Main where+import Prelude (IO)+import System.ImportGraph.AppMain (appMain)++main :: IO ()+main = appMain
+ haskell-import-graph.cabal view
@@ -0,0 +1,51 @@+name: haskell-import-graph+version: 1.0.0+synopsis: create haskell import graph for graphviz+description: {+create haskell import graph for graphviz+How to:+> cabal build+> haskell-import-graph+Or,+> haskell-import-graph dist/build/foo/foo-tmp/bar.hi+}+license: MIT+license-file: LICENSE+author: ncaq+maintainer: ncaq@ncaq.net+copyright: Copyright (c) 2015 ncaq+category: Development+build-type: Simple+cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/ncaq/haskell-import-graph.git++library+ hs-source-dirs: lib+ exposed-modules: System.ImportGraph.AppMain+ , System.ImportGraph.GetIface+ , System.ImportGraph.ModuleCluster++ ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-monomorphism-restriction -fwarn-identities+ default-language: Haskell2010+ default-extensions: NamedFieldPuns+ NoImplicitPrelude+ OverloadedStrings+ RecordWildCards++ build-depends: base >= 4.8 && < 4.9+ , classy-prelude >= 0.12 && < 0.13+ , ghc >= 7.10 && < 7.11+ , graphviz >= 2999 && < 3000+ , process >= 1.2 && < 1.3+ , text >= 1.2 && < 1.3+ , transformers >= 0.4 && < 0.5++executable haskell-import-graph+ hs-source-dirs: exec+ main-is: Main.hs+ ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-monomorphism-restriction -fwarn-identities+ default-language: Haskell2010+ build-depends: base, haskell-import-graph
+ lib/System/ImportGraph/AppMain.hs view
@@ -0,0 +1,45 @@+module System.ImportGraph.AppMain where+import ClassyPrelude+import Data.GraphViz+import Data.GraphViz.Attributes.Complete+import Data.GraphViz.Printing (renderDot)+import qualified Data.GraphViz.Types.Generalised as G+import Data.GraphViz.Types.Monadic+import qualified Data.Text.Lazy as L+import qualified Data.Text.Lazy.IO as L+import GHC+import System.ImportGraph.GetIface+import System.ImportGraph.ModuleCluster+import System.Process++appMain :: IO ()+appMain = do+ args <- getArgs+ libDir <- getLibDirReadProcess+ runGhc libDir $+ case args of+ ["-h"] -> liftIO $ L.putStrLn help+ ["--help"] -> liftIO $ L.putStrLn help+ [] -> do+ ifaces <- findIfaces+ liftIO . L.putStrLn $ renderGraph ifaces+ [hiPath] -> do+ iface <- getIface $ unpack hiPath+ liftIO . L.putStrLn $ renderGraph [iface]+ _ -> liftIO $ L.putStrLn help++getLibDirReadProcess :: IO (Maybe FilePath)+getLibDirReadProcess = listToMaybe . lines <$> readProcess "ghc" ["--print-libdir"] ""++help :: L.Text+help = unlines [ "Usage: cabal build && haskell-import-graph"+ , "or: cabal build && haskell-import-graph dist/build/foo/foo-tmp/bar.hi"+ ]++renderGraph :: [ModIface] -> L.Text+renderGraph = renderDot . toDot . importGraph (Str "haskell-import-graph")++importGraph :: GraphID -> [ModIface] -> G.DotGraph L.Text+importGraph graphName mods = digraph graphName $ do+ graphAttrs [Compound True, RankDir FromLeft]+ mapM moduleCluster mods
+ lib/System/ImportGraph/GetIface.hs view
@@ -0,0 +1,20 @@+module System.ImportGraph.GetIface where+import BinIface+import ClassyPrelude+import GHC+import System.Process+import TcRnMonad++findIfaces :: Ghc [ModIface]+findIfaces = do+ his <- liftIO findHiFiles+ _ <- setSessionDynFlags =<< getSessionDynFlags+ mapM getIface his++findHiFiles :: IO [FilePath]+findHiFiles = lines <$> readProcess "find" ["-iname", "*.hi"] ""++getIface :: FilePath -> Ghc ModIface+getIface filename = do+ hsc_env <- getSession+ liftIO . initTcRnIf 's' hsc_env () () $ readBinIface IgnoreHiWay QuietBinIFaceReading filename
+ lib/System/ImportGraph/ModuleCluster.hs view
@@ -0,0 +1,43 @@+module System.ImportGraph.ModuleCluster where+import Avail+import ClassyPrelude+import Data.GraphViz+import Data.GraphViz.Attributes.Complete+import Data.GraphViz.Types.Monadic+import qualified Data.Text.Lazy as L+import HscTypes+import Module+import Name++moduleCluster :: ModIface -> Dot L.Text+moduleCluster iface@ModIface{..} = do+ cluster (Str (ifaceName iface)) $ do+ graphAttrs [textLabel (ifaceName iface)]+ node (ifaceDummyNodeName iface) [Style [SItem Invisible []]]+ mapM node' exports+ mapM_ (ifaceUsageEdges iface) mi_usages+ where exports = map (pack . getOccString . availName) mi_exports++ifaceName :: ModIface -> L.Text+ifaceName = moduleText . mi_module++moduleText :: Module -> L.Text+moduleText = pack . moduleNameString . moduleName++ifaceDummyNodeName :: ModIface -> L.Text+ifaceDummyNodeName iface = ifaceName iface <> "_dummy_node"++ifaceClusterName :: ModIface -> L.Text+ifaceClusterName iface = "cluster_" <> ifaceName iface++ifaceUsageEdges :: ModIface -> Usage -> Dot L.Text+ifaceUsageEdges iface UsagePackageModule{..} = do+ ifaceEdge iface (moduleText usg_mod)+ node (moduleText usg_mod) [Shape Component]+ifaceUsageEdges iface UsageHomeModule{..} =+ mapM_ (ifaceEdge iface . pack . occNameString . fst) usg_entities+ifaceUsageEdges iface UsageFile{..} =+ ifaceEdge iface (pack usg_file_path)++ifaceEdge :: ModIface -> L.Text -> Dot L.Text+ifaceEdge iface edgeTo = edge (ifaceDummyNodeName iface) edgeTo [LTail (ifaceClusterName iface)]