auto/config: Rewrite add_task to use a Python script that cribs the logic from lp:ubuntu-archive-publishing's generate_extra_overrides.py. This means we can avoid some dubious hacks around seeding snaps and no longer depend on the Task headers in the archive.

add-new-budgie
Michael Hudson-Doyle 2 years ago
parent db029cd387
commit a65c181596

9
debian/changelog vendored

@ -1,3 +1,12 @@
livecd-rootfs (2.837) UNRELEASED; urgency=medium
* auto/config: Rewrite add_task to use a Python script that cribs the logic
from lp:ubuntu-archive-publishing's generate_extra_overrides.py. This
means we can avoid some dubious hacks around seeding snaps and no longer
depend on the Task headers in the archive. (LP: #2019265)
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Fri, 23 Sep 2022 10:58:29 +1200
livecd-rootfs (2.836) mantic; urgency=medium
* canary: include cryptsetup in the live layer

@ -36,6 +36,7 @@ mkdir -p config
cp -af /usr/share/livecd-rootfs/live-build/functions config/functions
cp -af /usr/share/livecd-rootfs/live-build/lb_*_layered config/
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-parse.py config/snap-seed-parse
cp -af /usr/share/livecd-rootfs/live-build/expand-task config/expand-task
cp -af /usr/share/livecd-rootfs/live-build/squashfs-exclude-files config/
mkdir -p config/package-lists
@ -106,55 +107,36 @@ add_task ()
{
local pass="$1"
shift
local task
local snap_list_file
local snap_list_files
local curseed
local file pkg_file snap_file task
_check_immutable_passes_to_layers
_register_pass "$pass"
# The removal of direct task installation support from live-build
# poses some problems. If the chroot has multiarch configured - for
# example, if we're building for amd64 - then dumpavail will show
# foreign-architecture packages which will have their own Task
# lines, but which we don't want to install. (Compare
# PackageContainerInterface::FromTask in apt, which restricts task
# expansion to the native architecture.) We therefore restrict our
# search to stanzas with Architecture: $ARCH or all.
#
# However, even this may not be accurate enough. At the moment I
# have no idea what happens if an Architecture: all package has
# different Task fields on different architectures. This is
# probably a lurking timebomb that we need to fix. In the meantime,
# the Architecture restriction at least saves us from abject
# failure.
#
# We want as well to grab the snap list for each PASS. Resolve for all
# given task, and deduplicate them to generate snaps for the PASS.
for task; do
# We need a ridiculous number of backslashes to protect
# parentheses from eval.
echo "!chroot chroot apt-cache dumpavail | grep-dctrl -nsPackage \\\\\\( -XFArchitecture $ARCH -o -XFArchitecture all \\\\\\) -a -wFTask $task" >> "config/package-lists/livecd-rootfs.list.chroot_$pass"
curseed=$(seed_from_task ${task})
if [ -z "${curseed}" ]; then
echo "W: No seed matching task ${task}"
continue
if [ ! -e config/germinate-output/structure ]; then
echo "add_task too soon" >&2
exit 1
fi
snap_list_file="config/package-lists/seed.${curseed}.snaplist.full"
snap_from_seed "${curseed}" $snap_list_file
if [ -e "$snap_list_file" ]; then
snap_list_files="${snap_list_files} $snap_list_file"
pkg_file="config/package-lists/livecd-rootfs.list.chroot_$pass"
if [ $PASSES_TO_LAYERS = "true" ]; then
snap_file="config/package-lists/livecd-rootfs.snaplist.chroot_$pass.full"
else
snap_file="config/seeded-snaps"
fi
for task; do
./config/expand-task config/germinate-output $FLAVOUR $task packages >> "$pkg_file"
./config/expand-task config/germinate-output $FLAVOUR $task snaps >> "$snap_file"
done
# The snap list is one line, and could be duplicated between seeds via inheritance.
# Uniquely sort them and store them back in one line.
if [ -n "${snap_list_files}" ]; then
cat ${snap_list_files}|xargs -n1|sort -u > "config/package-lists/livecd-rootfs.snaplist.chroot_${pass}.full"
rm ${snap_list_files}
for file in $pkg_file $snap_file; do
if [ -s $file ]; then
sort -u -o $file $file
else
rm -f $file
fi
done
}
add_package ()
@ -639,34 +621,34 @@ fi
mkdir -p config/germinate-output
case $PROJECT in
kubuntu*)
SEED=kubuntu.$SUITE
FLAVOUR=kubuntu
;;
xubuntu*)
SEED=xubuntu.$SUITE
FLAVOUR=xubuntu
;;
ubuntu-mate*)
SEED=ubuntu-mate.$SUITE
FLAVOUR=ubuntu-mate
;;
ubuntu-unity*)
SEED=ubuntu-unity.$SUITE
FLAVOUR=ubuntu-unity
;;
lubuntu*)
SEED=lubuntu.$SUITE
FLAVOUR=lubuntu
;;
ubuntu-budgie*)
SEED=ubuntu-budgie.$SUITE
FLAVOUR=ubuntu-budgie
;;
ubuntukylin*)
SEED=ubuntukylin.$SUITE
FLAVOUR=ubuntukylin
;;
ubuntustudio*)
SEED=ubuntustudio.$SUITE
FLAVOUR=ubuntustudio
;;
ubuntucinnamon*)
SEED=ubuntucinnamon.$SUITE
;;
*)
SEED=ubuntu.$SUITE
FLAVOUR=ubuntu
;;
esac
@ -694,7 +676,7 @@ if ! [ -e config/germinate-output/structure ]; then
GERMINATE_ARG="-c $(echo $COMPONENTS | sed -e's/ \+/,/g')"
fi
(cd config/germinate-output && germinate --no-rdepends --no-installer \
-S $SEEDMIRROR -m $MIRROR -d $SUITE -s $SEED \
-S $SEEDMIRROR -m $MIRROR -d $SUITE -s $FLAVOUR.$SUITE \
$GERMINATE_ARG -a $ARCH)
fi
@ -957,8 +939,6 @@ case $PROJECT in
add_task ubuntu-server-minimal server-minimal
add_package ubuntu-server-minimal lxd-installer
add_task ubuntu-server-minimal.ubuntu-server minimal standard server
# add_task really should do this itself but for now...
snap_from_seed server config/package-lists/livecd-rootfs.snaplist.chroot_ubuntu-server-minimal.ubuntu-server.full
add_package ubuntu-server-minimal.ubuntu-server cloud-init
add_package ubuntu-server-minimal.ubuntu-server.installer linux-firmware casper openssh-server
@ -1188,9 +1168,6 @@ case $PROJECT:${SUBPROJECT:-} in
;;
esac
if [ "$PASSES_TO_LAYERS" != "true" ] && [ -n "${BASE_SEED}" ]; then
snap_from_seed "${BASE_SEED}" config/seeded-snaps
fi
if [ "$PROJECT:${SUBPROJECT:-}" = ubuntu-cpc:minimized ]; then
# We install a lxc script that installs the snap when invoked. We don't
# want any other snaps to come in without due consideration, so fail the

