module Propellor.Property.Ccache (
hasCache,
hasLimits,
Limit(..),
DataSize,
) where
import Propellor.Base
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt
import Utility.DataUnits
import System.Posix.Files
import qualified Data.Semigroup as Sem
data Limit
= MaxSize DataSize
| MaxFiles Integer
| NoLimit
| Limit :+ Limit
instance Sem.Semigroup Limit where
(<>) = (:+)
instance Monoid Limit where
mempty = NoLimit
mappend = (Sem.<>)
type DataSize = String
maxSizeParam :: DataSize -> Maybe String
maxSizeParam s = readSize dataUnits s
>>= \sz -> Just $ "--max-size=" ++ ccacheSizeUnits sz
ccacheSizeUnits :: Integer -> String
ccacheSizeUnits sz = filter (/= ' ') (roughSize cfgfileunits True sz)
where
cfgfileunits :: [Unit]
cfgfileunits =
[ Unit (p 4) "Ti" "terabyte"
, Unit (p 3) "Gi" "gigabyte"
, Unit (p 2) "Mi" "megabyte"
, Unit (p 1) "Ki" "kilobyte"
]
p :: Integer -> Integer
p n = 1024^n
hasLimits :: FilePath -> Limit -> Property DebianLike
path `hasLimits` limit = go `requires` installed
where
go
| null params' = doNothing
| null errors =
cmdPropertyEnv "ccache" params' [("CCACHE_DIR", path)]
`changesFileContent` (path </> "ccache.conf")
| otherwise = property "couldn't parse ccache limits" $
errorMessage $ unlines errors
params = limitToParams limit
(errors, params') = partitionEithers params
limitToParams :: Limit -> [Either String String]
limitToParams NoLimit = []
limitToParams (MaxSize s) = case maxSizeParam s of
Just param -> [Right param]
Nothing -> [Left $ "unable to parse data size " ++ s]
limitToParams (MaxFiles f) = [Right $ "--max-files=" ++ val f]
limitToParams (l1 :+ l2) = limitToParams l1 <> limitToParams l2
hasCache :: Group -> Limit -> RevertableProperty DebianLike UnixLike
group@(Group g) `hasCache` limit = (make `requires` installed) <!> delete
where
make = propertyList ("ccache for " ++ g ++ " group exists") $ props
& File.dirExists path
& File.ownerGroup path (User "root") group
& File.mode path (combineModes $
readModes ++ executeModes ++
[ ownerWriteMode
, groupWriteMode
, setGroupIDMode
]) `onChange` fixSetgidBit
& hasLimits path limit
delete = check (doesDirectoryExist path) $
cmdProperty "rm" ["-r", path] `assume` MadeChange
`describe` ("ccache for " ++ g ++ " does not exist")
fixSetgidBit :: Property UnixLike
fixSetgidBit =
(cmdProperty "find"
[ path
, "-type", "d"
, "-exec", "chmod", "g+s"
, "{}", "+"
] `assume` MadeChange)
`before`
(cmdProperty "chown"
[ "-R"
, "root:" ++ g
, path
] `assume` MadeChange)
path = "/var/cache/ccache-" ++ g
installed :: Property DebianLike
installed = Apt.installed ["ccache"]