packages feed

darcs2dot-0.1.0.0: darcs2dot.hs

#!/usr/bin/env runhaskell

{-# language GADTs, TypeOperators, ViewPatterns, FlexibleContexts, ScopedTypeVariables #-}


import Data.Graph.Wrapper
import Data.Map (Map, (!))
import qualified Data.Map as Map
import Data.String.Conversions

import Text.Printf

import Control.Applicative

import Darcs.Repository
import Darcs.Witnesses.Ordered
import Darcs.Patch.Named
import Darcs.Patch.Info
import Darcs.Patch.Choices
import Darcs.Patch.Patchy


main = withRepository [] $ RepoJob $ \ repo ->
    putStr . toDot . dependencies . patchSetToPatches =<< readRepo repo


dependencies :: Patchy (Named p) => FL (Named p) x y -> Graph Tag String
dependencies fl =
    let choices = patchChoices fl
        tags = getNamedTags choices
    in fromList $ flip map tags $ \ (name, tag) ->
        let firsts = getFirsts $ forceFirst tag choices
            depends = filter (\ (n, t) -> t /= tag) firsts
        in (tag, name, map snd depends) :: (Tag, String, [Tag])


type NamedTag = (String, Tag)

getFirsts :: Patchy (Named p) => PatchChoices (Named p) x y -> [NamedTag]
getFirsts (getChoices -> (a :> _)) = getTagsFL a

getNamedTags :: Patchy (Named p) => PatchChoices (Named p) x y -> [NamedTag]
getNamedTags (getChoices -> (a :> (b :> c))) =
    getTagsFL a ++
    getTagsFL b ++
    getTagsFL c

getTagsFL :: FL (TaggedPatch (Named p)) x y -> [(String, Tag)]
getTagsFL NilFL = []
getTagsFL (a :>: b) = e : getTagsFL b
  where
    e = (cs . _piName . patch2patchinfo . tpPatch $ a, tag a)

-- not used
showChoices :: Patchy (Named p) => PatchChoices (Named p) x y -> String
showChoices choices =
    case getChoices choices of
        (a :> (b :> c)) -> showFL a ++ " :> (" ++ showFL b ++ " :> " ++ showFL c ++ ")"

-- not used
showFL :: FL (TaggedPatch (Named p)) x y -> String
showFL fl =
    case mapFL (cs . _piName . patch2patchinfo . tpPatch) fl of
         [] -> "[]"
         x -> unwords x


-- * graph stuff

transitiveReduction :: Ord i => Graph i v -> Graph i v
transitiveReduction g =
    fromList $ map inner $ toList g
  where
    inner (i, v, outgoing) =
        (i, v, filter (\ o -> not $ hasIndirectPath i o) outgoing)
    hasIndirectPath a b = any (\ m -> a ~> m && m ~> b) (vertices g)
    a ~> b = b `elem` successors g a


-- * dot

toDot :: (Ord i) => Graph i String -> String
toDot graph =
    "digraph g {\n" ++
        (concatMap inner $ toList $ fmap (take 15) $ transitiveReduction $ indexToInt graph) ++
    "}\n"
  where
    inner (i, name, outgoing) =
        printf "    %i [label = \"%s\"];\n" i name ++
        concatMap (\ out -> printf "    %i -> %i;\n" i out) outgoing

-- | convert indices to Ints
indexToInt :: forall i v . Ord i => Graph i v -> Graph Int v
indexToInt g =
    fromList $ map inner $ toList g
  where
    inner (i, v, outgoing) = (intMap ! i, v, map (intMap !) outgoing)
    intMap :: Map i Int
    intMap = Map.fromList $ zip (vertices g) [0..]