Compare commits

..

No commits in common. '736cb493eabbbcb1710993460c506a6183e1aad5' and '5fd96553f5157a276e6e90e4768e90f2f9f14783' have entirely different histories.

@ -1,18 +1,3 @@
1.3.0 (2023-01-16)
------------------
- add hooks/maybe-jessie-or-older and hooks/maybe-merged-usr
- add --skip=check/signed-by
- hooks/jessie-or-older: split into two individual hook files
- skip running apt-get update if we are very sure that it was already run
- be more verbose when 'apt-get update' failed
- warn if a hook is named like one but not executable and if a hook is
executable but not named like one
- to find signed-by value, run gpg on the individual keys to print better
error messages in case it fails (gpg doesn't give an indication which file
it was unable to read) and print progress bar
- allow empty sources.list entries
1.2.5 (2023-01-04)
------------------

@ -119,7 +119,7 @@ def parse_config(confname):
return config_order, config_dict
def format_test(num, total, name, dist, mode, variant, fmt, config_dict):
def format_failed(num, total, name, dist, mode, variant, fmt, config_dict):
ret = f"({num}/{total}) {name}"
if len(config_dict[name].get("Dists", [])) > 1:
ret += f" --dist={dist}"
@ -287,7 +287,6 @@ def main():
failed = []
num_success = 0
num_finished = 0
time_per_test = {}
for i, (test, name, dist, mode, variant, fmt) in enumerate(tests):
if torun and i not in torun:
continue
@ -366,7 +365,6 @@ def main():
if args.format and args.format != fmt:
print(f"skipping because of --format={args.format}", file=sys.stderr)
continue
before = time.time()
proc = subprocess.Popen(argv)
try:
proc.wait()
@ -374,25 +372,21 @@ def main():
proc.terminate()
proc.wait()
break
after = time.time()
walltime = timedelta(seconds=int(after - before))
formated_test_name = format_test(
i + 1, len(tests), name, dist, mode, variant, fmt, config_dict
)
time_per_test[formated_test_name] = walltime
print(separator, file=sys.stderr)
print(f"duration: {walltime}", file=sys.stderr)
if proc.returncode != 0 or shellcheck != "":
if shellcheck != "":
print(shellcheck)
failed.append(formated_test_name)
failed.append(
format_failed(
i + 1, len(tests), name, dist, mode, variant, fmt, config_dict
)
)
print("result: FAILURE", file=sys.stderr)
else:
print("result: SUCCESS", file=sys.stderr)
num_success += 1
if args.maxfail and len(failed) >= args.maxfail:
break
print(separator, file=sys.stderr)
print(
"successfully ran %d tests" % num_success,
file=sys.stderr,
@ -408,28 +402,6 @@ def main():
for f in failed:
print(f, file=sys.stderr)
exit(1)
if len(time_per_test) > 1:
print(
"average time per test:",
sum(time_per_test.values(), start=timedelta()) / len(time_per_test),
file=sys.stderr,
)
print(
"median time per test:",
sorted(time_per_test.values())[len(time_per_test) // 2],
file=sys.stderr,
)
head_tail_num = 10
print(f"{head_tail_num} fastests tests:", file=sys.stderr)
for k, v in sorted(time_per_test.items(), key=lambda i: i[1])[
: min(head_tail_num, len(time_per_test))
]:
print(f" {k}: {v}", file=sys.stderr)
print(f"{head_tail_num} slowest tests:", file=sys.stderr)
for k, v in sorted(time_per_test.items(), key=lambda i: i[1], reverse=True)[
: min(head_tail_num, len(time_per_test))
]:
print(f" {k}: {v}", file=sys.stderr)
if __name__ == "__main__":

@ -307,7 +307,7 @@ Variants: essential
Modes: chrootless
Skip-If:
dist in ["oldstable", "stable"]
hostarch not in ["amd64", "arm64"]
hostarch != "amd64"
not run_ma_same_tests
Needs-QEMU: true
@ -358,9 +358,3 @@ Needs-QEMU: true
Test: jessie-or-older
Needs-QEMU: true
Variants: essential apt minbase
Test: apt-patterns
Test: apt-patterns-custom
Test: empty-sources.list

@ -8,9 +8,41 @@ fi
TARGET="$1"
# not needed since dpkg 1.17.11
for f in available diversions cmethopt; do
if [ ! -e "$TARGET/var/lib/dpkg/$f" ]; then
touch "$TARGET/var/lib/dpkg/$f"
fi
done
if [ -z "${MMDEBSTRAP_ESSENTIAL+x}" ]; then
MMDEBSTRAP_ESSENTIAL=
for f in "$TARGET/var/cache/apt/archives/"*.deb; do
[ -f "$f" ] || continue
f="${f#"$TARGET"}"
MMDEBSTRAP_ESSENTIAL="$MMDEBSTRAP_ESSENTIAL $f"
done
fi
fname_base_passwd=
fname_base_files=
fname_dpkg=
for pkg in $MMDEBSTRAP_ESSENTIAL; do
pkgname=$(dpkg-deb --show --showformat='${Package}' "$TARGET/$pkg")
# shellcheck disable=SC2034
case $pkgname in
base-passwd) fname_base_passwd=$pkg;;
base-files) fname_base_files=$pkg;;
dpkg) fname_dpkg=$pkg;;
esac
done
for var in base_passwd base_files dpkg; do
eval 'val=$fname_'"$var"
[ -z "$val" ] && continue
chroot "$TARGET" dpkg --install --force-depends "$val"
done
# shellcheck disable=SC2086
chroot "$TARGET" dpkg --unpack --force-depends $MMDEBSTRAP_ESSENTIAL
chroot "$TARGET" dpkg --configure --pending

