summaryrefslogtreecommitdiff
path: root/src/Main.hs
blob: 6884d1462cd52cb50d96fb6fc36c7b7dbf42fba4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import Control.Applicative( (<$>) )
import Control.Monad( unless )
import Data.Time.Clock( UTCTime(..) )
import Data.Time.LocalTime( TimeZone(), ZonedTime(..), zonedTimeToUTC, utcToZonedTime )
import Diddo( Diddo(..), LogEntry(..), parseDiddoLogline, formatDiddo, logToDiddo, parseToZonedTime )
import System.Console.GetOpt
import System.Environment( getArgs )
import System.Exit( exitSuccess, exitFailure )
import System.IO( stderr, hPutStr )
import qualified Data.Map as Map
import qualified Data.Text as T
import qualified Data.Text.IO as TIO

data Opt = Opt
    { optVerbose        :: Bool
    , optVersion        :: Bool
    , optHelp           :: Bool
    , optInputFiles     :: [String]
    , optOutputFile     :: String
    , optInputFormat    :: String
    , optOutputFormat   :: String
    , optStartDate      :: String
    , optEndDate        :: String
    }

defaultOpts :: Opt
defaultOpts = Opt
    { optVerbose        = False
    , optVersion        = False
    , optHelp           = False
    , optInputFiles     = []
    , optOutputFile     = ""
    , optInputFormat    = "%FT%T%z"
    , optOutputFormat   = "%FT%T%z"
    , optStartDate      = ""
    , optEndDate        = ""
    }

availableOptions :: [OptDescr (Opt -> IO Opt)]
availableOptions =
    [ Option ['h']    ["help"]
        (NoArg (\ _ -> putStrLn (usageInfo "Usage: diddohs [OPTION...]" availableOptions) >> exitSuccess))
        "Display program help"
    , Option ['v']    ["verbose"]
        (NoArg (\ opts -> return opts { optVerbose = True }))
        "More detailed output"
    , Option ['V']    ["version"]
        (NoArg (\ opts -> return opts { optVersion = True }))
        "Display program version"
    , Option ['f']    ["file"]
        (ReqArg (\ arg opts -> return opts { optInputFiles = optInputFiles opts ++ [arg]}) "FILE" )
        "Read from FILE"
    , Option ['w']    ["output"]
        (ReqArg (\ arg opts -> return opts { optOutputFile = arg }) "FILE")
        "Write to FILE"
    , Option ['i']    ["informat"]
        (ReqArg (\ arg opts -> return opts { optInputFormat = arg }) "FORMAT")
        "Timeformat used in input"
    , Option ['o']    ["outformat"]
        (ReqArg (\ arg opts -> return opts { optOutputFormat = arg }) "FORMAT")
        "Timeformat used in output"
    , Option ['s']    ["start"]
        (ReqArg (\ arg opts -> return opts { optStartDate = arg }) "DATE")
        "Start of reporting period"
    , Option ['e']    ["end"]
        (ReqArg (\ arg opts -> return opts { optEndDate = arg }) "DATE")
        "End of reporting period"
    ]

-- SECTION: Map of logentries to Map of Diddos
logentryMapToDiddoMap :: Map.Map UTCTime Diddo.LogEntry -> Map.Map UTCTime Diddo.Diddo
logentryMapToDiddoMap logmap = Map.mapWithKey toDddEntry logmap
    where
        toDddEntry key value    = Diddo.logToDiddo (precedingTimestamp key) value
        precedingTimestamp x    = case Map.lookupLT x logmap of
            Just (y,_)          -> y
            Nothing             -> fst $ Map.findMin logmap
-- SECTION: Map of logentries to Map of DiddoEntries

main :: IO ()
main = do
    -- SECTION: option processing
    (givenOptions,args,errs) <- getArgs >>= return . getOpt Permute availableOptions

    unless (null errs) $ do
        mapM_ (hPutStr stderr) errs
        exitFailure

    effectiveOptions <- foldl (>>=) (return defaultOpts) givenOptions

    let
        inDateFmt               = optInputFormat effectiveOptions
        outDateFmt              = optOutputFormat effectiveOptions

        startDate               = parseToZonedTime inDateFmt $ optStartDate effectiveOptions
        endDate                 = parseToZonedTime inDateFmt $ optEndDate effectiveOptions
    -- SECTION: option processing

    loglines <- case optInputFiles effectiveOptions of
            files@(_:_)     -> T.lines . T.concat <$> mapM TIO.readFile files
            []              -> T.lines <$> TIO.getContents

    let
        timestampLogentryMap                        = Map.fromList $ map Diddo.parseDiddoLogline loglines
        (_, _, startedTimestampLogentryMap)         = Map.splitLookup (zonedTimeToUTC startDate) timestampLogentryMap
        (endedTimestampLogentryMap, lastEntry, _)   = Map.splitLookup (zonedTimeToUTC endDate) startedTimestampLogentryMap
        timestampDiddoMap                           = logentryMapToDiddoMap timestampLogentryMap

    -- DEBUG
    mapM_ putStrLn args
    -- DEBUG

    mapM_ (TIO.putStrLn . snd) $ Map.toAscList $ Map.map (Diddo.formatDiddo outDateFmt) timestampDiddoMap