packages feed

zampolit-0.2: Zampolit.hs

{-# Language DeriveDataTypeable #-}

module Main where

import HSH hiding (space)

import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.String

import System.Console.CmdArgs
import System.FilePath (takeFileName)
import System.Directory (getCurrentDirectory)

import System.Locale
import System.IO
import Data.Time
import Data.Time.Format

import Data.Function
import Data.List
import Data.Map (Map,(!))
import qualified Data.Map as Map
import Data.Maybe
import Data.String.Utils

type Commit = String
type Author = String
type Date = UTCTime

data Cmd = Cmd {outfile :: FilePath,
                gameName :: String}
           deriving (Show,Data,Typeable)
                      

data CA = CA { commit :: Commit
             , date :: Date
             , author :: Author }

type Total = (Date,Author,Map Author Int)

foldNames "bts" = "brians"
foldNames "Paul Weaver" = "pweaver"
foldNames a = a

parseCA :: Parser [CA]
parseCA = many1 $ do
  string "commit "
  c <- count 40 hexDigit
  newline
  string "Author: "
  a' <- many1 (noneOf "<")
  let a = foldNames $ strip a'
  between (char '<') (char '>') $ many (noneOf ">")
  newline
  string "Date:   "
  d' <- many1 (noneOf "\n")
  let d = rTime d'
  newline
  return CA {commit = c, author = a, date = d}

rTime = readTime defaultTimeLocale "%a %b %e %T %Y %Z"
fTime = formatTime defaultTimeLocale "%s" 

wc ca = do
  runIO $ "git checkout " ++ commit ca
  s <- run $ "find . -name \\*tex -print0 -o -name \\*txt -print0" 
      -|- "xargs -0 wc -w"
      -|- "tail -1" -|- "grep -o '[0-9]\\+'"
  return $ read s

runningTotals :: [Total] -> (Author,Date,Int) -> [Total]
runningTotals totals (author,date,wc) = new:totals
  where
    new = (date,author,case totals of
                            [] -> f Map.empty
                            other -> f old)
    f = Map.insertWith (+) author wc
    old = (\(a,b,c)->c) $ head totals


printHeader :: FilePath -> String -> [Author] -> IO ()
printHeader output title authors = 
  withFile (output ++ ".gnuplot") WriteMode (\h -> do
    hPutStrLn h "set xdata time"
    hPutStrLn h "set timefmt \"%s\""
    hPutStrLn h "set format x \"%m/%d\""
    hPutStrLn h "set terminal pdf size 10in,7.5in"
    hPutStrLn h $ "set output \"" ++ output ++ ".pdf\""
    hPutStrLn h "set xlabel \"date\""
    hPutStrLn h "set ylabel \"words\""
    hPutStrLn h $ "set title \"" ++ title ++ " word counts by author\""
    hPutStrLn h "set datafile missing \"?\""
    hPutStr   h "plot "
    hPutStrLn h . intercalate ", " . map plotLine $ zip [2..] authors)
      where
        plotLine (n,a) = "'" ++ output ++ ".data' using 1:($" 
                         ++ show n ++ ") title \"" ++ a ++ "\""    

printRow :: Handle -> [Author] -> Total -> IO ()
printRow h authors (date,name,total) = do
  hPutStr   h $ fTime date
  hPutStr   h "\t"
  hPutStr   h $ take before $ cycle "?\t"
  hPutStr   h . show $ Map.findWithDefault 0 name total
  hPutStrLn h $ take after $ cycle "\t?"
    where
      i = fromJust $ elemIndex name authors
      before = 2*i
      after = 2*((length authors) - i)

main :: IO ()
main = do
  dir <- return . takeFileName =<< getCurrentDirectory
  let cmd = Cmd { outfile = def &= argPos 1 &= opt (dir ++ "-wc") &= typFile 
                , gameName = def &= argPos 0 &= opt dir &= typ "NAME"}
            &= program "zampolit"
  c <- cmdArgs cmd
  let title = gameName c
      output = outfile c
  cas <- run $ "git log" -|- "grep '^\\(commit\\|Auth\\|Date\\)'"
  case parse parseCA "" cas of 
    Left err -> print err
    Right cas -> do
      wcs <- mapM wc cas
      runIO $ "git checkout master"
      let totals = foldl runningTotals [] . reverse 
                 . zip3 (map author cas) (map date cas) 
                 . map (max 0) 
                 $ zipWith (-) wcs (tail wcs ++ [head $ reverse wcs])
          (_,_,mp) = head totals
          authors = sortBy (\x y -> compare (mp ! y) (mp ! x)) $ Map.keys mp
      printHeader output title authors
      withFile (output ++ ".data") WriteMode (\h ->
        mapM_ (printRow h authors) $ reverse totals)
      runIO $ "gnuplot " ++ output ++ ".gnuplot"