@ -1,47 +0,0 @@
#!/bin/sh
#
# needed until init 1.33 which pre-depends on systemd-sysv
# starting with init 1.34, init is not Essential:yes anymore
#
# jessie has init 1.22
set -eu
if [ "${MMDEBSTRAP_VERBOSITY:-1}" -ge 3 ]; then
set -x
fi
TARGET="$1"
if [ -z "${MMDEBSTRAP_ESSENTIAL+x}" ]; then
MMDEBSTRAP_ESSENTIAL=
for f in "$TARGET/var/cache/apt/archives/"*.deb; do
[ -f "$f" ] || continue
f="${f#"$TARGET"}"
MMDEBSTRAP_ESSENTIAL="$MMDEBSTRAP_ESSENTIAL $f"
done
fi
fname_base_passwd=
fname_base_files=
fname_dpkg=
for pkg in $MMDEBSTRAP_ESSENTIAL; do
pkgname=$(dpkg-deb --show --showformat='${Package}' "$TARGET/$pkg")
# shellcheck disable=SC2034
case $pkgname in
base-passwd) fname_base_passwd=$pkg;;
base-files) fname_base_files=$pkg;;
dpkg) fname_dpkg=$pkg;;
esac
done
for var in base_passwd base_files dpkg; do
eval 'val=$fname_'"$var"
[ -z "$val" ] && continue
chroot "$TARGET" dpkg --install --force-depends "$val"
done
# shellcheck disable=SC2086
chroot "$TARGET" dpkg --unpack --force-depends $MMDEBSTRAP_ESSENTIAL
chroot "$TARGET" dpkg --configure --pending

@ -1,28 +0,0 @@
#!/bin/sh
set -eu
# if dpkg is new enough, do nothing
# we cannot ask dpkg-query about the version because dpkg is only extracted
# but not installed at this point
dpkg_ver="$(chroot "$1" dpkg --version | grep --extended-regexp --only-matching '[0-9]+\.[0-9.]+')"
if dpkg --compare-versions "$dpkg_ver" ge 1.17.11; then
echo "dpkg version $dpkg_ver is >= 1.17.11 -- not running jessie-or-older extract00 hook" >&2
exit 0
else
echo "dpkg version $dpkg_ver is << 1.17.11 -- running jessie-or-older extract00 hook" >&2
fi
# resolve the script path using several methods in order:
# 1. using dirname -- "$0"
# 2. using ./hooks
# 3. using /usr/share/mmdebstrap/hooks/
for p in "$(dirname -- "$0")/.." ./hooks /usr/share/mmdebstrap/hooks; do
if [ -x "$p/jessie-or-older/extract00.sh" ] && [ -x "$p/jessie-or-older/extract01.sh" ]; then
"$p/jessie-or-older/extract00.sh" "$1"
exit 0
fi
done
echo "cannot find jessie-or-older hook anywhere" >&2
exit 1

@ -1,31 +0,0 @@
#!/bin/sh
set -eu
# If the init package has not been extracted, then it is not part of the
# Essential:yes set and we do not need this workaround. This holds true for the
# init package version 1.34 and later. Instead of asking apt about the init
# version (which might not be the same version that was picked to be installed)
# we check for the presence of the init package by checking whether
# /usr/share/doc/init/copyright exists.
if [ -e "$1/usr/share/doc/init/copyright" ]; then
echo "the init package is not Essential:yes -- not running jessie-or-older extract01 hook" >&2
exit 0
else
echo "the init package is Essential:yes -- running jessie-or-older extract01 hook" >&2
fi
# resolve the script path using several methods in order:
# 1. using dirname -- "$0"
# 2. using ./hooks
# 3. using /usr/share/mmdebstrap/hooks/
for p in "$(dirname -- "$0")/.." ./hooks /usr/share/mmdebstrap/hooks; do
if [ -x "$p/jessie-or-older/extract00.sh" ] && [ -x "$p/jessie-or-older/extract01.sh" ]; then
"$p/jessie-or-older/extract01.sh" "$1"
exit 0
fi
done
echo "cannot find jessie-or-older hook anywhere" >&2
exit 1

