4
# Publishing a release is a bit more complicated than publishing a daily. We
5
# have two trees: simple and full. The simple tree is intended for smaller
6
# mirrors and for ease of use by naïve end users. It contains a pool of
7
# images and a tree per release of symlinks into that pool with filenames
8
# that include the status of the image (e.g. preview, sounder-9, release).
10
# The full tree contains everything except the releases that are in the
11
# simple tree (so in practice it contains alpha/beta releases), and has a
12
# more complicated structure that ordinary users ultimately shouldn't have
13
# to pay too much attention to.
15
# Releases are always published based on a daily build. Nominate the version
18
export CDIMAGE_ROOT="${CDIMAGE_ROOT:-/srv/cdimage.ubuntu.com}"
19
. "$CDIMAGE_ROOT/etc/config"
21
if [ -z "$1" ] || [ -z "$2" ]; then
22
echo 'Usage: publish-release [--dry-run] DAILY-SOURCE DAILY-DATE TYPE OFFICIAL [STATUS]' >&2
23
echo 'OFFICIAL=yes to publish to releases.ubuntu.com, poolonly to pre-publish,' >&2
24
echo 'named to publish to cdimage.ubuntu.com as $PROJECT-$VERSION-*, otherwise no.' >&2
28
# TODO: proper option parsing
29
if [ "x$1" = x--dry-run ]; then
43
SOURCE="${SOURCE%/source}"
45
# Publish ports/daily to ports/releases/..., etc.
48
source_tail="${SOURCE#ubuntu-server/}"
49
TREE_SUFFIX="/${source_tail%%/*}"
52
source_tail="${SOURCE#ubuntu-netbook/}"
53
TREE_SUFFIX="/${source_tail%%/*}"
56
source_tail="${SOURCE#ubuntu-headless/}"
57
TREE_SUFFIX="/${source_tail%%/*}"
59
ubuntu-server/*|ubuntu-netbook/*|ubuntu-mid/*|ubuntu-headless/*)
63
TREE_SUFFIX="/${SOURCE%%/*}"
73
SIMPLE_TREE="simple$TREE_SUFFIX"
74
FULL_TREE="full$TREE_SUFFIX"
75
TORRENT_TREE="torrent$TREE_SUFFIX"
79
DAILY_TREE="full/$PROJECT"
80
SIMPLE_TREE="simple/$PROJECT$TREE_SUFFIX"
81
FULL_TREE="full/$PROJECT$TREE_SUFFIX"
82
TORRENT_TREE="torrent/$PROJECT$TREE_SUFFIX"
83
RELDIR="$PROJECT$TREE_SUFFIX"
89
netbook|mid|moblin-remix|uec|server-uec|preinstalled-*)
92
# TODO: maybe others? metalink is only supported for Wubi
151
echo "Unknown distribution: $DIST" >&2
156
# "beta-2" should end up in directories named "beta-2", but with filenames
157
# including "beta2" (otherwise we get hyphen overload).
163
FILESTATUS="$(echo "$STATUS" | sed 's/-//g')"
167
CDPREFIX="$PROJECT-$VERSION"
174
CDPREFIX="$PROJECT-$VERSION"
180
CDPREFIX="$PROJECT-$VERSION"
186
CDPREFIX="$PROJECT-$VERSION${FILESTATUS:+-$FILESTATUS}"
195
# Just to make sure ...
196
if $PUBLISH_DIST; then
200
if [ "$DIST" != "${ALL_DISTS##* }" ]; then
201
SOURCE="$DIST/$SOURCE"
202
if [ "$SOURCE" = "$DIST/ubuntu-server/daily" ]; then
203
SOURCE="ubuntu-server/$DIST/daily"
207
DAILY="$CDIMAGE_ROOT/www/$DAILY_TREE/$SOURCE/$DATE"
208
if [ ! -d "$DAILY" ] && [ "${DATE#*/}" != "$DATE" ]; then
209
if [ -d "$CDIMAGE_ROOT/www/full/$DATE" ]; then
210
DAILY="$CDIMAGE_ROOT/www/full/$DATE"
213
RELEASE_FULL="$CDIMAGE_ROOT/www/$FULL_TREE/releases/$DIST/${STATUS:-release}"
214
RELEASE_SIMPLE_POOL="$CDIMAGE_ROOT/www/$SIMPLE_TREE/.pool"
215
RELEASE_SIMPLE_DIST="$CDIMAGE_ROOT/www/$SIMPLE_TREE/$DIST"
216
RELEASE_SIMPLE_BASEDIR="$CDIMAGE_ROOT/www/simple"
217
RELEASE_SIMPLE_RELDIR="${RELDIR:+$RELDIR/}$DIST"
218
RELEASE_FULL_BASEDIR="$CDIMAGE_ROOT/www/full"
219
if [ "$OFFICIAL" = "named" ]; then
220
RELEASE_FULL_RELDIR="${RELDIR:+$RELDIR/}releases/$VERSION/${STATUS:-release}"
222
RELEASE_FULL_RELDIR="${RELDIR:+$RELDIR/}releases/$DIST/${STATUS:-release}"
225
DIST_TO_POOL=../.pool
229
RELEASE_FULL="$RELEASE_FULL/unpacked"
235
DAILY="$DAILY/source"
236
RELEASE_FULL="$RELEASE_FULL/source"
237
RELEASE_SIMPLE_DIST="$RELEASE_SIMPLE_DIST/source"
238
DIST_TO_POOL=../../.pool
241
if [ ! -e "$DAILY/$DIST-$TYPE-1.iso" ]; then
242
echo "No source daily for $DIST on $DATE!" >&2
246
# Perverse, but works.
247
ARCHES="$(find "$DAILY" -name "$DIST-$TYPE-*.iso" \
249
sed "s/$DIST-$TYPE-\\(.*\\)\\.iso/\\1/")"
253
# override the arch list for these types unconditionally
255
netbook|moblin-remix)
270
if [ "$TYPE" != netbook ] && [ "$TYPE" != mid ]; then
271
for arch in $ARCHES; do
272
if [ ! -e "$DAILY/$DIST-$TYPE-$arch.iso" ] && \
273
[ ! -e "$DAILY/$DIST-$TYPE-$arch.img" ] && \
274
[ ! -e "$DAILY/$DIST-$TYPE-$arch.img.gz" ] && \
275
[ ! -e "$DAILY/$DIST-$TYPE-$arch.img.tar.gz" ] && \
276
[ ! -e "$DAILY/$DIST-$TYPE-$arch.tar.gz" ] && \
277
[ ! -e "$DAILY/$arch.tar.xz" ]; then
278
echo "No daily for $DIST $arch on $DATE!" >&2
282
if [ -e "$DAILY/$DIST-$TYPE-$arch.OVERSIZED" ]; then
283
printf 'Daily for %s %s on %s is oversized! Continue?' \
284
"$DIST" "$arch" "$DATE"
290
if $PUBLISH_POOL; then
291
$echo mkdir -p "$RELEASE_SIMPLE_POOL"
293
if $PUBLISH_DIST; then
294
$echo mkdir -p "$RELEASE_SIMPLE_DIST"
295
if [ ! -h "$CDIMAGE_ROOT/www/$SIMPLE_TREE/$VERSION" ]; then
296
$echo ln -ns "$DIST" "$CDIMAGE_ROOT/www/$SIMPLE_TREE/$VERSION"
298
if [ -z "$CDIMAGE_NO_PURGE" ]; then
299
find "$RELEASE_SIMPLE_DIST/" -name "$CDPREFIX-$TYPE-*" -type l -print0 | xargs -0r $echo rm -f
302
if $PUBLISH_FULL; then
303
$echo mkdir -p "$RELEASE_FULL"
304
if [ ! -h "$CDIMAGE_ROOT/www/$FULL_TREE/releases/$VERSION" ]; then
305
$echo ln -ns "$DIST" "$CDIMAGE_ROOT/www/$FULL_TREE/releases/$VERSION"
309
echo "Constructing release trees ..."
311
for arch in $ARCHES; do
314
if dist_le intrepid; then
315
base="$DAILY/$PROJECT-$TYPE"
317
base="$DAILY/$DIST-$TYPE-$arch"
324
base="$DAILY/$DIST-$TYPE-$arch"
328
echo "Copying $TYPE-$arch image ..."
330
baseplain="$CDPREFIX-$TYPE-$arch"
331
basestatus="$CDPREFIX-${FILESTATUS:+$FILESTATUS-}$TYPE-$arch"
333
if [ ! -e "$base.iso" ] && \
334
[ ! -e "$base.img" ] && \
335
[ ! -e "$base.img.gz" ] && \
336
[ ! -e "$base.tar.gz" ] && \
337
[ ! -e "$base.img.tar.gz" ] && \
338
[ ! -e "$base.tar.xz" ]; then
342
# Copy, to make sure we have a canonical version of this.
343
for ext in iso list img img.gz img.tar.gz tar.gz tar.xz bootimg; do
344
if [ ! -e "$base.$ext" ]; then
347
if $PUBLISH_POOL; then
348
$echo cp -a "$base.$ext" \
349
"$RELEASE_SIMPLE_POOL/$basestatus.$ext"
350
$echo checksum-remove --no-sign \
351
"$RELEASE_SIMPLE_POOL" "$basestatus.$ext"
353
if $PUBLISH_DIST; then
354
$echo ln -sf "$DIST_TO_POOL/$basestatus.$ext" \
355
"$RELEASE_SIMPLE_DIST/$basestatus.$ext"
356
$echo checksum-remove --no-sign \
357
"$RELEASE_SIMPLE_DIST" "$basestatus.$ext"
359
if $PUBLISH_FULL; then
360
$echo cp -a "$base.$ext" \
361
"$RELEASE_FULL/$baseplain.$ext"
362
$echo checksum-remove --no-sign \
363
"$RELEASE_FULL" "$baseplain.$ext"
367
for ext in initrd-ec2 initrd-virtual vmlinuz-ec2 vmlinuz-virtual; do
368
if [ ! -e "${base}-$ext" ]; then
371
if $PUBLISH_POOL; then
372
$echo cp -a "${base}-$ext" \
373
"$RELEASE_SIMPLE_POOL/${basestatus}-$ext"
374
$echo checksum-remove --no-sign \
375
"$RELEASE_SIMPLE_POOL" "${basestatus}-$ext"
377
if $PUBLISH_DIST; then
378
$echo ln -sf "$DIST_TO_POOL/${basestatus}-$ext" \
379
"$RELEASE_SIMPLE_DIST/${basestatus}-$ext"
380
$echo checksum-remove --no-sign \
381
"$RELEASE_SIMPLE_DIST" "${basestatus}-$ext"
383
if $PUBLISH_FULL; then
384
$echo cp -a "${base}-$ext" \
385
"$RELEASE_FULL/${baseplain}-$ext"
386
$echo checksum-remove --no-sign \
387
"$RELEASE_FULL" "${baseplain}-$ext"
391
if [ -e "${base}-kernel-info.txt" ]; then
392
if $PUBLISH_DIST; then
393
$echo cp -a "${base}-kernel-info.txt" \
394
"$RELEASE_SIMPLE_DIST/${basestatus}-kernel-info.txt"
396
if $PUBLISH_FULL; then
397
$echo cp -a "${base}-kernel-info.txt" \
398
"$RELEASE_FULL/${baseplain}-kernel-info.txt"
402
if [ "$TYPE" = install ] || [ "$TYPE" = alternate ] || \
403
[ "$TYPE" = server ] || [ "$TYPE" = serveraddon ] || \
404
[ "$TYPE" = addon ] || \
405
[ "$TYPE" = src ]; then
406
if [ -e "$DAILY/$DIST-$TYPE-$arch.jigdo" ] && \
407
[ -e "$DAILY/$DIST-$TYPE-$arch.template" ]; then
408
if $PUBLISH_POOL; then
409
$echo cp -a "$DAILY/$DIST-$TYPE-$arch.template" \
410
"$RELEASE_SIMPLE_POOL/$basestatus.template"
412
echo "Would fix up jigdo file"
414
sed "s/=$DIST-$TYPE-$arch/=$basestatus/g" \
415
< "$DAILY/$DIST-$TYPE-$arch.jigdo" \
416
> "$RELEASE_SIMPLE_POOL/$basestatus.jigdo"
419
if $PUBLISH_DIST; then
420
for ext in template jigdo; do
421
$echo ln -sf "$DIST_TO_POOL/$basestatus.$ext" \
422
"$RELEASE_SIMPLE_DIST/$basestatus.$ext"
425
if $PUBLISH_FULL; then
426
$echo cp -a "$DAILY/$DIST-$TYPE-$arch.template" \
427
"$RELEASE_FULL/$baseplain.template"
429
echo "Would fix up jigdo file"
431
sed "s/=$DIST-$TYPE-$arch/=$baseplain/g" \
432
< "$DAILY/$DIST-$TYPE-$arch.jigdo" \
433
> "$RELEASE_FULL/$baseplain.jigdo"
437
for ext in jigdo template; do
438
if $PUBLISH_POOL; then
439
$echo rm -f "$RELEASE_SIMPLE_POOL/$basestatus.$ext"
441
if $PUBLISH_DIST; then
442
$echo rm -f "$RELEASE_SIMPLE_DIST/$basestatus.$ext"
444
if $PUBLISH_FULL; then
445
$echo rm -f "$RELEASE_FULL/$baseplain.$ext"
453
live|desktop|netbook|mid|moblin-remix|uec|server-uec|preinstalled-*|core|wubi)
457
# DVDs are allowed to not have .manifest files, but
458
# may have them depending on configuration.
459
if [ -e "$base.manifest" ]; then
464
if $want_manifest; then
465
# Copy, to make sure we have a canonical version of this.
466
if $PUBLISH_POOL; then
467
$echo cp -a "$base.manifest" \
468
"$RELEASE_SIMPLE_POOL/$basestatus.manifest"
470
if $PUBLISH_DIST; then
471
$echo ln -sf "$DIST_TO_POOL/$basestatus.manifest" \
472
"$RELEASE_SIMPLE_DIST/$basestatus.manifest"
474
if $PUBLISH_FULL; then
475
$echo cp -a "$base.manifest" \
476
"$RELEASE_FULL/$baseplain.manifest"
480
for ext in iso.zsync img.zsync img.gz.zsync tar.gz.zsync; do
481
if [ -e "$DAILY/$DIST-$TYPE-$arch.$ext" ]; then
482
baseext=${ext%.zsync}
483
if $PUBLISH_POOL; then
484
if which zsyncmake >/dev/null 2>&1; then
485
echo "Making $arch zsync metafile ..."
486
$echo rm -f "$RELEASE_SIMPLE_POOL/$basestatus.$ext"
487
$echo zsyncmake_wrapper \
489
-o "$RELEASE_SIMPLE_POOL/$basestatus.$ext" \
490
-u "$basestatus.$baseext" \
491
"$RELEASE_SIMPLE_POOL/$basestatus.$baseext"
493
elif $PUBLISH_FULL && [ "$OFFICIAL" = named ]; then
494
if which zsyncmake >/dev/null 2>&1; then
495
echo "Making $arch zsync metafile ..."
496
$echo rm -f "$RELEASE_FULL/$baseplain.$ext"
497
$echo zsyncmake_wrapper \
499
-o "$RELEASE_FULL/$baseplain.$ext" \
500
-u "$baseplain.$baseext" \
501
"$RELEASE_FULL/$baseplain.$baseext"
503
elif $PUBLISH_FULL; then
504
$echo cp -a "$DAILY/$DIST-$TYPE-$arch.$ext" \
505
"$RELEASE_FULL/$baseplain.$ext"
507
if $PUBLISH_DIST; then
508
$echo ln -sf "$DIST_TO_POOL/$basestatus.$ext" \
509
"$RELEASE_SIMPLE_DIST/$basestatus.$ext"
515
# There can only be one set of images per release in the per-release tree,
516
# so if we're publishing there then we can now safely clean up previous
517
# images for that release.
518
if $PUBLISH_DIST && [ -z "$CDIMAGE_NO_PURGE" ]; then
519
for dir in "$RELEASE_SIMPLE_DIST" "$RELEASE_SIMPLE_POOL"; do
520
find "$dir" -maxdepth 1 -name "$CDPREFIX-*" ! -regex ".*/$CDPREFIX${FILESTATUS:+-$FILESTATUS}-[^-]*-[^-]*" | while read file; do
527
if [ "$TYPE" = uec ] || [ "$TYPE" = server-uec ]; then
528
for file in published-ec2-release.txt tool-version-info.txt \
531
if [ ! -e "$DAILY/$file" ]; then
534
if $PUBLISH_DIST; then
535
$echo cp -a "$DAILY/$file" \
536
"$RELEASE_SIMPLE_DIST/$file"
538
if $PUBLISH_FULL; then
539
$echo cp -a "$DAILY/$file" \
540
"$RELEASE_FULL/$file"
545
if [ "$TYPE" != src ] && [ "$TYPE" != uec ] && [ "$TYPE" != server-uec ]; then
546
# Create and publish torrents
547
if $PUBLISH_DIST; then
548
TORRENTS="$CDIMAGE_ROOT/www/$TORRENT_TREE/simple/$DIST/$TYPE"
549
if [ -z "$CDIMAGE_NO_PURGE" ]; then
550
$echo mkemptydir "$TORRENTS"
552
$echo make-torrents "$RELEASE_SIMPLE_DIST" \
553
"$CDPREFIX-${FILESTATUS:+$FILESTATUS-}$TYPE" releases.ubuntu.com
555
if $PUBLISH_FULL; then
556
for dir in "$CDIMAGE_ROOT/www/$TORRENT_TREE/releases/$DIST"/*; do
557
[ -d "$dir" ] || continue
558
if [ "${dir##*/}" != "${STATUS:-release}" ]; then
562
TORRENTS="$CDIMAGE_ROOT/www/$TORRENT_TREE/releases/$DIST/${STATUS:-release}/$TYPE"
563
$echo mkemptydir "$TORRENTS"
564
$echo make-torrents "$RELEASE_FULL" "$CDPREFIX-$TYPE" cdimage.ubuntu.com
566
for arch in $ARCHES; do
567
if $PUBLISH_DIST; then
568
basestatus="$CDPREFIX-${FILESTATUS:+$FILESTATUS-}$TYPE-$arch"
569
for ext in iso img; do
570
[ -e "$RELEASE_SIMPLE_POOL/$basestatus.$ext" ] || continue
571
$echo ln -f "$RELEASE_SIMPLE_POOL/$basestatus.$ext" \
572
"$TORRENTS/$basestatus.$ext"
573
$echo ln -f "$RELEASE_SIMPLE_DIST/$basestatus.$ext.torrent" \
574
"$TORRENTS/$basestatus.$ext.torrent"
577
if $PUBLISH_FULL; then
578
baseplain="$CDPREFIX-$TYPE-$arch"
579
for ext in iso img; do
580
[ -e "$RELEASE_FULL/$baseplain.$ext" ] || continue
581
$echo ln -f "$RELEASE_FULL/$baseplain.$ext" \
582
"$TORRENTS/$baseplain.$ext"
583
$echo ln -f "$RELEASE_FULL/$baseplain.$ext.torrent" \
584
"$TORRENTS/$baseplain.$ext.torrent"
590
if $PUBLISH_DIST; then
591
$echo make-web-indices "$RELEASE_SIMPLE_DIST" "$CDPREFIX${FILESTATUS:+-$FILESTATUS}"
593
if $PUBLISH_FULL; then
594
$echo make-web-indices "$RELEASE_FULL" "$CDPREFIX"
597
if $PUBLISH_POOL; then
598
echo 'Checksumming simple tree (pool) ...'
599
$echo checksum-directory \
600
--map "s/^$CDPREFIX-${FILESTATUS:+$FILESTATUS-}/$DIST-/" \
601
"$RELEASE_SIMPLE_POOL" "$DAILY"
603
if $PUBLISH_DIST; then
604
echo "Checksumming simple tree ($DIST) ..."
605
$echo checksum-directory \
606
--map "s/^$CDPREFIX-${FILESTATUS:+$FILESTATUS-}/$DIST-/" \
607
"$RELEASE_SIMPLE_DIST" "$DAILY"
609
echo "Creating and publishing metalink files for the simple tree ($DIST) ..."
610
METALINK_VERSION="$VERSION"
611
if [ "$PROJECT" != ubuntu ]; then
612
METALINK_VERSION="$PROJECT/$VERSION"
614
$echo rm -f "$RELEASE_SIMPLE_DIST/MD5SUMS-metalink" \
615
"$RELEASE_SIMPLE_DIST/MD5SUMS-metalink.gpg"
616
if $echo make-metalink "$RELEASE_SIMPLE_BASEDIR" "$METALINK_VERSION" \
617
"$RELEASE_SIMPLE_RELDIR" releases.ubuntu.com; then
618
$echo checksum-directory --metalink "$RELEASE_SIMPLE_DIST"
620
$echo rm -f "$RELEASE_SIMPLE_DIST"/*.metalink
624
if $PUBLISH_FULL; then
625
echo 'Checksumming full tree ...'
626
$echo checksum-directory \
627
--map "s/^$CDPREFIX-/$DIST-/" \
628
"$RELEASE_FULL" "$DAILY"
630
echo "Creating and publishing metalink files for the full tree ..."
631
$echo rm -f "$RELEASE_FULL/MD5SUMS-metalink" \
632
"$RELEASE_FULL/MD5SUMS-metalink.gpg"
633
if $echo make-metalink "$RELEASE_FULL_BASEDIR" "$VERSION" \
634
"$RELEASE_FULL_RELDIR" cdimage.ubuntu.com; then
635
$echo checksum-directory --metalink "$RELEASE_FULL"
637
rm -f "$RELEASE_FULL"/*.metalink
642
if $PUBLISH_DIST || $PUBLISH_POOL; then
643
$echo site-manifest simple "$CDIMAGE_ROOT/www/simple" .manifest
645
# Create timestamps for this run.
647
echo "Would create trace file"
649
mkdir -p "$CDIMAGE_ROOT/www/simple/.trace"
650
date -u > "$CDIMAGE_ROOT/www/simple/.trace/$(hostname --fqdn)"
654
echo "Done! Remember to sync-mirrors after checking that everything is OK."
3
# Copyright (C) 2013 Canonical Ltd.
4
# Author: Colin Watson <cjwatson@ubuntu.com>
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; version 3 of the License.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
"""Publish a daily build as a release."""
20
from optparse import OptionParser
24
sys.path.insert(0, os.path.join(sys.path[0], os.pardir, "lib"))
25
from cdimage.config import Config
26
from cdimage.tree import Tree
30
parser = OptionParser(
31
"%prog [--dry-run] DAILY-SOURCE DAILY-DATE TYPE OFFICIAL [STATUS]\n"
32
"OFFICIAL=yes to publish to releases.ubuntu.com, poolonly to "
33
"pre-publish, named to publish to cdimage.ubuntu.com as "
34
"$PROJECT-$VERSION-*, otherwise no.")
36
"-n", "--dry-run", default=False, action="store_true",
37
help="Show equivalent commands rather than running them.")
38
options, args = parser.parse_args()
40
parser.error("need daily-source")
42
parser.error("need daily-date")
44
parser.error("need type")
46
parser.error("need official")
49
publish_type = args[2]
51
status = args[4] if len(args) >= 5 else None
53
tree = Tree.get_release(config, official)
55
publisher = tree.get_publisher(
56
"daily", official, status=status, dry_run=options.dry_run)
57
publisher.publish_release(source, date, publish_type)
60
if __name__ == "__main__":