add --verbose option that prints apt and dpkg output instead of progress bars

This commit is contained in:
Johannes 'josch' Schauer 2018-12-27 21:08:53 +01:00
parent 61ad8a8e45
commit f4263ebd74
Signed by untrusted user: josch
GPG key ID: F2CBA5C78FBD83E1

View file

@ -437,8 +437,10 @@ sub print_progress {
} }
sub run_dpkg_progress { sub run_dpkg_progress {
my $debs = shift; my $options = shift;
my @args = @_; my @args = @{$options->{ARGV}};
my @debs = @{$options->{PKGS}};
my $verbose = $options->{VERBOSE} // 0;
pipe my $rfh, my $wfh; pipe my $rfh, my $wfh;
my $dpkgpid = open (my $pipe_dpkg, '-|') // die "failed to fork(): $!"; my $dpkgpid = open (my $pipe_dpkg, '-|') // die "failed to fork(): $!";
if ($dpkgpid == 0) { if ($dpkgpid == 0) {
@ -450,7 +452,7 @@ sub run_dpkg_progress {
my $fd = fileno $wfh; my $fd = fileno $wfh;
# redirect dpkg's stderr to stdout so that we can capture it # redirect dpkg's stderr to stdout so that we can capture it
open(STDERR, '>&', STDOUT); open(STDERR, '>&', STDOUT);
exec { $args[0] } @args, "--status-fd=$fd", @{$debs}; exec { $args[0] } @args, "--status-fd=$fd", @debs;
die "cannot exec() dpkg"; die "cannot exec() dpkg";
} }
close $wfh; close $wfh;
@ -461,29 +463,32 @@ sub run_dpkg_progress {
my $pid = fork() // die "failed to fork(): $!"; my $pid = fork() // die "failed to fork(): $!";
if ($pid == 0) { if ($pid == 0) {
# child # child
print_progress 0.0; print_progress 0.0 if not $verbose;
my $num = 0; my $num = 0;
# each package has one install and one configure step, thus the total # each package has one install and one configure step, thus the total
# number is twice the number of packages # number is twice the number of packages
my $total = (scalar @{$debs}) * 2; my $total = (scalar @debs) * 2;
while (my $line = <$rfh>) { while (my $line = <$rfh>) {
if ($line =~ /^processing: (install|configure): /) { if ($line =~ /^processing: (install|configure): /) {
$num += 1; $num += 1;
} }
my $perc = $num/$total*100; my $perc = $num/$total*100;
print_progress $perc; print_progress $perc if not $verbose;
} }
print_progress "done"; print_progress "done" if not $verbose;
exit 0; exit 0;
} }
# parent # parent
my $dpkg_output; my $dpkg_output = '';
while (my $line = <$pipe_dpkg>) { while (my $line = <$pipe_dpkg>) {
# forward captured apt output if ($verbose) {
#print STDERR $line; print STDERR $line;
$dpkg_output .= $line; } else {
# forward captured apt output
$dpkg_output .= $line;
}
} }
close $pipe_dpkg; close $pipe_dpkg;
my $fail = 0; my $fail = 0;
@ -498,12 +503,15 @@ sub run_dpkg_progress {
# might interfere # might interfere
if ($fail) { if ($fail) {
print STDERR $dpkg_output; print STDERR $dpkg_output;
die ((join ' ', @args) . ' failed'); die ((join ' ', @args, @debs) . ' failed');
} }
} }
sub run_apt_progress { sub run_apt_progress {
my @args = @_; my $options = shift;
my @args = @{$options->{ARGV}};
my @debs = @{$options->{PKGS} // []};
my $verbose = $options->{VERBOSE} // 0;
pipe my $rfh, my $wfh; pipe my $rfh, my $wfh;
my $aptpid = open(my $pipe_apt, '-|') // die "failed to fork(): $!"; my $aptpid = open(my $pipe_apt, '-|') // die "failed to fork(): $!";
if ($aptpid == 0) { if ($aptpid == 0) {
@ -515,7 +523,7 @@ sub run_apt_progress {
my $fd = fileno $wfh; my $fd = fileno $wfh;
# redirect apt's stderr to stdout so that we can capture it # redirect apt's stderr to stdout so that we can capture it
open(STDERR, '>&', STDOUT); open(STDERR, '>&', STDOUT);
exec { $args[0] } @args, "-oAPT::Status-Fd=$fd"; exec { $args[0] } @args, "-oAPT::Status-Fd=$fd", @debs;
die "cannot exec apt-get update: $!"; die "cannot exec apt-get update: $!";
} }
close $wfh; close $wfh;
@ -526,14 +534,14 @@ sub run_apt_progress {
my $pid = fork() // die "failed to fork(): $!"; my $pid = fork() // die "failed to fork(): $!";
if ($pid == 0) { if ($pid == 0) {
# child # child
print_progress 0.0; print_progress 0.0 if not $verbose;
while (my $line = <$rfh>) { while (my $line = <$rfh>) {
if ($line =~ /(pmstatus|dlstatus):[^:]+:(\d+\.\d+):.*/) { if ($line =~ /(pmstatus|dlstatus):[^:]+:(\d+\.\d+):.*/) {
print_progress $2; print_progress $2 if not $verbose;
} }
#print STDERR "apt: $line"; #print STDERR "apt: $line";
} }
print_progress "done"; print_progress "done" if not $verbose;
exit 0; exit 0;
} }
@ -549,9 +557,12 @@ sub run_apt_progress {
} elsif ($line =~ '^Err:') { } elsif ($line =~ '^Err:') {
$has_error = 1; $has_error = 1;
} }
# forward captured apt output if ($verbose) {
#print STDERR $line; print STDERR $line;
$apt_output .= $line; } else {
# forward captured apt output
$apt_output .= $line;
}
} }
close($pipe_apt); close($pipe_apt);
my $fail = 0; my $fail = 0;
@ -566,7 +577,7 @@ sub run_apt_progress {
# might interfere # might interfere
if ($fail) { if ($fail) {
print STDERR $apt_output; print STDERR $apt_output;
die ((join ' ', @args) . ' failed'); die ((join ' ', @args, @debs) . ' failed');
} }
} }
@ -753,7 +764,10 @@ sub setup {
$ENV{"APT_CONFIG"} = "$tmpfile"; $ENV{"APT_CONFIG"} = "$tmpfile";
print STDERR "I: running apt-get update...\n"; print STDERR "I: running apt-get update...\n";
run_apt_progress 'apt-get', 'update'; run_apt_progress({
ARGV => ['apt-get', 'update'],
VERBOSE => $options->{verbose}
});
# check if anything was downloaded at all # check if anything was downloaded at all
{ {
@ -791,9 +805,13 @@ sub setup {
# 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')) {
print STDERR "I: downloading packages with apt...\n"; print STDERR "I: downloading packages with apt...\n";
run_apt_progress ('apt-get', '--yes', run_apt_progress({
'-oApt::Get::Download-Only=true', ARGV => ['apt-get', '--yes',
'install', keys %pkgs_to_install); '-oApt::Get::Download-Only=true',
'install'],
PKGS => [keys %pkgs_to_install],
VERBOSE => $options->{verbose}
});
} elsif ($options->{variant} eq 'apt') { } elsif ($options->{variant} eq 'apt') {
# if we just want to install Essential:yes packages, apt and their # if we just want to install Essential:yes packages, apt and their
# dependencies then we can make use of libapt treating apt as # dependencies then we can make use of libapt treating apt as
@ -809,9 +827,12 @@ sub setup {
# in the bugreport: "Are you crazy?!? Nobody in his # in the bugreport: "Are you crazy?!? Nobody in his
# right mind would even suggest depending on it!") # right mind would even suggest depending on it!")
print STDERR "I: downloading packages with apt...\n"; print STDERR "I: downloading packages with apt...\n";
run_apt_progress ('apt-get', '--yes', run_apt_progress({
'-oApt::Get::Download-Only=true', ARGV => ['apt-get', '--yes',
'dist-upgrade'); '-oApt::Get::Download-Only=true',
'dist-upgrade'],
VERBOSE => $options->{verbose}
});
} elsif (any { $_ eq $options->{variant} } ('essential', 'standard', 'important', 'required', 'buildd', 'minbase')) { } elsif (any { $_ eq $options->{variant} } ('essential', 'standard', 'important', 'required', 'buildd', 'minbase')) {
my %ess_pkgs; my %ess_pkgs;
open(my $pipe_apt, '-|', 'apt-get', 'indextargets', '--format', '$(FILENAME)', 'Created-By: Packages') or die "cannot start apt-get indextargets: $!"; open(my $pipe_apt, '-|', 'apt-get', 'indextargets', '--format', '$(FILENAME)', 'Created-By: Packages') or die "cannot start apt-get indextargets: $!";
@ -886,9 +907,13 @@ sub setup {
$? == 0 or die "apt-get indextargets failed: $?"; $? == 0 or die "apt-get indextargets failed: $?";
print STDERR "I: downloading packages with apt...\n"; print STDERR "I: downloading packages with apt...\n";
run_apt_progress ('apt-get', '--yes', run_apt_progress({
'-oApt::Get::Download-Only=true', ARGV => ['apt-get', '--yes',
'install', keys %ess_pkgs); '-oApt::Get::Download-Only=true',
'install'],
PKGS => [keys %ess_pkgs],
VERBOSE => $options->{verbose}
});
} else { } else {
die "unknown variant: $options->{variant}"; die "unknown variant: $options->{variant}";
} }
@ -971,15 +996,25 @@ sub setup {
if ($options->{variant} eq 'extract') { if ($options->{variant} eq 'extract') {
# nothing to do # nothing to do
} else { } else {
run_apt_progress ('apt-get', '--yes', @chrootless_opts, run_apt_progress({
'install', (map { "$options->{root}/$_" } @essential_pkgs)); ARGV => ['apt-get', '--yes',
@chrootless_opts,
'install'],
PKGS => [map { "$options->{root}/$_" } @essential_pkgs],
VERBOSE => $options->{verbose}
});
} }
if (any { $_ eq $options->{variant} } ('extract', 'custom')) { if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
# nothing to do # nothing to do
} elsif (any { $_ eq $options->{variant} } ('essential', 'apt', 'standard', 'important', 'required', 'buildd', 'minbase')) { } elsif (any { $_ eq $options->{variant} } ('essential', 'apt', 'standard', 'important', 'required', 'buildd', 'minbase')) {
if (%pkgs_to_install) { if (%pkgs_to_install) {
run_apt_progress ('apt-get', '--yes', @chrootless_opts, run_apt_progress({
'install', keys %pkgs_to_install); ARGV => ['apt-get', '--yes',
@chrootless_opts,
'install'],
PKGS => [keys %pkgs_to_install],
VERBOSE => $options->{verbose}
});
} }
} else { } else {
die "unknown variant: $options->{variant}"; die "unknown variant: $options->{variant}";
@ -1086,7 +1121,11 @@ sub setup {
# account and thus doesn't install them in the right order # account and thus doesn't install them in the right order
# And the --predep-package option is broken: #539133 # And the --predep-package option is broken: #539133
print STDERR "I: installing packages...\n"; print STDERR "I: installing packages...\n";
run_dpkg_progress [@essential_pkgs], @chrootcmd, 'dpkg', '--install', '--force-depends'; run_dpkg_progress({
ARGV => [@chrootcmd, 'dpkg', '--install', '--force-depends'],
PKGS => \@essential_pkgs,
VERBOSE => $options->{verbose}
});
# if the path-excluded option was added to the dpkg config, reinstall all # if the path-excluded option was added to the dpkg config, reinstall all
# packages # packages
@ -1098,7 +1137,11 @@ sub setup {
# without --skip-same-version, dpkg will install the given # without --skip-same-version, dpkg will install the given
# packages even though they are already installed # packages even though they are already installed
print STDERR "I: re-installing packages because of path-exclude...\n"; print STDERR "I: re-installing packages because of path-exclude...\n";
run_dpkg_progress [@essential_pkgs], @chrootcmd, 'dpkg', '--install', '--force-depends'; run_dpkg_progress({
ARGV => [@chrootcmd, 'dpkg', '--install', '--force-depends'],
PKGS => \@essential_pkgs,
VERBOSE => $options->{verbose}
});
} }
} }
@ -1148,9 +1191,13 @@ sub setup {
if (%pkgs_to_install_from_outside) { if (%pkgs_to_install_from_outside) {
print STDERR 'I: downloading ' . (join ', ', keys %pkgs_to_install_from_outside) . "...\n"; print STDERR 'I: downloading ' . (join ', ', keys %pkgs_to_install_from_outside) . "...\n";
run_apt_progress ('apt-get', '--yes', run_apt_progress({
'-oApt::Get::Download-Only=true', ARGV => ['apt-get', '--yes',
'install', (keys %pkgs_to_install_from_outside)); '-oApt::Get::Download-Only=true',
'install'],
PKGS => [keys %pkgs_to_install_from_outside],
VERBOSE => $options->{verbose}
});
my @debs_to_install; my @debs_to_install;
my $apt_archives = "/var/cache/apt/archives/"; my $apt_archives = "/var/cache/apt/archives/";
opendir my $dh, "$options->{root}/$apt_archives" or die "cannot read $apt_archives"; opendir my $dh, "$options->{root}/$apt_archives" or die "cannot read $apt_archives";
@ -1171,7 +1218,11 @@ sub setup {
# we need --force-depends because dpkg does not take Pre-Depends # we need --force-depends because dpkg does not take Pre-Depends
# into account and thus doesn't install them in the right order # into account and thus doesn't install them in the right order
print STDERR 'I: installing ' . (join ', ', keys %pkgs_to_install_from_outside) . "...\n"; print STDERR 'I: installing ' . (join ', ', keys %pkgs_to_install_from_outside) . "...\n";
run_dpkg_progress [@debs_to_install], @chrootcmd, 'dpkg', '--install', '--force-depends'; run_dpkg_progress({
ARGV => [@chrootcmd, 'dpkg', '--install', '--force-depends'],
PKGS => \@debs_to_install,
VERBOSE => $options->{verbose}
});
foreach my $deb (@debs_to_install) { foreach my $deb (@debs_to_install) {
unlink "$options->{root}/$deb" or die "cannot unlink $deb"; unlink "$options->{root}/$deb" or die "cannot unlink $deb";
} }
@ -1246,7 +1297,11 @@ sub setup {
} }
print STDERR "I: installing remaining packages inside the chroot...\n"; print STDERR "I: installing remaining packages inside the chroot...\n";
run_apt_progress @chrootcmd, 'apt-get', '--yes', 'install', keys %pkgs_to_install; run_apt_progress({
ARGV => [@chrootcmd, 'apt-get', '--yes', 'install'],
PKGS => [keys %pkgs_to_install],
VERBOSE => $options->{verbose}
});
# cleanup # cleanup
move("$options->{root}/sbin/start-stop-daemon.REAL", "$options->{root}/sbin/start-stop-daemon") or die "cannot move start-stop-daemon"; move("$options->{root}/sbin/start-stop-daemon.REAL", "$options->{root}/sbin/start-stop-daemon") or die "cannot move start-stop-daemon";
@ -1321,8 +1376,14 @@ sub setup {
unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap" or die "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!"; unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap" or die "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!";
print STDERR "I: cleaning package lists and apt cache...\n"; print STDERR "I: cleaning package lists and apt cache...\n";
run_apt_progress 'apt-get', '--option', 'Dir::Etc::SourceList=/dev/null', 'update'; run_apt_progress({
run_apt_progress 'apt-get', 'clean'; ARGV => ['apt-get', '--option', 'Dir::Etc::SourceList=/dev/null', 'update'],
VERBOSE => $options->{verbose}
});
run_apt_progress({
ARGV => ['apt-get', 'clean'],
VERBOSE => $options->{verbose}
});
if (defined $options->{qemu} and $options->{mode} ne 'proot' and $options->{mode} ne 'fakechroot') { if (defined $options->{qemu} and $options->{mode} ne 'proot' and $options->{mode} ne 'fakechroot') {
unlink "$options->{root}/usr/bin/qemu-$options->{qemu}-static" or die "cannot unlink /usr/bin/qemu-$options->{qemu}-static"; unlink "$options->{root}/usr/bin/qemu-$options->{qemu}-static" or die "cannot unlink /usr/bin/qemu-$options->{qemu}-static";
@ -1367,6 +1428,7 @@ sub main() {
mode => 'auto', mode => 'auto',
dpkgopts => [], dpkgopts => [],
aptopts => [], aptopts => [],
verbose => 0,
}; };
chomp ($options->{architectures} = `dpkg --print-architecture`); chomp ($options->{architectures} = `dpkg --print-architecture`);
Getopt::Long::Configure ("bundling"); Getopt::Long::Configure ("bundling");
@ -1379,6 +1441,7 @@ sub main() {
'mode=s' => \$options->{mode}, 'mode=s' => \$options->{mode},
'dpkgopt=s@' => \$options->{dpkgopts}, 'dpkgopt=s@' => \$options->{dpkgopts},
'aptopt=s@' => \$options->{aptopts}, 'aptopt=s@' => \$options->{aptopts},
'verbose' => \$options->{verbose},
) or pod2usage(-exitval => 2, -verbose => 1); ) or pod2usage(-exitval => 2, -verbose => 1);
my @valid_variants = ('extract', 'custom', 'essential', 'apt', 'required', my @valid_variants = ('extract', 'custom', 'essential', 'apt', 'required',