1 import Control.Applicative( (<$>) )
2 import Control.Monad( unless )
3 import Data.Time.Clock( UTCTime(..) )
4 import Data.Time.LocalTime( TimeZone(), ZonedTime(..), zonedTimeToUTC, utcToZonedTime )
5 import Diddo( Diddo(..), LogEntry(..), parseDiddoLogline, formatDiddo, logToDiddo, parseToZonedTime )
6 import System.Console.GetOpt
7 import System.Environment( getArgs )
8 import System.Exit( exitSuccess, exitFailure )
9 import System.IO( stderr, hPutStr )
10 import qualified Data.Map as Map
11 import qualified Data.Text as T
12 import qualified Data.Text.IO as TIO
18 , optInputFiles :: [String]
19 , optOutputFile :: String
20 , optInputFormat :: String
21 , optOutputFormat :: String
22 , optStartDate :: String
23 , optEndDate :: String
33 , optInputFormat = "%FT%T%z"
34 , optOutputFormat = "%FT%T%z"
39 availableOptions :: [OptDescr (Opt -> IO Opt)]
41 [ Option ['h'] ["help"]
42 (NoArg (\ _ -> putStrLn (usageInfo "Usage: diddohs [OPTION...]" availableOptions) >> exitSuccess))
43 "Display program help"
44 , Option ['v'] ["verbose"]
45 (NoArg (\ opts -> return opts { optVerbose = True }))
46 "More detailed output"
47 , Option ['V'] ["version"]
48 (NoArg (\ opts -> return opts { optVersion = True }))
49 "Display program version"
50 , Option ['f'] ["file"]
51 (ReqArg (\ arg opts -> return opts { optInputFiles = optInputFiles opts ++ [arg]}) "FILE" )
53 , Option ['w'] ["output"]
54 (ReqArg (\ arg opts -> return opts { optOutputFile = arg }) "FILE")
56 , Option ['i'] ["informat"]
57 (ReqArg (\ arg opts -> return opts { optInputFormat = arg }) "FORMAT")
58 "Timeformat used in input"
59 , Option ['o'] ["outformat"]
60 (ReqArg (\ arg opts -> return opts { optOutputFormat = arg }) "FORMAT")
61 "Timeformat used in output"
62 , Option ['s'] ["start"]
63 (ReqArg (\ arg opts -> return opts { optStartDate = arg }) "DATE")
64 "Start of reporting period"
65 , Option ['e'] ["end"]
66 (ReqArg (\ arg opts -> return opts { optEndDate = arg }) "DATE")
67 "End of reporting period"
70 -- SECTION: Map of logentries to Map of Diddos
71 logentryMapToDiddoMap :: Map.Map UTCTime Diddo.LogEntry -> Map.Map UTCTime Diddo.Diddo
72 logentryMapToDiddoMap logmap = Map.mapWithKey toDddEntry logmap
74 toDddEntry key value = Diddo.logToDiddo (precedingTimestamp key) value
75 precedingTimestamp x = case Map.lookupLT x logmap of
77 Nothing -> fst $ Map.findMin logmap
78 -- SECTION: Map of logentries to Map of DiddoEntries
82 -- SECTION: option processing
83 (givenOptions,args,errs) <- getArgs >>= return . getOpt Permute availableOptions
85 unless (null errs) $ do
86 mapM_ (hPutStr stderr) errs
89 effectiveOptions <- foldl (>>=) (return defaultOpts) givenOptions
92 inDateFmt = optInputFormat effectiveOptions
93 outDateFmt = optOutputFormat effectiveOptions
95 startDate = parseToZonedTime inDateFmt $ optStartDate effectiveOptions
96 endDate = parseToZonedTime inDateFmt $ optEndDate effectiveOptions
97 -- SECTION: option processing
99 loglines <- case optInputFiles effectiveOptions of
100 files@(_:_) -> T.lines . T.concat <$> mapM TIO.readFile files
101 [] -> T.lines <$> TIO.getContents
104 timestampLogentryMap = Map.fromList $ map Diddo.parseDiddoLogline loglines
105 (_, _, startedTimestampLogentryMap) = Map.splitLookup (zonedTimeToUTC startDate) timestampLogentryMap
106 (endedTimestampLogentryMap, lastEntry, _) = Map.splitLookup (zonedTimeToUTC endDate) startedTimestampLogentryMap
107 timestampDiddoMap = logentryMapToDiddoMap timestampLogentryMap
113 mapM_ (TIO.putStrLn . snd) $ Map.toAscList $ Map.map (Diddo.formatDiddo outDateFmt) timestampDiddoMap