@ -1,25 +0,0 @@
#!/bin/sh
set -eu
# if the usr-is-merged package cannot be installed with apt, do nothing
if ! env --chdir="$1" APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-cache show --no-all-versions usr-is-merged > /dev/null 2>&1; then
echo "no package called usr-is-merged found -- not running merged-usr essential hook" >&2
exit 0
else
echo "package usr-is-merged found -- running merged-usr essential hook" >&2
fi
# resolve the script path using several methods in order:
# 1. using dirname -- "$0"
# 2. using ./hooks
# 3. using /usr/share/mmdebstrap/hooks/
for p in "$(dirname -- "$0")/.." ./hooks /usr/share/mmdebstrap/hooks; do
if [ -x "$p/merged-usr/setup00.sh" ] && [ -x "$p/merged-usr/essential00.sh" ]; then
"$p/merged-usr/essential00.sh" "$1"
exit 0
fi
done
echo "cannot find merged-usr hook anywhere" >&2
exit 1

@ -1,27 +0,0 @@
#!/bin/sh
set -eu
env --chdir="$1" APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-get update --error-on=any
# if the usr-is-merged package cannot be installed with apt, do nothing
if ! env --chdir="$1" APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-cache show --no-all-versions usr-is-merged > /dev/null 2>&1; then
echo "no package called usr-is-merged found -- not running merged-usr setup hook" >&2
exit 0
else
echo "package usr-is-merged found -- running merged-usr setup hook" >&2
fi
# resolve the script path using several methods in order:
# 1. using dirname -- "$0"
# 2. using ./hooks
# 3. using /usr/share/mmdebstrap/hooks/
for p in "$(dirname -- "$0")/.." ./hooks /usr/share/mmdebstrap/hooks; do
if [ -x "$p/merged-usr/setup00.sh" ] && [ -x "$p/merged-usr/essential00.sh" ]; then
"$p/merged-usr/setup00.sh" "$1"
exit 0
fi
done
echo "cannot find merged-usr hook anywhere" >&2
exit 1

@ -1 +0,0 @@
../merged-usr/essential00.sh

@ -0,0 +1,15 @@
#!/bin/sh
set -eu
if [ "${MMDEBSTRAP_VERBOSITY:-1}" -ge 3 ]; then
set -x
fi
TARGET="$1"
APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get --yes install -oDPkg::Chroot-Directory="$TARGET" usr-is-merged
chroot "$TARGET" dpkg-query --showformat '${db:Status-Status}\n' --show usr-is-merged | grep -q '^installed$'
chroot "$TARGET" dpkg-query --showformat '${Source}\n' --show usr-is-merged | grep -q '^usrmerge$'
dpkg --compare-versions "1" "lt" "$(chroot "$TARGET" dpkg-query --showformat '${Version}\n' --show usr-is-merged)"

