1 (* HCoop
Domtool (http
://hcoop
.sourceforge
.net
/)
2 * Copyright (c
) 2006, Adam Chlipala
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
.
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
.
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
.
19 (* Domain
-related primitive actions
*)
21 structure Domain
:> DOMAIN
= struct
23 fun isIdent ch
= Char.isLower ch
orelse Char.isDigit ch
26 size s
> 0 andalso size s
< 20
27 andalso CharVector
.all (fn ch
=> isIdent ch
orelse ch
= #
"-") s
30 size s
> 0 andalso size s
< 100
31 andalso List.all
validHost (String.fields (fn ch
=> ch
= #
".") s
)
33 val _
= Env
.type_one
"host"
37 val _
= Env
.type_one
"domain"
43 val befores
= ref (fn (_
: string) => ())
44 val afters
= ref (fn (_
: string) => ())
46 fun registerBefore f
=
50 befores
:= (fn x
=> (old x
; f x
))
57 afters
:= (fn x
=> (old x
; f x
))
61 val currentPath
= ref
""
65 fun currentDomain () = !current
67 fun domainFile name
= TextIO.openOut (!currentPath ^ name
)
71 val toks
= String.fields (fn ch
=> ch
= #
".") domain
73 val elems
= foldr (fn (piece
, elems
) =>
75 val elems
= piece
:: elems
76 val path
= String.concatWith
"/" (Config
.resultRoot
:: rev elems
)
77 val tmpPath
= String.concatWith
"/" (Config
.tmpDir
:: rev elems
)
79 (if Posix
.FileSys
.ST
.isDir
80 (Posix
.FileSys
.stat path
) then
83 (OS
.FileSys
.remove path
;
84 OS
.FileSys
.mkDir path
))
85 handle OS
.SysErr _
=> OS
.FileSys
.mkDir path
;
87 (if Posix
.FileSys
.ST
.isDir
88 (Posix
.FileSys
.stat tmpPath
) then
91 (OS
.FileSys
.remove tmpPath
;
92 OS
.FileSys
.mkDir tmpPath
))
93 handle OS
.SysErr _
=> OS
.FileSys
.mkDir tmpPath
;
98 fn root
=> String.concatWith
"/" (root
:: rev ("" :: elems
))
101 datatype file_action
' =
102 Add
' of {src
: string, dst
: string}
104 | Modify
' of {src
: string, dst
: string}
108 val realPath
= getPath dom Config
.resultRoot
109 val tmpPath
= !currentPath
111 val dir
= Posix
.FileSys
.opendir realPath
114 case Posix
.FileSys
.readdir dir
of
115 NONE
=> (Posix
.FileSys
.closedir dir
;
119 val real = OS
.Path
.joinDirFile
{dir
= realPath
,
121 val tmp
= OS
.Path
.joinDirFile
{dir
= tmpPath
,
124 if Posix
.FileSys
.ST
.isDir (Posix
.FileSys
.stat
real) then
126 else if Posix
.FileSys
.access (tmp
, []) then
127 if Slave
.shell
[Config
.diff
, " ", real, " ", tmp
] then
130 loopReal (Modify
' {src
= tmp
, dst
= real} :: acts
)
132 loopReal (Delete
' real :: acts
)
135 val acts
= loopReal
[]
137 val dir
= Posix
.FileSys
.opendir tmpPath
140 case Posix
.FileSys
.readdir dir
of
141 NONE
=> (Posix
.FileSys
.closedir dir
;
145 val real = OS
.Path
.joinDirFile
{dir
= realPath
,
147 val tmp
= OS
.Path
.joinDirFile
{dir
= tmpPath
,
150 if Posix
.FileSys
.ST
.isDir (Posix
.FileSys
.stat tmp
) then
152 else if Posix
.FileSys
.access (real, []) then
155 loopTmp (Add
' {src
= tmp
, dst
= real} :: acts
)
158 val acts
= loopTmp acts
163 val _
= Env
.container_one
"domain"
164 ("domain", Env
.string)
167 val path
= getPath dom Config
.tmpDir
178 val diffs
= findDiffs dom
180 val diffs
= map (fn Add
' {src
, dst
} =>
181 (Slave
.shellF ([Config
.cp
, " ", src
, " ", dst
],
182 fn cl
=> "Copy failed: " ^ cl
);
187 (OS
.FileSys
.remove dst
188 handle OS
.SysErr _
=>
189 ErrorMsg
.error
NONE ("Delete failed for " ^ dst
);
190 {action
= Slave
.Delete
,
193 | Modify
' {src
, dst
} =>
194 (Slave
.shellF ([Config
.cp
, " ", src
, " ", dst
],
195 fn cl
=> "Copy failed: " ^ cl
);
196 {action
= Slave
.Modify
,
200 if !ErrorMsg
.anyErrors
then
203 Slave
.handleChanges diffs
;
204 ignore (Slave
.shellF ([Config
.rm
, " -rf ", Config
.tmpDir
, "/*"],
205 fn cl
=> "Temp file cleanup failed: " ^ cl
))