introduce main() function and remove 36 global variables

This commit is contained in:
Johannes 'josch' Schauer 2016-12-24 13:04:06 +01:00
parent 13e9f08da8
commit aa2cfef40b

View file

@ -1,6 +1,7 @@
#!/usr/bin/perl #!/usr/bin/perl
# Copyright (C) 2009-2011 Neil Williams <codehelp@debian.org> # Copyright (C) 2009-2015 Neil Williams <codehelp@debian.org>
# Copyright (C) 2015-2017 Johannes Schauer <josch@mister-muffin.de>
# #
# This package is free software; you can redistribute it and/or modify # This package is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -26,27 +27,26 @@ use POSIX qw(locale_h);
use Locale::gettext; use Locale::gettext;
use File::Copy; use File::Copy;
use vars qw/ $progname $ourversion $dstrap $extra @aptsources main();
$deb $cachedir $config_str %packages $retval $str $retries
$dir $include $arch $foreign $url $unpack $sourcedir $msg $etcdir sub main {
@e $sourcesname $libdir $dpkgdir @debootstrap %suites %components $chk use vars qw/ @aptsources %packages $str $retries $dir $arch $foreign
$repo @dirs @touch %sources $section %keys $host $key $value $preffile $unpack $sourcedir @debootstrap %suites %components %sources %keys $host
$type $file $config $tidy $noauth $keyring %keyrings $deflist $cfgdir $preffile $file $tidy $noauth %keyrings $deflist @extrapkgs @includes
@extrapkgs @includes %source $setupsh $configsh $omitrequired $dryrun $setupsh $configsh $omitrequired $omitpreinst @reinstall $tgzname @check
$omitpreinst @reinstall $tgzname %required $check @check $explicit_suite $allow_recommends %omitdebsrc @dsclist %flatfile
$explicit_suite $allow_recommends %omitdebsrc @dsclist @sectoutput %important $addimportant @debconf %hooks $warn_count @foreignarches
%flatfile %important $addimportant @debconf $hookdir %hooks $olddpkg $ignorenative $markauto $default_release/;
$warn_count $use_shortcut @foreignarches $olddpkg $ignorenative
%foreignpkgs $markauto $default_release $pre_config_str/;
setlocale(LC_MESSAGES, ""); setlocale(LC_MESSAGES, "");
textdomain("multistrap"); textdomain("multistrap");
$progname = basename($0); my $progname = basename($0);
$ourversion = &our_version(); my $ourversion = &our_version();
$default_release = "*"; $default_release = "*";
$unpack = "true"; $unpack = "true";
%omitdebsrc=(); %omitdebsrc=();
%foreignpkgs=(); my $dryrun;
my $use_shortcut;
while( @ARGV ) { while( @ARGV ) {
$_= shift( @ARGV ); $_= shift( @ARGV );
last if m/^--$/; last if m/^--$/;
@ -85,17 +85,16 @@ if (defined $use_shortcut) {
$short = "/etc/multistrap.d/".$use_shortcut.".conf"; $short = "/etc/multistrap.d/".$use_shortcut.".conf";
$file = $short if (-f $short); $file = $short if (-f $short);
} }
$msg = sprintf (_g("Need a configuration file - use %s -f\n"), $progname); if (not defined $file) {
die ($msg) die (sprintf (_g("Need a configuration file - use %s -f\n"), $progname));
if (not defined $file); }
undef ($msg);
$cachedir = "var/cache/apt/"; # archives my $cachedir = "var/cache/apt/"; # archives
$libdir = "var/lib/apt/"; # lists my $libdir = "var/lib/apt/"; # lists
$etcdir = "etc/apt/"; # sources my $etcdir = "etc/apt/"; # sources
$dpkgdir = "var/lib/dpkg/"; # state my $dpkgdir = "var/lib/dpkg/"; # state
$cfgdir=dirname($file); my $cfgdir=dirname($file);
cascade($file); cascade($file);
# Translators: fields are programname, version string, include file. # Translators: fields are programname, version string, include file.
printf (_g("%s %s using %s\n"), $progname, $ourversion, $file); printf (_g("%s %s using %s\n"), $progname, $ourversion, $file);
@ -180,8 +179,8 @@ if (defined $preffile) {
print MPREF @prefs; print MPREF @prefs;
close (MPREF); close (MPREF);
} }
@dirs = qw/ alternatives info parts updates /; my @dirs = qw/ alternatives info parts updates /;
@touch = qw/ arch diversions statoverride status lock/; my @touch = qw/ arch diversions statoverride status lock/;
foreach my $dpkgd (@dirs) { foreach my $dpkgd (@dirs) {
if (not -d "${dir}${dpkgdir}$dpkgd") { if (not -d "${dir}${dpkgdir}$dpkgd") {
mkdir_fatal ("${dir}${dpkgdir}$dpkgd"); mkdir_fatal ("${dir}${dpkgdir}$dpkgd");
@ -216,7 +215,7 @@ system_fatal ("rm -rf " . shellescape("${dir}etc/apt/sources.list.d") . "/*");
unlink ("${dir}etc/apt/sources.list") unlink ("${dir}etc/apt/sources.list")
if (-f "${dir}etc/apt/sources.list"); if (-f "${dir}etc/apt/sources.list");
foreach $repo (sort keys %suites) { foreach my $repo (sort keys %suites) {
if (not -e "${dir}${cachedir}") { if (not -e "${dir}${cachedir}") {
mkdir_fatal ("${dir}${cachedir}"); mkdir_fatal ("${dir}${cachedir}");
} }
@ -301,7 +300,7 @@ if ((defined $k) and (not defined $noauth)) {
} }
} }
$pre_config_str = ''; my $pre_config_str = '';
$pre_config_str .= "Dir::Etc \"${dir}${etcdir}\";\n"; $pre_config_str .= "Dir::Etc \"${dir}${etcdir}\";\n";
$pre_config_str .= "Dir::Etc::Parts \"${dir}${etcdir}apt.conf.d/\";\n"; $pre_config_str .= "Dir::Etc::Parts \"${dir}${etcdir}apt.conf.d/\";\n";
$pre_config_str .= "Dir::Etc::PreferencesParts \"${dir}${etcdir}preferences.d/\";\n"; $pre_config_str .= "Dir::Etc::PreferencesParts \"${dir}${etcdir}preferences.d/\";\n";
@ -313,7 +312,7 @@ open CONFIG, ">$tmp_apt_conf";
print CONFIG $pre_config_str; print CONFIG $pre_config_str;
close CONFIG; close CONFIG;
$config_str = ''; my $config_str = '';
$config_str .= " -o Apt::Architecture=" . shellescape($arch); $config_str .= " -o Apt::Architecture=" . shellescape($arch);
$config_str .= " -o Dir::Etc::TrustedParts=" . shellescape("${dir}${etcdir}trusted.gpg.d"); $config_str .= " -o Dir::Etc::TrustedParts=" . shellescape("${dir}${etcdir}trusted.gpg.d");
$config_str .= " -o Dir::Etc::Trusted=" . shellescape("${dir}${etcdir}trusted.gpg"); $config_str .= " -o Dir::Etc::Trusted=" . shellescape("${dir}${etcdir}trusted.gpg");
@ -329,7 +328,7 @@ $config_str .= " -o Dir::Etc::PreferencesParts=" . shellescape("${dir}${etcdir}p
$config_str .= " -o APT::Default-Release=" . shellescape($default_release); $config_str .= " -o APT::Default-Release=" . shellescape($default_release);
# if (not defined $preffile); # if (not defined $preffile);
if (defined $deflist) { if (defined $deflist) {
$sourcesname = "sources.list.d/multistrap.sources.list"; my $sourcesname = "sources.list.d/multistrap.sources.list";
$config_str .= " -o Dir::Etc::SourceList=" . shellescape("${dir}${etcdir}$sourcesname"); $config_str .= " -o Dir::Etc::SourceList=" . shellescape("${dir}${etcdir}$sourcesname");
} }
$config_str .= " -o Dir::State=" . shellescape("${dir}${libdir}"); $config_str .= " -o Dir::State=" . shellescape("${dir}${libdir}");
@ -340,7 +339,7 @@ my $apt_get = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-get $config_str
my $apt_mark = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-mark $config_str"; my $apt_mark = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-mark $config_str";
printf (_g("Getting package lists: %s update\n"), $apt_get); printf (_g("Getting package lists: %s update\n"), $apt_get);
$retval = system ("$apt_get update"); my $retval = system ("$apt_get update");
$retval >>= 8; $retval >>= 8;
die (sprintf (_g("apt update failed. Exit value: %d\n"), $retval)) die (sprintf (_g("apt update failed. Exit value: %d\n"), $retval))
if ($retval != 0); if ($retval != 0);
@ -348,7 +347,7 @@ my @s = ();
$str = ""; $str = "";
if (not defined $omitrequired) { if (not defined $omitrequired) {
print _g("I: Calculating required packages.\n"); print _g("I: Calculating required packages.\n");
&get_required_debs; my %required = &get_required_debs($libdir);
$str .= join (' ', keys %required); $str .= join (' ', keys %required);
if (defined $addimportant) { if (defined $addimportant) {
my $imps = join (' ', sort keys %important); my $imps = join (' ', sort keys %important);
@ -391,8 +390,8 @@ $retval = system ("$apt_get -y install $str");
$retval >>= 8; $retval >>= 8;
die (sprintf (_g("apt download failed. Exit value: %d\n"),$retval)) die (sprintf (_g("apt download failed. Exit value: %d\n"),$retval))
if ($retval != 0); if ($retval != 0);
&force_unpack if ($unpack eq "true"); &force_unpack($cachedir, $libdir, $dpkgdir) if ($unpack eq "true");
&mark_manual_install ($str) if (defined $markauto); &mark_manual_install ($apt_mark, $cachedir, $str) if (defined $markauto);
system ("touch " . shellescape("${dir}${libdir}lists/lock")); system ("touch " . shellescape("${dir}${libdir}lists/lock"));
if ((defined $setupsh) and (-x $setupsh)) { if ((defined $setupsh) and (-x $setupsh)) {
$retval = 0; $retval = 0;
@ -410,10 +409,10 @@ if (defined $err and $err != 0) {
warn (_g("Native mode configuration reported an error!\n")); warn (_g("Native mode configuration reported an error!\n"));
$warn_count++; $warn_count++;
} }
&add_extra_packages; &add_extra_packages($apt_get, $cachedir, $libdir, $dpkgdir);
system ("cp " . shellescape($configsh) . " " . shellescape("$dir/")) if ((defined $configsh) and (-f $configsh)); system ("cp " . shellescape($configsh) . " " . shellescape("$dir/")) if ((defined $configsh) and (-f $configsh));
&handle_source_packages; &handle_source_packages($apt_get, $cachedir, $dpkgdir);
(not defined $tidy) ? system ("$apt_get update") : &tidy_apt; (not defined $tidy) ? system ("$apt_get update") : &tidy_apt($cachedir, $libdir);
&guard_lib64($dir); &guard_lib64($dir);
# cleanly separate the bootstrap sources from the final apt sources. # cleanly separate the bootstrap sources from the final apt sources.
@ -458,7 +457,7 @@ foreach my $aptsrc (@aptsources) {
} }
} }
# altered the sources, so get apt to update. # altered the sources, so get apt to update.
(not defined $tidy) ? system ("$apt_get update") : &tidy_apt; (not defined $tidy) ? system ("$apt_get update") : &tidy_apt($cachedir, $libdir);
# run second set of hooks # run second set of hooks
&run_completion_hooks(sort @{$hooks{'A'}}) if (defined ($hooks{'A'})); &run_completion_hooks(sort @{$hooks{'A'}}) if (defined ($hooks{'A'}));
unlink $tmp_apt_conf; unlink $tmp_apt_conf;
@ -493,8 +492,7 @@ if (not defined $warn_count) {
} else { } else {
exit $warn_count; exit $warn_count;
} }
}
######### sub routine start ##########
# avoid dependency on String::ShellQuote by implementing the mechanism # avoid dependency on String::ShellQuote by implementing the mechanism
# from python's shlex.quote function # from python's shlex.quote function
@ -520,17 +518,23 @@ sub our_version {
} }
sub add_extra_packages { sub add_extra_packages {
my $apt_get = shift;
my $cachedir = shift;
my $libdir = shift;
my $dpkgdir = shift;
if (scalar @extrapkgs > 0) { if (scalar @extrapkgs > 0) {
$str = join (' ', @extrapkgs); $str = join (' ', @extrapkgs);
print "$apt_get -y install $str\n"; print "$apt_get -y install $str\n";
system ("$apt_get -y install $str"); system ("$apt_get -y install $str");
&force_unpack (@extrapkgs) if ($unpack eq "true"); &force_unpack ($cachedir, $libdir, $dpkgdir, @extrapkgs) if ($unpack eq "true");
system ("touch " . shellescape("${dir}${libdir}lists/lock")); system ("touch " . shellescape("${dir}${libdir}lists/lock"));
&native if (not defined ($foreign)); &native if (not defined ($foreign));
} }
} }
sub mark_manual_install { sub mark_manual_install {
my $apt_mark = shift;
my $cachedir = shift;
my @manual = split(/ +/, $_[0]); my @manual = split(/ +/, $_[0]);
printf (_g("Marking automatically installed packages... please wait\n")); printf (_g("Marking automatically installed packages... please wait\n"));
opendir (DEBS, "${dir}${cachedir}archives/") opendir (DEBS, "${dir}${cachedir}archives/")
@ -550,6 +554,9 @@ sub mark_manual_install {
} }
sub force_unpack { sub force_unpack {
my $cachedir = shift;
my $libdir = shift;
my $dpkgdir = shift;
my (@limits) = @_; my (@limits) = @_;
my %unpack=(); my %unpack=();
my %filter = (); my %filter = ();
@ -568,7 +575,7 @@ sub force_unpack {
@archives = sort values %filter; @archives = sort values %filter;
} }
print _g("I: Calculating obsolete packages\n"); print _g("I: Calculating obsolete packages\n");
foreach $deb (sort @archives) { foreach my $deb (sort @archives) {
my $escaped_path = shellescape("${dir}${cachedir}archives/$deb"); my $escaped_path = shellescape("${dir}${cachedir}archives/$deb");
my $version = `LC_ALL=C dpkg -f $escaped_path Version`; my $version = `LC_ALL=C dpkg -f $escaped_path Version`;
my $package = `LC_ALL=C dpkg -f $escaped_path Package`; my $package = `LC_ALL=C dpkg -f $escaped_path Package`;
@ -604,7 +611,7 @@ sub force_unpack {
chomp ($old); chomp ($old);
chdir ("${dir}"); chdir ("${dir}");
printf (_g("Using directory %s for unpacking operations\n"), $dir); printf (_g("Using directory %s for unpacking operations\n"), $dir);
foreach $deb (sort @archives) { foreach my $deb (sort @archives) {
printf (_g("I: Extracting %s...\n"), $deb); printf (_g("I: Extracting %s...\n"), $deb);
my $escaped_path = shellescape("./${cachedir}archives/$deb"); my $escaped_path = shellescape("./${cachedir}archives/$deb");
my $ver=`LC_ALL=C dpkg -f $escaped_path Version`; my $ver=`LC_ALL=C dpkg -f $escaped_path Version`;
@ -851,6 +858,9 @@ sub check_bin_sh {
} }
sub handle_source_packages { sub handle_source_packages {
my $apt_get = shift;
my $cachedir = shift;
my $dpkgdir = shift;
return if (not defined $sourcedir); return if (not defined $sourcedir);
if ($unpack eq "true") { if ($unpack eq "true") {
opendir (DEBS, "${dir}${cachedir}/archives/") opendir (DEBS, "${dir}${cachedir}/archives/")
@ -911,6 +921,8 @@ sub handle_source_packages {
} }
sub tidy_apt { sub tidy_apt {
my $cachedir = shift;
my $libdir = shift;
print _g("I: Tidying up apt cache and list data.\n"); print _g("I: Tidying up apt cache and list data.\n");
if ($unpack eq "true") { if ($unpack eq "true") {
opendir (DEBS, "${dir}${cachedir}/archives/") opendir (DEBS, "${dir}${cachedir}/archives/")
@ -1006,11 +1018,12 @@ sub native {
} }
sub get_required_debs { sub get_required_debs {
my $libdir = shift;
# emulate required="$(get_debs Priority: required)" # emulate required="$(get_debs Priority: required)"
# from debootstrap/functions # from debootstrap/functions
# needs to be run after the first apt-get install so that # needs to be run after the first apt-get install so that
# Packages files exist # Packages files exist
%required=(); my %required=();
my %listfiles=(); my %listfiles=();
opendir (PKGS, "${dir}${libdir}lists/") opendir (PKGS, "${dir}${libdir}lists/")
or die sprintf(_g("Cannot open %s directory. %s\n"), or die sprintf(_g("Cannot open %s directory. %s\n"),
@ -1039,6 +1052,7 @@ sub get_required_debs {
} }
} }
} }
return %required;
} }
# inherited from apt-cross # inherited from apt-cross
@ -1070,6 +1084,8 @@ sub prepare_sources_list {
} }
sub usageversion { sub usageversion {
my $progname = basename($0);
my $ourversion = &our_version();
printf STDERR (_g(" printf STDERR (_g("
%s version %s %s version %s
@ -1143,19 +1159,22 @@ will be created - it is not packed into a .tgz once complete.
} }
sub cascade { sub cascade {
my $progname = basename($0);
$olddpkg = &check_multiarch_dpkg; $olddpkg = &check_multiarch_dpkg;
$file = shift; $file = shift;
my @req_arches=(); my @req_arches=();
$config = Config::Auto::parse($file, format => 'ini'); my $config = Config::Auto::parse($file, format => 'ini');
if (not defined $config or (scalar keys %$config) == 0) { if (not defined $config or (scalar keys %$config) == 0) {
die ("$progname: ". sprintf(_g("Failed to parse '%s'!\n"), $file)); die ("$progname: ". sprintf(_g("Failed to parse '%s'!\n"), $file));
} }
foreach $key (%$config) { my $type;
my $value;
foreach my $key (%$config) {
$type = lc($key) if (ref $key ne "HASH"); $type = lc($key) if (ref $key ne "HASH");
$value = $key if (ref $key eq "HASH"); $value = $key if (ref $key eq "HASH");
$keys{$type} = $value; $keys{$type} = $value;
} }
foreach $section (sort keys %keys) { foreach my $section (sort keys %keys) {
if ($section eq "general") { if ($section eq "general") {
$arch = $keys{$section}{'arch'} $arch = $keys{$section}{'arch'}
if (defined $keys{$section}{'arch'} and (not defined $arch)); if (defined $keys{$section}{'arch'} and (not defined $arch));
@ -1247,7 +1266,8 @@ sub cascade {
foreach my $inc (@i) { foreach my $inc (@i) {
# look for the full filepath or try same directory as current conf. # look for the full filepath or try same directory as current conf.
if (not -f $inc) { if (not -f $inc) {
$chk = realpath ("$cfgdir/$inc"); my $cfgdir=dirname($file);
my $chk = realpath ("$cfgdir/$inc");
chomp ($chk) if (defined $chk); chomp ($chk) if (defined $chk);
$inc = $chk if (-f $chk); $inc = $chk if (-f $chk);
} }
@ -1258,7 +1278,7 @@ sub cascade {
} }
push @includes, @i; push @includes, @i;
} else { } else {
$sources{$section}=$keys{$section}{'source'} if (not exists $source{$section}); $sources{$section}=$keys{$section}{'source'};
# don't set suite or component if URL is of apt-ftparchive trailing-slash form # don't set suite or component if URL is of apt-ftparchive trailing-slash form
# regexp is: optional string in '[]', string without '[' or ']', string ending in '/' # regexp is: optional string in '[]', string without '[' or ']', string ending in '/'
$flatfile{$section}++ if (($sources{$section} =~ /^(\[.*\] )*[^\[\]]+ .+\/$/)); $flatfile{$section}++ if (($sources{$section} =~ /^(\[.*\] )*[^\[\]]+ .+\/$/));
@ -1343,6 +1363,7 @@ sub system_fatal {
} }
sub mkdir_fatal { sub mkdir_fatal {
my $progname = basename($0);
my $d = shift; my $d = shift;
if (not -d "$d") { if (not -d "$d") {
my $ret = system ("mkdir -p " . shellescape($d)); my $ret = system ("mkdir -p " . shellescape($d));
@ -1366,8 +1387,9 @@ sub uniq_sort {
} }
sub dump_config { sub dump_config {
my $msg;
if (not defined $dir or not defined $arch) { if (not defined $dir or not defined $arch) {
my $msg = sprintf(_g("The supplied configuration file '%s'". $msg = sprintf(_g("The supplied configuration file '%s'".
" cannot be parsed correctly."), $file); " cannot be parsed correctly."), $file);
warn ("\n$msg\n\n"); warn ("\n$msg\n\n");
} }