@ -59,9 +59,7 @@ deletecache() {
esac
done
for f in "$dir/debian-"*.qcow; do
if [ -e "$f" ]; then
rm --one-file-system "$f"
fi
rm --one-file-system "$f"
done
if [ -e "$dir/debian/pool/main" ]; then
rm --one-file-system --recursive "$dir/debian/pool/main"
@ -360,22 +358,16 @@ if [ -e "./shared/cache.A" ] && [ -e "./shared/cache.B" ]; then
echo "cache symlink points to $(readlink ./shared/cache)" >&2
case "$(readlink ./shared/cache)" in
cache.A)
echo "removing ./shared/cache.B" >&2
rm -r ./shared/cache.B
echo "maybe rm -r ./shared/cache.B" >&2
;;
cache.B)
echo "removing ./shared/cache.A" >&2
rm -r ./shared/cache.A
echo "maybe rm -r ./shared/cache.A" >&2
;;
*)
echo "unexpected" >&2
exit 1
;;
esac
else
echo "./shared/cache doesn't exist" >&2
exit 1
fi
exit 1
fi
if [ -e "./shared/cache.A" ]; then
@ -417,11 +409,10 @@ mkdir -p "$newcachedir"
touch "$newcachedir/mmdebstrapcache"
HOSTARCH=$(dpkg --print-architecture)
arches="$HOSTARCH"
if [ "$HOSTARCH" = amd64 ]; then
arches="$arches arm64 i386"
elif [ "$HOSTARCH" = arm64 ]; then
arches="$arches amd64 armhf"
arches="amd64 arm64 i386"
else
arches="$HOSTARCH"
fi
for nativearch in $arches; do
@ -534,9 +525,6 @@ if [ "$HAVE_QEMU" = "yes" ]; then
if [ "$HOSTARCH" = amd64 ] && [ "$RUN_MA_SAME_TESTS" = "yes" ]; then
arches=amd64,arm64
pkgs="$pkgs,libfakechroot:arm64,libfakeroot:arm64"
elif [ "$HOSTARCH" = arm64 ] && [ "$RUN_MA_SAME_TESTS" = "yes" ]; then
arches=arm64,amd64
pkgs="$pkgs,libfakechroot:amd64,libfakeroot:amd64"
else
arches=$HOSTARCH
fi
@ -594,12 +582,12 @@ handler () {
} 2>&1;
} | { read xs; exit $xs; };
} 3>&1 || ret=$?
echo $ret > /mnt/exitstatus.txt
if [ -e cover_db.img ]; then
df -h cover_db
umount cover_db
fi
) > /mnt/output.txt 2>&1
echo $ret
) > /mnt/result.txt 2>&1
umount /mnt
systemctl poweroff
END

