]> git.decadent.org.uk Git - dak.git/blob - config/debian/dinstall.functions
* config/debian/dinstall.functions: Fix up mklslar a bit
[dak.git] / config / debian / dinstall.functions
1 # -*- mode:sh -*-
2 # Timestamp. Used for dinstall stat graphs
3 function ts() {
4         echo "Archive maintenance timestamp ($1): $(date +%H:%M:%S)"
5 }
6
7 # Remove daily lock
8 function remove_daily_lock() {
9     rm -f $LOCK_DAILY
10 }
11
12 # Remove all locks
13 function remove_all_locks() {
14     rm -f $LOCK_DAILY $LOCK_ACCEPTED $LOCK_NEW
15 }
16
17 # If we error out this one is called, *FOLLOWED* by cleanup above
18 function onerror() {
19     ERRDATE=$(date "+%Y.%m.%d-%H:%M:%S")
20
21     subject="ATTENTION ATTENTION!"
22     if [ "${error}" = "false" ]; then
23         subject="${subject} (continued)"
24     else
25         subject="${subject} (interrupted)"
26     fi
27     subject="${subject} dinstall error at ${ERRDATE} in ${STAGEFILE} - (Be quiet, Brain, or I'll stab you with a Q-tip)"
28
29     if [ -r "${STAGEFILE}.log" ]; then
30         cat "${STAGEFILE}.log"
31     else
32         echo "file ${STAGEFILE}.log does not exist, sorry"
33     fi | mail -s "${subject}" -a "X-Debian: DAK" cron@ftp-master.debian.org -- -F "Debian FTP Masters" -f ftpmaster@ftp-master.debian.org
34 }
35
36 ########################################################################
37 # the actual dinstall functions follow                                 #
38 ########################################################################
39
40 # pushing merkels QA user, part one
41 function qa1() {
42     log "Telling QA user that we start dinstall"
43     ssh -2 -i ~dak/.ssh/push_merkel_qa  -o BatchMode=yes -o SetupTimeOut=90 -o ConnectTimeout=90 qa@qa.debian.org sleep 1
44 }
45
46 # Updating various files
47 function updates() {
48     log "Updating Bugs docu, Mirror list and mailing-lists.txt"
49     cd $configdir
50     $scriptsdir/update-bugdoctxt
51     $scriptsdir/update-mirrorlists
52     $scriptsdir/update-mailingliststxt
53     $scriptsdir/update-pseudopackages.sh
54 }
55
56 # The first i18n one, syncing new descriptions
57 function i18n1() {
58     log "Synchronizing i18n package descriptions"
59     # First sync their newest data
60     cd ${scriptdir}/i18nsync
61     rsync -aq --delete --delete-after ddtp-sync:/does/not/matter . || true
62
63     # Now check if we still know about the packages for which they created the files
64     # is the timestamp signed by us?
65     if $(gpgv --keyring /srv/ftp-master.debian.org/s3kr1t/dot-gnupg/pubring.gpg timestamp.gpg timestamp); then
66         # now read it. As its signed by us we are sure the content is what we expect, no need
67         # to do more here. And we only test -d a directory on it anyway.
68         TSTAMP=$(cat timestamp)
69         # do we have the dir still?
70         if [ -d ${scriptdir}/i18n/${TSTAMP} ]; then
71             # Lets check!
72             if ${scriptsdir}/ddtp-i18n-check.sh . ${scriptdir}/i18n/${TSTAMP}; then
73                 # Yay, worked, lets copy around
74                 for dir in wheezy sid; do
75                     if [ -d dists/${dir}/ ]; then
76                         cd dists/${dir}/main/i18n
77                         rsync -aq --delete --delete-after --exclude Translation-en.bz2 --exclude Translation-*.diff/ . ${ftpdir}/dists/${dir}/main/i18n/.
78                     fi
79                     cd ${scriptdir}/i18nsync
80                 done
81             else
82                 echo "ARRRR, bad guys, wrong files, ARRR"
83                 echo "Arf, Arf, Arf, bad guys, wrong files, arf, arf, arf" | mail -a "X-Debian: DAK" -s "Don't you kids take anything. I'm watching you. I've got eye implants in the back of my head." debian-l10n-devel@lists.alioth.debian.org -- -F "Debian FTP Masters" -f ftpmaster@ftp-master.debian.org
84             fi
85         else
86             echo "ARRRR, missing the timestamp ${TSTAMP} directory, not updating i18n, ARRR"
87             echo "Arf, Arf, Arf, missing the timestamp ${TSTAMP} directory, not updating i18n, arf, arf, arf" | mail -a "X-Debian: DAK" -s "Lisa, if you don't like your job you don't strike. You just go in every day and do it really half-assed. That's the American way." debian-l10n-devel@lists.alioth.debian.org -- -F "Debian FTP Masters" -f ftpmaster@ftp-master.debian.org
88         fi
89     else
90         echo "ARRRRRRR, could not verify our timestamp signature, ARRR. Don't mess with our files, i18n guys, ARRRRR."
91         echo "Arf, Arf, Arf, could not verify our timestamp signature, arf. Don't mess with our files, i18n guys, arf, arf, arf" | mail -a "X-Debian: DAK" -s "You can't keep blaming yourself. Just blame yourself once, and move on." debian-l10n-devel@lists.alioth.debian.org -- -F "Debian FTP Masters" -f ftpmaster@ftp-master.debian.org
92     fi
93 }
94
95 function cruft() {
96     log "Checking for cruft in overrides"
97     dak check-overrides
98 }
99
100 function dominate() {
101     log "Removing obsolete source and binary associations"
102     dak dominate
103 }
104
105 function filelist() {
106     log "Generating file lists for apt-ftparchive"
107     dak generate-filelist
108 }
109
110 function fingerprints() {
111     log "Updating fingerprints"
112     dak import-keyring -L /srv/keyring.debian.org/keyrings/debian-keyring.gpg
113
114     OUTFILE=$(mktemp)
115     dak import-keyring --generate-users "%s" /srv/keyring.debian.org/keyrings/debian-maintainers.gpg >"${OUTFILE}"
116
117     if [ -s "${OUTFILE}" ]; then
118         /usr/sbin/sendmail -odq -oi -t -f envelope@ftp-master.debian.org <<EOF
119 From: Debian FTP Masters <ftpmaster@ftp-master.debian.org>
120 To: <debian-project@lists.debian.org>
121 Subject: Debian Maintainers Keyring changes
122 Content-Type: text/plain; charset=utf-8
123 X-Debian: DAK
124 MIME-Version: 1.0
125
126 The following changes to the debian-maintainers keyring have just been activated:
127
128 $(cat $OUTFILE)
129
130 Debian distribution maintenance software,
131 on behalf of the Keyring maintainers
132
133 EOF
134     fi
135     rm -f "$OUTFILE"
136 }
137
138 function overrides() {
139     log "Writing overrides into text files"
140     cd $overridedir
141     dak make-overrides
142
143     # FIXME
144     rm -f override.sid.all3
145     for i in main contrib non-free main.debian-installer; do cat override.sid.$i >> override.sid.all3; done
146 }
147
148 function mpfm() {
149     log "Generating package / file mapping"
150     dak make-pkg-file-mapping | bzip2 -9 > $base/ftp/indices/package-file.map.bz2
151 }
152
153 function packages() {
154     log "Generating Packages and Sources files"
155     dak generate-packages-sources2
156     dak contents generate
157 }
158
159 function pdiff() {
160     log "Generating pdiff files"
161     dak generate-index-diffs
162 }
163
164 function release() {
165     # XXX: disable once we can remove i18n/Index (#649314)
166     log "Generating i18n/Index"
167     (
168         cd "$ftpdir/dists";
169         for dist in testing unstable experimental proposed-updates testing-proposed-updates; do
170             $scriptsdir/generate-i18n-Index $dist;
171         done
172     )
173     log "Generating Release files"
174     dak generate-releases
175 }
176
177 function dakcleanup() {
178     log "Cleanup old packages/files"
179     dak clean-suites -m 10000
180     dak clean-queues
181 }
182
183 function buildd_dir() {
184     # Rebuilt the buildd dir to avoid long times of 403
185     log "Regenerating the buildd incoming dir"
186     STAMP=$(date "+%Y%m%d%H%M")
187     make_buildd_dir
188 }
189
190 function mklslar() {
191     cd $ftpdir
192
193     FILENAME=ls-lR
194
195     log "Removing any core files ..."
196     find -type f -name core -print -delete
197
198     log "Checking symlinks ..."
199     symlinks -rd .
200
201     log "Creating recursive directory listing ... "
202     rm -f ${FILENAME}.gz
203     TZ=UTC ls -lR | gzip -9c --rsyncable > ${FILENAME}.gz
204 }
205
206 function mkmaintainers() {
207     log 'Creating Maintainers index ... '
208
209     cd $indices
210     dak make-maintainers ${scriptdir}/masterfiles/pseudo-packages.maintainers
211     gzip -9v --rsyncable <Maintainers >Maintainers.gz
212     gzip -9v --rsyncable <Uploaders >Uploaders.gz
213 }
214
215 function copyoverrides() {
216     log 'Copying override files into public view ...'
217
218     for ofile in ${overridedir}/override.{squeeze,wheezy,sid}.{,extra.}{main,contrib,non-free}*; do
219         bname=${ofile##*/}
220         gzip -9cv --rsyncable ${ofile} > ${indices}/${bname}.gz
221         chmod g+w ${indices}/${bname}.gz
222     done
223 }
224
225 function mkfilesindices() {
226     umask 002
227     cd $base/ftp/indices/files/components
228
229     ARCHLIST=$(tempfile)
230
231     log "Querying postgres"
232     local query='SELECT l.path, f.filename, a.arch_string FROM location l JOIN files f ON (f.location = l.id) LEFT OUTER JOIN (binaries b JOIN architecture a ON (b.architecture = a.id)) ON (f.id = b.file)'
233     psql -At -c "$query" | sed 's/|//;s,^/srv/ftp-master.debian.org/ftp,.,' | sort >$ARCHLIST
234
235     includedirs () {
236         perl -ne 'print; while (m,/[^/]+$,) { $_=$`; print $_ . "\n" unless $d{$_}++; }'
237     }
238     poolfirst () {
239         perl -e '@nonpool=(); while (<>) { if (m,^\./pool/,) { print; } else { push @nonpool, $_; } } print for (@nonpool);'
240     }
241
242     log "Generating sources list"
243     (
244         sed -n 's/|$//p' $ARCHLIST
245         cd $base/ftp
246         find ./dists -maxdepth 1 \! -type d
247         find ./dists \! -type d | grep "/source/"
248     ) | sort -u | gzip -9 > source.list.gz
249
250     log "Generating arch lists"
251
252     ARCHES=$( (<$ARCHLIST sed -n 's/^.*|//p'; echo amd64) | grep . | grep -v all | sort -u)
253     for a in $ARCHES; do
254         (sed -n "s/|$a$//p" $ARCHLIST
255             sed -n 's/|all$//p' $ARCHLIST
256
257             cd $base/ftp
258             find ./dists -maxdepth 1 \! -type d
259             find ./dists \! -type d | grep -E "(proposed-updates.*_$a.changes$|/main/disks-$a/|/main/installer-$a/|/Contents-$a|/binary-$a/)"
260         ) | sort -u | gzip -9 > arch-$a.list.gz
261     done
262
263     log "Generating suite lists"
264
265     suite_list () {
266         local query
267         query="$(printf 'SELECT DISTINCT l.path, f.filename FROM (SELECT sa.source AS source FROM src_associations sa WHERE sa.suite = %d UNION SELECT b.source AS source FROM bin_associations ba JOIN binaries b ON (ba.bin = b.id) WHERE ba.suite = %d) s JOIN dsc_files df ON (s.source = df.source) JOIN files f ON (df.file = f.id) JOIN location l ON (f.location = l.id)' $1 $1)"
268         psql -F' ' -A -t -c "$query"
269
270         query="$(printf 'SELECT l.path, f.filename FROM bin_associations ba JOIN binaries b ON (ba.bin = b.id) JOIN files f ON (b.file = f.id) JOIN location l ON (f.location = l.id) WHERE ba.suite = %d' $1)"
271         psql -F' ' -A -t -c "$query"
272     }
273
274     psql -F' ' -At -c "SELECT id, suite_name FROM suite" |
275     while read id suite; do
276         [ -e $base/ftp/dists/$suite ] || continue
277         (
278             (cd $base/ftp
279                 distname=$(cd dists; readlink $suite || echo $suite)
280                 find ./dists/$distname \! -type d
281                 for distdir in ./dists/*; do
282                     [ "$(readlink $distdir)" != "$distname" ] || echo $distdir
283                 done
284             )
285             suite_list $id | tr -d ' ' | sed 's,^/srv/ftp-master.debian.org/ftp,.,'
286         ) | sort -u | gzip -9 > suite-${suite}.list.gz
287     done
288
289     log "Finding everything on the ftp site to generate sundries"
290     (cd $base/ftp; find . \! -type d \! -name 'Archive_Maintenance_In_Progress' | sort) >$ARCHLIST
291
292     rm -f sundries.list
293     zcat *.list.gz | cat - *.list | sort -u |
294     diff - $ARCHLIST | sed -n 's/^> //p' > sundries.list
295
296     log "Generating files list"
297
298     for a in $ARCHES; do
299         (echo ./project/trace; zcat arch-$a.list.gz source.list.gz) |
300         cat - sundries.list dists.list project.list docs.list indices.list |
301         sort -u | poolfirst > ../arch-$a.files
302     done
303
304     (cd $base/ftp/
305             for dist in sid wheezy; do
306                     find ./dists/$dist/main/i18n/ \! -type d | sort -u | gzip -9 > $base/ftp/indices/files/components/translation-$dist.list.gz
307             done
308     )
309
310     (cat ../arch-i386.files ../arch-amd64.files; zcat suite-proposed-updates.list.gz ; zcat translation-sid.list.gz ; zcat translation-wheezy.list.gz) |
311     sort -u | poolfirst > ../typical.files
312
313     rm -f $ARCHLIST
314     log "Done!"
315 }
316
317 function mkchecksums() {
318     dsynclist=$dbdir/dsync.list
319     md5list=$indices/md5sums
320
321     log -n "Creating md5 / dsync index file ... "
322
323     cd "$ftpdir"
324     ${bindir}/dsync-flist -q generate $dsynclist --exclude $dsynclist --md5
325     ${bindir}/dsync-flist -q md5sums $dsynclist | gzip -9n > ${md5list}.gz
326     ${bindir}/dsync-flist -q link-dups $dsynclist || true
327 }
328
329 function mirror() {
330     log "Regenerating \"public\" mirror/ hardlink fun"
331     DATE_SERIAL=$(date +"%Y%m%d01")
332     FILESOAPLUS1=$(awk '/serial/ { print $3+1 }' ${TRACEFILE} )
333     if [ "$DATE_SERIAL" -gt "$FILESOAPLUS1" ]; then
334         SERIAL="$DATE_SERIAL"
335     else
336         SERIAL="$FILESOAPLUS1"
337     fi
338     date -u > ${TRACEFILE}
339     echo "Using dak v1" >> ${TRACEFILE}
340     echo "Running on host: $(hostname -f)" >> ${TRACEFILE}
341     echo "Archive serial: ${SERIAL}" >> ${TRACEFILE}
342     cd ${mirrordir}
343     rsync -aH --link-dest ${ftpdir} --delete --delete-after --delete-excluded --exclude Packages.*.new --exclude Sources.*.new  --ignore-errors ${ftpdir}/. .
344 }
345
346 function expire() {
347     log "Expiring old database dumps..."
348     cd $base/backup
349     $scriptsdir/expire_dumps -d . -p -f "dump_*"
350 }
351
352 function transitionsclean() {
353     log "Removing out of date transitions..."
354     cd $base
355     dak transitions -c -a
356 }
357
358 function dm() {
359     log "Updating DM html page"
360     $scriptsdir/dm-monitor >$webdir/dm-uploaders.html
361 }
362
363 function bts() {
364     log "Categorizing uncategorized bugs filed against ftp.debian.org"
365     dak bts-categorize
366 }
367
368 function ddaccess() {
369     # Tell our dd accessible mirror to sync itself up. Including ftp dir.
370     log "Trigger dd accessible parts sync including ftp dir"
371     ssh -o Batchmode=yes -o ConnectTimeout=30 -o SetupTimeout=30 -2 -i ${base}/s3kr1t/pushddmirror dak@ries.debian.org pool
372 }
373
374 function mirrorpush() {
375     log "Checking the public archive copy"
376     cd ${mirrordir}/dists
377
378     broken=0
379     for release in $(find . -name "InRelease"); do
380         echo "Processing: ${release}"
381         subdir=${release%/InRelease}
382         while read SHASUM SIZE NAME; do
383             if ! [ -f "${subdir}/${NAME}" ]; then
384                bname=$(basename ${NAME})
385                 if [[ "${bname}" =~ ^(Packages|Sources|Translation-[a-zA-Z_]+)$ ]]; then
386                     # We don't keep unpacked files, don't check for their existance.
387                     # We might want to go and check their unpacked shasum, but right now
388                     # I don't care. I believe it should be enough if all the packed shasums
389                     # match.
390                     continue
391                 fi
392                 broken=$(( broken + 1 ))
393                 echo "File ${subdir}/${NAME} is missing"
394                 continue
395             fi
396
397            # We do have symlinks in the tree (see the contents files currently).
398            # So we use "readlink -f" to check the size of the target, as thats basically
399            # what gen-releases does
400             fsize=$(stat -c %s $(readlink -f "${subdir}/${NAME}"))
401             if [ ${fsize} -ne ${SIZE} ]; then
402                 broken=$(( broken + 1 ))
403                 echo "File ${subdir}/${NAME} has size ${fsize}, expected is ${SIZE}"
404                 continue
405             fi
406
407             fshasum=$(sha1sum $(readlink -f "${subdir}/${NAME}"))
408             fshasum=${fshasum%% *}
409             if [ "${fshasum}" != "${SHASUM}" ]; then
410                 broken=$(( broken + 1 ))
411                 echo "File ${subdir}/${NAME} has checksum ${fshasum}, expected is ${SHASUM}"
412                 continue
413             fi
414         done < <(sed '1,/SHA1:/d' "${release}" | sed '/SHA256:/,$d')
415     done
416
417     if [ $broken -gt 0 ]; then
418         log_error "Trouble with the public mirror, found ${broken} errors"
419         return 21
420     fi
421
422     log "Starting the mirrorpush"
423     date -u > /srv/ftp.debian.org/web/mirrorstart
424     echo "Using dak v1" >> /srv/ftp.debian.org/web/mirrorstart
425     echo "Running on host $(hostname -f)" >> /srv/ftp.debian.org/web/mirrorstart
426     sudo -H -u archvsync /home/archvsync/runmirrors > ~dak/runmirrors.log 2>&1 &
427 }
428
429 function i18n2() {
430     log "Exporting package data foo for i18n project"
431     STAMP=$(date "+%Y%m%d%H%M")
432     mkdir -p ${scriptdir}/i18n/${STAMP}
433     cd ${scriptdir}/i18n/${STAMP}
434     for suite in stable testing unstable; do
435         codename=$(dak admin s show ${suite}|grep '^Codename')
436         codename=${codename##* }
437         echo "Codename is ${codename}"
438         dak control-suite -l ${suite} >${codename}
439     done
440     echo "${STAMP}" > timestamp
441     gpg --secret-keyring /srv/ftp-master.debian.org/s3kr1t/dot-gnupg/secring.gpg --keyring /srv/ftp-master.debian.org/s3kr1t/dot-gnupg/pubring.gpg --no-options --batch --no-tty --armour --default-key 55BE302B --detach-sign -o timestamp.gpg timestamp
442     rm -f md5sum
443     md5sum * > md5sum
444     cd ${webdir}/
445     ln -sfT ${scriptdir}/i18n/${STAMP} i18n
446
447     cd ${scriptdir}
448     find ./i18n -mindepth 1 -maxdepth 1 -mtime +2 -not -name "${STAMP}" -type d -print0 | xargs --no-run-if-empty -0 rm -rf
449 }
450
451 function stats() {
452     log "Updating stats data"
453     cd $configdir
454     $scriptsdir/update-ftpstats $base/log/* > $base/misc/ftpstats.data
455     R --slave --vanilla < $base/misc/ftpstats.R
456     dak stats arch-space > $webdir/arch-space
457     dak stats pkg-nums > $webdir/pkg-nums
458 }
459
460 function aptftpcleanup() {
461     log "Clean up apt-ftparchive's databases"
462     cd $configdir
463     apt-ftparchive -q clean apt.conf
464 }
465
466 function cleantransactions() {
467     log "Cleanup transaction ids older than 3 months"
468     cd $base/backup/
469     find -maxdepth 1 -mindepth 1 -type f -name 'txid_*' -mtime +90 -print0 | xargs -0 --no-run-if-empty rm
470 }
471
472 function logstats() {
473     $masterdir/tools/logs.py "$1"
474 }
475
476 # save timestamp when we start
477 function savetimestamp() {
478         NOW=`date "+%Y.%m.%d-%H:%M:%S"`
479         echo ${NOW} > "${dbdir}/dinstallstart"
480 }
481
482 function maillogfile() {
483     cat "$LOGFILE" | mail -a "X-Debian: DAK" -s "Log for dinstall run of ${NOW}" cron@ftp-master.debian.org -- -F "Debian FTP Masters" -f ftpmaster@ftp-master.debian.org
484 }
485
486 function renamelogfile() {
487     if [ -f "${dbdir}/dinstallstart" ]; then
488         NOW=$(cat "${dbdir}/dinstallstart")
489 #        maillogfile
490         mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
491         logstats "$logdir/dinstall_${NOW}.log"
492         bzip2 -9 "$logdir/dinstall_${NOW}.log"
493     else
494         error "Problem, I don't know when dinstall started, unable to do log statistics."
495         NOW=`date "+%Y.%m.%d-%H:%M:%S"`
496 #        maillogfile
497         mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
498         bzip2 -9 "$logdir/dinstall_${NOW}.log"
499     fi
500 }
501
502 function testingsourcelist() {
503     dak ls -s testing -f heidi -r .| egrep 'source$' > ${webdir}/testing.list
504 }
505
506 # do a last run of process-unchecked before dinstall is on.
507 function process_unchecked() {
508     log "Processing the unchecked queue"
509     UNCHECKED_WITHOUT_LOCK="-p"
510     do_unchecked
511     sync_debbugs
512 }
513
514 # do a run of newstage only before dinstall is on.
515 function newstage() {
516     log "Processing the newstage queue"
517     UNCHECKED_WITHOUT_LOCK="-p"
518     do_newstage
519 }
520
521 # Function to update a "statefile" telling people what we are doing
522 # (more or less).
523 #
524 # This should be called with the argument(s)
525 #  - Status name we want to show.
526 #
527 function state() {
528     RIGHTNOW="$(date -u +"%a %b %d %T %Z %Y (%s)")"
529     cat >"${DINSTALLSTATE}" <<EOF
530 Dinstall start: ${DINSTALLBEGIN}
531 Current action: ${1}
532 Action start: ${RIGHTNOW}
533 EOF
534 }
535
536 # extract changelogs and stuff
537 function changelogs() {
538     log "Extracting changelogs"
539     dak make-changelog -e
540     mkdir -p ${exportpublic}/changelogs
541     cd ${exportpublic}/changelogs
542     rsync -aHW --delete --delete-after --ignore-errors ${exportdir}/changelogs/. .
543     sudo -H -u archvsync /home/archvsync/runmirrors metaftpdo > ~dak/runmirrors-metadata.log 2>&1 &
544 }
545
546 function gitpdiff() {
547     # Might be that we want to change this to have more than one git repository.
548     # Advantage of one is that we do not need much space in terms of storage in git itself,
549     # git gc is pretty good on our input.
550     # But it might be faster. Well, lets test.
551     log "Adjusting the git tree for pdiffs"
552     cd ${dbdir}/git/git/
553
554     # The regex needs the architectures seperated with \|
555     garchs=$(dak admin a list|sed -e ':q;N;s/\n/\\|/g;t q')
556
557     # First, get all the files we want to work on. ../dists/ is a symlink to the real dists/ we
558     # want to work with.
559     # Also, we only want contents, packages and sources.
560     for file in $(find ../dists/ -regex ".*/\(Contents-\($archs\)\|\(Packages\|Sources\)\).gz"); do
561         log "${file}"
562         basen=${file%%.gz};
563         basen=${basen##../};
564         dir=${basen%/*};
565         mkdir -p $dir;
566         zcat $file > $basen;
567     done
568
569     # Second, add all there is into git
570     cd dists
571     git add .
572     # Maybe we want to make this the same for tag and commit? But well, shouldn't matter
573     COMD=$(date  -Is)
574     TAGD=$(date +%Y-%m-%d-%H-%M)
575     git commit -m "Commit of ${COMD}"
576     git tag "${TAGD}"
577  }