summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/ConfFile.hs
blob: 72996c7499faa97a9fdc4b9e54c380ad6163fd53 (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
module Propellor.Property.ConfFile (containsIniPair) where

import Propellor
import Propellor.Property.File

import Data.List (isPrefixOf, foldl')

type SectionStart  = Line -> Bool -- ^ find the line that is the start of the
								  -- wanted section (eg, == "<Foo>")
type SectionPast   = Line -> Bool -- ^ find a line that indicates we are past
								  -- the section (eg, a new section header)
type AdjustSection = [Line] -> [Line] -- ^ run on all lines in the section,
									  -- including the SectionStart line and any
									  -- SectionEnd line; can add/delete/modify
									  -- lines, or even delete entire section
type InsertSection = [Line] -> [Line] -- ^ if SectionStart does not find the
									  -- section in the file, this is used to
									  -- insert the section somewhere within it

adjustSection
	:: String
	-> 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])

iniHeader :: String -> String
iniHeader header = '[' : header ++ "]"

adjustIniSection
	:: String
	-> String
	-> AdjustSection
	-> InsertSection
	-> FilePath
	-> Property NoInfo
adjustIniSection desc header =
	adjustSection
	desc
	(== iniHeader header)
	("[" `isPrefixOf`)

containsIniPair :: FilePath -> (String, String, String) -> Property NoInfo
containsIniPair 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]