mkCTM revision 18110
1#!/usr/local/bin/tclsh7.4
2
3#############################################################################
4### Add something
5#############################################################################
6# Type Name Mode User Group Barf Size Hash
7
8proc CTMadd {t n m u g b s h} {
9    global fo_files fo_mkdir changes CTMref
10
11    puts stderr "A $b  $t  $n"
12    incr changes
13
14    if {$t == "d"} {
15	puts $fo_mkdir "CTMDM $n $u $g $m"
16    } elseif {$t == "f"} {
17	puts $fo_files "CTMFM $n $u $g $m $h $s"
18	flush $fo_files
19	exec cat $CTMref/$n >@ $fo_files
20	puts $fo_files ""
21    } else {
22	puts "confused in CTMadd"
23	exit 0
24    }
25}
26
27#############################################################################
28### Delete something
29#############################################################################
30# Type Name Mode User Group Barf Size Hash
31
32proc CTMdel {t n m u g b s h} {
33    global fo_del fo_rmdir changes damage max_damage CTMlock
34
35    puts stderr "D $b  $t  $n"
36    incr damage 
37    incr changes
38
39    if {$damage > $max_damage} {
40	exec rm -f $CTMlock
41	return
42    }
43    if {$t == "d"} {
44	puts $fo_rmdir "CTMDR $n"
45    } elseif {$t == "f"} {
46	puts $fo_del "CTMFR $n $h"
47    } else {
48	puts "confused in CTMdel"
49	exit 0
50    }
51}
52
53#############################################################################
54### Change something
55#############################################################################
56# Type Name Mode User Group Barf Size Hash
57
58proc CTMchg {t1 n1 m1 u1 g1 b1 s1 h1 t2 n2 m2 u2 g2 b2 s2 h2} {
59    global fo_files CTMref CTMcopy changes damage CTMscratch
60
61    # Ignore attribute changes for directories
62    if {$t1 == "d" && $t2 == "d"} return
63
64    # turn file into dir or vice versa...
65    if {$t1 != $t2} {
66	CTMdel $t1 $n1 $m1 $u1 $g1 $b1 $s1 $h1
67	CTMadd $t2 $n2 $m2 $u2 $g2 $b2 $s2 $h2
68	return
69    }
70
71    # only files allowed past this poing...
72    if {$t1 != "f" && $t2 != "f"} {
73        puts "confused in CTMchg"
74        exit 0
75    }
76
77    # Ignore attribute changes for files
78    if {"x$h1" == "x$h2" && $s1 == $s2} return
79
80    if {$s2 == 0} { incr damage }
81    incr changes
82
83    # If diff will deal with it...
84    if {$b1 == "0" && $b2 == "0"} {
85	set i [catch "exec diff -n $CTMcopy/$n1 $CTMref/$n2 > $CTMscratch" j]
86	set s [file size $CTMscratch]
87	if {$s < $s2} {
88	    puts stderr "E $b1$b2 $t1$t2 $n1"
89	    puts $fo_files "CTMFN $n1 $u2 $g2 $m2 $h1 $h2 $s"
90	    flush $fo_files
91	    exec cat $CTMscratch >@ $fo_files
92	    puts $fo_files ""
93	    return
94	}
95    } 
96    puts stderr "R $b1$b2 $t1$t2 $n1"
97    puts $fo_files "CTMFS $n2 $u2 $g2 $m2 $h1 $h2 $s2"
98    flush $fo_files
99    exec cat $CTMref/$n2 >@ $fo_files
100    puts $fo_files ""
101}
102
103#############################################################################
104### Do we already have this delta ?
105#############################################################################
106
107proc find_delta {nbr} {
108    global CTMname CTMdest
109    if {[file exists [format "%s/$CTMname.%04d" $CTMdest $nbr]]} { return 1 }
110    if {[file exists [format "%s/$CTMname.%04d.gz" $CTMdest $nbr]]} { return 1 }
111    return 0
112}
113
114#############################################################################
115### The top level code...
116#############################################################################
117
118set CTMSW	/home/ctm/SW
119
120cd $CTMSW
121
122# Defaults...
123set CTMapply 1
124set CTMdont {^///}
125set CTMmail {}
126set CTMqueue {}
127set CTMqueuemail {}
128set CTMmaxctm 10000000
129set CTMmaxmsg 100000
130set CTMsuff {}
131set CTMdate     [exec date -u +%Y%m%d%H%M%SZ]
132set CTMtmp  {}
133set CTMcopy  {}
134set CTMdest  {}
135set CTMprefix  .
136set CTMtest 0
137set CTMspecial 0
138set CTMscan .
139set CTMfirst 0
140set max_damage 1200
141
142set damage 0
143set changes 0
144
145exec sh -c "date -u '+%y%m%d%H%M%S $argv'" >> /home/ctm/log
146source $argv
147
148if {$CTMtmp == ""} {
149    set CTMtmp $CTMSW/../tmp/${CTMname}_${CTMsuff}
150}
151if {$CTMcopy == ""} {
152    set CTMcopy $CTMSW/../$CTMname
153}
154if {$CTMdest == ""} {
155    set CTMdest $CTMSW/../CTM-pub/$CTMname
156}
157
158# Make sure we only run one at a time...
159
160set CTMlock Lck.${CTMname}.${CTMdate}.[pid]
161exec rm -f ${CTMlock}
162exec echo starting > ${CTMlock}
163if {[catch "exec ln $CTMlock LCK.$CTMname" a]} {
164	puts "Not going, lock exists..."
165	exec rm -f $CTMlock
166	exit 0
167}
168exec rm -f $CTMlock
169set CTMlock LCK.$CTMname
170
171set CTMscratch ${CTMtmp}.tmp
172
173while 1 {
174    if { ! $CTMspecial} {
175	if {$CTMfirst} {
176		set CTMnbr 0
177	} else {
178		set CTMnbr [lindex [exec cat $CTMcopy/.ctm_status] 1]
179	}
180
181	if {$CTMnbr > 0 && ![find_delta $CTMnbr]} {
182	    puts "$CTMname delta $CTMnbr doesn't exist..."
183	    exec rm -f $CTMlock
184	    exit 0
185	}
186
187	incr CTMnbr
188
189	if {[find_delta $CTMnbr]} {
190	    puts "$CTMname delta $CTMnbr does already exist..."
191	    exec rm -f $CTMlock
192	    exit 0
193	}
194
195	set fo [open $CTMref/.ctm_status w]
196	puts $fo "$CTMname $CTMnbr"
197	close $fo
198	incr changes -1
199
200    } else {
201	set CTMnbr [lindex [exec cat $CTMref/.ctm_status] 1]
202    }
203
204    if {"$CTMcopy" == "" } { 
205	set f1 [open /dev/null]
206    } else {
207	set f1 [open "| ./ctm_scan $CTMcopy $CTMscan"]
208    }
209
210    puts "Doing CTMname $CTMname CTMnbr $CTMnbr$CTMsuff CTMdate $CTMdate"
211    flush stdout
212    exec sh -c "rm -f ${CTMtmp}.* ${CTMtmp}:*" >&@ stdout
213
214    set f2 [open "| ./ctm_scan $CTMref $CTMscan"]
215
216    set fo_del   [open $CTMtmp.del w]
217    set fo_rmdir [open $CTMtmp.rmdir w]
218    set fo_mkdir [open $CTMtmp.mkdir w]
219    set fo_files [open $CTMtmp.files w]
220
221    set l1 ""
222    set l2 ""
223
224    while 1 {
225
226	if {$l1 == ""} {gets $f1 l1}
227
228	if {$l2 == ""} {gets $f2 l2}
229	
230	if {$l1 == "" && $l2 == ""} break
231
232	set n1 [lindex $l1 1]
233	set n2 [lindex $l2 1]
234
235	if {[regexp $CTMdont /$n1]} { set l1 "" ; continue }
236	if {[regexp $CTMdont /$n2]} { set l2 "" ; continue }
237
238	# they're all the same...
239	if {$l1 == $l2}  { set l1 "" ; set l2 "" ; continue }
240
241	if {$l1 == "" }   { eval CTMadd $l2 ; set l2 "" ; continue }
242
243	if {$l2 == "" }   { eval CTMdel $l1 ; set l1 "" ; continue }
244
245	# if the name is the same we're safe...
246	if {$n1 == $n2}  { 
247	    eval CTMchg $l1 $l2
248	    set l1 ""
249	    set l2 "" 
250	    continue 
251	}
252
253	# To avoid this anomaly:
254	# A -  d  src/gnu/lib/libreadline/readline/Attic
255	# A 0  f  src/gnu/lib/libreadline/readline/Attic/readline.h,v
256	# A 0  f  src/gnu/lib/libreadline/readline.c,v
257	# D 0  f  src/gnu/lib/libreadline/readline/readline.h,v
258	# D 0  f  src/gnu/lib/libreadline/readline.c,v
259	# we have to make things somewhat complicated...
260
261	# if they have the same number of components...
262	set ll1 [llength [split $n1 /]]
263	set ll2 [llength [split $n2 /]]
264	if {$ll1 == $ll2} {
265	    if {$n1 < $n2 } { 
266		eval CTMdel $l1 ; set l1 "" ; continue 
267	    } else {
268		eval CTMadd $l2 ; set l2 "" ; continue 
269	    }
270	} 
271	if {$ll1 < $ll2} {
272		eval CTMadd $l2 ; set l2 "" ; continue 
273	} else {
274		eval CTMdel $l1 ; set l1 "" ; continue 
275	}
276    }
277
278    close $fo_del
279    close $fo_rmdir
280    close $fo_mkdir
281    close $fo_files
282
283    if {$damage > $max_damage} {
284	puts "Too much damage: $damage deletes"
285		exec sh -c "rm -f ${CTMtmp}.*"
286		exec rm -f $CTMlock
287	exit 0
288    }
289
290    if {!$changes} {
291	puts "no changes"
292	exec sh -c "rm -f ${CTMtmp}.*"
293        exec rm -f $CTMlock
294	exit 0
295    }
296
297    exec echo CTM_BEGIN 2.0 $CTMname $CTMnbr $CTMdate $CTMprefix > $CTMtmp.begin
298
299    puts "Assembling delta"
300    flush stdout
301    set  nm [format "%s.%04d%s" $CTMname $CTMnbr $CTMsuff]
302
303    set fdout [open "| /sbin/md5 -p | gzip -9 > ${CTMtmp}:${nm}.gz" w]
304
305    foreach i {begin del rmdir mkdir files} {
306	exec cat $CTMtmp.$i >@$fdout
307    }
308    puts $fdout "CTM_END " nonewline
309    close $fdout ; unset fdout
310
311    exec sh -c "rm -f ${CTMtmp}.*" >&@ stdout
312
313    if {$CTMtest} {
314	puts "testing, stopping now."
315        exec rm -f $CTMlock
316	exit 0
317    }
318    if {$CTMapply} {
319	    puts "Applying delta"
320	    flush stdout
321	    exec echo now applying > $CTMlock
322	    exec sh -e -c "cd $CTMcopy ; $CTMSW/ctm -v -v -v ${CTMtmp}:${nm}.gz" >&@ stdout
323	    exec echo did apply > $CTMlock
324    }
325    puts "Moving delta"
326    flush stdout
327    exec mv ${CTMtmp}:${nm}.gz $CTMdest/.CTMtmp_${nm}.gz >&@ stdout
328    exec mv $CTMdest/.CTMtmp_${nm}.gz $CTMdest/${nm}.gz >&@ stdout
329    exec echo moved > $CTMlock
330
331    if {$CTMmail != ""} {
332	puts "Mailing delta"
333	flush stdout
334	exec $CTMSW/ctm_smail -m $CTMmaxmsg -c $CTMmaxctm $CTMdest/${nm}.gz $CTMmail >&@ stdout
335	if {$CTMqueue != "" && $CTMqueuemail != ""} {
336	    puts "Queueing delta"
337	    flush stdout
338	    exec $CTMSW/ctm_smail -m $CTMmaxmsg -c $CTMmaxctm -q $CTMqueue $CTMdest/${nm}.gz $CTMqueuemail >&@ stdout
339	}
340    }
341    exec echo mailed > $CTMlock
342
343    # If we did an absolute delta: stop.
344    if {$CTMsuff != ""} break
345
346    # Make a absolute delta (!) every 100 deltas
347    if {$CTMnbr == 0 || ($CTMnbr % 100)} break
348
349    # Make an absolute delta too...
350    set CTMref $CTMcopy
351    set CTMsuff A
352    set CTMcopy ""
353    set CTMmail ""
354    set CTMqueue ""
355    set CTMqueuemail ""
356    set CTMapply 0
357    set CTMspecial 1
358    exec rm -f $CTMlock
359}
360puts "done."
361exec rm -f $CTMlock
362