More Exim stuff
[hcoop/domtool2.git] / src / slave.sml
... / ...
CommitLineData
1(* HCoop Domtool (http://hcoop.sourceforge.net/)
2 * Copyright (c) 2006, Adam Chlipala
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *)
18
19(* Code for receiving and executing configuration files *)
20
21structure Slave :> SLAVE = struct
22
23datatype file_action =
24 Add
25 | Delete
26 | Modify
27
28type file_status = {action : file_action,
29 domain : string,
30 file : string}
31
32val fileHandler = ref (fn _ : file_status => ())
33val preHandler = ref (fn () => ())
34val postHandler = ref (fn () => ())
35
36fun registerFileHandler handler =
37 let
38 val old = !fileHandler
39 in
40 fileHandler := (fn x => (handler x; old x))
41 end
42
43fun registerPreHandler handler =
44 let
45 val old = !preHandler
46 in
47 preHandler := (fn () => (handler (); old ()))
48 end
49
50fun registerPostHandler handler =
51 let
52 val old = !postHandler
53 in
54 postHandler := (fn () => (handler (); old ()))
55 end
56
57fun handleChanges fs = (!preHandler ();
58 app (!fileHandler) fs;
59 !postHandler ())
60
61fun shell ss = OS.Process.isSuccess (OS.Process.system (String.concat ss))
62
63fun shellF (ss, msg) =
64 let
65 val s = String.concat ss
66 in
67 if OS.Process.isSuccess (OS.Process.system s) then
68 ()
69 else
70 ErrorMsg.error NONE (msg s)
71 end
72
73fun concatTo p fname =
74 let
75 fun visitDir dname =
76 let
77 val dir = Posix.FileSys.opendir dname
78
79 fun loop () =
80 case Posix.FileSys.readdir dir of
81 NONE => Posix.FileSys.closedir dir
82 | SOME fname' =>
83 let
84 val path = OS.Path.joinDirFile {dir = dname, file = fname'}
85 in
86 if Posix.FileSys.ST.isDir (Posix.FileSys.stat path) then
87 visitDir path
88 else if p fname' then
89 shellF ([Config.cat, " ", path, " >>", fname],
90 fn cl => "Error concatenating: " ^ cl)
91 else
92 ();
93 loop ()
94 end
95 in
96 TextIO.closeOut (TextIO.openOut fname);
97 loop ()
98 end
99 in
100 visitDir Config.resultRoot
101 end
102
103fun enumerateTo p sep fname =
104 let
105 val outf = TextIO.openOut fname
106
107 val first = ref true
108 val baseLen = length (String.fields (fn ch => ch = #"/") Config.resultRoot)
109
110 fun visitDir dname =
111 let
112 val dir = Posix.FileSys.opendir dname
113
114 fun loop () =
115 case Posix.FileSys.readdir dir of
116 NONE => Posix.FileSys.closedir dir
117 | SOME fname' =>
118 let
119 val path = OS.Path.joinDirFile {dir = dname, file = fname'}
120 in
121 if Posix.FileSys.ST.isDir (Posix.FileSys.stat path) then
122 visitDir path
123 else if p fname' then
124 let
125 val toks = String.fields (fn ch => ch = #"/") dname
126 val toks = List.drop (toks, baseLen)
127 val dom = String.concatWith "." (rev toks)
128 in
129 if !first then
130 first := false
131 else
132 TextIO.output (outf, sep);
133 TextIO.output (outf, dom)
134 end
135 else
136 ();
137 loop ()
138 end
139 in
140 loop ()
141 end
142 in
143 visitDir Config.resultRoot;
144 TextIO.closeOut outf
145 end
146
147end