summaryrefslogtreecommitdiffstats
path: root/perl-install/install/steps_interactive.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/install/steps_interactive.pm')
-rw-r--r--perl-install/install/steps_interactive.pm1158
1 files changed, 1158 insertions, 0 deletions
diff --git a/perl-install/install/steps_interactive.pm b/perl-install/install/steps_interactive.pm
new file mode 100644
index 000000000..55985e01a
--- /dev/null
+++ b/perl-install/install/steps_interactive.pm
@@ -0,0 +1,1158 @@
+package install::steps_interactive;
+
+
+use strict;
+use feature 'state';
+
+our @ISA = qw(install::steps);
+
+
+#-######################################################################################
+#- misc imports
+#-######################################################################################
+use common;
+use partition_table;
+use fs::type;
+use fs::partitioning;
+use fs::partitioning_wizard;
+use install::steps;
+use install::interactive;
+use install::any;
+use messages;
+use detect_devices;
+use run_program;
+use devices;
+use fsedit;
+use mouse;
+use modules;
+use modules::interactive;
+use lang;
+use keyboard;
+use any;
+use log;
+
+#-######################################################################################
+#- In/Out Steps Functions
+#-######################################################################################
+sub errorInStep {
+ my ($o, $err) = @_;
+ $err = ugtk3::escape_text_for_TextView_markup_format($err) if $o->isa('install::steps_gtk');
+ $o->ask_warn(N("Error"), [ N("An error occurred"), formatError($err) ]);
+}
+
+sub kill_action {
+ my ($o) = @_;
+ $o->kill;
+}
+
+#-######################################################################################
+#- Steps Functions
+#-######################################################################################
+#------------------------------------------------------------------------------
+
+sub acceptLicense {
+ my ($o) = @_;
+ return if $o->{useless_thing_accepted};
+
+ any::acceptLicense($o);
+}
+
+sub selectLanguage {
+ my ($o) = @_;
+
+ any::selectLanguage_install($o, $o->{locale});
+ install::steps::selectLanguage($o);
+
+ if ($o->isa('interactive::gtk')) {
+ $o->ask_warn('', formatAlaTeX(
+"If you see this message it is because you chose a language for
+which DrakX does not include a translation yet; however the fact
+that it is listed means there is some support for it anyway.
+
+That is, once GNU/Linux will be installed, you will be able to at
+least read and write in that language; and possibly more (various
+fonts, spell checkers, various programs translated etc. that
+varies from language to language).")) if $o->{locale}{lang} !~ /^en/ && !lang::load_mo();
+ } else {
+ #- no need to have this in po since it is never translated
+ $o->ask_warn('', "The characters of your language cannot be displayed in console,
+so the messages will be displayed in english during installation") if $ENV{LANGUAGE} eq 'C';
+ }
+}
+
+#------------------------------------------------------------------------------
+sub selectKeyboard {
+ my ($o, $clicked) = @_;
+
+ my $from_usb = keyboard::from_usb();
+ my $l = keyboard::lang2keyboards(lang::langs($o->{locale}{langs}));
+
+ if ($clicked || !($from_usb || @$l && $l->[0][1] >= 90) || listlength(lang::langs($o->{locale}{langs})) > 1) {
+ add2hash($o->{keyboard}, $from_usb);
+ my @best = uniq(grep { $_ } $from_usb && $from_usb->{KEYBOARD}, $o->{keyboard}{KEYBOARD},
+ map { $_->[0] } @$l);
+ @best = () if @best == 1;
+
+ my $format = sub { translate(keyboard::KEYBOARD2text($_[0])) };
+ my $other;
+ my $ext_keyboard = my $KEYBOARD = $o->{keyboard}{KEYBOARD};
+ $o->ask_from_(
+ { title => N("Keyboard"),
+ interactive_help_id => 'selectKeyboard',
+ advanced_label => N("More"),
+ },
+ [
+ { label => N("Please choose your keyboard layout"), title => 1 },
+ if_(@best, { val => \$KEYBOARD, type => 'list', format => $format, sort => 1,
+ list => [ @best ], changed => sub { $other = 0 } }),
+ if_(@best,
+ { label => N("Here is the full list of available keyboards:"), title => 1, advanced => 1 }),
+ { val => \$ext_keyboard, type => 'list', format => $format, changed => sub { $other = 1 },
+ list => [ difference2([ keyboard::KEYBOARDs() ], \@best) ], advanced => @best > 1 }
+ ]);
+ $o->{keyboard}{KEYBOARD} = !@best || $other ? $ext_keyboard : $KEYBOARD;
+ delete $o->{keyboard}{unsafe};
+ }
+ keyboard::group_toggle_choose($o, $o->{keyboard}) or goto &selectKeyboard;
+ install::steps::selectKeyboard($o);
+ if ($::isRestore) {
+ require MDV::Snapshot::Restore;
+ MDV::Snapshot::Restore::main($o);
+ $o->exit;
+ }
+}
+
+#------------------------------------------------------------------------------
+sub selectInstallClass {
+ my ($o) = @_;
+
+ return if $::isRestore;
+
+ my @l = install::any::find_root_parts($o->{fstab}, $::prefix);
+ # Don't list other archs as ugrading between archs is not supported
+ my $arch = arch() =~ /i.86/ ? $MDK::Common::System::compat_arch{arch()} : arch();
+ # Offer to upgrade only same arch and not mdv-2011+:
+ @l = grep { $_->{arch} eq $arch && $_->{version} !~ /201[1-9]/ } @l;
+ if (@l) {
+ _try_to_upgrade($o, @l);
+ }
+}
+
+sub _try_to_upgrade {
+ my ($o, @l) = @_;
+ log::l("proposing to upgrade partitions " . join(" ", map { $_->{part} && $_->{part}{device} } @l));
+
+ my @releases = uniq(map { "$_->{release} $_->{version}" } @l);
+ if (@releases != @l) {
+ #- same release name so adding the device to differentiate them:
+ $_->{release} .= " ($_->{part}{device})" foreach @l;
+ }
+
+ askInstallClass:
+ my $p;
+ $o->ask_from_({ title => N("Install/Upgrade"),
+ interactive_help_id => 'selectInstallClass',
+ },
+ [
+ { label => N("Is this an install or an upgrade?"), title => 1 },
+ { val => \$p,
+ list => [ @l, N_("_: This is a noun:\nInstall") ],
+ type => 'list',
+ format => sub { ref($_[0]) ? N("Upgrade %s", "$_[0]->{release} $_[0]->{version}") : translate($_[0]) }
+ } ]);
+ if (ref $p) {
+ _check_unsafe_upgrade_and_warn($o, $p->{part}) or $p = undef;
+ }
+
+ if (ref $p) {
+ _prepare_upgrade($o, $p);
+ }
+}
+
+sub _prepare_upgrade {
+ my ($o, $p) = @_;
+ if ($p->{part}) {
+ log::l("choosing to upgrade partition $p->{part}{device}");
+ $o->{migrate_device_names} = install::any::use_root_part($o->{all_hds}, $p->{part}, $o);
+ }
+
+ #- handle encrypted partitions (esp. /home)
+ foreach (grep { $_->{mntpoint} } @{$o->{fstab}}) {
+ my ($options, $_unknown) = fs::mount_options::unpack($_);
+ $options->{encrypted} or next;
+ $o->ask_from_({ focus_first => 1 },
+ [ { label => N("Encryption key for %s", $_->{mntpoint}),
+ hidden => 1, val => \$_->{encrypt_key} } ]);
+ }
+
+ $o->{previous_release} = $p;
+ $o->{isUpgrade} = (find { $p->{release_file} =~ /$_/ } 'mageia', 'mandriva', 'mandrake', 'conectiva', 'redhat') || 'unknown';
+ $o->{upgrade_by_removing_pkgs_matching} ||= {
+ conectiva => 'cl',
+ redhat => '.', #- everything!
+ }->{$o->{isUpgrade}};
+ log::l("upgrading $o->{isUpgrade} distribution" . ($o->{upgrade_by_removing_pkgs_matching} ? " (upgrade_by_removing_pkgs_matching $o->{upgrade_by_removing_pkgs_matching})" : ''));
+}
+
+sub _check_unsafe_upgrade_and_warn {
+ my ($o, $part) = @_;
+ !_is_unsafe_upgrade($part) || _warn_unsafe_upgrade($o);
+}
+
+sub _is_unsafe_upgrade {
+ my ($part) = @_;
+
+ my $r = run_program::get_stdout('dumpe2fs', devices::make($part->{device}));
+ my $block_size = $r =~ /^Block size:\s*(\d+)/m && $1;
+ log::l("block_size $block_size");
+ $block_size == 1024;
+}
+
+sub _warn_unsafe_upgrade {
+ my ($o) = @_;
+
+ log::l("_warn_unsafe_upgrade");
+
+ my @choices = (
+ N_("Cancel installation, reboot system"),
+ N_("New Installation"),
+ N_("Upgrade previous installation (not recommended)"),
+ );
+
+ my $choice;
+ $o->ask_from_({ messages => N("Installer has detected that your installed Linux system could not
+safely be upgraded to %s.
+
+New installation replacing your previous one is recommended.
+
+Warning : you should backup all your personal data before choosing \"New
+Installation\".", '%s') },
+ [ { val => \$choice, type => 'list', list => \@choices, format => \&translate } ]);
+
+ log::l("_warn_unsafe_upgrade: got $choice");
+
+ if ($choice eq $choices[0]) {
+ any::reboot();
+ } elsif ($choice eq $choices[1]) {
+ undef;
+ } else {
+ 1;
+ }
+}
+
+#------------------------------------------------------------------------------
+sub selectMouse {
+ my ($o, $force) = @_;
+
+ $force || $o->{mouse}{unsafe} or return;
+
+ mouse::select($o, $o->{mouse}) or return;
+
+ if ($o->{mouse}{device} eq "input/mice") {
+ modules::interactive::load_category($o, $o->{modules_conf}, 'bus/usb', 1, 0);
+ eval {
+ modules::load('usbhid');
+ };
+ }
+}
+#------------------------------------------------------------------------------
+sub setupSCSI {
+ my ($o) = @_;
+
+ install::any::configure_pcmcia($o);
+ {
+ my $_w = $o->wait_message(N("CD/DVD"), N("Configuring CD/DVD"));
+ modules::load(modules::category2modules('disk/cdrom'));
+ }
+ modules::interactive::load_category($o, $o->{modules_conf}, 'bus/firewire', 1);
+
+ my $have_non_scsi = detect_devices::hds(); #- at_least_one scsi device if we have no disks
+ modules::interactive::load_category($o, $o->{modules_conf}, 'disk/card_reader|ide|scsi|hardware_raid|sata|firewire|virtual', 1, !$have_non_scsi);
+ modules::interactive::load_category($o, $o->{modules_conf}, 'disk/card_reader|ide|scsi|hardware_raid|sata|firewire|virtual') if !detect_devices::hds(); #- we really want a disk!
+
+ install::interactive::tellAboutProprietaryModules($o);
+
+ install::any::getHds($o, $o);
+}
+
+#------------------------------------------------------------------------------
+sub doPartitionDisks {
+ my ($o) = @_;
+
+ if (!$o->{isUpgrade}) {
+ fs::partitioning_wizard::main($o, $o->{all_hds}, $o->{fstab}, $o->{manualFstab}, $o->{partitions}, $o->{partitioning}, $::local_install);
+ }
+}
+
+#------------------------------------------------------------------------------
+sub rebootNeeded {
+ my ($o) = @_;
+ fs::partitioning_wizard::warn_reboot_needed($o);
+ install::steps::rebootNeeded($o);
+}
+
+#------------------------------------------------------------------------------
+sub choosePartitionsToFormat {
+ my ($o) = @_;
+ fs::partitioning::choose_partitions_to_format($o, $o->{fstab});
+}
+
+sub formatMountPartitions {
+ my ($o, $_fstab) = @_;
+ fs::partitioning::format_mount_partitions($o, $o->{all_hds}, $o->{fstab});
+}
+
+#------------------------------------------------------------------------------
+#- group by CD
+sub ask_deselect_media__copy_on_disk {
+ my ($o, $hdlists, $o_copy_rpms_on_disk) = @_;
+
+ log::l("ask_deselect_media__copy_on_disk");
+
+ my @names = uniq(map { $_->{name} } @$hdlists);
+ my %selection = map { $_ => 1 } @names;
+
+ $o->ask_from_({ messages => formatAlaTeX(N("The following installation media have been found.
+If you want to skip some of them, you can unselect them now.")) },
+ [ (map { { type => 'bool', text => $_, val => \$selection{$_},
+ if_($_ eq $names[0], disabled => sub { 1 }),
+ } } @names),
+ if_($o_copy_rpms_on_disk,
+ { type => 'label', val => \(formatAlaTeX(N("You have the option to copy the contents of the CDs onto the hard disk drive before installation.
+It will then continue from the hard disk drive and the packages will remain available once the system is fully installed."))) },
+ { type => 'bool', text => N("Copy whole CDs"), val => $o_copy_rpms_on_disk },
+ ),
+ ]);
+ $_->{ignore} = !$selection{$_->{name}} foreach @$hdlists;
+ log::l("keeping media " . join ',', map { $_->{rpmsdir} } grep { !$_->{ignore} } @$hdlists);
+}
+
+sub while_suspending_time {
+ my ($o, $f) = @_;
+
+ my $time = time();
+
+ my $r = $f->();
+
+ #- add the elapsed time (otherwise the predicted time will be rubbish)
+ $o->{install_start_time} += time() - $time;
+
+ $r;
+}
+
+# nb: $file can be a directory
+sub ask_change_cd {
+ my ($o, $medium) = @_;
+
+ while_suspending_time($o, sub { ask_change_cd_($o, $medium) });
+}
+
+sub ask_change_cd_ {
+ my ($o, $medium) = @_;
+
+ local $::isWizard = 0; # make button name match text, aka being "cancel" rather than "previous"
+ $o->ask_okcancel('', N("Change your Cd-Rom!
+Please insert the Cd-Rom labelled \"%s\" in your drive and press Ok when done.
+If you do not have it, press Cancel to avoid installation from this Cd-Rom.", $medium), 1) or return;
+
+}
+
+sub selectSupplMedia {
+ my ($o) = @_;
+ install::any::selectSupplMedia($o);
+}
+
+#------------------------------------------------------------------------------
+sub choosePackages {
+ my ($o) = @_;
+
+ require pkgs;
+ add2hash_($o, { compssListLevel => pkgs::rpmsrate_rate_default() });
+
+ my $w = $o->wait_message('', N("Looking for available packages..."));
+ my $availableC = install::steps::choosePackages($o, pkgs::rpmsrate_rate_max());
+
+ require install::pkgs;
+
+ my $min_size = install::pkgs::selectedSize($o->{packages});
+ undef $w;
+ if ($min_size >= $availableC) {
+ my $msg = N("Your system does not have enough space left for installation or upgrade (%dMB > %dMB)",
+ $min_size / sqr(1024), $availableC / sqr(1024));
+ log::l($msg);
+ $o->ask_warn('', $msg);
+ install::steps::rebootNeeded($o);
+ }
+
+ my ($individual, $chooseGroups);
+
+ if (!$o->{isUpgrade}) {
+ my $tasks_ok = install::pkgs::packageByName($o->{packages}, 'task-plasma-minimal') &&
+ install::pkgs::packageByName($o->{packages}, 'task-gnome-minimal');
+ if ($tasks_ok && $availableC >= 2_500_000_000) {
+ _chooseDesktop($o, $o->{rpmsrate_flags_chosen}, \$chooseGroups);
+ } else {
+ $tasks_ok ? log::l("not asking for desktop since not enough place") :
+ log::l("not asking for desktop since kde and gnome are not available on media (useful for mini iso)");
+ $chooseGroups = 1;
+ }
+ }
+
+ chooseGroups:
+ $o->chooseGroups($o->{packages}, $o->{compssUsers}, \$individual) if $chooseGroups;
+
+ ($o->{packages_}{ind}) =
+ install::pkgs::setSelectedFromCompssList($o->{packages}, $o->{rpmsrate_flags_chosen}, $o->{compssListLevel}, $availableC);
+
+ $o->choosePackagesTree($o->{packages}) or goto chooseGroups if $individual;
+
+ install::any::warnAboutRemovedPackages($o, $o->{packages});
+}
+
+sub choosePackagesTree {
+ my ($o, $packages, $o_limit_to_medium) = @_;
+
+ $o->ask_many_from_list('', N("Choose the packages you want to install"),
+ {
+ list => [ grep { !$o_limit_to_medium || install::pkgs::packageMedium($packages, $_) == $o_limit_to_medium }
+ @{$packages->{depslist}} ],
+ value => \&URPM::Package::flag_selected,
+ label => \&URPM::Package::name,
+ sort => 1,
+ });
+}
+
+sub loadSavePackagesOnFloppy {
+ my ($o, $packages) = @_;
+ $o->ask_from('',
+N("Please choose load or save package selection.
+The format is the same as auto_install generated files."),
+ [ { val => \ (my $choice), list => [ N_("Load"), N_("Save") ], format => \&translate, type => 'list' } ]) or return;
+
+ if ($choice eq 'Load') {
+ while (1) {
+ log::l("load package selection");
+ my ($_h, $fh) = install::any::media_browser($o, '', 'package_list.pl') or return;
+ my $O = eval { install::any::loadO(undef, $fh) };
+ if ($@) {
+ $o->ask_okcancel('', N("Bad file")) or return;
+ } else {
+ install::any::unselectMostPackages($o);
+ install::pkgs::select_by_package_names($packages, $O->{default_packages} || []);
+ return 1;
+ }
+ }
+ } else {
+ log::l("save package selection");
+ install::any::g_default_packages($o);
+ }
+}
+
+sub _chooseDesktop {
+ my ($o, $rpmsrate_flags_chosen, $chooseGroups) = @_;
+
+ my @l = group_by2(
+ PLASMA => N("Plasma"),
+ GNOME => N("GNOME"),
+ Custom => N("Custom"),
+ );
+ my $title = N("Desktop Selection");
+ my $message = N("You can choose your workstation desktop profile.");
+
+ my $default_choice = (find { $rpmsrate_flags_chosen->{"CAT_" . $_->[0]} } @l) || $l[0];
+ my $choice = $default_choice;
+ if ($o->isa('interactive::gtk')) {
+ # perl_checker: require install::steps_gtk
+ $choice = install::steps_gtk::reallyChooseDesktop($o, $title, $message, \@l, $default_choice);
+ } else {
+ $o->ask_from_({ title => $title, message => $message }, [
+ { val => \$choice, list => \@l, type => 'list', format => sub { $_[0][1] } },
+ ]);
+ }
+ my $desktop = $choice->[0];
+ log::l("chosen Desktop: $desktop");
+ my @desktops = ('PLASMA', 'GNOME');
+ if (member($desktop, @desktops)) {
+ my ($want, $dontwant) = ($desktop, grep { $desktop ne $_ } @desktops);
+ $rpmsrate_flags_chosen->{"CAT_$want"} = 1;
+ $rpmsrate_flags_chosen->{"CAT_$dontwant"} = 0;
+ my @flags = map_each { if_($::b, $::a) } %$rpmsrate_flags_chosen;
+ log::l("flags ", join(' ', sort @flags));
+ install::any::unselectMostPackages($o);
+ } else {
+ $$chooseGroups = 1;
+ }
+}
+
+sub chooseGroups {
+ my ($o, $packages, $compssUsers, $individual) = @_;
+
+ my $w = $o->wait_message('', N("Looking for available packages..."));
+
+ #- for all groups available, determine package which belongs to each one.
+ #- this will enable getting the size of each groups more quickly due to
+ #- limitation of current implementation.
+ #- use an empty state for each one (no flag update should be propagated).
+
+ my $b = install::pkgs::saveSelected($packages);
+ install::any::unselectMostPackages($o);
+ install::pkgs::setSelectedFromCompssList($packages, { CAT_SYSTEM => 1 }, $o->{compssListLevel}, 0);
+ my $system_size = install::pkgs::selectedSize($packages);
+ my ($sizes, $pkgs) = install::pkgs::computeGroupSize($packages, $o->{compssListLevel});
+ install::pkgs::restoreSelected($b);
+ log::l("system_size: $system_size");
+
+ my %stable_flags = grep_each { $::b } %{$o->{rpmsrate_flags_chosen}};
+ delete $stable_flags{"CAT_$_"} foreach map { @{$_->{flags}} } @{$o->{compssUsers}};
+
+ undef $w;
+
+ my $compute_size = sub {
+ my %pkgs;
+ my %flags = %stable_flags; @flags{@_} = ();
+ my $total_size;
+ A: while (my ($k, $size) = each %$sizes) {
+ Or: foreach (split "\t", $k) {
+ foreach (split "&&") {
+ exists $flags{$_} or next Or;
+ }
+ $total_size += $size;
+ $pkgs{$_} = 1 foreach @{$pkgs->{$k}};
+ next A;
+ }
+ }
+ log::l("computed size $total_size (flags " . join(' ', keys %flags) . ")");
+ log::l("chooseGroups: ", join(" ", sort keys %pkgs));
+
+ int $total_size;
+ };
+
+ my ($size, $unselect_all);
+ my $available_size = install::any::getAvailableSpace($o) / sqr(1024);
+ my $size_to_display = sub {
+ my $lsize = $system_size + $compute_size->(map { "CAT_$_" } map { @{$_->{flags}} } grep { $_->{selected} } @$compssUsers);
+
+ #- if a profile is deselected, deselect everything (easier than deselecting the profile packages)
+ $unselect_all ||= $size > $lsize;
+ $size = $lsize;
+ N("Total size: %d / %d MB", install::pkgs::correctSize($size / sqr(1024)), $available_size);
+ };
+
+ while (1) {
+ if ($available_size < 200) {
+ # too small to choose anything. Defaulting to no group chosen
+ $_->{selected} = 0 foreach @$compssUsers;
+ last;
+ }
+
+ $o->reallyChooseGroups($size_to_display, $individual, $compssUsers) or return;
+
+ last if $::testing || install::pkgs::correctSize($size / sqr(1024)) < $available_size || every { !$_->{selected} } @$compssUsers;
+
+ $o->ask_warn('', N("Selected size is larger than available space"));
+ }
+ install::any::set_rpmsrate_category_flags($o, $compssUsers);
+
+ log::l("compssUsersChoice selected: ", join(', ', map { qq("$_->{path}|$_->{label}") } grep { $_->{selected} } @$compssUsers));
+
+ if (!$o->{isUpgrade}) {
+ #- do not try to deselect package (by default no groups are selected).
+ install::any::unselectMostPackages($o) if $unselect_all;
+
+ #- if no group have been chosen, ask for using base system only, or no X, or normal.
+ if (!any { $_->{selected} } @$compssUsers) {
+ offer_minimal_options($o) or goto &chooseGroups;
+ }
+ }
+ 1;
+}
+
+sub offer_minimal_options {
+ my ($o) = @_;
+ my $docs = !$o->{excludedocs};
+ state $minimal;
+ my $recommends = !$o->{no_recommends};
+
+ $o->ask_from_({ title => N("Type of install"),
+ message => N("You have not selected any group of packages.
+Please choose the minimal installation you want:"),
+ interactive_help_id => 'minimal-install'
+ },
+ [
+ { val => \$o->{rpmsrate_flags_chosen}{CAT_X}, type => 'bool', text => N("With X"), disabled => sub { $minimal } },
+ { val => \$recommends, type => 'bool', text => N("Install recommended packages"), disabled => sub { $minimal } },
+ { val => \$docs, type => 'bool', text => N("With basic documentation (recommended!)"), disabled => sub { $minimal } },
+ { val => \$minimal, type => 'bool', text => N("Truly minimal install (especially no urpmi)") },
+ ],
+ ) or return 0;
+
+ if ($minimal) {
+ $o->{rpmsrate_flags_chosen}{CAT_X} = $docs = $recommends = 0;
+ $o->{rpmsrate_flags_chosen}{CAT_SYSTEM} = 0;
+ }
+ $o->{excludedocs} = !$docs;
+ $o->{rpmsrate_flags_chosen}{CAT_MINIMAL_DOCS} = $docs;
+ $o->{no_recommends} = !$recommends;
+ $o->{compssListLevel} = pkgs::rpmsrate_rate_max() if !$recommends;
+ log::l("install settings: no_recommends=$o->{no_recommends}, excludedocs=$o->{excludedocs}, really_minimal_install=$minimal");
+
+ install::any::unselectMostPackages($o);
+ 1;
+}
+
+sub reallyChooseGroups {
+ my ($o, $size_to_display, $individual, $compssUsers) = @_;
+
+ my $size_text = &$size_to_display;
+
+ my ($path, $all);
+ $o->ask_from_({ messages => N("Package Group Selection"),
+ interactive_help_id => 'choosePackageGroups',
+ }, [
+ { val => \$size_text, type => 'label' }, {},
+ (map {
+ my $old = $path;
+ $path = $_->{path};
+ if_($old ne $path, { val => translate($path) }),
+ {
+ val => \$_->{selected},
+ type => 'bool',
+ disabled => sub { $all },
+ text => translate($_->{label}),
+ help => translate($_->{descr}),
+ changed => sub { $size_text = &$size_to_display },
+ };
+ } @$compssUsers),
+ if_($individual, { text => N("Individual package selection"), val => $individual, advanced => 1, type => 'bool' }),
+ ]);
+
+ if ($all) {
+ $_->{selected} = 1 foreach @$compssUsers;
+ }
+ 1;
+}
+
+sub beforeInstallPackages {
+ my ($o) = @_;
+ my $_w = $o->{isUpgrade} && $o->wait_message('', N("Preparing upgrade..."));
+ $o->SUPER::beforeInstallPackages;
+}
+
+#------------------------------------------------------------------------------
+sub installPackages {
+ my ($o) = @_;
+ my ($current, $total) = (0, 0);
+
+ my ($_w, $wait_message) = $o->wait_message_with_progress_bar(N("Installing"));
+ $wait_message->(N("Preparing installation"), 0, 100); #- beware, interactive::curses::wait_message_with_progress_bar need to create the Dialog::Progress here because in installCallback we are chrooted
+
+ local *install::steps::installCallback = sub {
+ my ($packages, $type, $id, $subtype, $_amount, $total_) = @_;
+ if ($type eq 'user' && $subtype eq 'install') {
+ $total = $total_;
+ } elsif ($type eq 'inst' && $subtype eq 'start') {
+ my $p = $packages->{depslist}[$id];
+ $wait_message->(N("Installing package %s", $p->name), $current, $total);
+ $current += $p->size;
+ }
+ };
+
+ my $install_result;
+ catch_cdie { $install_result = $o->install::steps::installPackages('interactive') }
+ sub { installPackages__handle_error($o, $_[0]) };
+
+ if ($install::pkgs::cancel_install) {
+ $install::pkgs::cancel_install = 0;
+ die "setstep choosePackages\n";
+ }
+ $install_result;
+}
+
+sub installPackages__handle_error {
+ my ($o, $err_ref) = @_;
+
+ log::l("catch_cdie: $$err_ref");
+ my $time = time();
+ my $go_on;
+ if ($$err_ref =~ /^error ordering package list: (.*)/) {
+ $go_on = $o->ask_yesorno('', [
+ N("There was an error ordering packages:"), $1, N("Go on anyway?") ], 1);
+ } elsif ($$err_ref =~ /^error installing package list: (\S+)\s*(.*)/) {
+ my ($pkg_name, $medium_name) = ($1, $2);
+ my @choices = (
+ [ 'retry', N("Retry") ],
+ [ 'skip_one', N("Skip this package") ],
+ [ 'disable_media', N("Skip all packages from medium \"%s\"", $medium_name) ],
+ [ '', N("Go back to media and packages selection") ],
+ );
+ my $choice;
+ $o->ask_from_({ messages => N("There was an error installing package %s.", $pkg_name) },
+ [ { val => \$choice, type => 'list', list => \@choices, format => sub { $_[0][1] } } ]);
+ $go_on = $choice->[0];
+ }
+ if ($go_on) {
+ #- add the elapsed time (otherwise the predicted time will be rubbish)
+ $o->{install_start_time} += time() - $time;
+ $go_on;
+ } else {
+ $o->{askmedia} = 1;
+ $$err_ref = "already displayed";
+ 0;
+ }
+}
+
+
+sub afterInstallPackages($) {
+ my ($o) = @_;
+ local $o->{pop_wait_messages} = 1;
+ my $_w = $o->wait_message(N("Post-install configuration"), N("Post-install configuration"));
+ $o->SUPER::afterInstallPackages;
+}
+
+sub updatemodules {
+ my ($o, $dev, $rel_dir) = @_;
+
+ $o->ask_okcancel('', N("Please ensure the Update Modules media is in drive %s", $dev), 1) or return;
+ $o->SUPER::updatemodules($dev, $rel_dir);
+}
+
+#------------------------------------------------------------------------------
+sub configureNetwork {
+ my ($o) = @_;
+ #- don't overwrite configuration in a network install
+ if (!install::any::is_network_install($o)) {
+ require network::network;
+ network::network::easy_dhcp($o->{net}, $o->{modules_conf});
+ }
+ $o->SUPER::configureNetwork;
+}
+
+#------------------------------------------------------------------------------
+sub installUpdates {
+ my ($o) = @_;
+ $o->{updates} ||= {};
+
+ $o->hasNetwork or return;
+
+ if (install::any::is_network_install($o) &&
+ find { $_->{update} } install::media::allMediums($o->{packages})) {
+ log::l("installUpdates: skipping since updates were already available during install");
+ return;
+ }
+
+ $o->ask_yesorno_({ title => N("Updates"), messages => formatAlaTeX(
+N("You now have the opportunity to setup online media.") . "\n\n" .
+N("This allows to install security updates.") . "\n\n" .
+N("To setup those media, you will need to have a working Internet
+connection.
+
+Do you want to setup the update media?")),
+ interactive_help_id => 'installUpdates',
+ }, 1) or do {
+ log::l("installUpdates: skipping since user say no to media setup");
+ return;
+ };
+
+ my $urpmi_options = { mirror_url => '$MIRRORLIST', downloader => $o->{options}{downloader} };
+
+ try_again:
+ #- bring all interface up for installing updates packages.
+ install::interactive::upNetwork($o);
+
+ any::ask_mirror_and_downloader($o, $urpmi_options);
+
+ if (!any::urpmi_set_downloader($o, $o->{packages}, $urpmi_options->{downloader})) {
+ log::l("installUpdates: failed to change urpmi downloader");
+ local $::isWizard = 0; # make button names "ok" and "cancel", not "next" and "previous"
+ if ($o->ask_okcancel(N("Warning"),
+ N("That downloader could not be installed") . "\n" . N("Retry?"))) {
+ goto try_again;
+ } else {
+ return 0;
+ }
+ }
+
+ if ($urpmi_options->{mirror_url} ne '$MIRRORLIST') {
+ $urpmi_options->{mirror_url} = any::ask_mirror($o, 'distrib', $urpmi_options->{mirror_url});
+ }
+
+ install::pkgs::clean_rpmdb_shared_regions();
+ if (any::urpmi_add_all_media($o, $o->{previous_release}, $urpmi_options->{mirror_url})) {
+ log::l("installUpdates: successfully added media");
+ } else {
+ log::l("installUpdates: failed to add media");
+ local $::isWizard = 0; # make button names "ok" and "cancel", not "next" and "previous"
+ if ($o->ask_okcancel(N("Warning"),
+ N("Failure when adding medium") . "\n" . N("Retry?"))) {
+ goto try_again;
+ } else {
+ return 0;
+ }
+ }
+
+ $o->ask_yesorno_({ title => N("Updates"), messages => formatAlaTeX(
+N("You now have the opportunity to download updated packages. These packages
+have been updated after the distribution was released. They may
+contain security or bug fixes.
+
+To download these packages, you will need to have a working Internet
+connection.
+
+Do you want to install the updates?")),
+ interactive_help_id => 'installUpdates',
+ }, 1) or do {
+ log::l("installUpdates: skipping since user say no to updates");
+ return;
+ };
+
+ my $binary = find { whereis_binary($_, $::prefix) } if_(check_for_xserver(), 'gurpmi2'), 'urpmi' or return;
+ my $log_file = '/root/drakx/updates.log';
+ run_program::raw({ root => $::prefix, timeout => 'never' }, $binary, '>>', $log_file, '2>>', $log_file, '--auto-select');
+
+ install::pkgs::clean_rpmdb_shared_regions();
+
+ #- not downing network, even PPP. We don't care much since it is the end of install :)
+}
+
+
+#------------------------------------------------------------------------------
+sub configureTimezone {
+ my ($o, $clicked) = @_;
+
+ any::configure_timezone($o, $o->{timezone}, $clicked) or return;
+
+ install::steps::configureTimezone($o);
+ 1;
+}
+
+#------------------------------------------------------------------------------
+sub configureServices {
+ my ($o, $clicked) = @_;
+ require services;
+ $o->{services} = services::ask($o) if $clicked;
+ install::steps::configureServices($o);
+}
+
+
+sub summaryBefore {
+ my ($o) = @_;
+
+ install::any::preConfigureTimezone($o);
+ #- get back network configuration.
+ require network::network;
+ eval {
+ network::network::read_net_conf($o->{net});
+ };
+ log::l("summaryBefore: network configuration: ", formatError($@)) if $@;
+}
+
+sub summary_prompt {
+ my ($o, $l, $check_complete) = @_;
+
+ foreach (@$l) {
+ my $val = $_->{val};
+ ($_->{format}, $_->{val}) = (sub { $val && $val->() || N("not configured") }, '');
+ }
+
+ $o->ask_from_({
+ messages => N("Summary"),
+ interactive_help_id => 'summary',
+ cancel => '',
+ callbacks => { complete => sub { !$check_complete->() } },
+ }, $l);
+}
+
+sub summary {
+ my ($o) = @_;
+
+ my @l;
+
+ my $timezone_manually_set;
+ push @l, {
+ group => N("System"),
+ label => N("Timezone"),
+ val => sub { $o->{timezone}{timezone} },
+ clicked => sub { $timezone_manually_set = $o->configureTimezone(1) || $timezone_manually_set },
+ };
+ push @l, {
+ group => N("System"),
+ label => N("Country / Region"),
+ val => sub { lang::c2name($o->{locale}{country}) },
+ clicked => sub {
+ any::selectCountry($o, $o->{locale}) or return;
+
+ my $pkg_locale = lang::locale_to_main_locale(lang::getlocale_for_country($o->{locale}{lang}, $o->{locale}{country}));
+ my @pkgs = URPM::packages_providing($o->{packages}, "locales-$pkg_locale");
+ $o->pkg_install(map { $_->name } @pkgs) if @pkgs;
+
+ lang::write_and_install($o->{locale}, $o->do_pkgs);
+ if (!$timezone_manually_set && !$o->{isUpgrade}) {
+ delete $o->{timezone};
+ install::any::preConfigureTimezone($o); #- now we can precise the timezone thanks to the country
+ }
+ },
+ };
+ local $o->{bootloader}{boot} = 'ESP' if is_uefi();
+ push @l, {
+ group => N("System"),
+ label => N("Bootloader"),
+ val => sub {
+
+ $o->{bootloader}{boot} ?
+ #-PO: example: grub2-graphic on /dev/sda1
+ N("%s on %s", $o->{bootloader}{method}, $o->{bootloader}{boot}) : N("None");
+ },
+ if_(is_uefi(), tip => N("EFI System Partition")),
+ clicked => sub {
+ any::setupBootloader($o, $o->{bootloader}, $o->{all_hds}, $o->{fstab}, $o->{security}) or return;
+ },
+ } if !$::local_install;
+
+ push @l, {
+ group => N("System"),
+ label => N("User management"),
+ clicked => sub {
+ if (my $u = any::ask_user($o, $o->{users}, $o->{security}, needauser => 1)) {
+ #- getpwnam, getgrnam, getgrid works
+ symlinkf("$::prefix/etc/passwd", '/etc/passwd');
+ symlinkf("$::prefix/etc/group", '/etc/group');
+ any::add_users([$u], $o->{authentication});
+ }
+ },
+ };
+
+ push @l, {
+ group => N("System"),
+ label => N("Services"),
+ val => sub {
+ require services;
+ my ($l, $activated) = services::services();
+ N("%d activated for %d registered", int(@$activated), int(@$l));
+ },
+ clicked => sub {
+ require services;
+ $o->{services} = services::ask($o) and services::doit($o, $o->{services});
+ },
+ };
+
+ push @l, {
+ group => N("Hardware"),
+ label => N("Keyboard"),
+ val => sub { $o->{keyboard} && translate(keyboard::keyboard2text($o->{keyboard})) },
+ clicked => sub { $o->selectKeyboard(1) },
+ } if !$o->{match_all_hardware};
+
+ push @l, {
+ group => N("Hardware"),
+ label => N("Mouse"),
+ val => sub { translate($o->{mouse}{type}) . ' ' . translate($o->{mouse}{name}) },
+ clicked => sub { selectMouse($o, 1); mouse::write($o->do_pkgs, $o->{mouse}) },
+ } if !$o->{match_all_hardware};
+
+
+ my @sound_cards = $o->{match_all_hardware} ? () : detect_devices::getSoundDevices();
+
+ my $sound_index = 0;
+ foreach my $device (@sound_cards) {
+ $device->{sound_slot_index} = $sound_index;
+ push @l, {
+ group => N("Hardware"),
+ label => N("Sound card"),
+ val => sub {
+ $device->{driver} && modules::module2description($device->{driver}) || $device->{description};
+ },
+ clicked => sub {
+ require harddrake::sound;
+ harddrake::sound::config($o, $o->{modules_conf}, $device);
+ },
+ };
+ $sound_index++;
+ }
+
+ push @l, {
+ group => N("Hardware"),
+ label => N("Graphical interface"),
+ val => sub { $o->{raw_X} ? Xconfig::various::to_string($o->{raw_X}) : '' },
+ clicked => sub { configureX($o, 'expert') },
+ } if !$o->{match_all_hardware};
+
+ push @l, {
+ group => N("Network & Internet"),
+ label => N("Network"),
+ val => sub { $o->{net}{type} },
+ format => sub { $_[0] =~ s/.*:://; $_[0] },
+ clicked => sub {
+ require network::netconnect;
+ network::netconnect::real_main($o->{net}, $o, $o->{modules_conf});
+ },
+ } if !$o->{match_all_hardware};
+
+ $o->{miscellaneous} ||= {};
+ push @l, {
+ group => N("Network & Internet"),
+ label => N("Proxies"),
+ val => sub { $o->{miscellaneous}{http_proxy} || $o->{miscellaneous}{ftp_proxy} ? N("configured") : N("not configured") },
+ clicked => sub {
+ require network::network;
+ network::network::miscellaneous_choose($o, $o->{miscellaneous});
+ network::network::proxy_configure($o->{miscellaneous}) if !$::testing;
+ },
+ } if !$o->{match_all_hardware};
+
+ push @l, {
+ group => N("Security"),
+ label => N("Security Level"),
+ val => sub {
+ require security::level;
+ security::level::to_string($o->{security});
+ },
+ clicked => sub {
+ require security::level;
+ my $security = $o->{security};
+ set_sec_level:
+ if (security::level::level_choose($o, \$security, \$o->{security_user})) {
+ check_security_level($o, $security) or goto set_sec_level;
+ $o->{security} = $security;
+ install::any::set_security($o);
+ }
+ },
+ } if -x "$::prefix/usr/sbin/msec";
+ # FIXME: install msec if needed instead
+
+ push @l, {
+ group => N("Security"),
+ label => N("Firewall"),
+ val => sub {
+ require network::shorewall;
+ my $shorewall = network::shorewall::read();
+ $shorewall && !$shorewall->{disabled} ? N("activated") : N("disabled");
+ },
+ clicked => sub {
+ require network::drakfirewall;
+ if (my @rc = network::drakfirewall::main($o, $o->{security} < 1)) {
+ $o->{firewall_ports} = !$rc[0] && $rc[1];
+ }
+ },
+ } if detect_devices::get_net_interfaces();
+
+ my $check_complete = sub {
+ return 1 if $o->{match_all_hardware};
+ require install::pkgs;
+ my $p = install::pkgs::packageByName($o->{packages}, 'task-x11');
+ $o->{raw_X} || !$::testing && $p && !$p->flag_installed ||
+ $o->ask_yesorno('', N("You have not configured X. Are you sure you really want this?"));
+ };
+
+ $o->summary_prompt(\@l, $check_complete);
+
+ any::installBootloader($o, $o->{bootloader}, $o->{all_hds}) if !$::local_install;
+ install::steps::configureTimezone($o) if !$timezone_manually_set; #- do not forget it.
+}
+
+#------------------------------------------------------------------------------
+#-setRootPassword_addUser
+#------------------------------------------------------------------------------
+sub setRootPassword_addUser {
+ my ($o) = @_;
+ $o->{users} ||= [];
+
+ my $sup = $o->{superuser} ||= {};
+ $sup->{password2} ||= $sup->{password} ||= "";
+
+ any::ask_user_and_root($o, $sup, $o->{users}, $o->{security});
+
+ install::steps::setRootPassword($o);
+ install::steps::addUser($o);
+}
+
+#------------------------------------------------------------------------------
+sub setupBootloaderBefore {
+ my ($o) = @_;
+ local $o->{pop_wait_messages} = 1;
+ my $_w = $o->wait_message(N("Please wait"),
+ #-PO: This is NOT the boot loader (just the kernel initrds)!!!!
+ N("Preparing initial startup program...") . "\n" .
+ N("Be patient, this may take a while...")
+ );
+ $o->SUPER::setupBootloaderBefore;
+}
+
+#------------------------------------------------------------------------------
+sub setupBootloader {
+ my ($o) = @_;
+ {
+ any::setupBootloader_simple($o, $o->{bootloader}, $o->{all_hds}, $o->{fstab}, $o->{security}) or return;
+ }
+}
+
+sub check_security_level {
+ my ($o, $security) = @_;
+ if ($security > 3 && find { $_->{fs_type} eq 'vfat' } @{$o->{fstab}}) {
+ $o->ask_okcancel('', N("In this security level, access to the files in the Windows partition is restricted to the administrator.")) or return 0;
+ }
+ return 1;
+}
+
+sub miscellaneous {
+ my ($o, $_clicked) = @_;
+
+ install::steps::miscellaneous($o);
+}
+
+#------------------------------------------------------------------------------
+sub configureX {
+ my ($o, $expert) = @_;
+
+ install::steps::configureXBefore($o);
+ symlink "$::prefix/etc/gtk", "/etc/gtk";
+
+ require Xconfig::main;
+ my ($raw_X) = Xconfig::main::configure_everything_or_configure_chooser($o, install::any::X_options_from_o($o), !$expert, $o->{keyboard}, $o->{mouse});
+ if ($raw_X) {
+ $o->{raw_X} = $raw_X;
+ install::steps::configureXAfter($o);
+ }
+}
+
+#------------------------------------------------------------------------------
+sub generateAutoInstFloppy {
+ my ($o, $replay) = @_;
+ my $img = install::any::getAndSaveAutoInstallFloppies($o, $replay) or return;
+
+ my $floppy = detect_devices::floppy();
+ $o->ask_okcancel('', N("Insert a blank floppy in drive %s", $floppy), 1) or return;
+
+ my $_w = $o->wait_message('', N("Creating auto install floppy..."));
+ require install::commands;
+ install::commands::dd("if=$img", 'of=' . devices::make($floppy));
+ common::sync();
+}
+
+#------------------------------------------------------------------------------
+sub exitInstall {
+ my ($o, $alldone) = @_;
+
+ return $o->{step} = '' if !$alldone && !$o->ask_yesorno(N("Warning"),
+N("Some steps are not completed.
+
+Do you really want to quit now?"), 0);
+
+ install::steps::exitInstall($o);
+
+ $o->exit unless $alldone;
+
+ $o->ask_from_no_check(
+ {
+ title => N("Congratulations"),
+ messages => formatAlaTeX(messages::install_completed()),
+ interactive_help_id => 'exitInstall',
+ ok => $::local_install ? N("Quit") : N("Reboot"),
+ }, []) if $alldone;
+}
+
+
+#-######################################################################################
+#- Misc Steps Functions
+#-######################################################################################
+
+1;