Codebase list metche / bd28228
More cleanups ! Lunar 18 years ago
1 changed file(s) with 168 addition(s) and 150 deletion(s). Raw diff Collapse all Expand all
+168
-150
metche less more
2424 ### Auxiliary functions
2525 ###
2626
27 function display_usage {
27 display_usage() {
2828 ( echo "Usage: `basename $0` [-h HOST] list"
29 echo " `basename $0` [-h HOST] report [{stable|testing|unstable}-YYYYMMDDHHMM]"
29 echo " `basename $0` [-h HOST] report" \
30 "[{stable|testing|unstable}-YYYYMMDDHHMM]"
3031 echo " `basename $0` [-h HOST] cron"
3132 echo " `basename $0` [-h HOST] stabilize [testing-YYYYMMDDHHMM]"
32 echo "If -h is specified, /etc/metche/HOST.conf is used instead of /etc/metche.conf."
33 echo "If -h is specified, /etc/metche/HOST.conf is used" \
34 "instead of /etc/metche.conf."
3335 echo ""
3436 ) >&2
3537 }
3638
37 function fatal() {
39 fatal() {
3840 echo -e "$@" >&2
3941 exit 2
4042 }
4143
42 function debug() {
44 debug() {
4345 [ $DEBUG -eq 0 ] || echo -e "debug: $@" >&2
4446 }
4547
46 function email() {
48 email() {
4749 debug "email $@"
48 local SUBJECT="$_MAIL_SUBJECT : $1"
50 local subject="$_MAIL_SUBJECT : $1"
4951 if [ $ENCRYPT_EMAIL = "yes" ]; then
50 cat |
51 LC_ALL="$LOCALE" gpg --batch --armor --encrypt \
52 --recipient "$EMAIL_ADDRESS" |
53 LC_ALL="$LOCALE" mutt -s "$SUBJECT" "$EMAIL_ADDRESS"
52 LC_ALL="$LOCALE" gpg --batch --armor --encrypt \
53 --recipient "$EMAIL_ADDRESS" |
54 LC_ALL="$LOCALE" mutt -s "$subject" "$EMAIL_ADDRESS"
5455 else
55 cat |
56 LC_ALL="$LOCALE" mutt -s "$SUBJECT" "$EMAIL_ADDRESS"
56 LC_ALL="$LOCALE" mutt -s "$subject" "$EMAIL_ADDRESS"
5757 fi
5858 }
5959
7070 STABLE_TIME="3"
7171 EMAIL_ADDRESS="root@`hostname -f`"
7272 ENCRYPT_EMAIL="no"
73 TAR_OPTS="--exclude *.swp --exclude #* --exclude *~ --exclude=*.key --exclude=ifstate"
73 TAR_OPTS="--exclude *.swp --exclude #* --exclude *~ \
74 --exclude=*.key --exclude=ifstate"
7475 LOCALE="C"
7576 VSERVER_EXEC_PREFIX=""
7677
140141 test -d "$WATCHED_DIR" || fatal "WATCHED_DIR ($WATCHED_DIR) does not exist."
141142 test -d "$BACKUP_DIR" || fatal "BACKUP_DIR ($BACKUP_DIR) does not exist."
142143
143 if [ $ENCRYPT_EMAIL = "yes" ]; then
144 if [ "$ENCRYPT_EMAIL" = "yes" ]; then
144145 gpg --batch --list-public-keys $EMAIL_ADDRESS >/dev/null 2>&1 ||
145146 fatal "GnuPG public key for $EMAIL_ADDRESS not found."
146147 fi
170171 ###
171172
172173 # Returns 0 if, and only if, specified milestone exists.
173 function milestone_exists() {
174 local MILESTONE="$1"
175 if [ -f "${BACKUP_DIR}/${MILESTONE}.tar.bz2" -o -L "${BACKUP_DIR}/${MILESTONE}.tar.bz2" ]; then
174 milestone_exists() {
175 local milestone="$1"
176 if [ -f "${BACKUP_DIR}/${milestone}.tar.bz2" -o \
177 -L "${BACKUP_DIR}/${milestone}.tar.bz2" ]; then
176178 return 0
177179 else
178180 return 1
182184 # Echoes the given milestone's version (i.e. "stable", "testing", "unstable")
183185 # if it has a valid version, else "none".
184186 # The given milestone can be inexistant.
185 function milestone_version() {
186 local MILESTONE="$1"
187 local VERSION="`echo $MILESTONE | sed 's/-.*$//'`"
188 case $VERSION in
187 milestone_version() {
188 local milestone="$1"
189 local version="`echo $milestone | sed 's/-.*$//'`"
190 case $version in
189191 stable|testing|unstable)
190 echo $VERSION;;
192 echo $version;;
191193 *)
192194 echo "none";;
193195 esac
196198 # Echoes given milestone's date.
197199 # Symlinks (e.g.: *-latest) are dereferenced if needed.
198200 # The given milestone can be inexistant.
199 function milestone_date() {
200 local MILESTONE="$1"
201 [ ! -L "${BACKUP_DIR}/${MILESTONE}.tar.bz2" ] ||
202 MILESTONE="`readlink ${BACKUP_DIR}/${MILESTONE}.tar.bz2`"
203 echo `basename $MILESTONE` | sed 's/.*-//' | sed 's/\..*$//'
204 }
205
206 # Returns 0 if, and only if, the given milestone ($1) is the latest one of its type.
201 milestone_date() {
202 local milestone="$1"
203
204 if [ -L "${BACKUP_DIR}/${milestone}.tar.bz2" ]; then
205 milestone="`readlink ${BACKUP_DIR}/${milestone}.tar.bz2`"
206 fi
207 echo `basename $milestone` | sed 's/.*-//' | sed 's/\..*$//'
208 }
209
210 # Returns 0 if, and only if, the given milestone ($1) is the latest one
211 # of its type.
207212 # The given milestone can be inexistant.
208 function is_latest() {
209 local FILE MILESTONE
210 local REF_MILESTONE="$1"
211 local REF_DATE="`milestone_date $REF_MILESTONE`"
212 local REF_VERSION="`milestone_version $REF_MILESTONE`"
213 for FILE in "${BACKUP_DIR}/${REF_VERSION}-"*.tar.bz2; do
214 MILESTONE=`basename $FILE | sed 's/\.tar\.bz2$//'`
215 if [ `milestone_date $MILESTONE` -gt $REF_DATE ]; then
213 is_latest() {
214 local file milestone ref_milestone ref_date ref_version
215
216 ref_milestone="$1"
217 ref_date="`milestone_date $ref_milestone`"
218 ref_version="`milestone_version $ref_milestone`"
219 for file in "${BACKUP_DIR}/${ref_version}-"*.tar.bz2; do
220 milestone=`basename $file | sed 's/\.tar\.bz2$//'`
221 if [ "`milestone_date $milestone`" -gt "$ref_date" ]; then
216222 return 1
217223 fi
218224 done
220226 }
221227
222228 # This will save an archive of the watched directory with the given prefix
223 function save_files() {
229 save_files() {
224230 debug " - save_files $@"
225231 tar jcf "$BACKUP_DIR/$1-$DATE".tar.bz2 \
226232 -C "$WATCHED_PARENT" $TAR_OPTS `basename "$WATCHED_DIR"`
228234 }
229235
230236 # This will save packages list with the given prefix
231 function save_packages() {
237 save_packages() {
232238 debug " - save_packages $@"
233239 $VSERVER_EXEC_PREFIX apt-show-versions -i
234240 $VSERVER_EXEC_PREFIX apt-show-versions |
237243 }
238244
239245 # This will save Changelogs with the given prefix
240 function save_changelogs() {
246 save_changelogs() {
241247 debug " - save_changelogs $@"
242 local CHANGELOG DOMAIN file
248 local changelog domain file
243249
244250 for file in "$CHANGELOG_DIR"/*/Changelog; do
245 CHANGELOG="${file##$CHANGELOG_DIR/}"
246 DOMAIN="${CHANGELOG%%/Changelog}"
247 cat "$file" > "$BACKUP_DIR/$1-$DATE.$DOMAIN.Changelog"
248 ln -sf "$1-$DATE.$DOMAIN.Changelog" \
249 "$BACKUP_DIR/$1-latest.$DOMAIN.Changelog"
251 changelog="${file##$CHANGELOG_DIR/}"
252 domain="${changelog%%/Changelog}"
253 cat "$file" > "$BACKUP_DIR/$1-$DATE.$domain.Changelog"
254 ln -sf "$1-$DATE.$domain.Changelog" \
255 "$BACKUP_DIR/$1-latest.$domain.Changelog"
250256 done
251257 }
252258
253259 # Save whatever reflect the current state with the given prefix
254 function save_state() {
260 save_state() {
255261 debug "save_state $@"
256262 save_files "$1"
257263 [ $DO_PACKAGES = "no" ] || save_packages "$1"
259265 }
260266
261267 # Report changes against given version to standard output
262 function report_changes() {
268 report_changes() {
263269 debug "report_changes $@"
264 local RULER TMP TMPDIR CHANGELOG DOMAIN DIFF TAR_DIFF DIFF_DIFF
265 local FILES OLD NEW TMP_PACKAGES file
266
267 # Just for fancy graphics
268 RULER=`echo "$WATCHED_DIR" | tr '[:print:]' '='`
269
270 local tmp tmpdir changelog domain diff tar_diff diff_diff
271 local files old new tmp_packages file
272
270273 # File to store results
271 TMP=`mktemp -q`
274 tmp=`mktemp -q`
272275 # We need to diff against given version, so extract it
273 TMPDIR=`mktemp -d -q`
274 tar jxf "$BACKUP_DIR/$1".tar.bz2 -C "$TMPDIR"
275
276 echo "$MAIN_HEADER" >> "$TMP"
276 tmpdir=`mktemp -d -q`
277 tar jxf "$BACKUP_DIR/$1".tar.bz2 -C "$tmpdir"
278
279 echo "$MAIN_HEADER" >> "$tmp"
277280
278281 if [ $DO_CHANGELOGS = "yes" ]; then
279 echo "$CHANGELOGS_HEADER" >> "$TMP"
282 echo "$CHANGELOGS_HEADER" >> "$tmp"
280283 for file in "$CHANGELOG_DIR"/*/Changelog; do
281 CHANGELOG="${file##$CHANGELOG_DIR/}"
282 DOMAIN="${CHANGELOG%%/Changelog}"
283 DIFF=`LC_ALL=$LOCALE \
284 diff -wEbBN "$BACKUP_DIR/$1.$DOMAIN.Changelog" \
284 changelog="${file##$CHANGELOG_DIR/}"
285 domain="${changelog%%/Changelog}"
286 diff=`LC_ALL=$LOCALE \
287 diff -wEbBN "$BACKUP_DIR/$1.$domain.Changelog" \
285288 "$file"` ||
286289 # diff returns false when files differ
287 (echo "$DOMAIN:" ; echo "$DIFF" |
288 grep -v '^[0-9-]\|^\\') >> "$TMP"
290 (echo "$domain:" ; echo "$diff" |
291 grep -v '^[0-9-]\|^\\') >> "$tmp"
289292 done
290293 fi
291294
292 echo "$FILES_HEADER" >> "$TMP"
295 echo "$FILES_HEADER" >> "$tmp"
293296
294297 # Find differences with tar
295 TAR_DIFF=$(tar jdf "$BACKUP_DIR/$1".tar.bz2 \
298 tar_diff=$(tar jdf "$BACKUP_DIR/$1".tar.bz2 \
296299 -C "$WATCHED_PARENT" $TAR_OPTS 2>&1 |
297300 # transform:
298301 # etc/issue: Gid differs -> etc/issue
299302 # tar: etc/irssi.conf: ... -> etc/irssi.conf
300303 sed -e 's/\(tar: \)\?\([^:]*\):.*/\2/')
301304 # Get new files
302 DIFF_DIFF=$(diff -qr $TAR_OPTS "$TMPDIR"/`basename "$WATCHED_DIR"` \
305 diff_diff=$(diff -qr $TAR_OPTS "$tmpdir"/`basename "$WATCHED_DIR"` \
303306 "$WATCHED_DIR" 2>/dev/null |
304307 # Only in test/etc: issue -> test/etc/issue
305308 sed -n -e "s,^Only in $WATCHED_PARENT\([^:]*\): \(.*\),\1/\2,p")
306 FILES="$TAR_DIFF$DIFF_DIFF"
307 if [ "$FILES" = "" ]; then
308 echo "$_NO_CHANGE" >> "$TMP"
309 files="$tar_diff$diff_diff"
310 if [ -z "$files" ]; then
311 echo "$_NO_CHANGE" >> "$tmp"
309312 else
310 for file in $FILES; do
311 OLD="$TMPDIR"/"$file"
312 NEW="$WATCHED_PARENT$file"
313 if [ -e "$OLD" -a -e "$NEW" ]; then
313 for file in $files; do
314 old="$tmpdir"/"$file"
315 new="$WATCHED_PARENT$file"
316 if [ -e "$old" -a -e "$new" ]; then
314317 echo -n '< '
315 ls -ld "$OLD" | sed -e "s;$TMPDIR/;;"
318 ls -ld "$old" | sed -e "s;$tmpdir/;;"
316319 echo -n '> '
317 ls -ld "$NEW" | sed -e "s;$WATCHED_PARENT;;"
318 elif [ -e "$OLD" ]; then
320 ls -ld "$new" | sed -e "s;$WATCHED_PARENT;;"
321 elif [ -e "$old" ]; then
319322 echo -n '- '
320 ls -ld "$OLD" | sed -e "s;$TMPDIR/;;"
321 elif [ -e "$NEW" ]; then
323 ls -ld "$old" | sed -e "s;$tmpdir/;;"
324 elif [ -e "$new" ]; then
322325 echo -n '+ '
323 ls -ld "$NEW" | sed -e "s;$WATCHED_PARENT;;"
326 ls -ld "$new" | sed -e "s;$WATCHED_PARENT;;"
324327 fi
325 done >> "$TMP"
328 done >> "$tmp"
326329 fi
327330
328 if [ $DO_PACKAGES = "yes" ]; then
329 echo "$DEBIAN_PACKAGES_HEADER" >> "$TMP"
330
331 TMP_PACKAGES=`mktemp -q`
331 if [ "$DO_PACKAGES" = "yes" ]; then
332 echo "$DEBIAN_PACKAGES_HEADER" >> "$tmp"
333
334 tmp_packages=`mktemp -q`
332335 $VSERVER_EXEC_PREFIX apt-show-versions -i
333 $VSERVER_EXEC_PREFIX apt-show-versions | sort > "$TMP_PACKAGES"
334 if diff -wEbB "$BACKUP_DIR/$1".packages "$TMP_PACKAGES"; then
336 $VSERVER_EXEC_PREFIX apt-show-versions | sort > "$tmp_packages"
337 if diff -wEbB "$BACKUP_DIR/$1".packages "$tmp_packages"; then
335338 echo "$_NO_DEBIAN_PACKAGES_CHANGE"
336 fi | grep -v '^[0-9-]' >> "$TMP"
337 fi
338
339 echo "$FILES_DETAILS_HEADER" >> "$TMP"
339 fi | grep -v '^[0-9-]' >> "$tmp"
340 fi
341
342 echo "$FILES_DETAILS_HEADER" >> "$tmp"
340343
341344 # Just diff it!
342345 if (LC_ALL=$LOCALE diff -urBN $TAR_OPTS \
343 --minimal "$TMPDIR"/`basename "$WATCHED_DIR"` \
346 --minimal "$tmpdir"/`basename "$WATCHED_DIR"` \
344347 "$WATCHED_DIR" 2>/dev/null); then
345348 echo "$_NO_CHANGE"
346349 fi | grep -v '^--- \|diff ' |
347350 sed -e "s;^+++ $WATCHED_PARENT\([^ ]*\) .*;+++ \1;" \
348 >> "$TMP"
349
350 # Put report on standard output
351 cat "$TMP"
351 >> "$tmp"
352
353 # Put on standard output
354 cat "$tmp"
352355
353356 # Clean temporaries
354 rm -rf "$TMP" "$TMPDIR"
357 rm -rf "$tmp" "$tmpdir"
355358 }
356359
357360 # Turns into stable the given testing.
358361 # NB: argument validity is supposed to have been already checked.
359 function stabilize_state() {
362 stabilize_state() {
360363 debug "stabilize_state $@"
361 local TESTING STABLE FILE DST
362 TESTING="$1"
364 local testing stable file dst
365
366 testing="$1"
363367 # follow symlink if needed
364 if [ -L "${BACKUP_DIR}/$TESTING".tar.bz2 ]; then
365 TESTING="`readlink ${BACKUP_DIR}/${TESTING}.tar.bz2`"
366 TESTING="`basename $TESTING | sed 's/\..*//'`"
367 fi
368 STABLE="`echo $TESTING | sed 's/^testing/stable/'`"
369 for FILE in "${BACKUP_DIR}/${TESTING}"*; do
370 DST="`echo $FILE | sed 's/\/testing-/\/stable-/'`"
371 cp "$FILE" "$DST"
368 if [ -L "${BACKUP_DIR}/$testing".tar.bz2 ]; then
369 testing="`readlink ${BACKUP_DIR}/${testing}.tar.bz2`"
370 testing="`basename $testing | sed 's/\..*//'`"
371 fi
372 stable="`echo $testing | sed 's/^testing/stable/'`"
373 for file in "${BACKUP_DIR}/${testing}"*; do
374 dst="`echo $file | sed 's/\/testing-/\/stable-/'`"
375 cp "$file" "$dst"
372376 # create/change stable-latest* links if, and only if,
373377 # it's really the latest
374 is_latest $STABLE &&
375 ln -sf "`basename $DST`" "${BACKUP_DIR}/`basename $DST |
376 sed 's/-[0-9]*\./-latest\./'`"
378 if is_latest $stable; then
379 ln -sf "`basename $dst`" "${BACKUP_DIR}/`basename $dst |
380 sed 's/-[0-9]*\./-latest\./'`"
381 fi
377382 done
383 }
384
385 # Returns true if $WATCHED_DIR has not changed since $1 minutes
386 no_change_since() {
387 local time
388
389 time="$1"
390 test -z "`find "$WATCHED_DIR" -cmin "-$time" | head -1`"
391 }
392
393 # Returns true if $WATCHED_DIR has changed since file $1 last modification
394 changed_from() {
395 local ref_file
396
397 ref_file="$1"
398 test "`find "$WATCHED_DIR" -newer "$ref_file" | head -1`"
378399 }
379400
380401 ###
388409 case "$CMD" in
389410
390411 report)
391 [ "$MILESTONE" = "" ] &&
392 { report_changes "testing-latest"; exit 0; }
393 milestone_exists "$MILESTONE" &&
394 { report_changes "$MILESTONE"; exit 0; }
395 display_usage
396 fatal "The specified state does not exist."
412 if [ -z "$MILESTONE" ]; then
413 report_changes "testing-latest"
414 elif milestone_exists "$MILESTONE"; then
415 report_changes "$MILESTONE"
416 else
417 display_usage
418 fatal "The specified state does not exist."
419 fi
397420 ;;
398421
399422 list)
400423 for file in "$BACKUP_DIR"/*.tar.bz2; do
401424 echo `basename ${file%%.tar.bz2}`
402425 done
403 exit 0
404426 ;;
405427
406428 cron)
429 STABLE_TIME_MIN=`expr 24 '*' 60 '*' "$STABLE_TIME"`
430
407431 ### Algorithm
408432 #
409433 # if (no change happened for TESTING_TIME) then
421445 # if (something has changed since the last unstable) then
422446 # save a new unstable state
423447 # fi
424 # else
448 # else
425449 # save a new unstable state
426450 # fi
427 if [ "`find "$WATCHED_DIR" -cmin "-$TESTING_TIME" |
428 head -1`" = "" ]; then
429 if [ "`find "$WATCHED_DIR" -newer \
430 "$BACKUP_DIR"/testing-latest.tar.bz2 |
431 head -1`" != "" ]; then
451 if no_change_since "$TESTING_TIME"; then
452 debug "no change since TESTING_TIME"
453 if changed_from "$BACKUP_DIR"/testing-latest.tar.bz2; then
454 debug "changed from testing-latest"
432455 report_changes "testing-latest" | email "testing-$DATE"
433456 save_state "testing"
434457 debug "removing all saved unstable states."
435458 find "$BACKUP_DIR" -name 'unstable-*' -exec rm "{}" \;
436 elif [ "`find "$WATCHED_DIR" -ctime "-$STABLE_TIME" |
437 head -1`" = "" ]; then
438 if [ "`find "$WATCHED_DIR" -newer \
439 "$BACKUP_DIR"/stable-latest.tar.bz2 |
440 head -1`" != "" ]; then
459 elif no_change_since "$STABLE_TIME_MIN"; then
460 if changed_from "$BACKUP_DIR"/stable-latest.tar.bz2; then
441461 save_state "stable"
442462 echo "metche saved a new stable state : stable-${DATE}." |
443463 email "stable-$DATE"
447467 -ctime +"$STABLE_TIME" -exec rm "{}" \;
448468 fi
449469 fi
450 exit 0
470 elif milestone_exists unstable-latest; then
471 if changed_from "$BACKUP_DIR"/unstable-latest.tar.bz2; then
472 debug "changed from unstable-latest"
473 save_state "unstable"
474 fi
475 else
476 save_state "unstable"
451477 fi
452 milestone_exists unstable-latest && \
453 {
454 if [ "`find "$WATCHED_DIR" -newer \
455 "$BACKUP_DIR"/unstable-latest.tar.bz2 |
456 head -1`" != "" ]; then
457 save_state "unstable"
458 fi;
459 exit 0;
460 }
461 save_state "unstable"
462478 ;;
463479
464480 stabilize)
465 [ "$MILESTONE" = "" ] && { stabilize_state "testing-latest"; exit 0; }
466 "`milestone_version $MILESTONE`" == "testing" &&
467 milestone_exists $MILESTONE &&
481 if [ -z "$MILESTONE" ]; then
482 stabilize_state "testing-latest"
483 elif [ "`milestone_version $MILESTONE`" = "testing" -a \
484 milestone_exists $MILESTONE ]; then
468485 stabilize_state "$MILESTONE"
469 display_usage
470 fatal "The specified state is not an existing testing state."
471 exit 0
486 else
487 display_usage
488 fatal "The specified state is not an existing testing state."
489 fi
472490 ;;
473491
474492 test)