From e91be5bd125b18197f89ee17dc18c31938a1171f Mon Sep 17 00:00:00 2001 From: Philip Date: Sat, 5 Nov 2016 09:55:37 +0100 Subject: [PATCH] v2.4.4 - [partition] remove sgdisk dependency - [displaymanager] use configparser and add better autologin handling - [displaymanager] set a preferred Xsession for autologin - [netinstall] Support selecting visible groups by default - [packages] Add option of updating packages db before perfoming package operations - [packages] Allow try_install and try_remove entries in packages module - [unpackfs] Do not fail if rsync returns exit code 23 --- README.md | 2 - src/modules/bootloader/main.py | 29 +------------ src/modules/displaymanager/main.py | 42 +++++++++---------- src/modules/netinstall/NetInstallPage.cpp | 2 +- .../widgets/groupselectionwidget.cpp | 3 +- .../netinstall/widgets/groupselectionwidget.h | 2 +- src/modules/packages/main.py | 31 ++++++++++++++ src/modules/packages/packages.conf | 9 ++-- .../partition/core/PartitionActions.cpp | 3 +- .../partition/core/PartitionCoreModule.cpp | 21 ++-------- src/modules/unpackfs/main.py | 13 +++++- 11 files changed, 79 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 584bebc6c..2f125b1cb 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,8 @@ Modules: * extra-cmake-modules * KF5: KCoreAddons, KConfig, KI18n, KIconThemes, KIO, KService * KPMcore >= 2.2 - * sgdisk * bootloader: * systemd-boot or GRUB - * sgdisk * unpackfs: * squashfs-tools * rsync diff --git a/src/modules/bootloader/main.py b/src/modules/bootloader/main.py index d292de6fd..e367eebbb 100644 --- a/src/modules/bootloader/main.py +++ b/src/modules/bootloader/main.py @@ -258,7 +258,7 @@ def vfat_correct_case(parent, name): def prepare_bootloader(fw_type): - """ Prepares bootloader and set proper flags to EFI boot partition (esp,boot). + """ Prepares bootloader. Based on value 'efi_boot_loader', it either calls systemd-boot or grub to be installed. :param fw_type: @@ -267,33 +267,6 @@ def prepare_bootloader(fw_type): efi_boot_loader = libcalamares.job.configuration["efiBootLoader"] efi_directory = libcalamares.globalstorage.value("efiSystemPartition") - if fw_type == "efi": - partitions = libcalamares.globalstorage.value("partitions") - boot_p = "" - device = "" - - for partition in partitions: - if partition["mountPoint"] == efi_directory: - boot_device = partition["device"] - boot_p = boot_device[-1:] - device = boot_device[:-1] - - if not boot_p or not device: - return ("EFI directory \"{!s}\" not found!".format(efi_directory), - "Boot partition: \"{!s}\"".format(boot_p), - "Boot device: \"{!s}\"".format(device)) - else: - print("EFI directory: \"{!s}\"".format(efi_directory)) - print("Boot partition: \"{!s}\"".format(boot_p)) - print("Boot device: \"{!s}\"".format(device)) - - if not device: - print("WARNING: no EFI system partition or EFI system partition mount point not set.") - print(" >>> no EFI bootloader will be installed <<<") - return None - print("Set 'EF00' flag") - subprocess.call(["sgdisk", "--typecode={!s}:EF00".format(boot_p), "{!s}".format(device)]) - if efi_boot_loader == "systemd-boot" and fw_type == "efi": install_systemd_boot(efi_directory) else: diff --git a/src/modules/displaymanager/main.py b/src/modules/displaymanager/main.py index 7fa4be0fd..433e114ea 100644 --- a/src/modules/displaymanager/main.py +++ b/src/modules/displaymanager/main.py @@ -24,6 +24,7 @@ import os import collections import re import libcalamares +import configparser DesktopEnvironment = collections.namedtuple('DesktopEnvironment', ['executable', 'desktop_file']) @@ -253,34 +254,31 @@ def set_autologin(username, displaymanagers, default_desktop_environment, root_m # Systems with Sddm as Desktop Manager sddm_conf_path = os.path.join(root_mount_point, "etc/sddm.conf") + sddm_config = configparser.ConfigParser() + # Make everything case sensitive + sddm_config.optionxform = str + if os.path.isfile(sddm_conf_path): - libcalamares.utils.debug('SDDM config file exists') - else: - libcalamares.utils.check_target_env_call(["sh", "-c", "sddm --example-config > /etc/sddm.conf"]) + sddm_config.read(sddm_conf_path) - text = [] + autologin_section = {} + if 'Autologin' in sddm_config: + autologin_section = sddm_config['Autologin'] - with open(sddm_conf_path, 'r') as sddm_conf: - text = sddm_conf.readlines() + if do_autologin: + autologin_section['User'] = username - with open(sddm_conf_path, 'w') as sddm_conf: - for line in text: - # User= line, possibly commented out - if re.match('\\s*(?:#\\s*)?User=', line): - if do_autologin: - line = 'User={!s}\n'.format(username) - else: - line = '#User=\n' + if default_desktop_environment is not None: + autologin_section['Session'] = default_desktop_environment.desktop_file - # Session= line, commented out or with empty value - if re.match('\\s*#\\s*Session=|\\s*Session=$', line): - if default_desktop_environment is not None: - if do_autologin: - line = 'Session={!s}.desktop\n'.format(default_desktop_environment.desktop_file) - else: - line = '#Session={!s}.desktop\n'.format(default_desktop_environment.desktop_file) + if autologin_section: + if 'Autologin' in sddm_config: + sddm_config['Autologin'].update(autologin_section) + else: + sddm_config['Autologin'] = autologin_section - sddm_conf.write(line) + with open(sddm_conf_path, 'w') as sddm_config_file: + sddm_config.write(sddm_config_file, space_around_delimiters=False) return None diff --git a/src/modules/netinstall/NetInstallPage.cpp b/src/modules/netinstall/NetInstallPage.cpp index 0e3a18c95..89f8e58dd 100644 --- a/src/modules/netinstall/NetInstallPage.cpp +++ b/src/modules/netinstall/NetInstallPage.cpp @@ -111,7 +111,7 @@ NetInstallPage::dataIsHere( QNetworkReply* reply ) continue; } - GroupSelectionWidget* groupWidget = new GroupSelectionWidget( group.name, group.description, group.packages, this ); + GroupSelectionWidget* groupWidget = new GroupSelectionWidget( group.name, group.description, group.packages, group.selected, this ); m_groupWidgets.insert( groupKey, groupWidget ); ui->groupswidget->layout()->addWidget( groupWidget ); diff --git a/src/modules/netinstall/widgets/groupselectionwidget.cpp b/src/modules/netinstall/widgets/groupselectionwidget.cpp index b477c0453..3048fb01f 100644 --- a/src/modules/netinstall/widgets/groupselectionwidget.cpp +++ b/src/modules/netinstall/widgets/groupselectionwidget.cpp @@ -20,7 +20,7 @@ #include -GroupSelectionWidget::GroupSelectionWidget( QString name, QString description, QStringList packages, QWidget* parent ) : +GroupSelectionWidget::GroupSelectionWidget( QString name, QString description, QStringList packages, bool selected, QWidget* parent ) : QWidget( parent ), m_isToggled( false ) { @@ -29,6 +29,7 @@ GroupSelectionWidget::GroupSelectionWidget( QString name, QString description, Q connect( ui.group, &QCheckBox::toggled, this, &GroupSelectionWidget::toggleGroup ); ui.group->setText( name ); + ui.group->setChecked( selected ); // also triggers the toggleGroup slot ui.description->setText( description ); const int columns = 4; const int rows = ( packages.size() - 1 ) / columns + 1; diff --git a/src/modules/netinstall/widgets/groupselectionwidget.h b/src/modules/netinstall/widgets/groupselectionwidget.h index a003f4833..1f7a0fc97 100644 --- a/src/modules/netinstall/widgets/groupselectionwidget.h +++ b/src/modules/netinstall/widgets/groupselectionwidget.h @@ -29,7 +29,7 @@ class GroupSelectionWidget : public QWidget { Q_OBJECT public: - explicit GroupSelectionWidget( QString name, QString description, QStringList packages, QWidget* parent = nullptr ); + explicit GroupSelectionWidget( QString name, QString description, QStringList packages, bool selected, QWidget* parent = nullptr ); // Current status of the group: is it selected in the view? bool isToggled() const; diff --git a/src/modules/packages/main.py b/src/modules/packages/main.py index 943b032cc..f0f7b38a3 100644 --- a/src/modules/packages/main.py +++ b/src/modules/packages/main.py @@ -18,6 +18,7 @@ # You should have received a copy of the GNU General Public License # along with Calamares. If not, see . +import subprocess import libcalamares from libcalamares.utils import check_target_env_call, target_env_call @@ -91,6 +92,22 @@ class PackageManager: elif self.backend == "entropy": check_target_env_call(["equo", "rm"] + pkgs) + def update_db(self): + if self.backend == "packagekit": + check_target_env_call(["pkcon", "refresh"]) + elif self.backend == "zypp": + check_target_env_call(["zypper", "update"]) + elif self.backend == "urpmi": + check_target_env_call(["urpmi.update", "-a"]) + elif self.backend == "apt": + check_target_env_call(["apt-get", "update"]) + elif self.backend == "pacman": + check_target_env_call(["pacman", "-Sy"]) + elif self.backend == "portage": + check_target_env_call(["emerge", "--sync"]) + elif self.backend == "entropy": + check_target_env_call(["equo", "update"]) + def run_operations(pkgman, entry): """ Call package manager with given parameters. @@ -101,8 +118,18 @@ def run_operations(pkgman, entry): for key in entry.keys(): if key == "install": pkgman.install(entry[key]) + elif key == "try_install": + try: + pkgman.install(entry[key]) + except subprocess.CalledProcessError: + libcalamares.utils.debug("WARNING: could not install packages {}".format(", ".join(entry[key]))) elif key == "remove": pkgman.remove(entry[key]) + elif key == "try_remove": + try: + pkgman.remove(entry[key]) + except subprocess.CalledProcessError: + libcalamares.utils.debug("WARNING: could not remove packages {}".format(", ".join(entry[key]))) elif key == "localInstall": pkgman.install(entry[key], from_local=True) @@ -121,6 +148,10 @@ def run(): pkgman = PackageManager(backend) operations = libcalamares.job.configuration.get("operations", []) + update_db = libcalamares.job.configuration.get("update_db", False) + if update_db and libcalamares.globalstorage.value("hasInternet"): + pkgman.update_db() + for entry in operations: run_operations(pkgman, entry) diff --git a/src/modules/packages/packages.conf b/src/modules/packages/packages.conf index e72763731..4039278b3 100644 --- a/src/modules/packages/packages.conf +++ b/src/modules/packages/packages.conf @@ -12,6 +12,9 @@ # - entropy - Sabayon package manager # backend: packagekit + +update_db: true + # # List of maps with package operations such as install or remove. # Distro developers can provide a list of packages to remove @@ -33,12 +36,12 @@ backend: packagekit # - remove: # - pkg3 # - pkg4 -# - install: +# - try_install: # no system install failure if a package cannot be installed # - pkg5 -# - remove: +# - try_remove: # no system install failure if a package cannot be removed # - pkg2 # - pkg1 -# install: +# - install: # - pkgs6 # - pkg7 # - localInstall: diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index e2c6ca638..aa9c0af36 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -140,7 +140,8 @@ doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPass PartitionRole( PartitionRole::Primary ), FileSystem::Fat32, firstFreeSector, - lastSector + lastSector, + PartitionTable::FlagEsp ); PartitionInfo::setFormat( efiPartition, true ); PartitionInfo::setMountPoint( efiPartition, Calamares::JobQueue::instance() diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index cf2b2c2a5..4e8da4f56 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -547,29 +547,14 @@ PartitionCoreModule::scanForEfiSystemPartitions() devices.append( device ); } - //FIXME: Unfortunately right now we have to call sgdisk manually because - // the KPM submodule does not expose the ESP flag from libparted. - // The following findPartitions call and lambda should be scrapped and - // rewritten based on libKPM. -- Teo 5/2015 QList< Partition* > efiSystemPartitions = KPMHelpers::findPartitions( devices, []( Partition* partition ) -> bool { - QProcess process; - process.setProgram( "sgdisk" ); - process.setArguments( { "-i", - QString::number( partition->number() ), - partition->devicePath() } ); - process.setProcessChannelMode( QProcess::MergedChannels ); - process.start(); - if ( process.waitForFinished() ) + if ( partition->activeFlags().testFlag( PartitionTable::FlagEsp ) ) { - if ( process.readAllStandardOutput() - .contains( "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" ) ) - { - cDebug() << "Found EFI system partition at" << partition->partitionPath(); - return true; - } + cDebug() << "Found EFI system partition at" << partition->partitionPath(); + return true; } return false; } ); diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py index 926bc0f01..34d9829d9 100644 --- a/src/modules/unpackfs/main.py +++ b/src/modules/unpackfs/main.py @@ -119,7 +119,18 @@ def file_copy(source, dest, progress_cb): process.wait() - if process.returncode != 0: + # 23 is the return code rsync returns if it cannot write extended attributes + # (with -X) because the target file system does not support it, e.g., the + # FAT EFI system partition. We need -X because distributions using file + # system capabilities and/or SELinux require the extended attributes. But + # distributions using SELinux may also have SELinux labels set on files + # under /boot/efi, and rsync complains about those. The only clean way would + # be to split the rsync into one with -X and --exclude /boot/efi and a + # separate one without -X for /boot/efi, but only if /boot/efi is actually + # an EFI system partition. For now, this hack will have to do. See also: + # https://bugzilla.redhat.com/show_bug.cgi?id=868755#c50 + # for the same issue in Anaconda, which uses a similar workaround. + if process.returncode != 0 and process.returncode != 23: return "rsync failed with error code {}.".format(process.returncode) return None