@ -23,7 +23,7 @@
use strict;
use warnings;
our $VERSION = '1.3.0';
our $VERSION = '1.2.5';
use English;
use Getopt::Long;
@ -2072,7 +2072,7 @@ sub run_setup() {
}
# write /etc/apt/sources.list and files in /etc/apt/sources.list.d/
if (scalar @{ $options->{sourceslists} } > 0) {
{
my $firstentry = $options->{sourceslists}->[0];
# if the first sources.list entry is of one-line type and without
# explicit filename, then write out an actual /etc/apt/sources.list
@ -2275,19 +2275,8 @@ sub run_update() {
CHDIR => $options->{root},
};
# Maybe "apt-get update" was already run in the setup hook? If yes, skip
# running it here. We are overly strict on purpose because better to run it
# twice on accident than not at all.
if ( !-d "$options->{root}/var/lib/apt/lists/auxfiles"
|| !-d "$options->{root}/var/lib/apt/lists/partial"
|| !-e "$options->{root}/var/lib/apt/lists/lock"
|| !-e "$options->{root}/var/cache/apt/pkgcache.bin"
|| !-e "$options->{root}/var/cache/apt/srcpkgcache.bin") {
info "running apt-get update...";
run_apt_progress($aptopts);
} else {
info "skipping apt-get update because it was already run";
}
info "running apt-get update...";
run_apt_progress($aptopts);
# check if anything was downloaded at all
{
@ -2298,36 +2287,11 @@ sub run_update() {
);
close $fh;
if ($indextargets eq '') {
warning("apt-get indextargets output is empty");
if (scalar @{ $options->{sourceslists} } == 0) {
warning "no known apt sources.list entry";
}
for my $list (@{ $options->{sourceslists} }) {
if (defined $list->{fname}) {
info("Filename: $list->{fname}");
}
info("Type: $list->{type}");
info("Content:");
for my $line (split "\n", $list->{content}) {
info(" $line");
}
}
open(my $fh, '-|', 'apt-cache', 'policy')
// error "failed to fork(): $!";
while (my $line = <$fh>) {
chomp $line;
info $line;
}
close $fh;
my $msg
= "apt-get update did not find any indices "
. "for architecture '$options->{nativearch}' in ";
if (length $options->{suite}) {
$msg .= "suite '$options->{suite}'";
} else {
$msg .= "the configured apt sources";
if ($verbosity_level >= 1) {
0 == system('apt-cache', 'policy')
or error "apt-cache failed: $?";
}
error $msg;
error "apt-get update didn't download anything";
}
}
@ -2377,7 +2341,18 @@ sub run_download() {
info "nothing to download -- skipping...";
return ([], \@cached_debs);
}
my @apt_argv = ('install', @{ $options->{include} });
my @apt_argv = ('install');
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
push @apt_argv, $pkg;
}
}
@dl_debs = run_apt_download_progress({
APT_ARGV => [@apt_argv],
@ -2905,9 +2880,20 @@ sub run_essential() {
sub run_install() {
my $options = shift;
my @pkgs_to_install = (@{ $options->{include} });
my %pkgs_to_install;
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
$pkgs_to_install{$pkg} = ();
}
}
if ($options->{variant} eq 'buildd') {
push @pkgs_to_install, 'build-essential';
$pkgs_to_install{'build-essential'} = ();
}
if (any { $_ eq $options->{variant} }
('required', 'important', 'standard', 'buildd')) {
@ -2924,8 +2910,7 @@ sub run_install() {
$priority = '?and(?or(~prequired,~pimportant,~pstandard),'
. '?not(?essential))';
}
push @pkgs_to_install,
(
$pkgs_to_install{
"?narrow("
. (
length($options->{suite})
@ -2937,8 +2922,9 @@ sub run_install() {
)
. "?architecture($options->{nativearch}),"
. "$priority)"
);
} = ();
}
my @pkgs_to_install = keys %pkgs_to_install;
if ($options->{mode} eq 'chrootless') {
if (scalar @pkgs_to_install > 0) {
@ -4507,27 +4493,13 @@ sub main() {
opendir(my $dh, $opt_value)
or error "Can't opendir($opt_value): $!";
while (my $entry = readdir $dh) {
# skip the "." and ".." entries
next if $entry eq ".";
next if $entry eq "..";
my $found = 0;
foreach
my $hook ('setup', 'extract', 'essential', 'customize') {
if ($entry =~ m/^\Q$hook\E/) {
if (-x "$opt_value/$entry") {
push @{ $scripts{$hook} }, "$opt_value/$entry";
$count += 1;
$found = 1;
} else {
warning("$opt_value/$entry is named like a "
. "hook but not executable");
}
if ($entry =~ m/^\Q$hook\E/ and -x "$opt_value/$entry") {
push @{ $scripts{$hook} }, "$opt_value/$entry";
$count += 1;
}
}
if (!$found && -x "$opt_value/$entry") {
warning("$opt_value/$entry: is executable "
. "but not prefixed with a hook name");
}
}
closedir($dh);
if ($count == 0) {
@ -5085,21 +5057,17 @@ sub main() {
## no critic (InputOutput::ProhibitExplicitStdin)
<STDIN>;
};
if ($content eq "") {
warning "sources.list from standard input is empty";
} else {
my $type = guess_sources_format($content);
if (!defined $type
|| ($type ne "deb822" and $type ne "one-line")) {
error "cannot determine sources.list format";
}
push @{$sourceslists},
{
type => $type,
fname => undef,
content => $content,
};
my $type = guess_sources_format($content);
if (!defined $type
|| ($type ne "deb822" and $type ne "one-line")) {
error "cannot determine sources.list format";
}
push @{$sourceslists},
{
type => $type,
fname => undef,
content => $content,
};
} else {
my @components = ();
foreach my $comp (@{ $options->{components} }) {
@ -5119,24 +5087,22 @@ sub main() {
}
}
my $compstr = join " ", @components;
# From the suite name we can maybe infer which key we need. If we
# can infer this information, then we need to check whether the
# currently running apt actually trusts this key or not. If it
# doesn't, then we need to add a signed-by line to the sources.list
# entry.
# if the currently selected apt keyrings do not contain the
# necessary key material for the chosen suite, then attempt adding
# a signed-by option
my $signedby = '';
my %suite_by_vendor = get_suite_by_vendor();
my $gpgproc = sub {
{
my $keyring
= get_keyring_by_suite($options->{suite}, \%suite_by_vendor);
if (!defined $keyring) {
return '';
last;
}
# we can only check if we need the signed-by entry if we u
# automatically chosen keyring exists
if (!defined $keyring || !-e $keyring) {
return '';
last;
}
# we can only check key material if gpg is installed
@ -5164,9 +5130,9 @@ sub main() {
close $fh;
}
if ($? != 0 || !defined $ret || defined $message) {
warning
"gpg --version failed: cannot infer signed-by value";
return '';
info "gpg --version failed: cannot determine the right"
. " signed-by value";
last;
}
# initialize gpg trustdb with empty one
{
@ -5175,7 +5141,7 @@ sub main() {
}
if (!-d $options->{apttrustedparts}) {
warning "$options->{apttrustedparts} doesn't exist";
return '';
last;
}
# find all the fingerprints of the keys apt currently
# knows about
@ -5197,15 +5163,12 @@ sub main() {
}
my @aptfingerprints = ();
if (scalar @keyrings == 0) {
return " [signed-by=\"$keyring\"]";
$signedby = " [signed-by=\"$keyring\"]";
last;
}
info "finding correct signed-by value...";
my $progress = 0.0;
print_progress($progress);
for (my $i = 0 ; $i < scalar @keyrings ; $i++) {
my $k = $keyrings[$i];
open(my $fh, '-|', @gpgcmd, '--with-colons',
'--show-keys', $k) // error "failed to fork(): $!";
{
open(my $fh, '-|', @gpgcmd, '--with-colons', '--show-keys',
@keyrings) // error "failed to fork(): $!";
while (my $line = <$fh>) {
if ($line !~ /^fpr:::::::::([^:]+):/) {
next;
@ -5213,14 +5176,13 @@ sub main() {
push @aptfingerprints, $1;
}
close $fh;
if ($? != 0) {
warning("gpg failed to read $k");
}
print_progress($i / (scalar @keyrings) * 100.0, undef);
}
print_progress("done");
if ($? != 0) {
error "gpg failed";
}
if (scalar @aptfingerprints == 0) {
return " [signed-by=\"$keyring\"]";
$signedby = " [signed-by=\"$keyring\"]";
last;
}
# check if all fingerprints from the keyring that we guessed
# are known by apt and only add signed-by option if that's not
@ -5236,20 +5198,15 @@ sub main() {
# if this fingerprint is not known by apt, then we need
#to add the signed-by option
if (none { $_ eq $1 } @aptfingerprints) {
return " [signed-by=\"$keyring\"]";
$signedby = " [signed-by=\"$keyring\"]";
last;
}
}
close $fh;
if ($? != 0) {
warning "gpg failed -- cannot infer signed-by value";
}
}
return '';
};
if (any { $_ eq 'check/signed-by' } @{ $options->{skip} }) {
info "skipping check/signed-by as requested";
} else {
$signedby = $gpgproc->();
if ($? != 0) {
error "gpg failed";
}
}
if (scalar @ARGV > 0) {
for my $arg (@ARGV) {
@ -5260,32 +5217,26 @@ sub main() {
## no critic (InputOutput::ProhibitExplicitStdin)
<STDIN>;
};
if ($content eq "") {
warning
"sources.list from standard input is empty";
my $type = guess_sources_format($content);
if (!defined $type
|| ($type ne 'deb822' and $type ne 'one-line')) {
error "cannot determine sources.list format";
}
# if last entry is of same type and without filename,
# then append
if ( scalar @{$sourceslists} > 0
&& $sourceslists->[-1]{type} eq $type
&& !defined $sourceslists->[-1]{fname}) {
$sourceslists->[-1]{content}
.= ($type eq 'one-line' ? "\n" : "\n\n")
. $content;
} else {
my $type = guess_sources_format($content);
if (!defined $type
|| ($type ne 'deb822' and $type ne 'one-line'))
{
error "cannot determine sources.list format";
}
# if last entry is of same type and without filename,
# then append
if ( scalar @{$sourceslists} > 0
&& $sourceslists->[-1]{type} eq $type
&& !defined $sourceslists->[-1]{fname}) {
$sourceslists->[-1]{content}
.= ($type eq 'one-line' ? "\n" : "\n\n")
. $content;
} else {
push @{$sourceslists},
{
type => $type,
fname => undef,
content => $content,
};
}
push @{$sourceslists},
{
type => $type,
fname => undef,
content => $content,
};
}
} elsif ($arg =~ /^deb(-src)? /) {
my $content = "$arg\n";
@ -5330,31 +5281,24 @@ sub main() {
$content .= $line;
}
close $fh;
if ($content eq "") {
warning "$arg is empty";
my $type = undef;
if ($arg =~ /\.list$/) {
$type = 'one-line';
} elsif ($arg =~ /\.sources$/) {
$type = 'deb822';
} else {
my $type = undef;
if ($arg =~ /\.list$/) {
$type = 'one-line';
} elsif ($arg =~ /\.sources$/) {
$type = 'deb822';
} else {
$type = guess_sources_format($content);
}
if (!defined $type
|| ($type ne 'deb822' and $type ne 'one-line'))
{
error "cannot determine sources.list format";
}
push @{$sourceslists},
{
type => $type,
fname => basename($arg),
content => $content,
};
$type = guess_sources_format($content);
}
} elsif ($arg eq '') {
# empty
if (!defined $type
|| ($type ne 'deb822' and $type ne 'one-line')) {
error "cannot determine sources.list format";
}
push @{$sourceslists},
{
type => $type,
fname => basename($arg),
content => $content,
};
} else {
error "invalid mirror: $arg";
}
@ -5373,7 +5317,7 @@ sub main() {
}
}
if (scalar @{$sourceslists} == 0) {
warning "empty apt sources.list";
error "empty apt sources.list";
}
debug("sources list entries:");
for my $list (@{$sourceslists}) {
@ -6242,12 +6186,7 @@ I<TARGET> is C<-> or if no I<TARGET> was specified.
=head1 OPTIONS
Options are case insensitive. Short options may be bundled. Long options
require a double dash and may be abbreviated to uniqueness. Options can be
placed anywhere on the command line, even before or mixed with the I<SUITE>,
I<TARGET>, and I<MIRROR> arguments. A double dash C<--> can be used to stop
interpreting command line arguments as options to allow I<SUITE>, I<TARGET> and
I<MIRROR> arguments that start with a single or double dash. Option order only
matters for options that can be passed multiple times as documented below.
require a double dash and may be abbreviated to uniqueness.
=over 8
@ -6968,8 +6907,6 @@ Upon startup, several checks are carried out, like:
=item * whether the output directory is empty. This check can be disabled using B<--skip=check/empty>
=item * whether adding a C<signed-by> to C<apt/sources.list> is necessary. This requires gpg and can be disabled using B<--skip=check/signed-by>
=back
=item B<setup>
@ -7009,10 +6946,7 @@ variant uses the fact that libapt treats the C<apt> packages as implicitly
essential to download only all C<Essential:yes> packages plus apt using
C<apt-get dist-upgrade>. In the remaining variants, all Packages files
downloaded by the B<update> step are inspected to find the C<Essential:yes>
package set as well as all packages of the required priority. If I<SUITE> is a
non-empty string, then only packages from the archive with suite or codename
matching I<SUITE> will be considered for selection of C<Essential:yes>
packages.
package set as well as all packages of the required priority.
=item B<mount>

@ -23,8 +23,8 @@ done
cd ./shared;
$SUDO sh -x ./test.sh;
echo $?;
) 2>&1 | tee shared/output.txt
if [ "$(cat shared/exitstatus.txt)" -ne 0 ]; then
) 2>&1 | tee shared/result.txt | head --lines=-1
if [ "$(tail --lines=1 shared/result.txt)" -ne 0 ]; then
echo "test.sh failed"
exit 1
fi

@ -11,11 +11,10 @@ cleanup() {
rm -f "$tmpdir/debian-$DEFAULT_DIST-overlay.qcow"
rm -f "$tmpdir/log"
[ -e "$tmpdir" ] && rmdir "$tmpdir"
if [ -n "${TAIL_PID:-}" ]; then
kill "$TAIL_PID"
fi
if [ -e shared/output.txt ]; then
res="$(cat shared/exitstatus.txt)"
if [ -e shared/result.txt ]; then
head --lines=-1 shared/result.txt
res="$(tail --lines=1 shared/result.txt)"
rm shared/result.txt
if [ "$res" != "0" ]; then
# this might possibly overwrite another non-zero rv
rv=1
@ -46,14 +45,6 @@ case $ARCH in
*) echo "qemu kvm not supported on $ARCH" >&2;;
esac
echo 1 > shared/exitstatus.txt
if [ -e shared/output.txt ]; then
rm shared/output.txt
fi
touch shared/output.txt
tail -f shared/output.txt &
TAIL_PID=$!
# the path to debian-$DEFAULT_DIST.qcow must be absolute or otherwise qemu will
# look for the path relative to debian-$DEFAULT_DIST-overlay.qcow
qemu-img create -f qcow2 -b "$(realpath "$cachedir")/debian-$DEFAULT_DIST.qcow" -F qcow2 "$tmpdir/debian-$DEFAULT_DIST-overlay.qcow"

@ -1,8 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
{{ CMD }} --mode={{ MODE }} --variant=essential \
--include '?or(?exact-name(dummy-does-not-exist),?exact-name(apt))' \
{{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt -

@ -1,9 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
{{ CMD }} --mode={{ MODE }} --variant=custom \
--include '?narrow(?archive(^{{ DIST }}$),?essential)' \
--include apt \
{{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -

@ -61,15 +61,8 @@ for f in shadow shadow-; do
fi
done
# isc-dhcp-client postinst doesn't create this file in debootstrap run with
# unshared wrapper. The responsible postinst snippet was automatically added
# by dh_apparmor since isc-dhcp-client 4.4.3-P1-1.1
if [ -e /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient ] && [ ! -s /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient ]; then
echo /sbin/setcap > /tmp/debian-debootstrap/etc/apparmor.d/local/sbin.dhclient
fi
# check if the file content differs
diff --unified --no-dereference --recursive /tmp/debian-debootstrap /tmp/debian-mm >&2
diff --no-dereference --recursive /tmp/debian-debootstrap /tmp/debian-mm >&2
# check permissions, ownership, symlink targets, modification times using tar
# mtimes of directories created by mmdebstrap will differ, thus we equalize them first

@ -2,10 +2,14 @@
set -eu
export LC_ALL=C.UTF-8
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
if dpkg --compare-versions "$(dpkg-query -W -f='${Version}' libpam-runtime)" le 1.5.2-5; then
# https://bugs.debian.org/1022952
exit 0
fi
trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM
# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand
# DPKG_ROOT
for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do
for INCLUDE in '' 'systemd-sysv'; do
for MODE in root chrootless; do
{{ CMD }} --mode=$MODE --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \
${INCLUDE:+--include="$INCLUDE"} \

@ -16,7 +16,7 @@ prefix=
# DPKG_ROOT
# permissions drwxr-sr-x and extended attributes of ./var/log/journal/ cannot
# be preserved under fakeroot
for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do
for INCLUDE in '' 'systemd-sysv'; do
{{ CMD }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \
--customize-hook='if [ -d "$1"/var/log/journal ]; then rmdir "$1"/var/log/journal; mkdir --mode=2755 "$1"/var/log/journal; chroot "$1" chown root:systemd-journal /var/log/journal; fi' \
${INCLUDE:+--include="$INCLUDE"} \

@ -8,42 +8,20 @@ if [ ! -e /mmdebstrap-testenv ]; then
exit 1
fi
deb2qemu() {
case "$1" in
amd64) echo x86_64;;
arm64) echo aarch64;;
armel|armhf) echo arm;;
ppc64el) echo ppc64le;;
*) echo "$1";;
esac
}
if [ "$(dpkg --print-architecture)" = "arm64" ]; then
arch=amd64
else
arch=arm64
fi
[ "$(id -u)" -eq 0 ]
[ -e "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")" ]
[ -e /proc/sys/fs/binfmt_misc/qemu-aarch64 ]
# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand
# DPKG_ROOT
#
# dpkg is unable to install architecture arch:all packages with a
# dependency on an arch:any package (perl-modules-5.34 in this case)
# inside foreign architecture chrootless chroots, because dpkg will use
# its own architecture as the native architecture, see #825385 and #1020533
# So we are not testing the installation of apt,build-essential here.
for INCLUDE in '' 'apt' 'systemd-sysv'; do
echo 1 > "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")"
arch-test "$arch"
{{ CMD }} --mode=root --architecture="$arch" --variant={{ VARIANT }} \
for INCLUDE in '' 'systemd-sysv'; do
echo 1 > /proc/sys/fs/binfmt_misc/qemu-aarch64
arch-test arm64
{{ CMD }} --mode=root --architecture=arm64 --variant={{ VARIANT }} \
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
{{ DIST }} "/tmp/root.tar" {{ MIRROR }}
echo 0 > "/proc/sys/fs/binfmt_misc/qemu-$(deb2qemu "$arch")"
arch-test "$arch" && exit 1
{{ CMD }} --mode=chrootless --architecture="$arch" --variant={{ VARIANT }} \
echo 0 > /proc/sys/fs/binfmt_misc/qemu-aarch64
arch-test arm64 && exit 1
{{ CMD }} --mode=chrootless --architecture=arm64 --variant={{ VARIANT }} \
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
{{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }}
# when creating a foreign architecture chroot, the tarballs are not

@ -1,8 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
printf '' | {{ CMD }} --mode={{ MODE }} --variant=apt \
--setup-hook='echo "deb {{ MIRROR }} {{ DIST }} main" > "$1"/etc/apt/sources.list' \
{{ DIST }} /tmp/debian-chroot.tar -
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -

@ -7,7 +7,6 @@ export LC_ALL=C.UTF-8
head --lines=-1 /tmp/log > /tmp/trimmed
cat << LOG | diff -u - /tmp/trimmed
I: chroot architecture {{ HOSTARCH }} is equal to the host's architecture
I: finding correct signed-by value...
I: automatically chosen format: directory
I: running apt-get update...
I: downloading packages with apt...

@ -9,6 +9,7 @@ rm -r /tmp/debian-chroot/usr/share/doc/doc-debian
rm /tmp/debian-chroot/usr/share/lintian/overrides/tzdata
rm /tmp/debian-chroot/etc/localtime
rm /tmp/debian-chroot/etc/timezone
rm /tmp/debian-chroot/usr/sbin/tzconfig
rm -r /tmp/debian-chroot/usr/share/doc/tzdata
rm -r /tmp/debian-chroot/usr/share/zoneinfo
rm /tmp/debian-chroot/var/lib/apt/extended_states

Loading…
Cancel
Save