blob: 3b080c469ad69edc16980c3669d0639a6b1e5528 [file] [log] [blame]
Matthias Andreas Benkard262110d2021-08-24 06:35:55 +02001{-# LANGUAGE PatternSynonyms #-}
2{-# LANGUAGE TypeApplications #-}
3{-# LANGUAGE UndecidableInstances #-}
4
5module Mulkup.Main where
6
7import Colog (Message, richMessageAction, simpleMessageAction)
8import Colog.Polysemy.Effect (Log, runLogAction)
9import qualified Data.List.NonEmpty as NonEmpty
10import qualified Data.Set as Set
11import Data.Time
12import Mulkup.Bupstash
13import Mulkup.Config
14import Mulkup.Flags
15import Mulkup.Logging
16import Mulkup.Prelude
17import Optics
18import Options.Applicative
19 ( execParser,
20 fullDesc,
21 helper,
22 info,
23 )
24import Polysemy (Member, Sem)
25import Polysemy.Error
26import Polysemy.Final
27import Polysemy.Reader (Reader, asks, runReader)
28
29main :: IO ()
30main = do
31 flags <- execParser $ info (flagParser <**> helper) fullDesc
32 let messageAction =
33 if verbose flags
34 then richMessageAction
35 else simpleMessageAction
36
37 config <- readConfig "./config.dhall"
38
39 result <-
40 main'
41 & runBupstash
42 & runLogAction @IO messageAction
43 & runReader (config :: MulkupConfig)
44 & errorToIOFinal @Text
45 & embedToFinal @IO
46 & runFinal @IO
47
48 case result of
49 Left err -> do
50 error err
51 Right () ->
52 return ()
53
54main' :: (Member (Log Message) r, Member (Reader MulkupConfig) r, Member Bupstash r) => Sem r ()
55main' = do
56 stashes <- asks @MulkupConfig (^. #stashes)
57 forM_ stashes $ \stash -> do
58 let labels = [("name", stash ^. #name)]
59
60 currentItems <- bupList (BupFilter labels Nothing)
61
62 let tiers =
63 [ (utctHour . bupItemUTCTime, #hourly),
64 (utctJulianDay . bupItemUTCTime, #daily),
65 (utctWeek . bupItemUTCTime, #weekly),
66 (utctMonth . bupItemUTCTime, #monthly)
67 ]
68
69 let keepIds =
70 Set.unions $
71 map
72 ( \(discriminator, cfgLens) ->
73 let tierCfg = stash ^. #tiers ^. cfgLens
74 in tierKeepIds discriminator (tierCfg ^. #keep) currentItems
75 )
76 tiers
77
78 let currentIds = Set.fromList (map (^. #id) currentItems)
79 let rmIds = Set.difference currentIds keepIds
80
81 logInfo (show labels <> " Keeping: " <> show (Set.toList keepIds))
82 logInfo (show labels <> " Removing: " <> show (Set.toList rmIds))
83 bupRemove (Set.toList rmIds)
84
85 logInfo (show labels <> " Creating backup.")
86 bupPut
87 (stash ^. #baseDir)
88 (stash ^. #exclusions)
89 labels
90
91tierKeepIds :: (BupItem -> Integer) -> Natural -> [BupItem] -> Set Text
92tierKeepIds discriminator keep items =
93 fromList $
94 take (fromIntegral keep) $
95 map (^. #id) $
96 reverse $
97 sortWith bupItemUTCTime $
98 map (head . NonEmpty.sortWith bupItemUTCTime) $
99 elems $
100 (groupBy discriminator items :: HashMap Integer (NonEmpty BupItem))
101
102utctHour :: UTCTime -> Integer
103utctHour (UTCTime (ModifiedJulianDay julianDay) tdiff) = (julianDay * 24) + (diffTimeToPicoseconds tdiff `div` (10 ^ (12 :: Integer)) `div` 3600)
104
105utctJulianDay :: UTCTime -> Integer
106utctJulianDay (UTCTime (ModifiedJulianDay julianDay) _) = julianDay
107
108utctWeek :: UTCTime -> Integer
109utctWeek (UTCTime day _) =
110 julianDay + fromIntegral (dayOfWeekDiff (dayOfWeek day) Sunday)
111 where
112 (ModifiedJulianDay julianDay) = day
113 dayOfWeekDiff a b = mod (fromEnum a - fromEnum b) 7
114
115utctMonth :: UTCTime -> Integer
116utctMonth (UTCTime day _) = fromIntegral m
117 where
118 (_, m, _) = toGregorian day