forked from josch/mmdebstrap
Compare commits
1 commit
e4e10b670c
...
444b3b6fec
Author | SHA1 | Date | |
---|---|---|---|
444b3b6fec |
3 changed files with 366 additions and 149 deletions
123
coverage.sh
123
coverage.sh
|
@ -127,7 +127,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
starttime=
|
starttime=
|
||||||
total=177
|
total=213
|
||||||
skipped=0
|
skipped=0
|
||||||
runtests=0
|
runtests=0
|
||||||
i=1
|
i=1
|
||||||
|
@ -2141,10 +2141,6 @@ tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt
|
||||||
ppc64el)
|
ppc64el)
|
||||||
echo ./lib64;
|
echo ./lib64;
|
||||||
;;
|
;;
|
||||||
s390x)
|
|
||||||
echo ./lib32;
|
|
||||||
echo ./usr/lib32/;
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
} | sort -u | diff -u - tar2.txt
|
} | sort -u | diff -u - tar2.txt
|
||||||
rm -r /tmp/debian-chroot
|
rm -r /tmp/debian-chroot
|
||||||
|
@ -3080,6 +3076,123 @@ END
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# test all variants
|
||||||
|
|
||||||
|
for variant in essential apt required minbase buildd important debootstrap - standard; do
|
||||||
|
print_header "mode=root,variant=$variant: create tarball"
|
||||||
|
cat << END > shared/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
$CMD --mode=root --variant=$variant $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
|
||||||
|
tar -tf /tmp/debian-chroot.tar | sort > "$variant.txt"
|
||||||
|
rm /tmp/debian-chroot.tar
|
||||||
|
END
|
||||||
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
|
./run_qemu.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
else
|
||||||
|
./run_null.sh SUDO
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
fi
|
||||||
|
# check if the other modes produce the same result in each variant
|
||||||
|
for mode in unshare fakechroot proot; do
|
||||||
|
print_header "mode=$mode,variant=$variant: create tarball"
|
||||||
|
# fontconfig doesn't install reproducibly because differences
|
||||||
|
# in /var/cache/fontconfig/. See
|
||||||
|
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864082
|
||||||
|
if [ "$variant" = standard ]; then
|
||||||
|
echo "skipping test because of #864082" >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then
|
||||||
|
echo "HAVE_UNSHARE != yes -- Skipping test..." >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then
|
||||||
|
echo "HAVE_PROOT != yes -- Skipping test..." >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
cat << END > shared/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then
|
||||||
|
if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
|
echo "this test modifies the system and should only be run inside a container" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
adduser --gecos user --disabled-password user
|
||||||
|
fi
|
||||||
|
if [ "$mode" = unshare ]; then
|
||||||
|
if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
|
echo "this test modifies the system and should only be run inside a container" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sysctl -w kernel.unprivileged_userns_clone=1
|
||||||
|
fi
|
||||||
|
prefix=
|
||||||
|
[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --"
|
||||||
|
\$prefix $CMD --mode=$mode --variant=$variant $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
|
||||||
|
tar -tf /tmp/debian-chroot.tar | sort | diff -u "./$variant.txt" -
|
||||||
|
rm /tmp/debian-chroot.tar
|
||||||
|
END
|
||||||
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
|
./run_qemu.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
else
|
||||||
|
./run_null.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# some variants are equal and some are strict superset of the last
|
||||||
|
# special case of the buildd variant: nothing is a superset of it
|
||||||
|
case "$variant" in
|
||||||
|
essential) ;; # nothing to compare it to
|
||||||
|
apt)
|
||||||
|
[ $(comm -23 shared/essential.txt shared/apt.txt | wc -l) -eq 0 ]
|
||||||
|
[ $(comm -13 shared/essential.txt shared/apt.txt | wc -l) -gt 0 ]
|
||||||
|
rm shared/essential.txt
|
||||||
|
;;
|
||||||
|
required)
|
||||||
|
[ $(comm -23 shared/apt.txt shared/required.txt | wc -l) -eq 0 ]
|
||||||
|
[ $(comm -13 shared/apt.txt shared/required.txt | wc -l) -gt 0 ]
|
||||||
|
rm shared/apt.txt
|
||||||
|
;;
|
||||||
|
minbase) # equal to required
|
||||||
|
cmp shared/required.txt shared/minbase.txt
|
||||||
|
rm shared/required.txt
|
||||||
|
;;
|
||||||
|
buildd)
|
||||||
|
[ $(comm -23 shared/minbase.txt shared/buildd.txt | wc -l) -eq 0 ]
|
||||||
|
[ $(comm -13 shared/minbase.txt shared/buildd.txt | wc -l) -gt 0 ]
|
||||||
|
rm shared/buildd.txt # we need minbase.txt but not buildd.txt
|
||||||
|
;;
|
||||||
|
important)
|
||||||
|
[ $(comm -23 shared/minbase.txt shared/important.txt | wc -l) -eq 0 ]
|
||||||
|
[ $(comm -13 shared/minbase.txt shared/important.txt | wc -l) -gt 0 ]
|
||||||
|
rm shared/minbase.txt
|
||||||
|
;;
|
||||||
|
debootstrap) # equal to important
|
||||||
|
cmp shared/important.txt shared/debootstrap.txt
|
||||||
|
rm shared/important.txt
|
||||||
|
;;
|
||||||
|
-) # equal to debootstrap
|
||||||
|
cmp shared/debootstrap.txt shared/-.txt
|
||||||
|
rm shared/debootstrap.txt
|
||||||
|
;;
|
||||||
|
standard)
|
||||||
|
[ $(comm -23 shared/-.txt shared/standard.txt | wc -l) -eq 0 ]
|
||||||
|
[ $(comm -13 shared/-.txt shared/standard.txt | wc -l) -gt 0 ]
|
||||||
|
rm shared/-.txt shared/standard.txt
|
||||||
|
;;
|
||||||
|
*) exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# test extract variant also with chrootless mode
|
# test extract variant also with chrootless mode
|
||||||
for mode in root unshare fakechroot proot chrootless; do
|
for mode in root unshare fakechroot proot chrootless; do
|
||||||
print_header "mode=$mode,variant=extract: unpack doc-debian"
|
print_header "mode=$mode,variant=extract: unpack doc-debian"
|
||||||
|
|
|
@ -224,9 +224,6 @@ Apt::Get::Download-Only true;
|
||||||
Acquire::Languages "none";
|
Acquire::Languages "none";
|
||||||
Dir::Etc::Trusted "/etc/apt/trusted.gpg";
|
Dir::Etc::Trusted "/etc/apt/trusted.gpg";
|
||||||
Dir::Etc::TrustedParts "/etc/apt/trusted.gpg.d";
|
Dir::Etc::TrustedParts "/etc/apt/trusted.gpg.d";
|
||||||
Acquire::http::Dl-Limit "1000";
|
|
||||||
Acquire::https::Dl-Limit "1000";
|
|
||||||
Acquire::Retries "5";
|
|
||||||
END
|
END
|
||||||
|
|
||||||
> "$rootdir/var/lib/dpkg/status"
|
> "$rootdir/var/lib/dpkg/status"
|
||||||
|
@ -469,17 +466,6 @@ cleanuptmpdir() {
|
||||||
export SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$newmirrordir/dists/$DEFAULT_DIST/Release")" +%s)
|
export SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$newmirrordir/dists/$DEFAULT_DIST/Release")" +%s)
|
||||||
|
|
||||||
if [ "$HAVE_QEMU" = "yes" ]; then
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
case "$HOSTARCH" in
|
|
||||||
amd64|i386)
|
|
||||||
# okay
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "qemu support is only available on amd64 and i386" >&2
|
|
||||||
echo "because syslinux is only available on those arches" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# We must not use any --dpkgopt here because any dpkg options still
|
# We must not use any --dpkgopt here because any dpkg options still
|
||||||
# leak into the chroot with chrootless mode.
|
# leak into the chroot with chrootless mode.
|
||||||
# We do not use our own package cache here because
|
# We do not use our own package cache here because
|
||||||
|
@ -521,9 +507,6 @@ if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
arches=$HOSTARCH
|
arches=$HOSTARCH
|
||||||
fi
|
fi
|
||||||
$CMD --variant=apt --architectures=$arches --include="$pkgs" \
|
$CMD --variant=apt --architectures=$arches --include="$pkgs" \
|
||||||
--aptopt='Acquire::http::Dl-Limit "1000"' \
|
|
||||||
--aptopt='Acquire::https::Dl-Limit "1000"' \
|
|
||||||
--aptopt='Acquire::Retries "5"' \
|
|
||||||
$DEFAULT_DIST - "$mirror" > "$tmpdir/debian-chroot.tar"
|
$DEFAULT_DIST - "$mirror" > "$tmpdir/debian-chroot.tar"
|
||||||
|
|
||||||
cat << END > "$tmpdir/extlinux.conf"
|
cat << END > "$tmpdir/extlinux.conf"
|
||||||
|
@ -557,7 +540,7 @@ END
|
||||||
cat << 'END' > "$tmpdir/worker.sh"
|
cat << 'END' > "$tmpdir/worker.sh"
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo 'root:root' | chpasswd
|
echo 'root:root' | chpasswd
|
||||||
mount -t 9p -o trans=virtio,access=any,msize=128k mmdebstrap /mnt
|
mount -t 9p -o trans=virtio,access=any mmdebstrap /mnt
|
||||||
# need to restart mini-httpd because we mounted different content into www-root
|
# need to restart mini-httpd because we mounted different content into www-root
|
||||||
systemctl restart mini-httpd
|
systemctl restart mini-httpd
|
||||||
|
|
||||||
|
|
373
mmdebstrap
373
mmdebstrap
|
@ -1510,7 +1510,8 @@ sub setup {
|
||||||
run_update($options);
|
run_update($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
(my $essential_pkgs, my $cached_debs) = run_download($options);
|
(my $pkgs_to_install, my $essential_pkgs, my $cached_debs)
|
||||||
|
= run_download($options);
|
||||||
|
|
||||||
# in theory, we don't have to extract the packages in chrootless mode
|
# in theory, we don't have to extract the packages in chrootless mode
|
||||||
# but we do it anyways because otherwise directory creation timestamps
|
# but we do it anyways because otherwise directory creation timestamps
|
||||||
|
@ -1532,7 +1533,7 @@ sub setup {
|
||||||
|
|
||||||
run_hooks('essential', $options);
|
run_hooks('essential', $options);
|
||||||
|
|
||||||
run_install($options, $chrootcmd);
|
run_install($options, $pkgs_to_install, $chrootcmd);
|
||||||
|
|
||||||
run_hooks('customize', $options);
|
run_hooks('customize', $options);
|
||||||
}
|
}
|
||||||
|
@ -1991,6 +1992,22 @@ sub run_update() {
|
||||||
sub run_download() {
|
sub run_download() {
|
||||||
my $options = shift;
|
my $options = shift;
|
||||||
|
|
||||||
|
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') {
|
||||||
|
$pkgs_to_install{'build-essential'} = ();
|
||||||
|
}
|
||||||
|
|
||||||
# We use /var/cache/apt/archives/ to figure out which packages apt chooses
|
# We use /var/cache/apt/archives/ to figure out which packages apt chooses
|
||||||
# to install. That's why the directory must be empty if:
|
# to install. That's why the directory must be empty if:
|
||||||
# - /var/cache/apt/archives exists, and
|
# - /var/cache/apt/archives exists, and
|
||||||
|
@ -2014,7 +2031,7 @@ sub run_download() {
|
||||||
if (
|
if (
|
||||||
!$options->{dryrun}
|
!$options->{dryrun}
|
||||||
&& ((none { $_ eq $options->{variant} } ('extract', 'custom'))
|
&& ((none { $_ eq $options->{variant} } ('extract', 'custom'))
|
||||||
|| scalar @{ $options->{include} } != 0)
|
|| scalar keys %pkgs_to_install != 0)
|
||||||
&& -d "$options->{root}/var/cache/apt/archives/"
|
&& -d "$options->{root}/var/cache/apt/archives/"
|
||||||
) {
|
) {
|
||||||
my $apt_archives = "/var/cache/apt/archives/";
|
my $apt_archives = "/var/cache/apt/archives/";
|
||||||
|
@ -2047,22 +2064,10 @@ sub run_download() {
|
||||||
# (essential variant) then we have to compute the package set ourselves.
|
# (essential variant) then we have to compute the package set ourselves.
|
||||||
# Same if we want to install priority based variants.
|
# Same if we want to install priority based variants.
|
||||||
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
|
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
|
||||||
if (scalar @{ $options->{include} } == 0) {
|
if (scalar keys %pkgs_to_install == 0) {
|
||||||
info "nothing to download -- skipping...";
|
info "nothing to download -- skipping...";
|
||||||
return ([], []);
|
return ([], []);
|
||||||
}
|
}
|
||||||
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} = ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my %result = ();
|
my %result = ();
|
||||||
if ($options->{dryrun}) {
|
if ($options->{dryrun}) {
|
||||||
|
@ -2121,10 +2126,7 @@ sub run_download() {
|
||||||
],
|
],
|
||||||
%result
|
%result
|
||||||
});
|
});
|
||||||
} elsif (
|
} elsif ($options->{variant} eq 'essential') {
|
||||||
any { $_ eq $options->{variant} }
|
|
||||||
('essential', 'standard', 'important', 'required', 'buildd')
|
|
||||||
) {
|
|
||||||
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
|
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
|
||||||
# 17:27 < DonKult> (?essential includes 'apt' through)
|
# 17:27 < DonKult> (?essential includes 'apt' through)
|
||||||
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
|
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
|
||||||
|
@ -2149,7 +2151,7 @@ sub run_download() {
|
||||||
'install',
|
'install',
|
||||||
'?narrow('
|
'?narrow('
|
||||||
. (
|
. (
|
||||||
length($options->{suite})
|
defined($options->{suite})
|
||||||
? '?archive(' . $options->{suite} . '),'
|
? '?archive(' . $options->{suite} . '),'
|
||||||
: ''
|
: ''
|
||||||
)
|
)
|
||||||
|
@ -2159,6 +2161,209 @@ sub run_download() {
|
||||||
],
|
],
|
||||||
%result
|
%result
|
||||||
});
|
});
|
||||||
|
} elsif (
|
||||||
|
any { $_ eq $options->{variant} }
|
||||||
|
('standard', 'important', 'required', 'minbase', 'buildd')
|
||||||
|
) {
|
||||||
|
# In the future, after bug https://bugs.debian.org/989558 is fixed, we
|
||||||
|
# want to use apt patterns to select the packages to install:
|
||||||
|
#
|
||||||
|
# ?narrow(?archive(unstable),?architecture(amd64),?priority(important))
|
||||||
|
#
|
||||||
|
# Once this is possible, we can append above statement to the apt-get
|
||||||
|
# install call in run_download() instead of assembling the package list
|
||||||
|
# here and passing it through all the way. Then this function only
|
||||||
|
# takes care of retrieving the essential packages.
|
||||||
|
#
|
||||||
|
# https://salsa.debian.org/apt-team/apt/-/merge_requests/185
|
||||||
|
my %ess_pkgs;
|
||||||
|
my %ess_pkgs_target;
|
||||||
|
my %pkgs_to_install_target = %pkgs_to_install;
|
||||||
|
my $num_suite_matches = 0;
|
||||||
|
my $num_suite_mismatch = 0;
|
||||||
|
open(
|
||||||
|
my $pipe_apt,
|
||||||
|
'-|',
|
||||||
|
'apt-get',
|
||||||
|
'indextargets',
|
||||||
|
'--format',
|
||||||
|
('$(CODENAME)' . "\t" . '$(SUITE)' . "\t" . '$(FILENAME)'),
|
||||||
|
'Created-By: Packages'
|
||||||
|
) or error "cannot start apt-get indextargets: $!";
|
||||||
|
while (my $line = <$pipe_apt>) {
|
||||||
|
chomp $line;
|
||||||
|
my ($codename, $suite, $fname) = split /\t/, $line, 3;
|
||||||
|
debug "processing indextarget output for $codename $suite $fname";
|
||||||
|
my $suite_matches = 0;
|
||||||
|
if (
|
||||||
|
defined $options->{suite}
|
||||||
|
and
|
||||||
|
($options->{suite} eq $codename or $options->{suite} eq $suite)
|
||||||
|
) {
|
||||||
|
$suite_matches = 1;
|
||||||
|
$num_suite_matches++;
|
||||||
|
} else {
|
||||||
|
$num_suite_mismatch++;
|
||||||
|
}
|
||||||
|
open(my $pipe_cat, '-|', '/usr/lib/apt/apt-helper', 'cat-file',
|
||||||
|
$fname)
|
||||||
|
or error "cannot start apt-helper cat-file: $!";
|
||||||
|
|
||||||
|
my $pkgname;
|
||||||
|
my $ess = '';
|
||||||
|
my $prio = 'optional';
|
||||||
|
my $arch = '';
|
||||||
|
while (my $line = <$pipe_cat>) {
|
||||||
|
chomp $line;
|
||||||
|
# Dpkg::Index takes 10 seconds to parse a typical Packages
|
||||||
|
# file. Thus we instead use a simple parser that just retrieve
|
||||||
|
# the information we need.
|
||||||
|
if ($line ne "") {
|
||||||
|
if ($line =~ /^Package: (.*)/) {
|
||||||
|
$pkgname = $1;
|
||||||
|
} elsif ($line =~ /^Essential: yes$/) {
|
||||||
|
$ess = 'yes';
|
||||||
|
} elsif ($line =~ /^Priority: (.*)/) {
|
||||||
|
$prio = $1;
|
||||||
|
} elsif ($line =~ /^Architecture: (.*)/) {
|
||||||
|
$arch = $1;
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
# we are only interested of packages of native architecture or
|
||||||
|
# Architecture:all
|
||||||
|
if ($arch eq $options->{nativearch} or $arch eq 'all') {
|
||||||
|
# the line is empty, thus a package stanza just finished
|
||||||
|
# processing and we can handle it now
|
||||||
|
if ($ess eq 'yes') {
|
||||||
|
$ess_pkgs{$pkgname} = ();
|
||||||
|
if ($suite_matches) {
|
||||||
|
$ess_pkgs_target{$pkgname} = ();
|
||||||
|
}
|
||||||
|
} elsif ($options->{variant} eq 'essential') {
|
||||||
|
# for this variant we are only interested in the
|
||||||
|
# essential packages
|
||||||
|
} elsif (
|
||||||
|
any { $_ eq $options->{variant} } (
|
||||||
|
'standard', 'important', 'required', 'buildd',
|
||||||
|
'minbase'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if ($prio eq 'optional' or $prio eq 'extra') {
|
||||||
|
# always ignore packages of priority optional and
|
||||||
|
# extra
|
||||||
|
} elsif ($prio eq 'standard') {
|
||||||
|
if (
|
||||||
|
none { $_ eq $options->{variant} }
|
||||||
|
('important', 'required', 'buildd', 'minbase')
|
||||||
|
) {
|
||||||
|
$pkgs_to_install{$pkgname} = ();
|
||||||
|
if ($suite_matches) {
|
||||||
|
$pkgs_to_install_target{$pkgname} = ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($prio eq 'important') {
|
||||||
|
if (
|
||||||
|
none { $_ eq $options->{variant} }
|
||||||
|
('required', 'buildd', 'minbase')
|
||||||
|
) {
|
||||||
|
$pkgs_to_install{$pkgname} = ();
|
||||||
|
if ($suite_matches) {
|
||||||
|
$pkgs_to_install_target{$pkgname} = ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($prio eq 'required') {
|
||||||
|
# required packages are part of all sets except
|
||||||
|
# essential and apt
|
||||||
|
$pkgs_to_install{$pkgname} = ();
|
||||||
|
if ($suite_matches) {
|
||||||
|
$pkgs_to_install_target{$pkgname} = ();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error "unknown priority: $prio";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error "unknown variant: $options->{variant}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# reset values
|
||||||
|
undef $pkgname;
|
||||||
|
$ess = '';
|
||||||
|
$prio = 'optional';
|
||||||
|
$arch = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
close $pipe_cat;
|
||||||
|
$? == 0 or error "apt-helper cat-file failed: $?";
|
||||||
|
}
|
||||||
|
close $pipe_apt;
|
||||||
|
$? == 0 or error "apt-get indextargets failed: $?";
|
||||||
|
|
||||||
|
# We now have two package sets, %pkgs_to_install and
|
||||||
|
# %pkgs_to_install_target, where the latter was only filled if the
|
||||||
|
# suite matched the codename or the suite name of one of the given
|
||||||
|
# apt indices.
|
||||||
|
# We only need to bother with this distinction if one or more of the
|
||||||
|
# indices matched and one or more of the indices mismatched. If either
|
||||||
|
# nothing matched or all matched, then we can just use %pkgs_to_install
|
||||||
|
if ( defined $options->{suite}
|
||||||
|
and $num_suite_matches > 0
|
||||||
|
and $num_suite_mismatch > 0) {
|
||||||
|
# Now we know that some matched and some didn't. But we only
|
||||||
|
# replace the results from all indices with the results from those
|
||||||
|
# indices that matched if the results are actually different and
|
||||||
|
# if there is more than zero packages from the indices that matched
|
||||||
|
if (scalar keys %ess_pkgs_target > 0
|
||||||
|
and keys %ess_pkgs != %ess_pkgs_target) {
|
||||||
|
info( "multiple sources defined, using those matching "
|
||||||
|
. "'$options->{suite}' to find essential packages");
|
||||||
|
%ess_pkgs = %ess_pkgs_target;
|
||||||
|
}
|
||||||
|
if (scalar keys %pkgs_to_install_target > 0
|
||||||
|
and keys %pkgs_to_install != keys %pkgs_to_install_target) {
|
||||||
|
if ($options->{variant} eq 'essential') {
|
||||||
|
error "logic error";
|
||||||
|
} elsif (
|
||||||
|
any { $_ eq $options->{variant} }
|
||||||
|
('standard', 'important', 'required', 'buildd', 'minbase')
|
||||||
|
) {
|
||||||
|
info( "multiple sources defined -- using those matching "
|
||||||
|
. "'$options->{suite}' to find packages for variant "
|
||||||
|
. "'$options->{variant}'");
|
||||||
|
%pkgs_to_install = %pkgs_to_install_target;
|
||||||
|
} else {
|
||||||
|
error "unknown variant: $options->{variant}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug "Identified the following Essential:yes packages:";
|
||||||
|
foreach my $pkg (sort keys %ess_pkgs) {
|
||||||
|
debug " $pkg";
|
||||||
|
}
|
||||||
|
|
||||||
|
my %result = ();
|
||||||
|
if ($options->{dryrun}) {
|
||||||
|
info "simulate downloading packages with apt...";
|
||||||
|
} else {
|
||||||
|
# if there are already packages in /var/cache/apt/archives/, we
|
||||||
|
# need to use our proxysolver to obtain the solution chosen by apt
|
||||||
|
if (scalar @cached_debs > 0) {
|
||||||
|
$result{EDSP_RES} = \@dl_debs;
|
||||||
|
}
|
||||||
|
info "downloading packages with apt...";
|
||||||
|
}
|
||||||
|
run_apt_progress({
|
||||||
|
ARGV => [
|
||||||
|
'apt-get',
|
||||||
|
'--yes',
|
||||||
|
'-oApt::Get::Download-Only=true',
|
||||||
|
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
|
||||||
|
'install'
|
||||||
|
],
|
||||||
|
PKGS => [keys %ess_pkgs],
|
||||||
|
%result
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
error "unknown variant: $options->{variant}";
|
error "unknown variant: $options->{variant}";
|
||||||
}
|
}
|
||||||
|
@ -2228,7 +2433,7 @@ sub run_download() {
|
||||||
# list before returning it.
|
# list before returning it.
|
||||||
@essential_pkgs = sort @essential_pkgs;
|
@essential_pkgs = sort @essential_pkgs;
|
||||||
|
|
||||||
return (\@essential_pkgs, \@cached_debs);
|
return ([keys %pkgs_to_install], \@essential_pkgs, \@cached_debs);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run_extract() {
|
sub run_extract() {
|
||||||
|
@ -2670,51 +2875,12 @@ sub run_essential() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run_install() {
|
sub run_install() {
|
||||||
my $options = shift;
|
my $options = shift;
|
||||||
my $chrootcmd = shift;
|
my $pkgs_to_install = shift;
|
||||||
|
my $chrootcmd = shift;
|
||||||
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') {
|
|
||||||
$pkgs_to_install{'build-essential'} = ();
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
any { $_ eq $options->{variant} }
|
|
||||||
('required', 'important', 'standard', 'buildd')
|
|
||||||
) {
|
|
||||||
my $priority;
|
|
||||||
if (any { $_ eq $options->{variant} } ('required', 'buildd')) {
|
|
||||||
$priority = '?priority(required)';
|
|
||||||
} elsif ($options->{variant} eq 'important') {
|
|
||||||
$priority = '?or(?priority(required),?priority(important))';
|
|
||||||
} elsif ($options->{variant} eq 'standard') {
|
|
||||||
$priority = '?or(~prequired,~pimportant,~pstandard)';
|
|
||||||
}
|
|
||||||
$pkgs_to_install{
|
|
||||||
"?narrow("
|
|
||||||
. (
|
|
||||||
length($options->{suite})
|
|
||||||
? '?archive(' . $options->{suite} . '),'
|
|
||||||
: ''
|
|
||||||
)
|
|
||||||
. "?architecture($options->{nativearch}),"
|
|
||||||
. "$priority)"
|
|
||||||
} = ();
|
|
||||||
}
|
|
||||||
my @pkgs_to_install = keys %pkgs_to_install;
|
|
||||||
|
|
||||||
if ($options->{mode} eq 'chrootless') {
|
if ($options->{mode} eq 'chrootless') {
|
||||||
if (scalar @pkgs_to_install > 0) {
|
if (scalar @{$pkgs_to_install} > 0) {
|
||||||
my @chrootless_opts = (
|
my @chrootless_opts = (
|
||||||
'-oDPkg::Options::=--force-not-root',
|
'-oDPkg::Options::=--force-not-root',
|
||||||
'-oDPkg::Options::=--force-script-chrootless',
|
'-oDPkg::Options::=--force-script-chrootless',
|
||||||
|
@ -2725,7 +2891,7 @@ sub run_install() {
|
||||||
);
|
);
|
||||||
run_apt_progress({
|
run_apt_progress({
|
||||||
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
|
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
|
||||||
PKGS => [@pkgs_to_install],
|
PKGS => $pkgs_to_install,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} elsif (
|
} elsif (
|
||||||
|
@ -2733,7 +2899,7 @@ sub run_install() {
|
||||||
('root', 'unshare', 'fakechroot', 'proot')
|
('root', 'unshare', 'fakechroot', 'proot')
|
||||||
) {
|
) {
|
||||||
if ($options->{variant} ne 'custom'
|
if ($options->{variant} ne 'custom'
|
||||||
and scalar @pkgs_to_install > 0) {
|
and scalar @{$pkgs_to_install} > 0) {
|
||||||
# Advantage of running apt on the outside instead of inside the
|
# Advantage of running apt on the outside instead of inside the
|
||||||
# chroot:
|
# chroot:
|
||||||
#
|
#
|
||||||
|
@ -2779,7 +2945,7 @@ sub run_install() {
|
||||||
'--yes',
|
'--yes',
|
||||||
'install'
|
'install'
|
||||||
],
|
],
|
||||||
PKGS => [@pkgs_to_install],
|
PKGS => $pkgs_to_install,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
$options
|
$options
|
||||||
|
@ -2792,7 +2958,7 @@ sub run_install() {
|
||||||
'apt-get', '--yes',
|
'apt-get', '--yes',
|
||||||
'-oAPT::Get::Simulate=true', 'install'
|
'-oAPT::Get::Simulate=true', 'install'
|
||||||
],
|
],
|
||||||
PKGS => [@pkgs_to_install],
|
PKGS => $pkgs_to_install,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3794,9 +3960,6 @@ sub get_keyring_by_suite {
|
||||||
|
|
||||||
my $debianvendor;
|
my $debianvendor;
|
||||||
my $ubuntuvendor;
|
my $ubuntuvendor;
|
||||||
# make $@ local, so we don't print "Can't locate Dpkg/Vendor/Debian.pm"
|
|
||||||
# in other parts where we evaluate $@
|
|
||||||
local $@ = '';
|
|
||||||
eval {
|
eval {
|
||||||
require Dpkg::Vendor::Debian;
|
require Dpkg::Vendor::Debian;
|
||||||
require Dpkg::Vendor::Ubuntu;
|
require Dpkg::Vendor::Ubuntu;
|
||||||
|
@ -3916,9 +4079,6 @@ sub get_sourceslist_by_suite {
|
||||||
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
||||||
my $bullseye_or_later = 0;
|
my $bullseye_or_later = 0;
|
||||||
my $distro_info = '/usr/share/distro-info/debian.csv';
|
my $distro_info = '/usr/share/distro-info/debian.csv';
|
||||||
# make $@ local, so we don't print "Can't locate Debian/DistroInfo.pm"
|
|
||||||
# in other parts where we evaluate $@
|
|
||||||
local $@ = '';
|
|
||||||
eval { require Debian::DistroInfo; };
|
eval { require Debian::DistroInfo; };
|
||||||
if (!$@) {
|
if (!$@) {
|
||||||
# libdistro-info-perl is installed
|
# libdistro-info-perl is installed
|
||||||
|
@ -4145,20 +4305,9 @@ sub main() {
|
||||||
'h|help' => sub { pod2usage(-exitval => 0, -verbose => 1) },
|
'h|help' => sub { pod2usage(-exitval => 0, -verbose => 1) },
|
||||||
'man' => sub { pod2usage(-exitval => 0, -verbose => 2) },
|
'man' => sub { pod2usage(-exitval => 0, -verbose => 2) },
|
||||||
'version' => sub { print STDOUT "mmdebstrap $VERSION\n"; exit 0; },
|
'version' => sub { print STDOUT "mmdebstrap $VERSION\n"; exit 0; },
|
||||||
'components=s@' => \$options->{components},
|
'components=s@' => \$options->{components},
|
||||||
'variant=s' => \$options->{variant},
|
'variant=s' => \$options->{variant},
|
||||||
'include=s' => sub {
|
'include=s@' => \$options->{include},
|
||||||
my ($opt_name, $opt_value) = @_;
|
|
||||||
for my $pkg (split /[,\s]+/, $opt_value) {
|
|
||||||
# strip leading and trailing whitespace
|
|
||||||
$pkg =~ s/^\s+|\s+$//g;
|
|
||||||
# skip if the remainder is an empty string
|
|
||||||
if ($pkg eq '') {
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
push @{ $options->{include} }, $pkg;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'architectures=s@' => \$options->{architectures},
|
'architectures=s@' => \$options->{architectures},
|
||||||
'mode=s' => \$options->{mode},
|
'mode=s' => \$options->{mode},
|
||||||
'dpkgopt=s@' => \$options->{dpkgopts},
|
'dpkgopt=s@' => \$options->{dpkgopts},
|
||||||
|
@ -4281,10 +4430,6 @@ sub main() {
|
||||||
if (any { $_ eq $options->{variant} } ('-', 'debootstrap')) {
|
if (any { $_ eq $options->{variant} } ('-', 'debootstrap')) {
|
||||||
$options->{variant} = 'important';
|
$options->{variant} = 'important';
|
||||||
}
|
}
|
||||||
# minbase is an alias for required
|
|
||||||
if ($options->{variant} eq 'minbase') {
|
|
||||||
$options->{variant} = 'required';
|
|
||||||
}
|
|
||||||
|
|
||||||
# fakeroot is an alias for fakechroot
|
# fakeroot is an alias for fakechroot
|
||||||
if ($options->{mode} eq 'fakeroot') {
|
if ($options->{mode} eq 'fakeroot') {
|
||||||
|
@ -4353,7 +4498,7 @@ sub main() {
|
||||||
# the --robot option was introduced in 1.20.0 but until 1.20.2 the
|
# the --robot option was introduced in 1.20.0 but until 1.20.2 the
|
||||||
# output contained a string after the version, separated by a
|
# output contained a string after the version, separated by a
|
||||||
# whitespace -- since then, it's only the version
|
# whitespace -- since then, it's only the version
|
||||||
if ($? == 0 and $content =~ /^([0-9.]+).*$/) {
|
if ($? == 0 and $content =~ /^([0-9.]+)( .*)?$/) {
|
||||||
# dpkg is new enough for the --robot option
|
# dpkg is new enough for the --robot option
|
||||||
$dpkgversion = version->new($1);
|
$dpkgversion = version->new($1);
|
||||||
}
|
}
|
||||||
|
@ -4374,8 +4519,8 @@ sub main() {
|
||||||
and $content =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/m) {
|
and $content =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/m) {
|
||||||
$aptversion = version->new($1);
|
$aptversion = version->new($1);
|
||||||
}
|
}
|
||||||
if ($aptversion < "2.3.10") {
|
if ($aptversion < "2.3.7") {
|
||||||
error "need apt >= 2.3.10 but have $aptversion";
|
error "need apt >= 2.3.7 but have $aptversion";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6007,9 +6152,9 @@ option depends on the selected variant. The B<extract> and B<custom> variants
|
||||||
install no packages by default, so for these variants, the packages specified
|
install no packages by default, so for these variants, the packages specified
|
||||||
by this option will be the only ones that get either extracted or installed by
|
by this option will be the only ones that get either extracted or installed by
|
||||||
dpkg, respectively. For all other variants, apt is used to install the
|
dpkg, respectively. For all other variants, apt is used to install the
|
||||||
additional packages. Package names are directly passed to apt and thus, you
|
additional packages. Package names are directly passed to
|
||||||
can use apt features like C<pkg/suite>, C<pkg=version>, C<pkg->, use a glob or
|
apt and thus, you can use apt features like C<pkg/suite>, C<pkg=version>,
|
||||||
regex for C<pkg> or use apt patterns. See apt(8) for the supported
|
C<pkg-> or use a glob or regex for C<pkg>. See apt(8) for the supported
|
||||||
syntax. The option can be specified multiple times and the packages are
|
syntax. The option can be specified multiple times and the packages are
|
||||||
concatenated in the order in which they are given on the command line. If
|
concatenated in the order in which they are given on the command line. If
|
||||||
later list items are repeated, then they get dropped so that the resulting
|
later list items are repeated, then they get dropped so that the resulting
|
||||||
|
@ -6316,10 +6461,8 @@ All package sets also include the direct and indirect hard dependencies (but
|
||||||
not recommends) of the selected package sets. The variants B<minbase>,
|
not recommends) of the selected package sets. The variants B<minbase>,
|
||||||
B<buildd> and B<->, resemble the package sets that debootstrap would install
|
B<buildd> and B<->, resemble the package sets that debootstrap would install
|
||||||
with the same I<--variant> argument. The release with a name matching the
|
with the same I<--variant> argument. The release with a name matching the
|
||||||
I<SUITE> argument as well as the native architecture will be used to determine
|
I<SUITE> argument will be used to determine the C<Essential:yes> and priority
|
||||||
the C<Essential:yes> and priority values. To select packages with matching
|
values.
|
||||||
priority from any suite, specify the empty string for I<SUITE>. The default
|
|
||||||
variant is B<debootstrap>.
|
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
|
@ -6346,30 +6489,19 @@ The B<essential> set plus apt.
|
||||||
=item B<required>, B<minbase>
|
=item B<required>, B<minbase>
|
||||||
|
|
||||||
The B<essential> set plus all packages with Priority:required and apt.
|
The B<essential> set plus all packages with Priority:required and apt.
|
||||||
It is roughly equivalent to running mmdebstrap with
|
|
||||||
|
|
||||||
--variant=essential --include="?priority(required)"
|
|
||||||
|
|
||||||
=item B<buildd>
|
=item B<buildd>
|
||||||
|
|
||||||
The B<minbase> set plus build-essential.
|
The B<minbase> set plus build-essential.
|
||||||
It is roughly equivalent to running mmdebstrap with
|
|
||||||
|
|
||||||
--variant=essential --include="?priority(required),build-essential"
|
|
||||||
|
|
||||||
=item B<important>, B<debootstrap>, B<->
|
=item B<important>, B<debootstrap>, B<->
|
||||||
|
|
||||||
The B<required> set plus all packages with Priority:important. This is the
|
The B<required> set plus all packages with Priority:important. This is the
|
||||||
default of debootstrap. It is roughly equivalent to running mmdebstrap with
|
default of debootstrap.
|
||||||
|
|
||||||
--variant=essential --include="~prequired|~pimportant"
|
|
||||||
|
|
||||||
=item B<standard>
|
=item B<standard>
|
||||||
|
|
||||||
The B<important> set plus all packages with Priority:standard.
|
The B<important> set plus all packages with Priority:standard.
|
||||||
It is roughly equivalent to running mmdebstrap with
|
|
||||||
|
|
||||||
--variant=essential --include="~prequired|~pimportant|~pstandard"
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
@ -6847,17 +6979,6 @@ Create a system that can be used with podman:
|
||||||
root
|
root
|
||||||
$ podman rmi debian
|
$ podman rmi debian
|
||||||
|
|
||||||
As a docker/podman replacement:
|
|
||||||
|
|
||||||
$ mmdebstrap unstable | mmtarfilter --path-exclude='/dev/*' > chroot.tar
|
|
||||||
[...]
|
|
||||||
$ mmdebstrap --variant=custom --skip=update \
|
|
||||||
--setup-hook='tar-in chroot.tar /' \
|
|
||||||
--customize-hook='chroot "$1" whoami' unstable /dev/null
|
|
||||||
[...]
|
|
||||||
root
|
|
||||||
$ rm chroot.tar
|
|
||||||
|
|
||||||
=head1 ENVIRONMENT VARIABLES
|
=head1 ENVIRONMENT VARIABLES
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
Loading…
Reference in a new issue