home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / bin / tasksel < prev    next >
Encoding:
Text File  |  2007-03-14  |  18.5 KB  |  728 lines

  1. #!/usr/bin/perl
  2. # Debian task selector, mark II.
  3. # Copyright 2004-2006 by Joey Hess <joeyh@debian.org>.
  4. # Licensed under the GPL, version 2 or higher.
  5. use Locale::gettext;
  6. use Getopt::Long;
  7. use POSIX qw(floor);
  8. use warnings;
  9. use strict;
  10. textdomain('tasksel');
  11.  
  12. my $debconf_helper="/usr/lib/tasksel/tasksel-debconf";
  13. my $testdir="/usr/lib/tasksel/tests";
  14. my $packagesdir="/usr/lib/tasksel/packages";
  15. my $descdir="/usr/share/tasksel";
  16. my $localdescdir="/usr/local/share/tasksel";
  17. my $statusfile="/var/lib/dpkg/status";
  18. my $infodir="/usr/lib/tasksel/info";
  19. my $testmode=0;
  20.  
  21. sub warning {
  22.     print STDERR "tasksel: @_\n";
  23. }
  24.  
  25. sub error {
  26.     print STDERR "tasksel: @_\n";
  27.     exit 1;
  28. }
  29.  
  30. # Run a shell command except in test mode, and returns its exit code.
  31. # Prints the command in test mode. Parameters should be pre-split for
  32. # system.
  33. sub run {
  34.     if ($testmode) {
  35.         print join(" ", @_)."\n";
  36.         return 0;
  37.     }
  38.     else {
  39.         return system(@_) >> 8;
  40.     }
  41. }
  42.  
  43. # A list of all available task desc files.
  44. sub list_task_descs {
  45.     return glob("$descdir/*.desc"), glob("$localdescdir/*.desc");
  46. }
  47.  
  48. # Returns a list of hashes; hash values are arrays for multi-line fields.
  49. sub read_task_desc {
  50.     my $desc=shift;
  51.     my @ret;
  52.     open (DESC, "<$desc") || die "read $desc\: $!";
  53.     local $/="\n\n";
  54.     while (<DESC>) {
  55.         my %data;
  56.         my @lines=split("\n");
  57.         while (@lines) {
  58.             my $line=shift(@lines);
  59.             if ($line=~/^([^ ]+):(?: (.*))?/) {
  60.                 my ($key, $value)=($1, $2);
  61.                 $key=lc($key);
  62.                 if (@lines && $lines[0] =~ /^\s+/) {
  63.                     # multi-line field
  64.                     my @values;
  65.                     if (defined $value && length $value) {
  66.                         push @values, $value;
  67.                     }
  68.                     while (@lines && $lines[0] =~ /^\s+(.*)/) {
  69.                         push @values, $1;
  70.                         shift @lines;
  71.                     }
  72.                     $data{$key}=[@values];
  73.                 }
  74.                 else {
  75.                     $data{$key}=$value;
  76.                 }
  77.             }
  78.             else {
  79.                 warning "parse error in stanza $. of $desc";
  80.             }
  81.         }
  82.         if (%data) {
  83.             $data{relevance}=5 unless exists $data{relevance};
  84.             $data{shortdesc}=$data{description}->[0];
  85.             $data{shortdesctrans}=dgettext("debian-tasks", $data{shortdesc});
  86.             push @ret, \%data;
  87.         }
  88.     }
  89.     close DESC;
  90.     return @ret;
  91. }
  92.  
  93. # Loads info for all tasks, and returns a set of task structures.
  94. sub all_tasks {
  95.     my %seen;
  96.     grep { $seen{$_->{task}}++; $seen{$_->{task}} < 2 }
  97.     map { read_task_desc($_) } list_task_descs();
  98. }
  99.  
  100. # Returns a list of all available packages.
  101. sub list_avail {
  102.     my @list;
  103.     # Might be better to use the perl apt bindings, but they are not
  104.     # currently in base.
  105.     open (AVAIL, "apt-cache dumpavail|");
  106.     local $_;
  107.     while (<AVAIL>) {
  108.         chomp;
  109.         if (/^Package: (.*)/) {
  110.             push @list, $1;
  111.         }
  112.     }
  113.     close AVAIL;
  114.     return @list;
  115. }
  116.  
  117. # Returns a list of all installed packages.
  118. sub list_installed {
  119.     my @list;
  120.     local $/="\n\n";
  121.     open (STATUS, $statusfile);
  122.     local $_;
  123.     while (<STATUS>) {
  124.         if (/^Status: .* installed$/m && /Package: (.*)$/m) {
  125.             push @list, $1;
  126.         }
  127.     }
  128.     close STATUS;
  129.     return @list;
  130. }
  131.  
  132. my %avail_pkgs;
  133. # Given a package name, checks to see if it's available. Memoised.
  134. sub package_avail {
  135.     my $package=shift;
  136.     
  137.     if (! %avail_pkgs) {
  138.         foreach my $pkg (list_avail()) {
  139.             $avail_pkgs{$pkg} = 1;
  140.         }
  141.     }
  142.  
  143.     return $avail_pkgs{$package} || package_installed($package);
  144. }
  145.  
  146. my %installed_pkgs;
  147. # Given a package name, checks to see if it's installed. Memoised.
  148. sub package_installed {
  149.     my $package=shift;
  150.     
  151.     if (! %installed_pkgs) {
  152.         foreach my $pkg (list_installed()) {
  153.             $installed_pkgs{$pkg} = 1;
  154.         }
  155.     }
  156.  
  157.     return $installed_pkgs{$package};
  158. }
  159.  
  160. # Given a task hash, checks if its key packages are available.
  161. sub task_avail {
  162.     local $_;
  163.     my $task=shift;
  164.     if (! ref $task->{key}) {
  165.         return 1;
  166.     }
  167.     else {
  168.         foreach my $pkg (@{$task->{key}}) {
  169.             if (! package_avail($pkg)) {
  170.                 return 0;
  171.             }
  172.         }
  173.         return 1;
  174.     }
  175. }
  176.  
  177. # Given a task hash, checks to see if it is already installed.
  178. # (All of its key packages must be installed.)
  179. sub task_installed {
  180.     local $_;
  181.     my $task=shift;
  182.     if (! ref $task->{key}) {
  183.         return 0; # can't tell with no key packages
  184.     }
  185.     else {
  186.         foreach my $pkg (@{$task->{key}}) {
  187.             if (! package_installed($pkg)) {
  188.                 return 0;
  189.             }
  190.         }
  191.         return 1;
  192.     }
  193. }
  194.  
  195. # Given task hash, returns a list of all available packages in the task.
  196. # If the apt_get_tasks parameter is true, then it does not expand tasks
  197. # that apt-get knows about, and just returns apt-get task syntax for
  198. # those.
  199. sub task_packages {
  200.     my $task=shift;
  201.     my $apt_get_tasks=shift;
  202.     
  203.     my %list;
  204.  
  205.     # key packages are always included
  206.     if (ref $task->{key}) {
  207.         map { $list{$_}=1 } @{$task->{key}};
  208.     }
  209.         
  210.     if ($task->{packages} eq 'task-fields') {
  211.         # task-fields method is built-in for speed and to support
  212.         # apt-get task definitions
  213.         if ($apt_get_tasks) {
  214.             return $task->{task}.'^';
  215.         }
  216.         else {
  217.             local $/="\n\n";
  218.             open (AVAIL, "apt-cache dumpavail|");
  219.             while (<AVAIL>) {
  220.                 if (/^Task: (.*)/m) {
  221.                     my @tasks=split(", ", $1);
  222.                     if (grep { $_ eq $task->{task} } @tasks) { 
  223.                         $list{$1}=1 if /^Package: (.*)/m;
  224.                     }
  225.                 }
  226.             }
  227.             close AVAIL;
  228.         }
  229.     }
  230.     elsif ($task->{packages} eq 'standard') {
  231.         # standard method is built in since it cannot easily be
  232.         # implemented externally.
  233.         #return "~pstandard", "~prequired", "~pimportant";
  234.         # Unfortunately, this needs aptitude, not apt-get, and we
  235.         # have to use apt-get for other reasons ...
  236.         die "'Packages: standard' not supported by this version of tasksel\n";
  237.     }
  238.     elsif ($task->{packages} eq 'manual') {
  239.         # manual package selection is a special case
  240.         return;
  241.     }
  242.     else {
  243.         # external method
  244.         my ($method, @params);
  245.         if (ref $task->{packages}) {
  246.             @params=@{$task->{packages}};
  247.             $method=shift @params;
  248.         }
  249.         else {
  250.             $method=$task->{packages};
  251.         }
  252.         
  253.         map { $list{$_}=1 }
  254.             grep { package_avail($_) }
  255.             split(' ', `$packagesdir/$method $task->{task} @params`);
  256.     }
  257.  
  258.     return keys %list;
  259. }
  260.  
  261. # Given a task hash, runs any test program specified in its data, and sets
  262. # the _display and _install fields to 1 or 0 depending on its result.
  263. sub task_test {
  264.     my $task=shift;
  265.     my $new_install=shift;
  266.     $task->{_display} = shift; # default
  267.     $task->{_install} = shift; # default
  268.     $ENV{NEW_INSTALL}=$new_install if defined $new_install;
  269.     foreach my $test (grep /^test-.*/, keys %$task) {
  270.         $test=~s/^test-//;
  271.         if (-x "$testdir/$test") {
  272.             my $ret=system("$testdir/$test", $task->{task}, split " ", $task->{"test-$test"}) >> 8;
  273.             if ($ret == 0) {
  274.                 $task->{_display} = 0;
  275.                 $task->{_install} = 1;
  276.             }
  277.             elsif ($ret == 1) {
  278.                 $task->{_display} = 0;
  279.                 $task->{_install} = 0;
  280.             }
  281.             elsif ($ret == 2) {
  282.                 $task->{_display} = 1;
  283.                 $task->{_install} = 1;
  284.             }
  285.             elsif ($ret == 3) {
  286.                 $task->{_display} = 1;
  287.                 $task->{_install} = 0;
  288.             }
  289.         }
  290.     }
  291.     
  292.     delete $ENV{NEW_INSTALL};
  293.     return $task;
  294. }
  295.  
  296. # Hides a task and marks it not to be installed if it enhances other
  297. # tasks.
  298. sub hide_enhancing_tasks {
  299.     my $task=shift;
  300.     if (exists $task->{enhances} && length $task->{enhances}) {
  301.         $task->{_display} = 0;
  302.         $task->{_install} = 0;
  303.     }
  304.     return $task;
  305. }
  306.  
  307. # Converts a list of tasks into a debconf list of their short descriptions.
  308. sub task_to_debconf {
  309.     my $field = shift;
  310.     join ", ", map {
  311.         my $desc=$_->{$field};
  312.         if ($desc=~/, /) {
  313.             warning("task ".$_->{task}." contains a comma in its short description: \"$desc\"");
  314.         }
  315.         $desc;
  316.     } @_;
  317. }
  318.  
  319. # Given a first parameter that is a debconf list of short descriptions of
  320. # tasks, or a dependency style list of task names, and then a list of task
  321. # hashes, returns a list of hashes for all the tasks in the list.
  322. sub list_to_tasks {
  323.     my $list=shift;
  324.     my %desc_to_task = map { $_->{shortdesc} => $_, $_->{task} => $_ } @_;
  325.     return grep { defined } map { $desc_to_task{$_} } split ", ", $list;
  326. }
  327.  
  328. # Orders a list of tasks for display.
  329. sub order_for_display {
  330.     sort {
  331.         $b->{relevance} <=> $a->{relevance}
  332.                       || 0 ||
  333.           $a->{section} cmp $b->{section}
  334.                       || 0 ||
  335.             $a->{shortdesc} cmp $b->{shortdesc}
  336.     } @_;
  337. }
  338.  
  339. # Given a set of tasks and a name, returns the one with that name.
  340. sub name_to_task {
  341.     my $name=shift;
  342.     return (grep { $_->{task} eq $name } @_)[0];
  343. }
  344.  
  345. sub find_task_script {
  346.     my $task=shift;
  347.     my $script=shift;
  348.  
  349.     my $path="$infodir/$task.$script";
  350.     if (-e $path && -x _) {
  351.         return $path;
  352.     } else {
  353.         return undef;
  354.     }
  355. }
  356.  
  357. sub run_task_script {
  358.     my $path=pop;
  359.     my @prefix=@_;
  360.  
  361.     my $ret=run(@prefix, $path);
  362.     if ($ret != 0) {
  363.         warning("$path exited with nonzero code $ret");
  364.         return 0;
  365.     }
  366.     return 1;
  367. }
  368.  
  369. sub debconf_apt_command {
  370.     my $dap=shift;
  371.     my $from=shift;
  372.     my $to=shift;
  373.     my $options=shift;
  374.  
  375.     my @cmd=($dap, '--from', $from, '--to', $to);
  376.     push @cmd, @$options if defined $options;
  377.     push @cmd, '--';
  378.     return @cmd;
  379. }
  380.  
  381. # Works out the region of a progress bar needed for a given invocation of
  382. # debconf-apt-progress, and returns the appropriate debconf-apt-progress
  383. # command.
  384. sub task_region {
  385.     my $dap=shift;
  386.     my $start=shift;
  387.     my $end=shift;
  388.     my $options=shift;
  389.     my $cur_region=shift;
  390.     my $step_region=shift;
  391.     my $num_regions=shift;
  392.  
  393.     if (defined $start and defined $end and $num_regions) {
  394.         my $from=floor($start + ($end - $start) * $cur_region / $num_regions + 0.5);
  395.         my $to=floor($start + ($end - $start) * ($cur_region + $step_region) / $num_regions + 0.5);
  396.         return debconf_apt_command($dap, $from, $to, $options);
  397.     } else {
  398.         return;
  399.     }
  400. }
  401.  
  402. sub usage {
  403.     print STDERR gettext(q{Usage:
  404. tasksel install <task>
  405. tasksel remove <task>
  406. tasksel [options]
  407.     -t, --test          test mode; don't really do anything
  408.         --new-install   automatically install some tasks
  409.         --list-tasks    list tasks that would be displayed and exit
  410.         --task-packages list available packages in a task
  411.         --task-desc     returns the description of a task
  412. });
  413. }
  414.  
  415. # Process command line options and return them in a hash.
  416. sub getopts {
  417.     my %ret;
  418.     Getopt::Long::Configure ("bundling");
  419.     if (! GetOptions(\%ret, "test|t", "new-install", "list-tasks",
  420.            "task-packages=s@", "task-desc=s",
  421.            "debconf-apt-from=i", "debconf-apt-to=i",
  422.            "debconf-apt-progress=s")) {
  423.         usage();
  424.         exit(1);
  425.     }
  426.     # Special case apt-like syntax.
  427.     if (@ARGV && $ARGV[0] eq "install") {
  428.         shift @ARGV;
  429.         $ret{install} = shift @ARGV;
  430.     }
  431.     if (@ARGV && $ARGV[0] eq "remove") {
  432.         shift @ARGV;
  433.         $ret{remove} = shift @ARGV;
  434.     }
  435.     if (@ARGV) {
  436.         usage();
  437.         exit 1;
  438.     }
  439.     $testmode=1 if $ret{test}; # set global
  440.     return %ret;
  441. }
  442.  
  443. sub main {
  444.     my %options=getopts();
  445.     my @tasks_remove;
  446.     my @tasks_install;
  447.  
  448.     # Options that output stuff and don't need a full processed list of
  449.     # tasks.
  450.     if (exists $options{"task-packages"}) {
  451.         my @tasks=all_tasks();
  452.         foreach my $taskname (@{$options{"task-packages"}}) {
  453.             my $task=name_to_task($taskname, @tasks);
  454.             if ($task) {
  455.                 print "$_\n" foreach task_packages($task);
  456.             }
  457.         }
  458.         exit(0);
  459.     }
  460.     elsif ($options{"task-desc"}) {
  461.         my $task=name_to_task($options{"task-desc"}, all_tasks());
  462.         if ($task) {
  463.             my $extdesc=join(" ", @{$task->{description}}[1..$#{$task->{description}}]);
  464.             print dgettext("debian-tasks", $extdesc)."\n";
  465.             exit(0);
  466.         }
  467.         else {
  468.             exit(1);
  469.         }
  470.     }
  471.  
  472.     # This is relatively expensive, get the full list of available tasks and
  473.     # mark them.
  474.     my @tasks=map { hide_enhancing_tasks($_) } map { task_test($_, $options{"new-install"}, 1, 0) }
  475.               grep { task_avail($_) } all_tasks();
  476.     
  477.     if ($options{"list-tasks"}) {
  478.         map { $_->{_installed} = task_installed($_) } @tasks;
  479.         print "".($_->{_installed} ? "i" : "u")." ".$_->{task}."\t".$_->{shortdesc}."\n"
  480.             foreach order_for_display(grep { $_->{_display} } @tasks);
  481.         exit(0);
  482.     }
  483.     
  484.     if (! $options{"new-install"}) {
  485.         # Don't install hidden tasks if this is not a new install.
  486.         map { $_->{_install} = 0 } grep { $_->{_display} == 0 } @tasks;
  487.     }
  488.     if ($options{"install"}) {
  489.         my $task=name_to_task($options{"install"}, @tasks);
  490.         $task->{_install} = 1 if $task;
  491.     }
  492.     if ($options{"remove"}) {
  493.         my $task=name_to_task($options{"remove"}, @tasks);
  494.         push @tasks_remove, $task;
  495.     }
  496.     
  497.     # The interactive bit.
  498.     my $interactive=0;
  499.     my @list = order_for_display(grep { $_->{_display} == 1 } @tasks);
  500.     if (@list && ! $options{install} && ! $options{remove}) {
  501.         $interactive=1;
  502.         if (! $options{"new-install"}) {
  503.             # Find tasks that are already installed.
  504.             map { $_->{_installed} = task_installed($_) } @list;
  505.             # Don't install new tasks unless manually selected.
  506.             map { $_->{_install} = 0 } @list;
  507.         }
  508.         else {
  509.             # Assume that no tasks are installed, to ensure
  510.             # that complete tasks get installed on new
  511.             # installs.
  512.             map { $_->{_installed} = 0 } @list;
  513.         }
  514.         my $question="tasksel/tasks";
  515.         if ($options{"new-install"}) {
  516.             $question="tasksel/first";
  517.         }
  518.         my @default = grep { $_->{_display} == 1 && ($_->{_install} == 1 || $_->{_installed} == 1) } @tasks;
  519.         my $tmpfile=`tempfile`;
  520.         chomp $tmpfile;
  521.         my $ret=system($debconf_helper, $tmpfile,
  522.             task_to_debconf("shortdesc", @list),
  523.             task_to_debconf("shortdesctrans", @list),
  524.             task_to_debconf("shortdesc", @default),
  525.             $question) >> 8;
  526.         if ($ret == 30) {
  527.             exit 10; # back up
  528.         }
  529.         elsif ($ret != 0) {
  530.             error "debconf failed to run";
  531.         }
  532.         open(IN, "<$tmpfile");
  533.         $ret=<IN>;
  534.         if (! defined $ret) {
  535.             die "tasksel canceled\n";
  536.         }
  537.         chomp $ret;
  538.         close IN;
  539.         unlink $tmpfile;
  540.         
  541.         # Set _install flags based on user selection.
  542.         map { $_->{_install} = 0 } @list;
  543.         foreach my $task (list_to_tasks($ret, @tasks)) {
  544.             if (! $task->{_installed}) {
  545.                 $task->{_install} = 1;
  546.             }
  547.             $task->{_selected} = 1;
  548.         }
  549.         foreach my $task (@list) {
  550.             if (! $task->{_selected} && $task->{_installed}) {
  551.                 push @tasks_remove, $task;
  552.             }
  553.         }
  554.     }
  555.  
  556.     # Select enhancing tasks for install.
  557.     my %provided;
  558.     foreach my $task (grep { $_->{_install} && exists $_->{enhances} &&
  559.                              length $_->{enhances} } @tasks) {
  560.         # If an enhancing task is already marked for
  561.         # install, probably by preseeding, mark the tasks
  562.         # it enhances for install.
  563.         map { $_->{_install}=1 } list_to_tasks($task->{enhances}, @tasks);
  564.         if (exists $task->{provides} && length $task->{provides}) {
  565.             $provided{$task->{provides}}=1;
  566.         }
  567.     }
  568.     foreach my $task (grep { ! $_->{_install} && exists $_->{enhances} &&
  569.                              length $_->{enhances} } @tasks) {
  570.         # Mark enhancing tasks for install if their
  571.         # dependencies are met and if their test fields
  572.         # mark them for install.
  573.         task_test($task, $options{"new-install"}, 0, 1);
  574.         foreach my $dep (list_to_tasks($task->{enhances}, @tasks)) {
  575.             if (! $dep->{_install}) {
  576.                 $task->{_install} = 0;
  577.             }
  578.         }
  579.         # If two enhancing tasks that both provide
  580.         # the same thing, only install one of them.
  581.         if ($task->{_install} && exists $task->{provides} &&
  582.             length $task->{provides}) {
  583.             if (exists $provided{$task->{provides}}) {
  584.                 $task->{_install}=0;
  585.             }
  586.             $provided{$task->{provides}}=1;
  587.         }
  588.     }
  589.  
  590.     # Add tasks to install and see if any selected task requires manual
  591.     # selection.
  592.     my $manual_selection=0;
  593.     foreach my $task (grep { $_->{_install} } @tasks) {
  594.         push @tasks_install, $task;
  595.         if ($task->{packages} eq 'manual') {
  596.             $manual_selection=1;
  597.         }
  598.     }
  599.     
  600.     my $dap;
  601.     my ($dap_from, $dap_to);
  602.     my @dap_options;
  603.     my @apt;
  604.     my $no_recommends;
  605.     if ($manual_selection) {
  606.         # Manaul selection and task installs, as best
  607.         # aptitude can do it currently. Disables use of
  608.         # debconf-apt-progress.
  609.         @apt="aptitude";
  610.         $no_recommends="--without-recommends";
  611.     }
  612.     elsif (-x "/usr/bin/debconf-apt-progress") {
  613.         $dap="debconf-apt-progress";
  614.         if (exists $options{'debconf-apt-from'} and
  615.             exists $options{'debconf-apt-to'}) {
  616.             $dap_from=$options{'debconf-apt-from'};
  617.             $dap_to=$options{'debconf-apt-to'};
  618.         }
  619.         push @dap_options, split(' ', $options{'debconf-apt-progress'})
  620.             if exists $options{'debconf-apt-progress'};
  621.         @apt=qw{apt-get -q};
  622.         $no_recommends="--no-install-recommends";
  623.     }
  624.     else {
  625.         @apt="apt-get";
  626.         $no_recommends="--no-install-recommends";
  627.     }
  628.  
  629.     # We arbitrarily allocate 5% of the progress bar to task scripts,
  630.     # divided equally among all the scripts. (If you change this, the
  631.     # new percentage should divide equally into 100.)
  632.     my $num_regions=0;
  633.     foreach my $task (@tasks_remove) {
  634.         if (defined find_task_script($task->{task}, "prerm")) {
  635.             ++$num_regions;
  636.         }
  637.         if (defined find_task_script($task->{task}, "postrm")) {
  638.             ++$num_regions;
  639.         }
  640.     }
  641.     foreach my $task (@tasks_install) {
  642.         if (defined find_task_script($task->{task}, "preinst")) {
  643.             ++$num_regions;
  644.         }
  645.         if (defined find_task_script($task->{task}, "postinst")) {
  646.             ++$num_regions;
  647.         }
  648.     }
  649.     $num_regions*=20;
  650.     my $cur_region=0;
  651.  
  652.     # Task removal..
  653.     if (@tasks_remove) {
  654.         my @packages_remove=map { task_packages($_, 0) } @tasks_remove;
  655.         foreach my $task (@tasks_remove) {
  656.             my $path=find_task_script($task->{task}, "prerm");
  657.             if (defined $path) {
  658.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  659.                 run_task_script(@prefix, $path);
  660.             }
  661.         }
  662.         my $ret=run(@apt, "-y", "remove", @packages_remove);
  663.         if ($ret != 0) {
  664.             error gettext("aptitude failed")." ($ret)";
  665.         }
  666.         foreach my $task (@tasks_remove) {
  667.             my $path=find_task_script($task->{task}, "postrm");
  668.             if (defined $path) {
  669.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  670.                 run_task_script(@prefix, $path);
  671.             }
  672.         }
  673.     }
  674.     
  675.     # And finally, act on selected tasks.
  676.     if (@tasks_install || $manual_selection) {
  677.         my @packages_install=map {task_packages($_, 1) } @tasks_install;
  678.         foreach my $task (@tasks_install) {
  679.             my $path=find_task_script($task->{task}, "preinst");
  680.             if (defined $path) {
  681.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  682.                 run_task_script(@prefix, $path);
  683.             }
  684.         }
  685.         # If the user selected no other tasks and manual package
  686.         # selection, run aptitude w/o the --visual-preview parameter.
  687.         if (! @packages_install && $manual_selection) {
  688.             my $ret=run("aptitude");
  689.             if ($ret != 0) {
  690.                 error gettext("aptitude failed")." ($ret)";
  691.             }
  692.         }
  693.         else {
  694.             if ($manual_selection) {
  695.                 unshift @packages_install, "--visual-preview";
  696.             }
  697.             my @prefix;
  698.             if (defined $dap_from and defined $dap_to) {
  699.                 if ($num_regions) {
  700.                     # The main apt-get run takes up the
  701.                     # remaining 95% of the progress bar.
  702.                     @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region, $num_regions * 0.95, $num_regions);
  703.                     $cur_region=floor($cur_region + $num_regions * 0.95 + 0.5);
  704.                 } else {
  705.                     @prefix=debconf_apt_command($dap, $dap_from, $dap_to, \@dap_options);
  706.                 }
  707.             } elsif (defined $dap) {
  708.                 @prefix=($dap, @dap_options, '--');
  709.             }
  710.             my $ret=run(@prefix, @apt, $no_recommends,
  711.                                        "-y", "install",
  712.                                        @packages_install);
  713.             if ($ret != 0) {
  714.                 error gettext("aptitude failed")." ($ret)";
  715.             }
  716.         }
  717.         foreach my $task (@tasks_install) {
  718.             my $path=find_task_script($task->{task}, "postinst");
  719.             if (defined $path) {
  720.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  721.                 run_task_script(@prefix, $path);
  722.             }
  723.         }
  724.     }
  725. }
  726.  
  727. main();
  728.