update from MirBSD CVS
[shellsnippets/shellsnippets.git] / mksh / sysadmin / vcs2deb
1 #!/bin/mksh
2 # $Id: vcs2deb 3196 2012-09-23 15:43:52Z tglase $
3 # $MirOS: contrib/hosted/tg/deb/BuildDSC.sh,v 1.14 2011/11/17 15:27:53 tg Exp $
4 #-
5 # Copyright (c) 2010, 2011, 2012
6 #       Thorsten Glaser <t.glaser@tarent.de>
7 #
8 # Provided that these terms and disclaimer and all copyright notices
9 # are retained or reproduced in an accompanying document, permission
10 # is granted to deal in this work without restriction, including un-
11 # limited rights to use, publicly perform, distribute, sell, modify,
12 # merge, give away, or sublicence.
13 #
14 # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15 # the utmost extent permitted by applicable law, neither express nor
16 # implied; without malicious intent or gross negligence. In no event
17 # may a licensor, author or contributor be held liable for indirect,
18 # direct, other damage, loss, or other issues arising in any way out
19 # of dealing in the work, even if advised of the possibility of such
20 # damage or existence of a defect, except proven that it results out
21 # of said person's immediate fault when using the work as intended.
22 #-
23 # root@dev-hudson:/usr/local/bin/vcs2deb
24 #
25 # This wants two checkboxen ENABLE_UPLOAD and VERSION_AS_SNAPSHOT in
26 # Jenkins ("parametrized build"). Example usage:
27 # vcs2deb -b lenny-backports -r 'deb foo main' -r 'deb bar tarent' \
28 #     -o -sa -o -m'Dev Jenkins <buildd@domain.de>' -j portal-setup \
29 #     -d squeeze -s main -O [http:/]/path/to/foo-1.2.3.orig.tar.xz \
30 #     -X junk -T HEAD :ext:anoncvs@server.com:/cvs src/modulename
31 # These arguments are passed to the scripts as follows:
32 # * kuhbauer [-r {r*}] {b} *.dsc [{o*}]
33 # * mvndput {j} {d} {s} *.changes (if ENABLE_UPLOAD)
34
35 # sanitise environment
36 unset LANGUAGE
37 export LC_ALL=C
38 wd=$(realpath .)
39 cd "$wd"
40
41 usage() { cat <<EOF
42 Syntax: $0 -b DIST [-r aptrepo [-r ...]] [-o debbuiltopt [-o ...]]
43         -j jobname -d targetdistribution -s targetsuite
44         [-O [http:/]/path/to/origtgz] [-T tag] [-X junk [-X ...]] scmpath
45 Tags: cvs (tag/branch[:date]), git (branch), bzr (revisionspec), hg (idem)
46 Knobs: ENABLE_UPLOAD, VERSION_AS_SNAPSHOT
47 Environment: DEBEMAIL (for snapshots)
48 EOF
49         exit ${1:-1}
50 }
51
52 # preload
53 sync
54 date >/dev/null
55 stime_rfc=$(date +"%a, %d %b %Y %H:%M:%S %z")
56 stime_vsn=$(date -u +"%Y%m%d.%H%M%S")
57
58 [[ $VERSION_AS_SNAPSHOT != true ]]; snap=$?
59 [[ $ENABLE_UPLOAD != true ]]; dodput=$?
60
61 if (( snap )) && [[ -z $DEBEMAIL ]]; then
62         print -u2 'Please set $DEBEMAIL to "First M. Last <email@domain.com>"'
63         usage
64 fi
65
66 DIST=
67 targdist=
68 jobname=
69 origtgz=
70 set -A dbo
71 xrepo=
72 targsuite=
73 scmtag=
74 set -A excludefiles
75 while getopts 'b:d:hj:O:o:r:s:T:X:' ch; do
76         case $ch {
77         (b)     DIST=$OPTARG ;;
78         (d)     targdist=$OPTARG ;;
79         (h)     usage 0 ;;
80         (j)     jobname=$OPTARG ;;
81         (O)     origtgz=$OPTARG ;;
82         (o)     dbo[${#dbo[*]}]=$OPTARG ;;
83         (r)     xrepo="${xrepo}|$OPTARG" ;;
84         (s)     targsuite=$OPTARG ;;
85         (T)     scmtag=$OPTARG ;;
86         (X)     excludefiles[${#excludefiles[*]}]=$OPTARG ;;
87         (*)     usage ;;
88         }
89 done
90 shift $((OPTIND - 1))
91
92 [[ -n $1 ]] || usage
93 scmrepo=$1
94 shift
95 case $scmrepo {
96 (:ext:*|:extssh:*|:pserver:*)
97         scmtype=cvs
98         ;;
99 (svn://*|svn+ssh://*)
100         scmtype=svn
101         ;;
102 (git://*)
103         scmtype=git
104         ;;
105 (@(cvs|svn|git|bzr|hg),*)
106         scmtype=${scmrepo%%,*}
107         scmrepo=${scmrepo#*,}
108         ;;
109 (*)
110         print -u2 "Invalid SCM repository '$scmrepo'"
111         print -u2 "Valid are CVS (ext/pserver), Subversion (svn, svn+ssh), git,"
112         print -u2 "or specifying the name of the SCM (cvs, svn, git, bzr, hg)"
113         print -u2 "followed by a comma before the repository identifier."
114         usage
115         ;;
116 }
117 case $scmtype {
118 (cvs)
119         scmmodule=$1
120         i=1
121         ;;
122 (svn)
123         i=0
124         if [[ -n $scmtag ]]; then
125                 print -u2 "Subversion does not support tags or branches."
126                 usage
127         fi
128         ;;
129 (git|bzr|hg)
130         i=0
131         ;;
132 }
133 if (( $# != i )); then
134         print -u2 "Invalid syntax. The first non-option argument must be the"
135         print -u2 "SCM repository identifier. For CVS, another argument must"
136         print -u2 "be passed to specify the module. No further arguments are"
137         print -u2 "permitted."
138         usage
139 fi
140
141 if [[ $DIST != @(sarge|etch|lenny|squeeze|wheezy|jessie|sid|dapper|hardy|karmic|lucid|maverick|natty|oneiric|precise)?(-backports?(-sloppy))?(/i386) ]]; then
142         print -u2 "Missing -b option, which is mandatory, or invalid value '$DIST'"
143         usage
144 fi
145 if [[ -z $targdist ]]; then
146         print -u2 "Missing -d option, which is mandatory"
147         usage
148 fi
149 if [[ -z $jobname ]]; then
150         print -u2 "Missing -j option, which is mandatory"
151         usage
152 fi
153 if [[ -z $targsuite ]]; then
154         print -u2 "Missing -s option, which is mandatory"
155         usage
156 fi
157
158 if [[ $DIST = */i386 && $(uname -m) != x86_64 ]]; then
159         print -ru2 "The -b option indicates using an i386 chroot on an amd64"
160         print -ru2 "system, but this is a '$(uname -m)' system."
161         exit 1
162 fi
163
164 if ! T=$(mktemp -d "$wd/vcs2deb.XXXXXXXXXX"); then
165         print -u2 Cannot create temporary directory.
166         exit 255
167 fi
168
169 cd "$T"
170
171 haspipe=0
172 hascmd2=0
173 case $scmtype {
174 (cvs)
175         export CVS_RSH=ssh
176         [[ -n $scmtag ]] || scmtag=HEAD
177         set -A cmd -- cvs -qz3 -d "$scmrepo" export -r"$scmtag" -dwc \
178             "$scmmodule"
179         ;;
180 (svn)
181         set -A cmd -- svn export "$scmrepo" wc
182         ;;
183 (git)
184         set -A cmd -- git archive --format=tar --prefix=wc/ \
185             --remote="$scmrepo" "${scmtag:-master}"
186         set -A cmdpipe -- tar -xvf -
187         # I hate git.
188         haspipe=1
189         # I hate GNU.
190         set -A cmd2 -- rm -f wc/pax_global_header
191         hascmd2=1
192         ;;
193 (bzr)
194         set -A cmd -- bzr export --format=dir
195         if [[ -n $scmtag ]]; then
196                 cmd[${#cmd[*]}]=-r
197                 cmd[${#cmd[*]}]=$scmtag
198         fi
199         cmd[${#cmd[*]}]=wc
200         cmd[${#cmd[*]}]=$scmrepo
201         ;;
202 (hg)
203         # Oh, now this is just too funny. NOT.
204         set -A cmd -- hg clone
205         if [[ -n $scmtag ]]; then
206                 cmd[${#cmd[*]}]=-r
207                 cmd[${#cmd[*]}]=$scmtag
208         fi
209         cmd[${#cmd[*]}]=wc
210         cmd[${#cmd[*]}]=$scmrepo
211         set -A cmd2 -- rm -rf wc/.hg
212         hascmd2=1
213         ;;
214 }
215
216 print -n +
217 for arg in "${cmd[@]}"; do
218         print -nr -- " '${arg//\'/\'\\\'\'}'"
219 done
220 if (( haspipe )); then
221         print -n " |"
222         for arg in "${cmdpipe[@]}"; do
223                 print -nr -- " '${arg//\'/\'\\\'\'}'"
224         done
225         print
226         "${cmd[@]}" | "${cmdpipe[@]}"
227 else
228         print
229         "${cmd[@]}"
230 fi
231 if (( hascmd2 )); then
232         print -n +
233         for arg in "${cmd2[@]}"; do
234                 print -nr -- " '${arg//\'/\'\\\'\'}'"
235         done
236         print
237         "${cmd2[@]}"
238 fi
239 # instead of an errorlevel check…
240 if [[ ! -d wc/debian/. ]]; then
241         print -u2 Checkout failed.
242         cd "$wd"
243         rm -rf "$T"
244         exit 1
245 fi
246
247 if [[ -n $origtgz ]]; then
248         if [[ $origtgz = /* ]]; then
249                 cp "$origtgz" .
250         else
251                 wget -qO "${origtgz##*/}" "$origtgz"
252         fi
253         origtgz=${origtgz##*/}
254         if [[ ! -s $origtgz ]]; then
255                 print -u2 Download of .orig.tar.gz failed.
256                 cd "$wd"
257                 rm -rf "$T"
258                 exit 1
259         fi
260 fi
261
262 cd wc
263
264 rmc=0
265 while :; do
266         dh_testdir >/dev/null 2>&1 && break
267         if [[ -s debian/control.in && -s debian/rules && \
268             -x debian/rules && ! -e debian/control ]]; then
269                 rmc=1
270                 debian/rules debian/control
271         fi
272         dh_testdir >/dev/null 2>&1 && break
273         ls -l
274         ls -l debian/
275         print -u2 Checkout is not a Debian source package.
276         cd "$wd"
277         rm -rf "$T"
278         exit 1
279 done
280 wc=$(realpath .)
281 for i in "${excludefiles[@]}"; do
282         i=$(realpath "$i")
283         [[ $i = "$wc"/* && -e $i ]] || continue
284         echo "Nuking \"$i\"..."
285         rm -rf "$i"
286 done
287 pkgstem=$(dpkg-parsechangelog -n1 | sed -n '/^Source: /s///p')
288 version=$(dpkg-parsechangelog -n1 | sed -n '/^Version: /s///p')
289 if [[ -z $origtgz && $version = *-* ]]; then
290         # Policy v3.9.2.0 §5.6.12
291         print -u2 "Debian native packages MUST NOT contain a dash in their"
292         print -u2 "version number ($version)."
293         cd "$wd"
294         rm -rf "$T"
295         exit 1
296 fi
297 if (( snap )); then
298         updir=$(cd ..; pwd)
299         dist=$(dpkg-parsechangelog -n1 | sed -n '/^Distribution: /s///p')
300         ssuf=snapshot.$stime_vsn
301         if [[ $dist = UNRELEASED || $dist = x* ]]; then
302                 # we’re at “current” already, reduce
303                 version=$version'~'$ssuf
304         else
305                 # we’re at an uploaded version, raise
306                 version=$version'+'$ssuf
307         fi
308         print "$pkgstem ($version) UNRELEASED; urgency=low\n\n  *" \
309             "Automatically built snapshot (not backport) package.\n\n --" \
310             "$DEBEMAIL  $stime_rfc\n" >debian/changelog~
311         cat debian/changelog >>debian/changelog~
312         mv -f debian/changelog~ debian/changelog
313         if (( rmc )); then
314                 rm -f debian/control
315                 debian/rules debian/control
316         fi
317 fi
318 upstreamversion=${version%%-*([!-])}
319 upstreamversion=${upstreamversion#+([0-9]):}
320
321 cd ..
322
323 [[ -n $origtgz ]] && \
324     if [[ $origtgz != ${pkgstem}_$upstreamversion.orig.tar.@(gz|bz2|lzma|xz) ]]; then
325         print -u2 "Invalid name: $origtgz"
326         print -u2 "Expecting: ${pkgstem}_$upstreamversion.orig.tar.*"
327         cd "$wd"
328         rm -rf "$T"
329         exit 1
330 fi
331
332 newname=$pkgstem-$upstreamversion
333 mv wc "$newname"
334 cd "$newname"
335 dpkg-buildpackage -d -rfakeroot -S -us -uc
336 rv=$?
337 cd ..
338 if (( rv )) || [[ ! -s ${pkgstem}_${version##+([0-9]):}.dsc || \
339     ! -s ${pkgstem}_${version##+([0-9]):}_source.changes ]]; then
340         ls -l
341         print -u2 "Error $rv creating the .dsc"
342         cd "$wd"
343         rm -rf "$T"
344         exit 1
345 fi
346 rm -f ${pkgstem}_${version##+([0-9]):}_source.changes
347
348 # * kuhbauer [-r {r*}] {b} *.dsc [{o*}]
349 set -A cmd -- sudo /usr/local/bin/kuhbauer
350 (( snap )) && cmd[${#cmd[*]}]=-S
351 if [[ -n $xrepo ]]; then
352         cmd[${#cmd[*]}]=-r
353         cmd[${#cmd[*]}]=${xrepo#'|'}
354 fi
355 cmd[${#cmd[*]}]=$DIST
356 cmd[${#cmd[*]}]=${pkgstem}_${version##+([0-9]):}.dsc
357 print -n +
358 for arg in "${cmd[@]}" "${dbo[@]}"; do
359         print -nr -- " '${arg//\'/\'\\\'\'}'"
360 done
361 print
362 "${cmd[@]}" "${dbo[@]}"
363 rv=$?
364 cp *.holzscheit "$wd/"
365 found=
366 for f in ${pkgstem}_${version##+([0-9]):}_*.changes; do
367         [[ -s $f ]] && found=$f
368         break
369 done
370 if (( rv )) || [[ -z $found ]]; then
371         ls -l
372         print -u2 "Error $rv during build"
373         cd "$wd"
374         rm -rf "$T"
375         exit 1
376 fi
377
378 if (( dodput )); then
379         /opt/mvn-debs/mvndput.sh "$jobname" "$targdist" "$targsuite" "$found"
380         rv=$?
381         if (( rv )); then
382                 print -u2 "Error $rv during repository upload"
383                 cd "$wd"
384                 rm -rf "$T"
385                 exit 1
386         fi
387 fi
388
389 cat >tmpcf <<-EOF
390         [tmpdp]
391         method = local
392         allow_unsigned_uploads = 1
393         incoming = $wd
394 EOF
395 rm -f *.upload
396 dput -c tmpcf tmpdp $found
397 rv=$?
398 if (( rv )); then
399         print -u2 "Error during result move, NOT cleaning up: $T"
400         exit 1
401 fi
402 print -u2 Cleaning up...
403 cd "$wd"
404 rm -rf "$T"
405 exit 0