diff options
| author | Joey Hess <joeyh@joeyh.name> | 2015-08-20 10:31:27 -0400 |
|---|---|---|
| committer | Joey Hess <joeyh@joeyh.name> | 2015-08-20 10:31:27 -0400 |
| commit | 565d3536da40f098d3931bd7fd2bcfa2625a90d1 (patch) | |
| tree | d8507539873b0c312ada94d822ded4d54bf7ac25 /src/Propellor/Property/ConfFile.hs | |
| parent | 9ec6bbbb3bbfea6b184053f3115bc7749688ce45 (diff) | |
| parent | 544a3111dd805fdcaddabe06a7d5c841e15faac5 (diff) | |
Merge branch 'joeyconfig'
Diffstat (limited to 'src/Propellor/Property/ConfFile.hs')
| -rw-r--r-- | src/Propellor/Property/ConfFile.hs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/Propellor/Property/ConfFile.hs b/src/Propellor/Property/ConfFile.hs new file mode 100644 index 00000000..1a2503dd --- /dev/null +++ b/src/Propellor/Property/ConfFile.hs @@ -0,0 +1,93 @@ +module Propellor.Property.ConfFile ( + -- * Generic conffiles with sections + SectionStart, + SectionPast, + AdjustSection, + InsertSection, + adjustSection, + -- * Windows .ini files + IniSection, + IniKey, + containsIniSetting, +) where + +import Propellor +import Propellor.Property.File + +import Data.List (isPrefixOf, foldl') + +-- | find the line that is the start of the wanted section (eg, == "<Foo>") +type SectionStart = Line -> Bool +-- | find a line that indicates we are past the section +-- (eg, a new section header) +type SectionPast = Line -> Bool +-- | run on all lines in the section, including the SectionStart line; +-- can add/delete/modify lines, or even delete entire section +type AdjustSection = [Line] -> [Line] +-- | if SectionStart does not find the section in the file, this is used to +-- insert the section somewhere within it +type InsertSection = [Line] -> [Line] + +-- | Adjusts a section of conffile. +adjustSection + :: Desc + -> SectionStart + -> SectionPast + -> AdjustSection + -> InsertSection + -> FilePath + -> Property NoInfo +adjustSection desc start past adjust insert f = + fileProperty desc go f + where + go ls = let (pre, wanted, post) = foldl' find ([], [], []) ls + in if null wanted + then insert ls + else pre ++ (adjust wanted) ++ post + find (pre, wanted, post) l + | null wanted && null post && (not . start) l = + (pre ++ [l], wanted, post) + | (start l && null wanted && null post) + || ((not . null) wanted && null post && (not . past) l) = + (pre, wanted ++ [l], post) + | otherwise = (pre, wanted, post ++ [l]) + +-- | Name of a section of a Windows-style .ini file. This value is put +-- in square braces to generate the section header. +type IniSection = String + +-- | Name of a configuration setting within a Windows-style .init file. +type IniKey = String + +iniHeader :: IniSection -> String +iniHeader header = '[' : header ++ "]" + +adjustIniSection + :: Desc + -> IniSection + -> AdjustSection + -> InsertSection + -> FilePath + -> Property NoInfo +adjustIniSection desc header = + adjustSection + desc + (== iniHeader header) + ("[" `isPrefixOf`) + +-- | Ensures that a Windows-style .ini file exists and contains a section +-- with a key=value setting. +containsIniSetting :: FilePath -> (IniSection, IniKey, String) -> Property NoInfo +containsIniSetting f (header, key, value) = + adjustIniSection + (f ++ " section [" ++ header ++ "] contains " ++ key ++ "=" ++ value) + header + go + (++ [confheader, confline]) + f + where + confheader = iniHeader header + confline = key ++ "=" ++ value + go [] = [confline] + go (l:ls) = if isKeyVal l then confline : ls else l : (go ls) + isKeyVal x = (filter (/= ' ') . takeWhile (/= '=')) x `elem` [key, '#':key] |
