split up setup() into multiple functions

This commit is contained in:
Johannes 'josch' Schauer 2020-04-09 23:07:02 +02:00
parent 895c388ede
commit 1076e9a78d
Signed by: josch
GPG key ID: F2CBA5C78FBD83E1

View file

@ -1191,6 +1191,49 @@ sub setup {
warning "cannot read $options->{apttrustedparts}";
}
run_setup($options);
run_hooks('setup', $options);
run_update($options);
(my $pkgs_to_install, my $essential_pkgs) = run_download($options);
if ( $options->{mode} ne 'chrootless'
or $options->{variant} eq 'extract') {
# We have to extract the packages from @essential_pkgs either if we run
# in chrootless mode and extract variant or in any other mode. In
# other words, the only scenario in which the @essential_pkgs are not
# extracted are in chrootless mode in any other than the extract
# variant.
run_extract($options, $essential_pkgs);
}
run_hooks('extract', $options);
if ($options->{variant} ne 'extract') {
my $chrootcmd = [];
if ($options->{mode} ne 'chrootless') {
$chrootcmd = run_prepare($options);
}
run_essential($options, $essential_pkgs, $chrootcmd);
run_hooks('essential', $options);
run_install($options, $pkgs_to_install, $chrootcmd);
run_hooks('customize', $options);
}
run_cleanup($options);
return;
}
sub run_setup() {
my $options = shift;
{
my @directories = (
'/etc/apt/apt.conf.d', '/etc/apt/sources.list.d',
@ -1580,8 +1623,11 @@ sub setup {
$ENV{PATH} = "/usr/sbin:/usr/bin:/sbin:/bin";
}
# run setup hooks
run_hooks('setup', $options);
return;
}
sub run_update() {
my $options = shift;
info "running apt-get update...";
run_apt_progress({
@ -1607,6 +1653,12 @@ sub setup {
}
}
return;
}
sub run_download() {
my $options = shift;
my @pkgs_to_install;
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
@ -1827,21 +1879,23 @@ sub setup {
}
}
# We have to extract the packages from @essential_pkgs either if we run in
# chrootless mode and extract variant or in any other mode.
# In other words, the only scenario in which the @essential_pkgs are not
# extracted are in chrootless mode in any other than the extract variant.
if ( $options->{mode} eq 'chrootless'
and $options->{variant} ne 'extract') {
# nothing to do
} elsif ($options->{dryrun}) {
return (\@pkgs_to_install, \@essential_pkgs);
}
sub run_extract() {
my $options = shift;
my $essential_pkgs = shift;
if ($options->{dryrun}) {
info "skip extracting packages because of --dry-run";
} else {
return;
}
info "extracting archives...";
print_progress 0.0;
my $counter = 0;
my $total = scalar @essential_pkgs;
foreach my $deb (@essential_pkgs) {
my $total = scalar @{$essential_pkgs};
foreach my $deb (@{$essential_pkgs}) {
$counter += 1;
# not using dpkg-deb --extract as that would replace the
# merged-usr symlinks with plain directories
@ -1869,81 +1923,13 @@ sub setup {
print_progress($counter / $total * 100);
}
print_progress "done";
return;
}
run_hooks('extract', $options);
sub run_prepare {
my $options = shift;
if ($options->{mode} eq 'chrootless') {
if ($options->{dryrun}) {
info "simulate installing packages...";
} else {
info "installing packages...";
}
# FIXME: the dpkg config from the host is parsed before the command
# line arguments are parsed and might break this mode
# Example: if the host has --path-exclude set, then this will also
# affect the chroot.
my @chrootless_opts = (
'-oDPkg::Options::=--force-not-root',
'-oDPkg::Options::=--force-script-chrootless',
'-oDPkg::Options::=--root=' . $options->{root},
'-oDPkg::Options::=--log=' . "$options->{root}/var/log/dpkg.log",
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
);
if (defined $options->{qemu}) {
# The binfmt support on the outside is used, so qemu needs to know
# where it has to look for shared libraries
if (defined $ENV{QEMU_LD_PREFIX}
&& $ENV{QEMU_LD_PREFIX} ne "") {
## no critic (Variables::RequireLocalizedPunctuationVars)
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
} else {
## no critic (Variables::RequireLocalizedPunctuationVars)
$ENV{QEMU_LD_PREFIX} = $options->{root};
}
}
if ($options->{variant} eq 'extract') {
# nothing to do
} else {
run_apt_progress({
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
PKGS => [map { "$options->{root}/$_" } @essential_pkgs],
});
}
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
# nothing to do
} elsif (
any { $_ eq $options->{variant} } (
'essential', 'apt', 'standard', 'important',
'required', 'buildd', 'minbase'
)
) {
# run essential hooks
run_hooks('essential', $options);
if (scalar @pkgs_to_install > 0) {
run_apt_progress({
ARGV =>
['apt-get', '--yes', @chrootless_opts, 'install'],
PKGS => [@pkgs_to_install],
});
}
} else {
error "unknown variant: $options->{variant}";
}
} elsif (
any { $_ eq $options->{mode} }
('root', 'unshare', 'fakechroot', 'proot')
) {
if (any { $_ eq $options->{variant} } ('extract')) {
# nothing to do
} elsif (
any { $_ eq $options->{variant} } (
'custom', 'essential', 'apt', 'standard',
'important', 'required', 'buildd', 'minbase'
)
) {
if ($options->{mode} eq 'fakechroot') {
# this borrows from and extends
# /etc/fakechroot/debootstrap.env and
@ -1951,18 +1937,15 @@ sub setup {
{
my @fakechrootsubst = ();
foreach my $d ('/usr/sbin', '/usr/bin', '/sbin', '/bin') {
push @fakechrootsubst,
"$d/chroot=/usr/sbin/chroot.fakechroot";
push @fakechrootsubst, "$d/chroot=/usr/sbin/chroot.fakechroot";
push @fakechrootsubst, "$d/mkfifo=/bin/true";
push @fakechrootsubst, "$d/ldconfig=/bin/true";
push @fakechrootsubst,
"$d/ldd=/usr/bin/ldd.fakechroot";
push @fakechrootsubst, "$d/ldd=/usr/bin/ldd.fakechroot";
push @fakechrootsubst, "$d/ischroot=/bin/true";
}
if (defined $ENV{FAKECHROOT_CMD_SUBST}
&& $ENV{FAKECHROOT_CMD_SUBST} ne "") {
push @fakechrootsubst, split /:/,
$ENV{FAKECHROOT_CMD_SUBST};
push @fakechrootsubst, split /:/, $ENV{FAKECHROOT_CMD_SUBST};
}
## no critic (Variables::RequireLocalizedPunctuationVars)
$ENV{FAKECHROOT_CMD_SUBST} = join ':', @fakechrootsubst;
@ -2054,15 +2037,13 @@ sub setup {
if (($? != 0) or (!$deb_host_multiarch)) {
error "dpkg-architecture failed: $?";
}
my $fakechrootdir
= "/usr/lib/$deb_host_multiarch/fakechroot";
my $fakechrootdir = "/usr/lib/$deb_host_multiarch/fakechroot";
if (!-e "$fakechrootdir/libfakechroot.so") {
error "$fakechrootdir/libfakechroot.so doesn't exist."
. " Install libfakechroot:$options->{nativearch}"
. " outside the chroot";
}
my $fakerootdir
= "/usr/lib/$deb_host_multiarch/libfakeroot";
my $fakerootdir = "/usr/lib/$deb_host_multiarch/libfakeroot";
if (!-e "$fakerootdir/libfakeroot-sysv.so") {
error "$fakerootdir/libfakeroot-sysv.so doesn't exist."
. " Install libfakeroot:$options->{nativearch}"
@ -2081,8 +2062,7 @@ sub setup {
# to know where it has to look for shared libraries
if (defined $ENV{QEMU_LD_PREFIX}
&& $ENV{QEMU_LD_PREFIX} ne "") {
$ENV{QEMU_LD_PREFIX}
= "$ENV{QEMU_LD_PREFIX}:$options->{root}";
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
} else {
$ENV{QEMU_LD_PREFIX} = $options->{root};
}
@ -2120,19 +2100,16 @@ sub setup {
. " work under proot";
info "this is likely due to missing support for"
. " renameat2 in proot";
info
"see https://github.com/proot-me/PRoot/issues/147";
info "see https://github.com/proot-me/PRoot/issues/147";
} else {
info "the /bin/mv binary inside the chroot doesn't"
. " work under fakechroot";
info "with certain versions of coreutils and glibc,"
. " this is due to missing support for renameat2 in"
. " fakechroot";
info
"see https://github.com/dex4er/fakechroot/issues/60";
info "see https://github.com/dex4er/fakechroot/issues/60";
}
info
"expect package post installation scripts not to work";
info "expect package post installation scripts not to work";
rmdir "$options->{root}/000-move-me"
or error "cannot rmdir: $!";
} else {
@ -2141,6 +2118,51 @@ sub setup {
}
}
return \@chrootcmd;
}
sub run_essential() {
my $options = shift;
my $essential_pkgs = shift;
my $chrootcmd = shift;
if ($options->{mode} eq 'chrootless') {
if ($options->{dryrun}) {
info "simulate installing packages...";
} else {
info "installing packages...";
}
# FIXME: the dpkg config from the host is parsed before the command
# line arguments are parsed and might break this mode
# Example: if the host has --path-exclude set, then this will also
# affect the chroot.
my @chrootless_opts = (
'-oDPkg::Options::=--force-not-root',
'-oDPkg::Options::=--force-script-chrootless',
'-oDPkg::Options::=--root=' . $options->{root},
'-oDPkg::Options::=--log=' . "$options->{root}/var/log/dpkg.log",
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
);
if (defined $options->{qemu}) {
# The binfmt support on the outside is used, so qemu needs to know
# where it has to look for shared libraries
if (defined $ENV{QEMU_LD_PREFIX}
&& $ENV{QEMU_LD_PREFIX} ne "") {
## no critic (Variables::RequireLocalizedPunctuationVars)
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
} else {
## no critic (Variables::RequireLocalizedPunctuationVars)
$ENV{QEMU_LD_PREFIX} = $options->{root};
}
}
run_apt_progress({
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
PKGS => [map { "$options->{root}/$_" } @{$essential_pkgs}],
});
} elsif (
any { $_ eq $options->{mode} }
('root', 'unshare', 'fakechroot', 'proot')
) {
# install the extracted packages properly
# we need --force-depends because dpkg does not take Pre-Depends
# into account and thus doesn't install them in the right order
@ -2153,11 +2175,11 @@ sub setup {
sub {
run_dpkg_progress({
ARGV => [
@chrootcmd, 'env',
@{$chrootcmd}, 'env',
'--unset=TMPDIR', 'dpkg',
'--install', '--force-depends'
],
PKGS => \@essential_pkgs,
PKGS => $essential_pkgs,
});
},
$options
@ -2181,11 +2203,11 @@ sub setup {
sub {
run_dpkg_progress({
ARGV => [
@chrootcmd, 'env',
@{$chrootcmd}, 'env',
'--unset=TMPDIR', 'dpkg',
'--install', '--force-depends'
],
PKGS => \@essential_pkgs,
PKGS => $essential_pkgs,
});
},
$options
@ -2193,18 +2215,48 @@ sub setup {
}
}
foreach my $deb (@essential_pkgs) {
} else {
error "unknown mode: $options->{mode}";
}
foreach my $deb (@{$essential_pkgs}) {
unlink "$options->{root}/$deb"
or error "cannot unlink $deb: $!";
}
return;
}
sub run_install() {
my $options = shift;
my $pkgs_to_install = shift;
my $chrootcmd = shift;
if ($options->{mode} eq 'chrootless') {
if (scalar @{$pkgs_to_install} > 0) {
my @chrootless_opts = (
'-oDPkg::Options::=--force-not-root',
'-oDPkg::Options::=--force-script-chrootless',
'-oDPkg::Options::=--root=' . $options->{root},
'-oDPkg::Options::=--log='
. "$options->{root}/var/log/dpkg.log",
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
);
run_apt_progress({
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
PKGS => $pkgs_to_install,
});
}
} elsif (
any { $_ eq $options->{mode} }
('root', 'unshare', 'fakechroot', 'proot')
) {
# run essential hooks
if ($options->{variant} ne 'custom') {
run_hooks('essential', $options);
}
if ($options->{variant} ne 'custom'
and scalar @pkgs_to_install > 0) {
and scalar @{$pkgs_to_install} > 0) {
# some packages have to be installed from the outside before
# anything can be installed from the inside.
#
@ -2233,15 +2285,13 @@ sub setup {
while (my $uri = <$pipe_apt>) {
if ($uri =~ /^https:\/\//) {
# FIXME: support for https is part of apt >= 1.5
push @pkgs_to_install_from_outside,
'apt-transport-https';
push @pkgs_to_install_from_outside, 'apt-transport-https';
push @pkgs_to_install_from_outside, 'ca-certificates';
last;
} elsif ($uri =~ /^tor(\+[a-z]+)*:\/\//) {
# tor URIs can be tor+http://, tor+https:// or even
# tor+mirror+file://
push @pkgs_to_install_from_outside,
'apt-transport-tor';
push @pkgs_to_install_from_outside, 'apt-transport-tor';
last;
}
}
@ -2288,19 +2338,17 @@ sub setup {
}
close $dh;
if (scalar @debs_to_install == 0) {
warning
"nothing got downloaded -- maybe the packages"
warning "nothing got downloaded -- maybe the packages"
. " were already installed?";
} else {
# we need --force-depends because dpkg does not take
# Pre-Depends into account and thus doesn't install
# them in the right order
info 'installing '
. (join ', ', @pkgs_to_install_from_outside)
. "...";
. (join ', ', @pkgs_to_install_from_outside) . "...";
run_dpkg_progress({
ARGV => [
@chrootcmd, 'env',
@{$chrootcmd}, 'env',
'--unset=TMPDIR', 'dpkg',
'--install', '--force-depends'
],
@ -2321,15 +2369,12 @@ sub setup {
. " chroot...";
run_apt_progress({
ARGV => [
@chrootcmd,
'env',
'--unset=APT_CONFIG',
'--unset=TMPDIR',
'apt-get',
'--yes',
@{$chrootcmd}, 'env',
'--unset=APT_CONFIG', '--unset=TMPDIR',
'apt-get', '--yes',
'install'
],
PKGS => [@pkgs_to_install],
PKGS => $pkgs_to_install,
});
},
$options
@ -2342,18 +2387,19 @@ sub setup {
'apt-get', '--yes',
'-oAPT::Get::Simulate=true', 'install'
],
PKGS => [@pkgs_to_install],
PKGS => $pkgs_to_install,
});
}
}
} else {
error "unknown variant: $options->{variant}";
}
} else {
error "unknown mode: $options->{mode}";
}
run_hooks('customize', $options);
return;
}
sub run_cleanup() {
my $options = shift;
# clean up temporary configuration file
unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap"
@ -2369,7 +2415,10 @@ sub setup {
});
run_apt_progress(
{ ARGV => ['apt-get', 'clean'], CHDIR => $options->{root} });
unlink $tmpfile or error "failed to unlink $tmpfile: $!";
if (defined $ENV{APT_CONFIG} && -e $ENV{APT_CONFIG}) {
unlink $ENV{APT_CONFIG}
or error "failed to unlink $ENV{APT_CONFIG}: $!";
}
# apt since 1.6 creates the auxfiles directory. If apt inside the chroot
# is older than that, then it will not know how to clean it.