diff options
Diffstat (limited to 'lib/MGA/DrakISO/BuildRoot.pm')
-rwxr-xr-x | lib/MGA/DrakISO/BuildRoot.pm | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/MGA/DrakISO/BuildRoot.pm b/lib/MGA/DrakISO/BuildRoot.pm new file mode 100755 index 0000000..7112cd9 --- /dev/null +++ b/lib/MGA/DrakISO/BuildRoot.pm @@ -0,0 +1,259 @@ +# Copyright (C) 2005 Mandriva +# Olivier Blin <oblin@mandriva.com> +# Copyright (C) 2017 Mageia +# Martin Whitaker <mageia@martin-whitaker.me.uk> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +package MGA::DrakISO::BuildRoot; + +use strict; + +use MDK::Common; +use common; + +use MGA::DrakISO::Live; +use MGA::DrakISO::Loopback; +use MGA::DrakISO::Utils; + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(install_live_system customise_live_system); + +sub install_live_system { + my ($live) = @_; + + my $repository = $live->{settings}{repository} . '/' . $live->{settings}{arch}; + + my $drakx_in_chroot = $repository . '/misc/drakx-in-chroot'; + my $remote_repository = $repository =~ m!^(ftp|http)://! && $1; + if ($remote_repository) { + my $local_drakx_in_chroot = $live->get_builddir . $live->{prefix}{build}{scripts} . '/drakx-in-chroot'; + mkdir_p(dirname($local_drakx_in_chroot)); + run_('curl', '--silent', '-o', $local_drakx_in_chroot, $drakx_in_chroot) + or die "unable to get drakx-in-chroot from remote repository\n"; + $drakx_in_chroot = $local_drakx_in_chroot; + } + + local %ENV = ( + %ENV, + (map { "DRAKLIVE_" . uc($_->[0]) => $_->[1] } group_by2(%{$live->{settings}})), + %{$live->{system}{install_env}}, + ); + $ENV{DRAKLIVE_LANGS} = join(':', $live->get_langs); + run_({ targetarch => $live->{settings}{arch} }, + 'perl', $drakx_in_chroot, + $repository, + $live->get_system_root, + if_($live->{system}{auto_install}, '--auto_install', $live->{settings}{config_root} . '/' . $live->{system}{auto_install}), + if_($live->{system}{patch_install}, '--defcfg', $live->{settings}{config_root} . '/' . $live->{system}{patch_install}), + if_($live->{system}{rpmsrate}, '--rpmsrate', $live->{settings}{config_root} . '/' . $live->{system}{rpmsrate}), + ($live->{system}{stage2_updates} ? (map { ('--stage2-update', $live->{settings}{config_root} . '/' . $_->[0], $_->[1]) } @{$live->{system}{stage2_updates}}) : ()), + ) or die "unable to install system chroot\n"; +} + +sub customise_live_system { + my ($live) = @_; + + my $previous_umask = umask; + #- workaround buggy installation of directories that are not owned by any packages + umask 022; + + mount_system_fs($live); + + #- copy resolv.conf for name resolution to work when adding media + cp_f("/etc/resolv.conf", $live->get_system_root . "/etc/"); + + #- remove previous draklive leftovers if needed + run_({ root => $live->get_system_root }, 'urpmi.removemedia', '-a'); + + foreach (@{$live->{system}{additional_media}}) { + run_({ root => $live->get_system_root }, 'urpmi.addmedia', if_($_->{distrib}, '--distrib'), $_->{name}, $_->{path}) + or die "unable to add media from $_->{path}\n"; + @{$_->{packages} || []} or next; + run_({ root => $live->get_system_root, targetarch => $live->{settings}{arch} }, + 'urpmi', '--auto', '--no-verify-rpm', if_(!$_->{distrib}, '--searchmedia', $_->{name}), @{$_->{packages}}) + or die "unable to install packages from $_->{path}\n"; + } + + #- additional rpms may have dependencies in additional media + if (@{$live->{system}{rpms} || []}) { + my $rpm_tmp_dir = '/tmp/draklive_rpms'; + mkdir_p($live->get_system_root . $rpm_tmp_dir); + cp_f((map { $live->{settings}{config_root} . '/' . $_ } @{$live->{system}{rpms}}), $live->get_system_root . $rpm_tmp_dir); + run_({ root => $live->get_system_root, targetarch => $live->{settings}{arch} }, + 'urpmi', '--auto', '--no-verify-rpm', + map { $rpm_tmp_dir . '/' . basename($_) } @{$live->{system}{rpms}}) + or die "unable to install additional system rpms\n"; + rm_rf($live->get_system_root . $rpm_tmp_dir); + } + + #- remove urpmi media added by drakx-in-chroot and additional media, they're unusable + run_({ root => $live->get_system_root }, 'urpmi.removemedia', '-a'); + + my $erase = join(' ', @{$live->{system}{erase_rpms} || []}); + run_({ root => $live->get_system_root, targetarch => $live->{settings}{arch} }, + 'sh', '-c', "rpm -qa $erase | xargs rpm -e ") if $erase; + + run_({ root => $live->get_system_root }, 'systemctl', 'disable', $_ . '.service') foreach @{$live->{system}{disable_services}}; + run_({ root => $live->get_system_root }, 'systemctl', 'disable', $_ . '.timer') foreach @{$live->{system}{disable_timers}}; + + #- make sure harddrake is run: + #- if previous HW config file is empty, we assumes DrakX has just completed the installation + #- (do it in chroot, or else Storable from the build box may write an incompatible config file) + run_({ root => $live->get_system_root }, + 'perl', '-MStorable', '-e', qq(Storable::store({ UNKNOWN => {} }, '/etc/sysconfig/harddrake2/previous_hw'))); + + #- remove some build-machine specific configuration + clean_system_conf_file($live, $_) + foreach qw(/etc/mtab /etc/iftab /etc/shorewall/interfaces /etc/mdadm.conf), + if_(!$live->{system}{skip_fstab}, '/etc/fstab'); + unlink($_) foreach map { glob($live->get_system_root . $_) } @{$live->{system}{remove_files} || []}; + + if ($live->{system}{modules_conf}) { + local $::prefix = $live->get_system_root; + local *modules::write_preload_conf = sub {}; #- FIXME, make this an option + my $modules_conf = modules::any_conf->vnew; + put_in_hash($modules_conf, $live->{system}{modules_conf}); + $modules_conf->write; + } + + my $mount_options = $live->{media}->get_media_setting('mount_options') || "defaults"; + output_with_perm($live->get_system_root . '/etc/fstab', 0644, + $live->{mount}{overlay} + ? "none / $live->{mount}{overlay} $mount_options 0 0\n" + : $live->{media}->get_media_setting('source') . " / " . $live->{media}->get_media_setting('fs') . " $mount_options 1 1\n" + ) unless $live->{system}{skip_fstab}; + + #- interactive mode can lead to race in initscripts + #- (don't use addVarsInSh from MDK::Common, it breaks shell escapes) + substInFile { s/^PROMPT=.*/PROMPT=no/ } $live->get_system_root . '/etc/sysconfig/init'; + + configure_draklive_resize($live); + + if ($live->{system}{preselect_kdm_user}) { + #- preselect specified user in kdm + my $kdm_cfg = $live->get_system_root . '/etc/kde/kdm/kdmrc'; + update_gnomekderc($kdm_cfg, 'X-:0-Greeter' => (PreselectUser => 'Default', DefaultUser => $live->{system}{preselect_kdm_user})) if -f $kdm_cfg; + } + + #- apply patches and install files after the configuration is cleaned + #- to allow special configuration files (especially modprobe.preload) + foreach (@{$live->{system}{patches}}) { + my $patch = $live->{settings}{config_root} . '/' . $_; + my @args = ('-p0', '-d', $live->get_system_root, '-i', $patch); + run_program::run('patch', '>', '/dev/null', '--dry-run', '-f', '-R', @args) || run_('patch', @args) + or die "unable to apply patch " . $patch . "\n"; + } + + copy_files_to($live, $live->{system}{files}, $live->get_system_root); + my @no_install_files = map { $_->[1] } grep { $_->[2] && $_->[2]{no_install} } @{$live->{system}{files}}; + output_p($live->get_system_root . '/etc/draklive-install.d/remove.d/draklive', map { "$_\n" } @no_install_files); + + eval { rm_rf($live->get_builddir . $live->{prefix}{build}{files}) }; + mkdir_p($live->get_builddir . $live->{prefix}{build}{files}); + if ($live->{media}{files}) { + copy_files_to($live, $live->{media}{files}, $live->get_builddir . $live->{prefix}{build}{files}); + } + remove_files_from($live->{media}{remove_files}, $live->get_builddir . $live->{prefix}{build}{files}); + + run_({ targetarch => $live->{settings}{arch} }, + "chroot", $live->get_system_root, "bash", "-c", $live->{system}{postInstall}) if $live->{system}{postInstall}; + + clean_system_conf_file($live, "/etc/resolv.conf"); + write_dist_lists($live); + + umount_external_fs($live); + + umask $previous_umask; +} + +sub configure_draklive_resize { + my ($live) = @_; + + my $resizable_loopback = find { $_->{min_size} } @{$live->{mount}{dirs} || []}; + if ($resizable_loopback) { + my $media_loopbacks = $live->get_media_prefix('loopbacks'); + my $ext = $loop_types{$resizable_loopback->{type}}{extension}; + output($live->get_system_root . '/etc/sysconfig/draklive-resize', <<EOF); +DRAKLIVE_RESIZE=yes +LOOPBACK=$live->{prefix}{live}{mnt}$live->{prefix}{media}{mnt}${media_loopbacks}$resizable_loopback->{path}$ext +TYPE=$resizable_loopback->{fs} +MIN_SIZE=$resizable_loopback->{min_size} +MOUNT=$live->{prefix}{live}{mnt}$resizable_loopback->{mountpoint}_resized +OLD_MOUNT=$live->{prefix}{live}{mnt}$resizable_loopback->{mountpoint} +UNION=/ +EOF + } +} + +sub copy_files_to { + my ($live, $files, $root) = @_; + foreach (@$files) { + my ($source, $dest, $o_opts) = @$_; + $dest = $root . '/' . $dest; + mkdir_p($dest =~ m|/$| ? $dest : dirname($dest)); + my @sources = MGA::DrakISO::Utils::glob__($live->{settings}{config_root} . '/' . $source); + print STDERR "copying @sources to $dest\n"; + cp_af(@sources, $dest); + my $o_perm = $o_opts && $o_opts->{mode}; + chmod $o_perm, $dest if $o_perm; + } +} + +sub remove_files_from { + my ($files, $root) = @_; + run_('find', $root, '(', join_lists('-o', map { [ '-name', $_ ] } @$files), ')', '-exec', 'rm', '-r', '{}', ';') + if $files && @$files; +} + +sub join_lists { + my ($separator, $head, @lists) = @_; + @{$head || []}, map { $separator, @$_ } @lists; +} + +sub clean_system_conf_file { + my ($live, $file) = @_; + substInFile { undef $_ if /^[^#]/ } $live->get_system_root . $file; +} + +sub write_dist_lists { + my ($live) = @_; + + my $lists_dir = $live->get_builddir . $live->{prefix}{build}{dist}; + mkdir_p($lists_dir); + + run_("chroot " . $live->get_system_root . " rpm -qa | sort > " . + $lists_dir . '/' . $live->get_name . '.lst'); + + run_("chroot " . $live->get_system_root . " rpm -qa --qf '%{name}\n' | sort > " . + $lists_dir . '/' . $live->get_name . '.lst.names'); + + run_("chroot " . $live->get_system_root . + qq( sh -c "rpm -qa --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) . + $lists_dir . '/' . $live->get_name . '.lst.full'); + + run_("chroot " . $live->get_system_root . + qq( sh -c "urpmi_rpm-find-leaves | xargs rpm -q --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) . + $lists_dir . '/' . $live->get_name . '.lst.leaves'); + + require lang; + my @live_langs = $live->get_langs; + my @langs = grep { member($_, @live_langs) || member(lang::locale_to_main_locale($_), @live_langs) } lang::list_langs(); + my $langs_file = $lists_dir . '/' . $live->get_name . '.langs'; + output_p($langs_file, map { lang::l2name($_) . " (" . $_ . ")\n" } sort(@langs)); +} + +1; |