summaryrefslogtreecommitdiff
path: root/src/Main.hs
blob: 24fefa72f09082e0291a8d3d6353227664cda6ae (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
115
116
117
118
119
120
121
122
123
124
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 Optionset = Optionset
    { optVerbose        :: Bool
    , optVersion        :: Bool
    , optHelp           :: Bool
    , optInputFiles     :: [String]
    , optOutputFile     :: String
    , optInputFormat    :: String
    , optOutputFormat   :: String
    , optStartDate      :: String
    , optEndDate        :: String
    }

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

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

getLoglines :: [String] -> IO [T.Text]
getLoglines []          = T.lines <$> TIO.getContents
getLoglines files@(_:_) = T.lines . T.concat <$> mapM TIO.readFile files

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

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

    opts <- foldl (>>=) (return defaultOpts) userOpts

    let
        inDateFmt   = optInputFormat opts
        outDateFmt  = optOutputFormat opts

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

    loglines <- getLoglines $ optInputFiles opts

    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