@ -0,0 +1,84 @@
#!/usr/bin/python3
import argparse
import glob
import os
import re
p = argparse.ArgumentParser()
p.add_argument('output_dir')
p.add_argument('flavour')
p.add_argument('task')
p.add_argument('what', choices=['packages', 'snaps'])
args = p.parse_args()
if args.what == 'snaps':
ext = '.snaps'
else:
ext = ''
# begin copy/paste from ubuntu-archive-publishing's generate_extra_overrides.
def parseTaskHeaders(seedtext):
"""Parse a seed for Task headers.
seedtext is a file-like object. Return a dictionary of Task headers,
with keys canonicalised to lower-case.
"""
task_headers = {}
task_header_regex = re.compile(
r"task-(.*?):(.*)", flags=re.IGNORECASE)
for line in seedtext:
match = task_header_regex.match(line)
if match is not None:
key, value = match.groups()
task_headers[key.lower()] = value.strip()
return task_headers
def getTaskName(task_headers, flavour, seedname, primary_flavour):
"""Work out the name of the Task to be generated from this seed.
If there is a Task-Name header, it wins; otherwise, seeds with a
Task-Per-Derivative header are honoured for all flavours and put in
an appropriate namespace, while other seeds are only honoured for
the first flavour and have archive-global names.
"""
if "name" in task_headers:
return task_headers["name"]
elif "per-derivative" in task_headers:
return "%s-%s" % (flavour, seedname)
elif primary_flavour:
return seedname
else:
return None
def getTaskSeeds(task_headers, seedname):
"""Return the list of seeds used to generate a task from this seed.
The list of packages in this task comes from this seed plus any
other seeds listed in a Task-Seeds header.
"""
scan_seeds = set([seedname])
if "seeds" in task_headers:
scan_seeds.update(task_headers["seeds"].split())
return sorted(scan_seeds)
# end copy/paste from ubuntu-archive-publishing's generate_extra_overrides.
for seedtext in glob.glob(f'{args.output_dir}/*.seedtext'):
hs = parseTaskHeaders(open(seedtext))
if not hs:
continue
seedname = os.path.splitext(os.path.basename(seedtext))[0]
tn = getTaskName(hs, args.flavour, seedname, args.flavour == 'ubuntu')
if tn != args.task:
continue
for seed in getTaskSeeds(hs, seedname):
for line in open(f'{args.output_dir}/{seed}{ext}'):
if re.match('^[a-z0-9]', line):
print(line.split()[0])
break
else:
raise Exception("did not find task %r" % (args.task,))

@ -766,56 +766,6 @@ snap_validate_seed() {
fi
}
snap_from_seed() {
local base_seed=$1
local out=$2
local all_snaps
local seeds_expanded
seeds_expanded=$(inheritance ${base_seed})
for seed in ${seeds_expanded}; do
echo "snap: considering ${seed}"
file=config/germinate-output/${seed}.snaps
[ -e "${file}" ] || continue
# extract the first column (snap package name) from germinate's output
# translate the human-readable "foo (classic)" into a
# more machine readable "foo/classic"
seed_snaps=$(sed -rn '1,/-----/d;/-----/,$d; s/(.*) \|.*/\1/; s, \(classic\),/classic,; p' "${file}")
for snap in ${seed_snaps}; do
echo "snap: found ${snap}"
all_snaps="${all_snaps:+${all_snaps} }${snap}"
done
done
if [ -n "${all_snaps}" ]; then
echo "${all_snaps}" > $out
fi
}
seed_from_task ()
{
# Retrieve the name of the seed from a task name
local task=$1
local seed
local seedfile
local seedfiles
seedfile="$(grep -lE "^Task-Key: +${task}\$" config/germinate-output/*seedtext|head -1)"
if [ -n "$seedfile" ]; then
basename $seedfile .seedtext
return
fi
seedfiles="$(grep -lE "^Task-Per-Derivative: *1\$" config/germinate-output/*seedtext)"
if [ -n "$seedfiles" ]; then
for seed in $(echo $seedfiles | xargs basename -s .seedtext); do
if [ ${PROJECT}-${seed} = $task ]; then
echo ${seed}
return
fi
done
fi
}
list_packages_from_seed () {
# Store all packages for a given seed, including its seed dependency
# $1: Name of the seed to expand to a package list

Loading…
Cancel
Save