diff --git a/common/modules/before_bootloader_mkdirs_context.conf b/common/modules/before_bootloader_mkdirs_context.conf new file mode 100644 index 0000000..6aeb829 --- /dev/null +++ b/common/modules/before_bootloader_mkdirs_context.conf @@ -0,0 +1,10 @@ +--- +dontChroot: true +timeout: 10 +firmwareType: + efi: + - -cp /cdrom/casper/vmlinuz ${ROOT}/boot/vmlinuz-$(uname -r) + - -mkdir -pv ${ROOT}/media/cdrom + - -mount --bind /cdrom ${ROOT}/media/cdrom + bios: + - -cp /cdrom/casper/vmlinuz ${ROOT}/boot/vmlinuz-$(uname -r) diff --git a/common/modules/copy_vmlinuz_shellprocess.conf b/common/modules/copy_vmlinuz_shellprocess.conf deleted file mode 100644 index 6c2d2c5..0000000 --- a/common/modules/copy_vmlinuz_shellprocess.conf +++ /dev/null @@ -1,5 +0,0 @@ ---- -dontChroot: true -timeout: 60 -script: - - command: "cp /cdrom/casper/vmlinuz ${ROOT}/boot/vmlinuz-$(uname -r)" diff --git a/common/modules/pkgselect/PackageSelectViewStep.cpp b/common/modules/pkgselect/PackageSelectViewStep.cpp index d48edfd..c9a3b53 100644 --- a/common/modules/pkgselect/PackageSelectViewStep.cpp +++ b/common/modules/pkgselect/PackageSelectViewStep.cpp @@ -1,59 +1,39 @@ #include "PackageSelectViewStep.h" -#include "ui_pkgselect.h" #include "JobQueue.h" #include "GlobalStorage.h" +#include "Branding.h" #include "network/Manager.h" -#include -#include -#include -#include -#include -#include -#include +#include -/** - * @brief Initializes a new PackageSelectViewStep object. - * @param parent The parent QObject. - */ -PackageSelectViewStep::PackageSelectViewStep(QObject* parent) - : Calamares::ViewStep(parent), - m_packageSelections(), - ui(new Ui::pkgselect), - m_widget(new QWidget()), // Parent set to nullptr - m_connectionsMade(false) +PackageSelectViewStep::PackageSelectViewStep( QObject* parent ) + : Calamares::ViewStep( parent ), + m_packageSelections(QVariantMap()), + ui(new Ui::pkgselect) { + m_widget = new QWidget(); ui->setupUi(m_widget); - - // Layout Adjustment to Prevent Shifting - // Ensures that hiding/showing elements does not disrupt the layout - QGridLayout* mainLayout = qobject_cast(ui->gridLayout); - if (mainLayout) { - mainLayout->setRowStretch(mainLayout->rowCount(), 1); - } } -/** - * @brief Cleans up the PackageSelectViewStep object. - */ PackageSelectViewStep::~PackageSelectViewStep() { delete ui; delete m_widget; } -QString PackageSelectViewStep::prettyName() const +QString +PackageSelectViewStep::prettyName() const { - return tr("Customize"); + return tr( "Customize" ); } bool PackageSelectViewStep::exists_and_true(const QString& key) const { - return m_packageSelections.contains(key) && m_packageSelections.value(key).toBool(); + return m_packageSelections.contains(key) && m_packageSelections[key].toBool() == true; } QWidget* PackageSelectViewStep::widget() -{ +{ return m_widget; } @@ -82,26 +62,71 @@ bool PackageSelectViewStep::isAtEnd() const return true; } -void PackageSelectViewStep::setConfigurationMap(const QVariantMap& configurationMap) -{ - m_configurationMap = configurationMap; -} - -/** - * @brief Activates the step, setting up the UI based on network availability and configuration. - * - * This method is called when the step becomes active. It handles network checks, - * dynamically creates package selection checkboxes, and connects signal handlers. - */ void PackageSelectViewStep::onActivate() { - // Check network availability - Calamares::Network::Manager network; - bool hasInternet = network.hasInternet(); + // Connect the Minimal Installation radio button + connect(ui->minimal_button, &QRadioButton::toggled, this, [this](bool checked) { + Calamares::Network::Manager network; + if (checked && network.hasInternet()) { + ui->extraparty_scroll->setVisible(false); + ui->extraparty_text->setVisible(false); + ui->mandatory_warning_label->setVisible(false); - // Handle network unavailability - //if (!hasInternet) { - // Disable almost all fancy features to avoid bugs, revert in 25.10 cycle + ui->element_button->setChecked(false); + ui->thunderbird_button->setChecked(false); + ui->virtmanager_button->setChecked(false); + ui->krita_button->setChecked(false); + + ui->element_button->setEnabled(false); + ui->thunderbird_button->setEnabled(false); + ui->virtmanager_button->setEnabled(false); + ui->krita_button->setEnabled(false); + } + }); + + // Connect the Normal Installation radio button + connect(ui->normal_button, &QRadioButton::toggled, this, [this](bool checked) { + Calamares::Network::Manager network; + if (checked && network.hasInternet()) { + ui->extraparty_scroll->setVisible(true); + ui->extraparty_text->setVisible(true); + ui->mandatory_warning_label->setVisible(true); + + ui->element_button->setChecked(false); + ui->thunderbird_button->setChecked(false); + ui->virtmanager_button->setChecked(false); + ui->krita_button->setChecked(false); + + ui->element_button->setEnabled(true); + ui->thunderbird_button->setEnabled(true); + ui->virtmanager_button->setEnabled(true); + ui->krita_button->setEnabled(true); + } + }); + + // Connect the Full Installation radio button + connect(ui->full_button, &QRadioButton::toggled, this, [this](bool checked) { + Calamares::Network::Manager network; + if (checked && network.hasInternet()) { + ui->extraparty_scroll->setVisible(true); + ui->extraparty_text->setVisible(true); + ui->mandatory_warning_label->setVisible(true); + + ui->element_button->setChecked(true); + ui->thunderbird_button->setChecked(true); + ui->virtmanager_button->setChecked(true); + ui->krita_button->setChecked(true); + + ui->element_button->setEnabled(false); + ui->thunderbird_button->setEnabled(false); + ui->virtmanager_button->setEnabled(false); + ui->krita_button->setEnabled(false); + } + }); + + // Disable many bits of functionality if network is not enabled + Calamares::Network::Manager network; + if (!network.hasInternet()) { ui->full_button->setVisible(false); ui->full_text->setVisible(false); @@ -115,277 +140,69 @@ void PackageSelectViewStep::onActivate() ui->extraparty_scroll->setVisible(false); ui->extraparty_text->setVisible(false); ui->mandatory_warning_label->setVisible(false); - //} - // Dynamically create package checkboxes only once - if (m_packageCheckBoxes.isEmpty()) { - QVariantList additionalPackages = m_configurationMap.value("packages").toMap().value("additional_packages").toList(); - QVBoxLayout* packagesLayout = ui->extraparty_scrollhouse->findChild("packages_layout"); - if (!packagesLayout) { - qWarning() << "packages_layout not found in UI."; - return; - } + ui->element_button->setChecked(false); + ui->thunderbird_button->setChecked(false); + ui->virtmanager_button->setChecked(false); + ui->krita_button->setChecked(false); - for (const QVariant& var : additionalPackages) { - QVariantMap pkg = var.toMap(); - QString packageId = pkg.value("id").toString(); - QString packageName = pkg.value("name").toString(); - QString packageDescription = pkg.value("description").toString(); - bool isSnap = pkg.value("snap").toBool(); - - // Create checkbox - QCheckBox* checkbox = new QCheckBox(packageName, m_widget); - checkbox->setObjectName(packageId); // Naming as packageId directly - - // Create description label - QLabel* descriptionLabel = new QLabel(packageDescription, m_widget); - QFont descFont = descriptionLabel->font(); - descFont.setPointSize(10); - descFont.setItalic(true); - descriptionLabel->setFont(descFont); - descriptionLabel->setWordWrap(true); - - // Add to layout - packagesLayout->addWidget(checkbox); - packagesLayout->addWidget(descriptionLabel); - - // Store in the map - m_packageCheckBoxes.insert(packageId, checkbox); - - // Connect checkbox toggled signal - connect(checkbox, &QCheckBox::toggled, this, &PackageSelectViewStep::updatePackageSelections); - } + ui->element_button->setEnabled(false); + ui->thunderbird_button->setEnabled(false); + ui->virtmanager_button->setEnabled(false); + ui->krita_button->setEnabled(false); } - // Handle installation modes - // Connect radio buttons to lambda functions only once - if (!m_connectionsMade) { - connect(ui->minimal_button, &QRadioButton::toggled, this, [this, hasInternet](bool checked) { - if (checked && hasInternet) { - // Hide additional packages UI - ui->extraparty_scroll->setVisible(false); - ui->extraparty_text->setVisible(false); - ui->mandatory_warning_label->setVisible(false); - - // Uncheck and disable all additional package checkboxes - QVariantList removePackages = m_configurationMap.value("packages").toMap().value("minimal_remove_packages").toList(); - for (const QVariant& var : removePackages) { - QString packageId = var.toString(); - QCheckBox* checkbox = m_packageCheckBoxes.value(packageId, nullptr); - if (checkbox) { - checkbox->setChecked(false); - checkbox->setEnabled(false); - } - } - } - }); - - connect(ui->normal_button, &QRadioButton::toggled, this, [this, hasInternet](bool checked) { - if (checked && hasInternet) { - // Show additional packages UI - ui->extraparty_scroll->setVisible(true); - ui->extraparty_text->setVisible(true); - ui->mandatory_warning_label->setVisible(true); - - // Enable all additional package checkboxes - for (auto checkbox : m_packageCheckBoxes) { - if (checkbox) { - checkbox->setEnabled(true); - } - } - } - }); - - connect(ui->full_button, &QRadioButton::toggled, this, [this, hasInternet](bool checked) { - if (checked && hasInternet) { - // Show additional packages UI - ui->extraparty_scroll->setVisible(true); - ui->extraparty_text->setVisible(true); - ui->mandatory_warning_label->setVisible(true); - - // Check and disable all additional package checkboxes - for (auto checkbox : m_packageCheckBoxes) { - if (checkbox) { - checkbox->setChecked(true); - checkbox->setEnabled(false); - } - } - } - }); - - m_connectionsMade = true; + // Thunderbird exists on Kubuntu already + if (Calamares::Branding::instance()->componentName() == "kubuntu") { + ui->thunderbird_button->setChecked(false); + ui->thunderbird_button->setEnabled(false); + ui->thunderbird_button->setVisible(false); + ui->thunderbird_text->setVisible(false); + ui->thunderbird_spacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); + ui->thunderbird_spacer->invalidate(); } - // Layout Adjustment to Prevent Shifting - // Ensure that hiding/showing elements does not center the remaining widgets - // This is generally handled by Qt's layout system, but adding stretch ensures stability - QGridLayout* mainLayout = qobject_cast(ui->gridLayout); - if (mainLayout) { - mainLayout->setRowStretch(mainLayout->rowCount(), 1); - } + // Connect the storage items + /// Full/Normal/Minimal + connect(ui->minimal_button, &QRadioButton::toggled, this, &PackageSelectViewStep::updatePackageSelections); + connect(ui->normal_button, &QRadioButton::toggled, this, &PackageSelectViewStep::updatePackageSelections); + connect(ui->full_button, &QRadioButton::toggled, this, &PackageSelectViewStep::updatePackageSelections); + /// Additional Options + connect(ui->updates_button, &QRadioButton::toggled, this, &PackageSelectViewStep::updatePackageSelections); + /// Third-Party Apps + connect(ui->element_button, &QCheckBox::toggled, this, &PackageSelectViewStep::updatePackageSelections); + connect(ui->thunderbird_button, &QCheckBox::toggled, this, &PackageSelectViewStep::updatePackageSelections); + connect(ui->virtmanager_button, &QCheckBox::toggled, this, &PackageSelectViewStep::updatePackageSelections); + connect(ui->krita_button, &QCheckBox::toggled, this, &PackageSelectViewStep::updatePackageSelections); } -/** - * @brief Handles actions to perform when leaving the step, such as storing selected packages. - * - * This method gathers the selected packages, determines the installation mode, - * and stores the relevant data into Calamares' GlobalStorage for use in subsequent steps. - */ -void PackageSelectViewStep::onLeave() +void +PackageSelectViewStep::onLeave() { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); - if (!gs) { - qWarning() << "GlobalStorage is not available."; - return; + QVariantMap config; + for (auto i = m_packageSelections.begin(); i != m_packageSelections.end(); ++i) { + if (exists_and_true(i.key())) { + config.insert(i.key(), i.value()); + } } - - bool isStackedSquashfs = m_configurationMap.value("stacked_squashfs").toBool(); - QVariantMap installationData = gs->value("installation_data").toMap(); - QString installationMode = installationData.value("installation_mode").toString(); - bool downloadUpdates = installationData.value("download_updates").toBool(); - QVariantList packagesToInstall = installationData.value("packages_to_install").toList(); - QVariantList packagesToRemove = installationData.value("packages_to_remove").toList(); - QVariantList presentSnaps = installationData.value("present_snaps").toList(); - - // Handle default value for rootMountPoint - QString rootMountPoint = "/"; - if (gs->contains("rootMountPoint")) { - rootMountPoint = gs->value("rootMountPoint").toString(); - } - - QVariantMap globalData; - - // Determine selected installation mode - if (ui->minimal_button->isChecked()) { - installationMode = "minimal"; - } else if (ui->normal_button->isChecked()) { - installationMode = "normal"; - } else if (ui->full_button->isChecked()) { - installationMode = "full"; - } - - globalData.insert("installation_mode", installationMode); - - // Used by unpackfs on stacked squashfs systems - if (installationMode == "minimal") { - } - - if (installationMode == "minimal") { - globalData.insert("unpack_regular", false); - if (!isStackedSquashfs) { - QVariantList minimalPackages = m_configurationMap.value("packages").toMap().value("minimal_remove_packages").toList(); - QVariantList installerPackages = m_configurationMap.value("packages").toMap().value("installer_remove_packages").toList(); - QVariantList combinedRemove = minimalPackages + installerPackages; - globalData.insert("packages_to_remove", combinedRemove); - } - } else { - globalData.insert("unpack_regular", true); - // For normal and full, store packages to install - QVariantList selectedPackagesList; - // Store the snaps that are already on the system by default - QStringList presentSnapList; - - // Process all checked boxes - for (auto it = m_packageCheckBoxes.constBegin(); it != m_packageCheckBoxes.constEnd(); ++it) { - const QString& packageId = it.key(); - QCheckBox* checkbox = it.value(); - if (checkbox && checkbox->isChecked()) { - // Retrieve package details from configuration - QVariantList additionalPackages = m_configurationMap.value("packages").toMap().value("additional_packages").toList(); - QVariantMap packageDetails; - for (const QVariant& var : additionalPackages) { - QVariantMap pkg = var.toMap(); - if (pkg.value("id").toString() == packageId) { - packageDetails.insert("id", pkg.value("id").toString()); - packageDetails.insert("snap", pkg.value("snap").toBool()); - break; - } - } - if (!packageDetails.isEmpty()) { - selectedPackagesList.append(packageDetails); - } - } - } - - // Add the additional packages to be installed and substitute locale - QVariantList installPackages = m_configurationMap.value("packages").toMap().value("regular_install_packages").toList(); - QString localeVal = gs->value("locale").toString(); - for (const QVariant& installPackage : installPackages) { - QString packageId = installPackage.toString().replace("$LOCALE", localeVal); - QVariantMap packageDetails; - packageDetails.insert("id", packageId); - packageDetails.insert("snap", false); - selectedPackagesList.append(packageDetails); - } - - // Ensure delta updates are processed first - QVariantList refreshSnaps = m_configurationMap.value("packages").toMap().value("refresh_snaps").toList(); - for (const QVariant& snapVar : refreshSnaps) { - QString snapId = snapVar.toString(); - presentSnapList.append(snapId); - } - - // As a temporary measure until OEM is refactored in the 25.10 cycle, - // we need to ensure that Calamares and its necessary dependencies are - // installed on the target, iff this is a stacked squashfs. - // FIXME: remove in favor of more nuanced stacked squashfs - // functionality in 25.10 - // Ref: https://discourse.ubuntu.com/t/implementation-of-ship-live-within-a-squashfs/57510 - // LP: #2104343 - if (isStackedSquashfs) { - QVector stage_two_packages = {"calamares", "kdialog"}; - for (QString& package_name : stage_two_packages) { - QVariantMap package_details; - package_details.insert("id", package_name); - package_details.insert("snap", false); - selectedPackagesList.append(package_details); - } - } - - globalData.insert("packages_to_install", selectedPackagesList); - if (!isStackedSquashfs) { - QVariantList installerPackages = m_configurationMap.value("packages").toMap().value("installer_remove_packages").toList(); - globalData.insert("packages_to_remove", installerPackages); - } - globalData.insert("present_snaps", presentSnapList); - } - - // Store the state of 'download_updates' checkbox - bool updatesChecked = ui->updates_button->isChecked(); - globalData.insert("download_updates", updatesChecked); - - gs->insert("installation_data", globalData); + gs->insert("packages", config); } -/** - * @brief Slot to handle checkbox toggle events. - * - * This method updates the internal package selection map based on user interactions - * with the package checkboxes. - * - * @param checked The new checked state of the checkbox. - */ -void PackageSelectViewStep::updatePackageSelections(bool checked) -{ - QCheckBox* checkbox = qobject_cast(sender()); - if (!checkbox) - return; +void PackageSelectViewStep::updatePackageSelections(bool checked) { + QObject* sender_obj = sender(); + if (!sender_obj) return; - QString packageId = checkbox->objectName(); - m_packageSelections[packageId] = checked; + QString key = sender_obj->objectName(); - emit packageSelectionsChanged(); + // snake_case -> camelCase + QStringList parts = key.split("_", Qt::SkipEmptyParts); + for (int i = 1; i < parts.size(); ++i) { + parts[i][0] = parts[i][0].toUpper(); + } + QString camelCaseKey = parts.join(""); + + m_packageSelections[camelCaseKey] = checked; } -/** - * @brief Retrieves the checkbox associated with a given package ID. - * - * @param id The package ID. - * @return A pointer to the QCheckBox, or nullptr if not found. - */ -QCheckBox* PackageSelectViewStep::getCheckboxById(const QString& id) const -{ - return m_packageCheckBoxes.value(id, nullptr); -} - -CALAMARES_PLUGIN_FACTORY_DEFINITION(PackageSelectViewStepFactory, registerPlugin(); ) +CALAMARES_PLUGIN_FACTORY_DEFINITION( PackageSelectViewStepFactory, registerPlugin< PackageSelectViewStep >(); ) diff --git a/common/modules/pkgselect/PackageSelectViewStep.h b/common/modules/pkgselect/PackageSelectViewStep.h index c345ae0..a68b4a1 100644 --- a/common/modules/pkgselect/PackageSelectViewStep.h +++ b/common/modules/pkgselect/PackageSelectViewStep.h @@ -1,143 +1,52 @@ #ifndef PACKAGESELECTVIEWSTEP_H #define PACKAGESELECTVIEWSTEP_H -#include -#include -#include +#include +#include + #include "DllMacro.h" #include "utils/PluginFactory.h" #include "viewpages/ViewStep.h" +#include "ui_pkgselect.h" + namespace Ui { class pkgselect; } -class QCheckBox; - -/** - * @class PackageSelectViewStep - * @brief A Calamares view step for selecting and customizing packages during installation. - * - * This class provides a user interface for selecting additional packages to install, - * managing installation modes, and handling network availability scenarios. - */ class PLUGINDLLEXPORT PackageSelectViewStep : public Calamares::ViewStep { Q_OBJECT public: - /** - * @brief Constructs a new PackageSelectViewStep object. - * @param parent The parent QObject. - */ - explicit PackageSelectViewStep(QObject* parent = nullptr); - - /** - * @brief Destroys the PackageSelectViewStep object. - */ + explicit PackageSelectViewStep( QObject* parent = nullptr ); ~PackageSelectViewStep() override; - /** - * @brief Returns the display name of the step. - * @return The pretty name as a QString. - */ QString prettyName() const override; - - /** - * @brief Returns the widget associated with this step. - * @return A pointer to the QWidget. - */ QWidget* widget() override; - - /** - * @brief Returns the list of jobs to execute for this step. - * @return An empty Calamares::JobList. - */ Calamares::JobList jobs() const override; - /** - * @brief Indicates whether the "Next" button is enabled. - * @return Always returns true. - */ bool isNextEnabled() const override; - - /** - * @brief Indicates whether the "Back" button is enabled. - * @return Always returns true. - */ bool isBackEnabled() const override; - - /** - * @brief Indicates whether the step is at the beginning. - * @return Always returns true. - */ bool isAtBeginning() const override; - - /** - * @brief Indicates whether the step is at the end. - * @return Always returns true. - */ bool isAtEnd() const override; - /** - * @brief Activates the step, setting up the UI based on network availability and configuration. - */ void onActivate() override; - - /** - * @brief Handles actions to perform when leaving the step, such as storing selected packages. - */ void onLeave() override; - /** - * @brief Sets the configuration map for the step. - * @param configurationMap The QVariantMap containing configuration data. - */ - void setConfigurationMap(const QVariantMap& configurationMap) override; - - /** - * @brief Retrieves the current package selections. - * @return A QVariantMap of package selections. - */ QVariantMap packageSelections() const { return m_packageSelections; } - -public slots: - /** - * @brief Slot to handle checkbox toggle events. - * @param checked The new checked state of the checkbox. - */ void updatePackageSelections(bool checked); signals: - /** - * @brief Signal emitted when package selections change. - */ void packageSelectionsChanged(); private: - /** - * @brief Retrieves the checkbox associated with a given package ID. - * @param id The package ID. - * @return A pointer to the QCheckBox, or nullptr if not found. - */ - QCheckBox* getCheckboxById(const QString& id) const; - - /** - * @brief Checks if a given key exists in package selections and is set to true. - * @param key The key to check. - * @return True if the key exists and is true, otherwise false. - */ + QVariantMap m_packageSelections; + Ui::pkgselect *ui; + QWidget* m_widget; bool exists_and_true(const QString& key) const; - - QVariantMap m_packageSelections; ///< Stores the state of package selections. - Ui::pkgselect* ui; ///< Pointer to the UI class. - QWidget* m_widget; ///< Pointer to the main widget of the step. - QVariantMap m_configurationMap; ///< Stores configuration data. - - QMap m_packageCheckBoxes; ///< Maps package IDs to their corresponding checkboxes. - bool m_connectionsMade; ///< Flag to ensure signal connections are made only once. }; -CALAMARES_PLUGIN_FACTORY_DECLARATION(PackageSelectViewStepFactory) +CALAMARES_PLUGIN_FACTORY_DECLARATION( PackageSelectViewStepFactory ) -#endif // PACKAGESELECTVIEWSTEP_H +#endif diff --git a/common/modules/pkgselect/pkgselect.conf b/common/modules/pkgselect/pkgselect.conf deleted file mode 100644 index 90d6b33..0000000 --- a/common/modules/pkgselect/pkgselect.conf +++ /dev/null @@ -1,51 +0,0 @@ ---- -packages: - additional_packages: - - id: "element-desktop" - name: "Element" - description: "Matrix-based end-to-end encrypted messenger and secure collaboration app." - snap: true - - id: "thunderbird" - name: "Thunderbird" - description: "Email, newsfeed, chat, and calendaring client." - snap: true - - id: "krita" - name: "Krita" - description: "Graphics editor designed primarily for digital art and 2D animation." - snap: true - minimal_remove_packages: - - "snapd" - - "lubuntu-snap-installation-monitor" - - "vlc" - - "plasma-discover" - - "transmission-qt" - - "quassel" - - "2048-qt" - - "featherpad" - - "noblenote" - - "kcalc" - - "qps" - - "zsync" - - "partitionmanager" - - "qapt-deb-installer" - - "picom" - - "qlipper" - - "qtpass" - - "libreoffice*" - installer_remove_packages: - - "^live-*" - - calamares-settings-lubuntu - - calamares - - zram-config - - cifs-utils - - lubuntu-installer-prompt - regular_install_packages: - - language-pack-$LOCALE - - language-pack-gnome-$LOCALE - - language-pack-kde-$LOCALE - - hunspell-$LOCALE - - libreoffice-help-$LOCALE - - libreoffice-l10n-$LOCALE - refresh_snaps: - - "firefox" - - "firmware-updater" diff --git a/common/modules/pkgselect/pkgselect.ui b/common/modules/pkgselect/pkgselect.ui index 70d4698..aed59e3 100644 --- a/common/modules/pkgselect/pkgselect.ui +++ b/common/modules/pkgselect/pkgselect.ui @@ -11,7 +11,7 @@ - Package Selection + Form QRadioButton { @@ -28,27 +28,6 @@ QLabel { } - - - - - - - 18 - 50 - false - - - - padding-left: 0px; padding-right: 0px; - - - Installation Mode - - - - - @@ -67,8 +46,401 @@ QLabel { - - + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 11 + 75 + false + true + + + + Note: Ubuntu and flavors are NOT responsible for third-party software installed from this list. + + + true + + + + + + + + 10 + true + + + + This saves time after installation, and keeps your system secure + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 16777215 + 21 + + + + + 12 + + + + Full Installation + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + + 10 + true + + + + All applications in the Normal Installation, and all extra third-party packages listed below + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 16777215 + 21 + + + + + 12 + + + + Download and install updates following installation + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 3 + + + + + + + + true + + + + + 0 + 0 + 762 + 281 + + + + + + + + 16777215 + 21 + + + + Virtual Machine Manager + + + + + + + + 16777215 + 21 + + + + Element + + + + + + + + 16777215 + 21 + + + + Krita + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 10 + true + + + + Matrix-based end-to-end encrypted messenger and secure collaboration app + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 10 + true + + + + Desktop user interface for managing virtual machines through libvirt + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 1 + 5 + + + + + + + + + 10 + true + + + + Email, newsfeed, chat, and calendaring client + + + + + + + + 16777215 + 21 + + + + Thunderbird + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 6 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 10 + true + + + + Graphics editor designed primarily for digital art and 2D animation + + + + + + + @@ -82,8 +454,69 @@ QLabel { - - + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 18 + 50 + false + + + + padding-left: 0px; padding-right: 0px; + + + Installation Mode + + + + + + + + 18 + 50 + false + + + + padding-left: 0px; padding-right: 0px; + + + Additional Options + + + + + + + + 10 + true + + + + Web browser, utilities, office software, games, and media players + + + @@ -105,216 +538,6 @@ QLabel { - - - - - - - 10 - true - - - - Web browser, utilities, office software, games, and media players - - - - - - - - - - 16777215 - 21 - - - - - 12 - - - - Full Installation - - - - - - - - - - 10 - true - - - - All applications in the Normal Installation, and all extra third-party packages listed below - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - - - - - 18 - 50 - false - - - - padding-left: 0px; padding-right: 0px; - - - Additional Options - - - - - - - - - - 16777215 - 21 - - - - - 12 - - - - Download and install updates following installation - - - - - - - - - - 10 - true - - - - This saves time after installation, and keeps your system secure - - - - - - - - - - 11 - 75 - false - true - - - - Note: Ubuntu and flavors are NOT responsible for third-party software installed from this list. - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -332,47 +555,51 @@ QLabel { - - - - - - true - - - - - 0 - 0 - 762 - 281 - - - - - - - - - - - - + + Qt::Vertical - QSizePolicy::Expanding + QSizePolicy::Fixed 20 - 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Horizontal + + + + 40 + 0 - diff --git a/common/modules/pkgselectprocess/CMakeLists.txt b/common/modules/pkgselectprocess/CMakeLists.txt deleted file mode 100644 index bfdc184..0000000 --- a/common/modules/pkgselectprocess/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -cmake_minimum_required(VERSION 3.16 FATAL_ERROR) - -include(FeatureSummary) - -set( CMAKE_CXX_STANDARD 23 ) -set( CMAKE_CXX_STANDARD_REQUIRED ON ) - -find_library(APT_PKG_LIB apt-pkg) -if (NOT APT_PKG_LIB) - message(FATAL_ERROR "Could not find libapt-pkg") -endif() - -find_package(ECM "6.0.0" NO_MODULE) -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH}) -find_package(KF6 REQUIRED COMPONENTS CoreAddons) -include(KDEInstallDirs) - -set( CALAMARES_VERSION_REQUIRED 3.3.9 ) -find_package(Calamares ${CALAMARES_VERSION_REQUIRED} NO_CMAKE_PACKAGE_REGISTRY) -if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui) - find_package(Calamares ${CALAMARES_VERSION_REQUIRED} REQUIRED) -endif() - -message(STATUS "Found Calamares version ${Calamares_VERSION}") -message(STATUS " libraries ${Calamares_LIB_DIRS}") -message(STATUS "") - -calamares_add_plugin( pkgselectprocess - TYPE job - EXPORT_MACRO PLUGINDLLEXPORT_PRO - SOURCES - PackageSelectProcess.cpp - SHARED_LIB - NO_CONFIG -) -add_executable(check_package checkpackage-backend.cpp) -target_link_libraries(check_package PRIVATE ${APT_PKG_LIB}) diff --git a/common/modules/pkgselectprocess/PackageSelectProcess.cpp b/common/modules/pkgselectprocess/PackageSelectProcess.cpp deleted file mode 100644 index ce0ec42..0000000 --- a/common/modules/pkgselectprocess/PackageSelectProcess.cpp +++ /dev/null @@ -1,573 +0,0 @@ -#include "PackageSelectProcess.h" -#include "GlobalStorage.h" -#include "JobQueue.h" -#include -#include -#include -#include -#include -#include - -CALAMARES_PLUGIN_FACTORY_DEFINITION(PackageSelectProcessFactory, registerPlugin();) - -PackageSelectProcess::PackageSelectProcess(QObject* parent) - : Calamares::CppJob(parent), - m_prettyStatus(tr("Preparing to install selected packages...")) -{ -} - -QString PackageSelectProcess::prettyName() const -{ - return tr("Installing selected packages"); -} - -QString PackageSelectProcess::prettyStatusMessage() const -{ - return m_prettyStatus; -} - -void PackageSelectProcess::setConfigurationMap(const QVariantMap& configurationMap) -{ - m_configurationMap = configurationMap; -} - -Calamares::JobResult PackageSelectProcess::runAptCommand(const QString& command, - const QString& rootMountPoint, - double startProgress, - double endProgress, - bool verboseProgress) -{ - qDebug() << "Running apt command:" << command; - QProcess aptProcess(this); - aptProcess.setProgram("/usr/sbin/chroot"); - aptProcess.setArguments({ rootMountPoint, "/bin/bash", "-c", command }); - aptProcess.setProcessChannelMode(QProcess::MergedChannels); - - constexpr int MAX_LINES = 5000; - double progressRange = endProgress - startProgress; - double progressPerLine = progressRange / static_cast(MAX_LINES); - int lineCount = 0; - - QString commandHRPrefix; - if (command.contains("install")) { - commandHRPrefix = tr("Installing packages: "); - } else if (command.contains("full-upgrade")) { - commandHRPrefix = tr("Upgrading installed system: "); - } else if (command.contains("remove")) { - commandHRPrefix = tr("Cleaning up packages: "); - } else if (command.contains("cdrom")) { - commandHRPrefix = tr("cdrom: "); - } - - QRegularExpression getRegex(R"(Get:\d+\s+[^ ]+\s+[^ ]+\s+(.+?)\s+\S+\s+(\S+)\s+\[(.*?)\])"); - - connect(&aptProcess, &QProcess::readyReadStandardOutput, this, - [this, &lineCount, progressPerLine, startProgress, endProgress, verboseProgress, commandHRPrefix, getRegex]() { - QProcess *aptProcess = (QProcess *)(QObject::sender()); - if (aptProcess == NULL) return; - while (aptProcess->canReadLine()) { - QString line = QString::fromUtf8(aptProcess->readLine()).trimmed(); - qDebug() << "Apt log line: " << line; - if (line.isEmpty()) { - continue; - } - - if (verboseProgress && !line.contains("Running in chroot, ignoring command") && - !line.contains("Waiting until unit") && !line.contains("Stopping snap") && - !line.contains("/dev/pts")) { - - // Process "Get:" lines to show download information - if (line.startsWith("Get:")) { - QRegularExpressionMatch match = getRegex.match(line); - if (match.hasMatch()) { - QString packageName = match.captured(1); - QString packageVersion = match.captured(2); - QString packageSize = match.captured(3); - line = tr("Downloading %1 %2 (%3)").arg(packageName, packageVersion, packageSize); - } - } - - m_prettyStatus = commandHRPrefix + line; - emit prettyStatusMessageChanged(m_prettyStatus); - qDebug() << m_prettyStatus; - } - - lineCount++; - double currentProgress = startProgress + (lineCount * progressPerLine); - currentProgress = qBound(startProgress, currentProgress, endProgress); - emit progress(currentProgress); - } - }); - - aptProcess.start(); - if (!aptProcess.waitForStarted()) { - qWarning() << "Failed to start apt command:" << aptProcess.errorString(); - return Calamares::JobResult::error(tr("Apt command failed"), - tr("Failed to start apt command: %1").arg(aptProcess.errorString())); - } - - while (!aptProcess.waitForFinished(100)) { - QCoreApplication::processEvents(); - } - - if (aptProcess.exitStatus() != QProcess::NormalExit || aptProcess.exitCode() != 0) { - QString errorOutput = QString::fromUtf8(aptProcess.readAllStandardError()).trimmed(); - qWarning() << "Apt command error:" << errorOutput; - return Calamares::JobResult::error(tr("Apt command failed"), - tr("Failed to execute apt command: %1").arg(errorOutput)); - } - - emit progress(endProgress); - m_prettyStatus = tr("Command executed successfully."); - emit prettyStatusMessageChanged(m_prettyStatus); - - return Calamares::JobResult::ok(); -} - -Calamares::JobResult PackageSelectProcess::runSnapCommand(const QStringList& snapPackages, - const QString& rootMountPoint, - double startProgress, - double endProgress) -{ - const QString seedDirectory = QDir::cleanPath(rootMountPoint + "/var/lib/snapd/seed"); - QDir dir(seedDirectory); - if (!dir.exists() && !dir.mkpath(".")) { - return Calamares::JobResult::error(tr("Snap installation failed"), - tr("Failed to create seed directory: %1").arg(seedDirectory)); - } - - QStringList snapCommandArgs = { "--seed", seedDirectory }; - snapCommandArgs += snapPackages; - - qDebug() << "Executing Snap Command:" << snapCommandArgs.join(" "); - - QProcess snapProcess(this); - snapProcess.setProgram("/usr/bin/snapd-seed-glue"); - snapProcess.setArguments(snapCommandArgs); - snapProcess.setProcessChannelMode(QProcess::MergedChannels); - - QString currentDescription; - - connect(&snapProcess, &QProcess::readyReadStandardOutput, this, - [&snapProcess, this, ¤tDescription, startProgress, endProgress]( ) { - while (snapProcess.canReadLine()) { - QString line = QString::fromUtf8(snapProcess.readLine()).trimmed(); - if (line.isEmpty()) { - continue; - } - - QStringList parts = line.split("\t"); - if (parts.size() != 2) { - qWarning() << "Unexpected output format from snap-seed-glue:" << line; - continue; - } - - bool ok = false; - double percentage = parts[0].toDouble(&ok); - const QString& description = parts[1]; - - if (!ok) { - qWarning() << "Failed to parse percentage from line:" << line; - continue; - } - - if (description != currentDescription) { - m_prettyStatus = description; - emit prettyStatusMessageChanged(m_prettyStatus); - currentDescription = description; - qDebug() << description; - } - - double scaledProgress = startProgress + (percentage / 100.0) * (endProgress - startProgress); - emit progress(scaledProgress); - } - }); - - m_prettyStatus = tr("Installing snap packages..."); - emit prettyStatusMessageChanged(m_prettyStatus); - emit progress(startProgress); - - snapProcess.start(); - if (!snapProcess.waitForStarted()) { - qWarning() << "Failed to start snap installation process:" << snapProcess.errorString(); - return Calamares::JobResult::error(tr("Snap installation failed"), - tr("Failed to start snap installation process: %1").arg(snapProcess.errorString())); - } - - while (!snapProcess.waitForFinished(100)) { - QCoreApplication::processEvents(); - } - - if (snapProcess.exitStatus() != QProcess::NormalExit || snapProcess.exitCode() != 0) { - QString errorOutput = QString::fromUtf8(snapProcess.readAllStandardError()).trimmed(); - qWarning() << "Snap installation error:" << errorOutput; - return Calamares::JobResult::error(tr("Snap installation failed"), - tr("Failed to install snap packages: %1").arg(errorOutput)); - } - - emit progress(endProgress); - m_prettyStatus = tr("Snap packages installed successfully!"); - emit prettyStatusMessageChanged(m_prettyStatus); - - return Calamares::JobResult::ok(); -} - -void PackageSelectProcess::divert(bool enable) -{ - for (auto it = dpkgDiversions.constBegin(); it != dpkgDiversions.constEnd(); ++it) { - const QString& name = it.key(); - const QString& path = it.value(); - QString divertedPath = path + ".REAL"; - QString command; - - if (enable) { - qDebug() << tr("Adding diversion for %1...").arg(name); - command = QString("dpkg-divert --quiet --add --divert %1 --rename %2") - .arg(divertedPath, path); - } else { - qDebug() << tr("Removing diversion for %1...").arg(name); - QFile::remove(rootMountPoint + path); - command = QString("dpkg-divert --quiet --remove --rename %1").arg(path); - } - - // Set up the QProcess to run the command in chroot - QProcess process; - process.setProgram("/usr/sbin/chroot"); - process.setArguments({ rootMountPoint, "/bin/bash", "-c", command }); - process.setProcessChannelMode(QProcess::MergedChannels); - - // Run the process - process.start(); - if (!process.waitForFinished()) { - qWarning() << "Process error:" << process.errorString(); - continue; - } - - if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { - qWarning() << "Error handling diversion for" << name << ":" << process.readAll(); - continue; - } - - if (!enable) { continue; } - - // Create the replacement script in chroot - QString scriptContent = QString( - "#!/bin/sh\n" - "echo \"%1: diverted (will be called later)\" >&1\n" - "exit 0\n" - ).arg(name); - - QString scriptPath = rootMountPoint + path; - QFile scriptFile(scriptPath); - - if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Error creating script for" << name << ":" << scriptFile.errorString(); - continue; - } - - QTextStream out(&scriptFile); - out << scriptContent; - scriptFile.close(); - - // Make the script executable - QFile::setPermissions(scriptPath, QFile::permissions(scriptPath) | QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther); - } -} - -Calamares::JobResult PackageSelectProcess::exec() -{ - auto gs = Calamares::JobQueue::instance()->globalStorage(); - if (!gs || !gs->contains("installation_data")) { - return Calamares::JobResult::error(tr("No installation data found."), - tr("Installation data is missing from global storage.")); - } - - const QVariantMap installationData = gs->value("installation_data").toMap(); - const QString installationMode = installationData.value("installation_mode").toString(); - const bool hasInternet = gs->value("hasInternet").toBool(); - const bool downloadUpdates = (installationData.value("download_updates").toBool() && hasInternet); - const QVariantList packagesToInstall = installationData.value("packages_to_install").toList(); - const QVariantList packagesToRemove = installationData.value("packages_to_remove").toList(); - const QVariantList presentSnaps = installationData.value("present_snaps").toList(); - - // Handle default value for rootMountPoint - rootMountPoint = "/"; - if (gs->contains("rootMountPoint")) { - rootMountPoint = gs->value("rootMountPoint").toString(); - } - - const QString checkpackage_path = "/usr/libexec/checkpackage-backend"; - const QString chroot_checkpackage_path = rootMountPoint + checkpackage_path; - QFile* cpbe = new QFile(chroot_checkpackage_path); - - static const QMap> allocationMap = { - { "minimal", { {0.0, 1.0} } }, - { "normal", { {0.0, 0.4}, {0.4, 1.0} } }, - { "full", { {0.0, 0.25}, {0.25, 1.0} } } - }; - - const QVector allocations = allocationMap.value(installationMode, { {0.0, 1.0} }); - const double aptRange = allocations[0].end - allocations[0].start; - const double updateStart = allocations[0].start; - const double updateEnd = updateStart + 0.1 * aptRange; - - // Temporarily copy ubuntu.sources elsewhere, if we do not have network - // This is so we can update the apt cache safely - // FIXME: there has to be a better, more native way to do this. It works - // for now, but in the 25.10 cycle, we're probably going to move some of - // these command-line apt calls to the libapt C library. LP: #2107287 - if (!hasInternet) { - const QString ubuntu_sources_path = rootMountPoint + "/etc/apt/sources.list.d/ubuntu.sources"; - QFile* ubuntu_sources = new QFile(ubuntu_sources_path); - // Just in case this module is used in a non-Ubuntu environment, make sure ubuntu.sources exists - // TODO: make this configurable in the 25.10 cycle - if (ubuntu_sources->exists()) { - const QString backup_name = ubuntu_sources_path + ".bak"; - if (!ubuntu_sources->rename(ubuntu_sources_path + ".bak")) { - return Calamares::JobResult::error(tr("Internal Error"), - tr("Permission denied when moving ubuntu.sources to prepare for offline install")); - } - Calamares::JobResult addCdromResult = runAptCommand("apt-cdrom add -m -d=/media/cdrom/", rootMountPoint, updateStart, updateEnd, true); - if (!addCdromResult) return std::move(addCdromResult); - } else { - return Calamares::JobResult::error(tr("Internal Error"), - tr("/etc/apt/sources.list.d/ubuntu.sources not found in the target, are you a downstream?")); - } - } - - // Run apt update - m_prettyStatus = tr("Updating apt cache"); - emit prettyStatusMessageChanged(m_prettyStatus); - emit progress(updateStart); - - Calamares::JobResult updateResult = runAptCommand("DEBIAN_FRONTEND=noninteractive apt-get update", - rootMountPoint, - updateStart, - updateEnd, - false); - if (!updateResult) { // Using operator bool() to check for errors - return std::move(updateResult); // Move to avoid copy - } - - QStringList debPackages; - for (const QVariant& var : packagesToInstall) { - const QVariantMap pkg = var.toMap(); - if (!pkg.value("snap").toBool()) { - debPackages << pkg.value("id").toString(); - } - } - - // Add diversions for dracut, update-initramfs, and locale-gen - /* - dpkgDiversions = { - {"dracut", "/usr/bin/dracut"}, - {"update-initramfs", "/usr/sbin/update-initramfs"}, - {"locale-gen", "/usr/sbin/locale-gen"} - }; - divert(true); - */ - - double installStart; - double installEnd; - if (downloadUpdates) { - const double upgradeStart = updateEnd; - const double upgradeEnd = upgradeStart + 0.25 * aptRange; - - Calamares::JobResult upgradeResult = runAptCommand( - "DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confnew' full-upgrade", - rootMountPoint, - upgradeStart, - upgradeEnd, - true - ); - if (!upgradeResult) { // Using operator bool() to check for errors - return std::move(upgradeResult); // Move to avoid copy - } - - installStart = upgradeEnd; - installEnd = installStart + 0.25 * aptRange; - } - else { - installStart = updateEnd; - installEnd = installStart + 0.5 * aptRange; - installEnd = qMin(installEnd, allocations[0].end); - } - - qDebug() << "Progress range: installStart:" << installStart << "installEnd:" << installEnd; - - if (!debPackages.isEmpty()) { - // Corresponding to the temporary hack in pkgselect adding calamares - // and kdialog to the list, we only want those two included in the - // final installation if we're actually in OEM mode. Otherwise, they - // can be ignored, and are just clutter. - // FIXME: When the OEM stack is rewritten in 25.10, this needs to be - // removed. - if (!QFile::exists("/etc/calamares/OEM_MODE_ACTIVATED")) { - QStringList wip_list; - for (auto debPackage : debPackages) { - if (!debPackage.contains(QString("calamares")) && - !debPackage.contains(QString("kdialog"))) { - wip_list << debPackage; - } - } - debPackages = wip_list; - } - - // checkpackage-backend needs to be explicitly copied to the chroot - // and removed later for systems with stacked squashfses, or the - // install command will fail. LP: #2104243 - if (!cpbe->exists()) { - QFile* parent_cpbe = new QFile(checkpackage_path); - if (!parent_cpbe->copy(chroot_checkpackage_path)) { - return Calamares::JobResult::error(tr("Internal Error"), - tr("Permission denied when copying checkpackage-backend, are you running Calamares correctly?")); - } - } - - const QString packageList = debPackages.join(" "); - const QString installCommand = QString("DEBIAN_FRONTEND=noninteractive apt-get -y install $(/usr/libexec/checkpackage-backend %1);").arg(packageList); - - Calamares::JobResult installResult = runAptCommand(installCommand, - rootMountPoint, - installStart, - installEnd, - true); - if (!installResult) { - if (!cpbe->remove()) qDebug() << "Warning: failed to clean up /usr/libexec/checkpackage-backend"; - return std::move(installResult); - } - } - else qDebug() << "No packages to install."; - - QStringList removeDebPackages; - for (const QVariant& var : packagesToRemove) { - removeDebPackages << var.toString(); - } - - // As part of the fix for LP: #2104343, we need to ensure that, if - // we are currently in OEM mode, Calamares and friends remain - // installed. During stage two, we clean it up. - // FIXME: When the OEM stack is rewritten in 25.10, this needs to be - // rewritten. - if (QFile::exists("/etc/calamares/OEM_MODE_ACTIVATED")) { - QStringList wip_list; - for (auto removeDebPackage : removeDebPackages) { - if (!removeDebPackage.contains(QString("calamares"))) wip_list << removeDebPackage; - } - removeDebPackages = wip_list; - } - - const double removeStart = installEnd; - const double removeEnd = removeStart + 0.2 * aptRange; - - if (!removeDebPackages.isEmpty()) { - const QString removeCommand = QString("DEBIAN_FRONTEND=noninteractive apt-get -y --purge remove $(/usr/libexec/checkpackage-backend %1);") - .arg(removeDebPackages.join(" ")); - Calamares::JobResult removeResult = runAptCommand(removeCommand, - rootMountPoint, - removeStart, - removeEnd, - true); - if (!removeResult) return std::move(removeResult); - } - - const double autoremoveStart = removeEnd; - const double autoremoveEnd = autoremoveStart + 0.2 * aptRange; - - Calamares::JobResult autoremoveResult = runAptCommand("DEBIAN_FRONTEND=noninteractive apt-get -y autoremove", - rootMountPoint, - autoremoveStart, - autoremoveEnd, - true); - - // Disable diversions - //divert(false); - - // Move ubuntu.sources back, and clean up the cdrom file - // FIXME: there has to be a better, more native way to do this. It works - // for now, but in the 25.10 cycle, we're probably going to move some of - // these command-line apt calls to the libapt C library. LP: #2107287 - try { - if (!hasInternet) { - const QString ubuntu_sources_path = rootMountPoint + "/etc/apt/sources.list.d/ubuntu.sources"; - const QString backup_name = ubuntu_sources_path + ".bak"; - QFile* ubuntu_sources = new QFile(ubuntu_sources_path); - QFile* ubuntu_sources_bak = new QFile(backup_name); - // Just in case this module is used in a non-Ubuntu environment, make sure ubuntu.sources exists - // TODO: make this configurable in the 25.10 cycle - if (ubuntu_sources->exists()) { - if (!ubuntu_sources->remove()) { - return Calamares::JobResult::error(tr("Internal Error"), - tr("/etc/apt/sources.list.d/ubuntu.sources already exists and it won't budge - this is a rare edge case, please report!")); - } - } - if (!ubuntu_sources_bak->rename(ubuntu_sources_path)) { - return Calamares::JobResult::error(tr("Internal Error"), - tr("Permission denied when moving ubuntu.sources back after offline install")); - } - - // Remove the apt-cdrom entry we added earlier - // This may seem drastic, but we already expect that the automirror - // module, ran before this, creates a deb822-style ubuntu.sources - QFile* cdrom_sources_list = new QFile(rootMountPoint + "/etc/apt/sources.list"); - if (!cdrom_sources_list->remove()) { - return Calamares::JobResult::error(tr("Internal Error"), - tr("Failed to remove classic sources.list file")); - } - } - } catch (const std::exception &exc) { - qDebug() << exc.what(); - } catch (...) { - qDebug() << "Caught unknown error"; - } - - // Handle snap packages - if (installationMode != "minimal") { - QStringList snapPackages; - QStringList presentSnapsList; - // Convert QVariantList to QStringList - for (const QVariant& var : presentSnaps) { - presentSnapsList << var.toString(); - } - - for (const QVariant& var : packagesToInstall) { - const QVariantMap pkg = var.toMap(); - if (pkg.value("snap").toBool()) { - snapPackages << pkg.value("id").toString(); - } - } - - QStringList finalSnapPackages; - - if (!snapPackages.isEmpty() && !presentSnapsList.isEmpty()) { - finalSnapPackages = presentSnapsList + snapPackages; - } - else if (!snapPackages.isEmpty()) { - finalSnapPackages = snapPackages; - } - else if (!presentSnapsList.isEmpty() && downloadUpdates) { - finalSnapPackages = presentSnapsList; - } - - if (!finalSnapPackages.isEmpty()) { - double snapStart = allocations.size() > 1 ? allocations[1].start : allocations[0].end; - double snapEnd = allocations.size() > 1 ? allocations[1].end : allocations[0].end; - - Calamares::JobResult snapResult = runSnapCommand(finalSnapPackages, - rootMountPoint, - snapStart, - snapEnd); - if (!snapResult) { // Using operator bool() to check for errors - return std::move(snapResult); // Move to avoid copy - } - } - } - - emit progress(1.0); - m_prettyStatus = tr("All selected packages installed successfully."); - emit prettyStatusMessageChanged(m_prettyStatus); - - if (!cpbe->remove()) qDebug() << "Warning: failed to clean up /usr/libexec/checkpackage-backend"; - - return Calamares::JobResult::ok(); -} diff --git a/common/modules/pkgselectprocess/PackageSelectProcess.h b/common/modules/pkgselectprocess/PackageSelectProcess.h deleted file mode 100644 index d2fa378..0000000 --- a/common/modules/pkgselectprocess/PackageSelectProcess.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef PACKAGESELECTPROCESS_H -#define PACKAGESELECTPROCESS_H - -#include -#include -#include -#include -#include "CppJob.h" -#include "utils/PluginFactory.h" -#include "DllMacro.h" - -class QProcess; - -class PLUGINDLLEXPORT PackageSelectProcess : public Calamares::CppJob -{ - Q_OBJECT - -public: - explicit PackageSelectProcess(QObject* parent = nullptr); - ~PackageSelectProcess() override = default; - - QString prettyName() const override; - QString prettyStatusMessage() const override; - - Calamares::JobResult exec() override; - - void setConfigurationMap(const QVariantMap& configurationMap) override; - -signals: - void prettyStatusMessageChanged(const QString&); - -private: - struct ProgressAllocation - { - double start; - double end; - }; - - Calamares::JobResult runAptCommand(const QString& command, - const QString& rootMountPoint, - double startProgress, - double endProgress, - bool verboseProgress); - Calamares::JobResult runSnapCommand(const QStringList& snapPackages, - const QString& rootMountPoint, - double startProgress, - double endProgress); - - void divert(bool enable); - - QMap dpkgDiversions; - QString rootMountPoint; - - QVariantMap m_configurationMap; - QString m_prettyStatus; -}; - -CALAMARES_PLUGIN_FACTORY_DECLARATION(PackageSelectProcessFactory) - -#endif // PACKAGESELECTPROCESS_H diff --git a/common/modules/pkgselectprocess/checkpackage-backend.cpp b/common/modules/pkgselectprocess/checkpackage-backend.cpp deleted file mode 100644 index 6cf2e8c..0000000 --- a/common/modules/pkgselectprocess/checkpackage-backend.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char* argv[]) { - pkgInitConfig(*_config); - pkgInitSystem(*_config, _system); - if (_system == 0) { - std::cerr << "apt-pkg not initialized\n"; - return 1; - } - - // Open the package cache. - pkgCacheFile *cache = new pkgCacheFile(); - OpProgress progress; - if (!cache || cache->Open(&progress, false) == false) { - std::cerr << "Error: could not open APT cache.\n"; - return 1; - } - pkgApplyStatus(*cache); - - std::vector package_names(argv + 1, argv + argc); - if (package_names.empty()) return 0; - - std::unordered_set seen_packages; - for (std::string package_name : package_names) { - if (seen_packages.contains(package_name)) continue; - seen_packages.insert(package_name); - - // Tasks and wildcards should just be passed through as-is, for now - if (package_name.starts_with('^') || package_name.contains('*')) { - std::cout << package_name << " "; - continue; - } - pkgCache::GrpIterator grp = cache->GetPkgCache()->FindGrp(package_name); - if (!grp.end()) { - pkgCache::PkgIterator it = grp.FindPreferredPkg(true); - if (!it.end() && !it.VersionList().end()) { - std::cout << package_name << " "; - } - } - } - - std::cout << "\n"; - cache->Close(); - return 0; -} diff --git a/common/modules/pkgselectprocess/module.desc b/common/modules/pkgselectprocess/module.desc deleted file mode 100644 index cd31c4c..0000000 --- a/common/modules/pkgselectprocess/module.desc +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: "job" -name: "pkgselectprocess" -interface: "qtplugin" -load: "libcalamares_job_pkgselectprocess.so" -noconfig: true -weight: 12 diff --git a/common/snap-seed-glue-emb/go.mod b/common/snap-seed-glue-emb/go.mod new file mode 100644 index 0000000..ac4aac1 --- /dev/null +++ b/common/snap-seed-glue-emb/go.mod @@ -0,0 +1,5 @@ +module snap-seed-glue + +go 1.22.1 + +require github.com/snapcore/snapd v0.0.0-20240328101726-fdc222fc37a0 diff --git a/common/snap-seed-glue-emb/main.go b/common/snap-seed-glue-emb/main.go new file mode 100644 index 0000000..cf95ab1 --- /dev/null +++ b/common/snap-seed-glue-emb/main.go @@ -0,0 +1,289 @@ +package main + +// Copyright (C) 2024 Simon Quigley +// +// 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 3 +// of the License, 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. + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/interfaces/builtin" + "gopkg.in/yaml.v2" +) + +type seed struct { + Snaps []struct { + Name string `yaml:"name"` + Channel string `yaml:"channel"` + File string `yaml:"file"` + } `yaml:"snaps"` +} + +func main() { + snap.SanitizePlugsSlots = builtin.SanitizePlugsSlots + + var seed_directory string + flag.StringVar(&seed_directory, "seed", "/var/lib/snapd/seed", "Specify the seed directory") + flag.Parse() + + snap_set := make(map[string]bool) + + snaps_dir := filepath.Join(seed_directory, "snaps") + assertions_dir := filepath.Join(seed_directory, "assertions") + seed_yaml := filepath.Join(seed_directory, "seed.yaml") + + ensure_seed_yaml(seed_yaml) + + existing_snaps_in_yaml := load_existing_snaps(seed_yaml) + + for _, snap_info := range flag.Args() { + parts := strings.SplitN(snap_info, "=", 2) + snap_name := parts[0] + channel := "stable" // Default to stable if no channel is specified + if len(parts) == 2 { + channel = parts[1] + } + process_snap_with_prereqs(snap_name, channel, &snap_set, snaps_dir, assertions_dir, seed_yaml, existing_snaps_in_yaml) + } + + essentialSnaps := []string{"snapd", "bare"} + for _, snapName := range essentialSnaps { + if !existing_snaps_in_yaml[snapName] { + process_snap_with_prereqs(snapName, "stable", &snap_set, snaps_dir, assertions_dir, seed_yaml, existing_snaps_in_yaml) + } + } + + update_seed_yaml(snaps_dir, seed_yaml, snap_set, existing_snaps_in_yaml) + + remove_state_json(filepath.Join(seed_directory, "..", "state.json")) + ensure_assertions(assertions_dir) + validate_seed(seed_yaml) +} + +func ensure_seed_yaml(seed_yaml string) { + if _, err := os.Stat(seed_yaml); os.IsNotExist(err) { + file, err := os.Create(seed_yaml) + if err != nil { + log.Fatalf("Failed to create seed.yaml: %v", err) + } + defer file.Close() + file.WriteString("snaps:\n") + } +} + +func load_existing_snaps(seed_yaml string) map[string]bool { + file, err := ioutil.ReadFile(seed_yaml) + if err != nil { + log.Fatalf("Failed to read seed.yaml: %v", err) + } + + var seed_data seed + if err := yaml.Unmarshal(file, &seed_data); err != nil { + log.Fatalf("Failed to parse seed.yaml: %v", err) + } + + existing := make(map[string]bool) + for _, snap := range seed_data.Snaps { + existing[snap.Name] = true + } + return existing +} + +func update_seed_yaml(snaps_dir, seed_yaml string, snap_set map[string]bool, existing_snaps map[string]bool) { + seed_data := load_seed_data(seed_yaml) + + for snap_name := range snap_set { + if !existing_snaps[snap_name] { + snap_files, err := filepath.Glob(filepath.Join(snaps_dir, fmt.Sprintf("%s_*.snap", snap_name))) + if err != nil || len(snap_files) == 0 { + log.Printf("No snap file found for %s", snap_name) + return + } + + snap_file := filepath.Base(snap_files[0]) + log.Printf(snap_file) + + // FIXME: should put the real name of the channel in here + seed_data.Snaps = append(seed_data.Snaps, struct { + Name string `yaml:"name"` + Channel string `yaml:"channel"` + File string `yaml:"file"` + }{snap_name, "latest/stable", snap_file}) + } + } + + // Marshal to YAML and write back to file + data, err := yaml.Marshal(&seed_data) + if err != nil { + log.Fatalf("Failed to marshal seed data to YAML: %v", err) + } + + if err := ioutil.WriteFile(seed_yaml, data, 0644); err != nil { + log.Fatalf("Failed to write updated seed.yaml: %v", err) + } +} + +func load_seed_data(seed_yaml string) seed { + file, err := ioutil.ReadFile(seed_yaml) + if err != nil { + log.Fatalf("Failed to read seed.yaml: %v", err) + } + + var seed_data seed + if err := yaml.Unmarshal(file, &seed_data); err != nil { + log.Fatalf("Failed to parse seed.yaml: %v", err) + } + return seed_data +} + +func remove_state_json(state_json_path string) { + if _, err := os.Stat(state_json_path); err == nil { + os.Remove(state_json_path) + } +} + +func validate_seed(seed_yaml string) { + cmd := exec.Command("snap", "debug", "validate-seed", seed_yaml) + if err := cmd.Run(); err != nil { + log.Printf("Error validating seed: %v", err) + } +} + +func process_snap_with_prereqs(snap_name, channel string, snap_set *map[string]bool, snaps_dir, assertions_dir, seed_yaml string, existing_snaps_in_yaml map[string]bool) { + if (*snap_set)[snap_name] { + return + } + + // Download the snap if not already processed or listed in seed.yaml + if !existing_snaps_in_yaml[snap_name] { + cmd := exec.Command("snap", "download", snap_name, "--channel="+channel, "--target-directory="+snaps_dir) + if err := cmd.Run(); err != nil { + log.Printf("Error downloading snap %s from channel %s: %v", snap_name, channel, err) + return + } + } + + snap_files, err := filepath.Glob(filepath.Join(snaps_dir, fmt.Sprintf("%s_*.snap", snap_name))) + if err != nil || len(snap_files) == 0 { + log.Printf("No snap file found for %s in channel %s", snap_name, channel) + return + } + + snap_file := snap_files[0] + + cmd := exec.Command("unsquashfs", "-n", "-d", filepath.Join(snaps_dir, fmt.Sprintf("%s_meta", snap_name)), snap_file, "meta/snap.yaml") + if err := cmd.Run(); err != nil { + log.Printf("Error extracting meta/snap.yaml from snap %s: %v", snap_name, err) + return + } + + yaml_data, err := ioutil.ReadFile(filepath.Join(snaps_dir, fmt.Sprintf("%s_meta/meta/snap.yaml", snap_name))) + if err != nil { + log.Printf("Error reading snap.yaml file for %s: %v", snap_name, err) + return + } + + info, err := snap.InfoFromSnapYaml(yaml_data) + if err != nil { + log.Printf("Error parsing snap.yaml data for %s: %v", snap_name, err) + return + } + + (*snap_set)[snap_name] = true + + tracker := snap.SimplePrereqTracker{} + missing_provider_content_tags := tracker.MissingProviderContentTags(info, nil) + for provider_snap := range missing_provider_content_tags { + if !(*snap_set)[provider_snap] { + process_snap_with_prereqs(provider_snap, "stable", snap_set, snaps_dir, assertions_dir, seed_yaml, existing_snaps_in_yaml) + } + } + + if info.Base != "" && !(*snap_set)[info.Base] { + process_snap_with_prereqs(info.Base, "stable", snap_set, snaps_dir, assertions_dir, seed_yaml, existing_snaps_in_yaml) + } + + assert_files, err := filepath.Glob(filepath.Join(snaps_dir, "*.assert")) + for _, file := range assert_files { + target_path := filepath.Join(assertions_dir, filepath.Base(file)) + err := os.Rename(file, target_path) + if err != nil { + log.Printf("Failed to move %s to %s: %v", file, assertions_dir, err) + } + } + + os.RemoveAll(filepath.Join(snaps_dir, fmt.Sprintf("%s_meta", snap_name))) +} + +func ensure_assertions(assertions_dir string) { + model := "generic-classic" + brand := "generic" + series := "16" + + model_assertion_path := filepath.Join(assertions_dir, "model") + account_key_assertion_path := filepath.Join(assertions_dir, "account-key") + account_assertion_path := filepath.Join(assertions_dir, "account") + + // Check and generate model assertion + if _, err := os.Stat(model_assertion_path); os.IsNotExist(err) { + output, err := exec.Command("snap", "known", "--remote", "model", "series="+series, "model="+model, "brand-id="+brand).CombinedOutput() + if err != nil { + log.Fatalf("Failed to fetch model assertion: %v, Output: %s", err, string(output)) + } + ioutil.WriteFile(model_assertion_path, output, 0644) + } + + // Generate account-key assertion if not exists + if _, err := os.Stat(account_key_assertion_path); os.IsNotExist(err) { + signKeySha3 := grep_pattern(model_assertion_path, "sign-key-sha3-384: ") + output, err := exec.Command("snap", "known", "--remote", "account-key", "public-key-sha3-384="+signKeySha3).CombinedOutput() + if err != nil { + log.Fatalf("Failed to fetch account-key assertion: %v, Output: %s", err, string(output)) + } + ioutil.WriteFile(account_key_assertion_path, output, 0644) + } + + // Generate account assertion if not exists + if _, err := os.Stat(account_assertion_path); os.IsNotExist(err) { + accountId := grep_pattern(account_key_assertion_path, "account-id: ") + output, err := exec.Command("snap", "known", "--remote", "account", "account-id="+accountId).CombinedOutput() + if err != nil { + log.Fatalf("Failed to fetch account assertion: %v, Output: %s", err, string(output)) + } + ioutil.WriteFile(account_assertion_path, output, 0644) + } +} + +func grep_pattern(filePath, pattern string) string { + content, err := ioutil.ReadFile(filePath) + if err != nil { + log.Fatalf("Failed to read from file %s: %v", filePath, err) + } + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if strings.Contains(line, pattern) { + parts := strings.SplitN(line, ":", 2) + if len(parts) == 2 { + return strings.TrimSpace(parts[1]) + } + } + } + log.Fatalf("Pattern %s not found in file %s", pattern, filePath) + return "" +} diff --git a/debian/changelog b/debian/changelog index 9c44282..7f0157c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +calamares-settings-ubuntu (1:25.10.2) questing; urgency=medium + + * Revert the packageselect refactoring from Plucky, go back to the + known-good package customization implementation. + + -- Aaron Rainbolt Wed, 13 Aug 2025 12:45:11 -0500 + calamares-settings-ubuntu (1:25.10.1) questing; urgency=medium * Update Kubuntu branding for 25.10. diff --git a/debian/control b/debian/control index 6cab9dd..2c94114 100644 --- a/debian/control +++ b/debian/control @@ -7,9 +7,11 @@ Build-Depends: debhelper-compat (= 13), dh-sequence-qmldeps, cmake, extra-cmake-modules, + golang-github-snapcore-snapd-dev (>= 2.62), + golang-go, + golang-gopkg-yaml.v2-dev, fakeroot, intltool, - libapt-pkg-dev, libcalamares-dev (>= 3.3.13-0ubuntu4), libkf6coreaddons-dev, libqt6svg6-dev, @@ -77,7 +79,6 @@ Depends: calamares (>= 3.3.13-0ubuntu4), kdialog, keyutils, libglib2.0-bin, - snapd-seed-glue, squashfs-tools, sudo, ${misc:Depends}, diff --git a/debian/rules b/debian/rules index 02b28c7..68d59c9 100755 --- a/debian/rules +++ b/debian/rules @@ -6,7 +6,6 @@ export GOPATH=/usr/share/gocode export GO111MODULE=off export GOCACHE=$(CURDIR)/.gocache export PKGSELECT = "common/modules/pkgselect" -export PKGSELECTPROCESS = "common/modules/pkgselectprocess" export USRDIR = "debian/calamares-settings-ubuntu-common/usr" export DATA_USRDIR = "debian/calamares-settings-ubuntu-common-data/usr" export MODULES_DIR = "debian/calamares-settings-ubuntu-common/usr/lib/$(DEB_HOST_MULTIARCH)/calamares/modules" @@ -19,12 +18,11 @@ DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) override_dh_auto_configure: (cd $(PKGSELECT) && mkdir build && cd build && cmake ..) - (cd $(PKGSELECTPROCESS) && mkdir build && cd build && cmake ..) override_dh_auto_build: make; (cd $(PKGSELECT)/build && $(MAKE)) - (cd $(PKGSELECTPROCESS)/build && $(MAKE)) + (cd common/snap-seed-glue-emb && go build -gcflags="all=-N -l" -ldflags="-compressdwarf=false" -o snap-seed-glue-emb main.go) override_dh_auto_clean: dh_auto_clean @@ -43,11 +41,8 @@ override_dh_missing: chmod 644 $(DATA_MODULES_DIR)/automirror/module.desc chmod 644 $(MODULES_DIR)/pkgselect/libcalamares_viewmodule_pkgselect.so chmod 644 $(MODULES_DIR)/pkgselect/module.desc - mkdir -pv $(MODULES_DIR)/pkgselectprocess - cp -v $(PKGSELECTPROCESS)/build/*.so $(PKGSELECTPROCESS)/build/*.desc $(MODULES_DIR)/pkgselectprocess - chmod 644 $(MODULES_DIR)/pkgselectprocess/libcalamares_job_pkgselectprocess.so - chmod 644 $(MODULES_DIR)/pkgselectprocess/module.desc + mkdir -pv $(USRDIR)/bin/ + cp -v common/snap-seed-glue-emb/snap-seed-glue-emb $(USRDIR)/bin/snap-seed-glue-emb mkdir -pv $(USRDIR)/libexec/ $(DATA_USRDIR)/libexec/ cp -v common/fixconkeys-part1 $(DATA_USRDIR)/libexec/fixconkeys-part1 cp -v common/fixconkeys-part2 $(DATA_USRDIR)/libexec/fixconkeys-part2 - cp -v $(PKGSELECTPROCESS)/build/check_package $(USRDIR)/libexec/checkpackage-backend diff --git a/kubuntu/modules/packages.conf b/kubuntu/modules/packages.conf new file mode 100644 index 0000000..931dac2 --- /dev/null +++ b/kubuntu/modules/packages.conf @@ -0,0 +1,16 @@ +update_db: true +backend: apt +operations: + - remove: + - "^live-*" + - calamares-settings-kubuntu + - calamares + - cifs-utils + - kubuntu-installer-prompt + - try_install: + - language-pack-$LOCALE + - language-pack-gnome-$LOCALE + - language-pack-kde-$LOCALE + - hunspell-$LOCALE + - libreoffice-help-$LOCALE + - libreoffice-l10n-$LOCALE diff --git a/kubuntu/modules/pkgselect.conf b/kubuntu/modules/pkgselect.conf deleted file mode 100644 index 821f779..0000000 --- a/kubuntu/modules/pkgselect.conf +++ /dev/null @@ -1,57 +0,0 @@ ---- -packages: - additional_packages: - - id: "element-desktop" - name: "Element" - description: "Matrix-based end-to-end encrypted messenger and secure collaboration app." - snap: true - - id: "krita" - name: "Krita" - description: "Graphics editor designed primarily for digital art and 2D animation." - snap: true - minimal_remove_packages: - - kmahjongg - - kmines - - kpat - - ksudoku - - skanlite - - skanpage - - okular - - "libreoffice*" - - kdeconnect - - krdc - - konversation - - neochat - - elisa - - haruna - - vim - - snapd - - partitionmanager - - usb-creator* - - plasma-welcome - - kde-config-tablet - installer_remove_packages: - - "^live-*" - - calamares-settings-kubuntu - - calamares - - cifs-utils - - fcitx5 - - fcitx5-frontend-all - - fcitx5-table - - fcitx5-pinyin - - fcitx5-module-cloudpinyin - - fcitx5-material-color - - fcitx5-chinese-addons - - kde-config-fcitx5 - - kubuntu-installer-prompt - regular_install_packages: - - language-pack-$LOCALE - - language-pack-gnome-$LOCALE - - language-pack-kde-$LOCALE - - hunspell-$LOCALE - - libreoffice-help-$LOCALE - - libreoffice-l10n-$LOCALE - refresh_snaps: - - "firefox" - - "thunderbird" - - "firmware-updater" diff --git a/kubuntu/modules/pkgselect_context.conf b/kubuntu/modules/pkgselect_context.conf new file mode 100644 index 0000000..74aa744 --- /dev/null +++ b/kubuntu/modules/pkgselect_context.conf @@ -0,0 +1,19 @@ +--- +dontChroot: false +timeout: 10800 +"packages.minimalButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get -y --purge remove kmahjongg kmines kpat ksudoku skanlite skanpage okular libreoffice* kdeconnect krdc konversation neochat elisa haruna vim snapd partitionmanager usb-creator* plasma-welcome kde-config-tablet plasma-welcome" + - "apt-get -y autoremove" +"packages.partyButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install ubuntu-restricted-addons unrar" +"packages.updatesButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confnew' full-upgrade" +"packages.virtmanagerButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install virt-manager" diff --git a/kubuntu/modules/pkgselect_snap_context.conf b/kubuntu/modules/pkgselect_snap_context.conf new file mode 100644 index 0000000..d75cd6c --- /dev/null +++ b/kubuntu/modules/pkgselect_snap_context.conf @@ -0,0 +1,9 @@ +--- +dontChroot: true +timeout: 10800 +"packages.elementButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed element-desktop" +"packages.kritaButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed krita" +"packages.thunderbirdButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed thunderbird" diff --git a/kubuntu/oem/calamares-launch-oem b/kubuntu/oem/calamares-launch-oem index 1fb44d1..fd4adc8 100755 --- a/kubuntu/oem/calamares-launch-oem +++ b/kubuntu/oem/calamares-launch-oem @@ -29,7 +29,7 @@ if kdialog --warningyesno "${msg}"; then sed -i "/- welcome$/a \ \ - oemid" /etc/calamares/settings.conf; # Enable OEM prep module - sed -i "/- pkgselectprocess$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; + sed -i "/- packages$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; # Fix OEM UID sed -i "/- shellprocess@oemprep$/a \ \ - shellprocess@fix-oem-uid" /etc/calamares/settings.conf; diff --git a/kubuntu/settings.conf b/kubuntu/settings.conf index 2dafd7f..20c7c53 100644 --- a/kubuntu/settings.conf +++ b/kubuntu/settings.conf @@ -2,12 +2,12 @@ modules-search: [ local ] instances: +- id: before_bootloader_mkdirs + module: contextualprocess + config: before_bootloader_mkdirs_context.conf - id: before_bootloader module: contextualprocess config: before_bootloader_context.conf -- id: copy_vmlinuz_shellprocess - module: shellprocess - config: copy_vmlinuz_shellprocess.conf - id: logs module: shellprocess config: shellprocess_logs.conf @@ -17,6 +17,12 @@ instances: - id: add386arch module: shellprocess config: shellprocess_add386arch.conf +- id: pkgselect_action + module: contextualprocess + config: pkgselect_context.conf +- id: pkgselect_snap_action + module: contextualprocess + config: pkgselect_snap_context.conf - id: oemprep module: shellprocess config: shellprocess_oemprep.conf @@ -53,7 +59,7 @@ sequence: - displaymanager - networkcfg - hwclock - - shellprocess@copy_vmlinuz_shellprocess + - contextualprocess@before_bootloader_mkdirs - shellprocess@bug-LP#1829805 - shellprocess@fixconkeys_part1 - shellprocess@fixconkeys_part2 @@ -64,7 +70,9 @@ sequence: - bootloader - shellprocess@add386arch - automirror - - pkgselectprocess + - packages + - contextualprocess@pkgselect_action + - contextualprocess@pkgselect_snap_action - shellprocess@logs - umount - show: diff --git a/lubuntu/modules/packages.conf b/lubuntu/modules/packages.conf new file mode 100644 index 0000000..bff093c --- /dev/null +++ b/lubuntu/modules/packages.conf @@ -0,0 +1,17 @@ +update_db: true +backend: apt +operations: + - remove: + - "^live-*" + - calamares-settings-lubuntu + - calamares + - zram-config + - cifs-utils + - lubuntu-installer-prompt + - try_install: + - language-pack-$LOCALE + - language-pack-gnome-$LOCALE + - language-pack-kde-$LOCALE + - hunspell-$LOCALE + - libreoffice-help-$LOCALE + - libreoffice-l10n-$LOCALE diff --git a/lubuntu/modules/pkgselect.conf b/lubuntu/modules/pkgselect.conf deleted file mode 100644 index 4184ebe..0000000 --- a/lubuntu/modules/pkgselect.conf +++ /dev/null @@ -1,26 +0,0 @@ ---- -stacked_squashfs: true -packages: - additional_packages: - - id: "element-desktop" - name: "Element" - description: "Matrix-based end-to-end encrypted messenger and secure collaboration app." - snap: true - - id: "thunderbird" - name: "Thunderbird" - description: "Email, newsfeed, chat, and calendaring client." - snap: true - - id: "krita" - name: "Krita" - description: "Graphics editor designed primarily for digital art and 2D animation." - snap: true - regular_install_packages: - - language-pack-$LOCALE - - language-pack-gnome-$LOCALE - - language-pack-kde-$LOCALE - - hunspell-$LOCALE - - libreoffice-help-$LOCALE - - libreoffice-l10n-$LOCALE - refresh_snaps: - - "firefox" - - "firmware-updater" diff --git a/lubuntu/modules/pkgselect_context.conf b/lubuntu/modules/pkgselect_context.conf new file mode 100644 index 0000000..6b304fe --- /dev/null +++ b/lubuntu/modules/pkgselect_context.conf @@ -0,0 +1,19 @@ +--- +dontChroot: false +timeout: 10800 +"packages.minimalButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get -y --purge remove snapd lubuntu-snap-installation-monitor vlc plasma-discover transmission-qt quassel 2048-qt featherpad noblenote kcalc qps zsync partitionmanager qapt-deb-installer picom qlipper qtpass libreoffice*" + - "apt-get -y autoremove" +"packages.partyButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install ubuntu-restricted-addons unrar" +"packages.updatesButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confnew' full-upgrade" +"packages.virtmanagerButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install virt-manager" diff --git a/lubuntu/modules/pkgselect_snap_context.conf b/lubuntu/modules/pkgselect_snap_context.conf new file mode 100644 index 0000000..d75cd6c --- /dev/null +++ b/lubuntu/modules/pkgselect_snap_context.conf @@ -0,0 +1,9 @@ +--- +dontChroot: true +timeout: 10800 +"packages.elementButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed element-desktop" +"packages.kritaButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed krita" +"packages.thunderbirdButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed thunderbird" diff --git a/lubuntu/oem/calamares-launch-oem b/lubuntu/oem/calamares-launch-oem index 961271b..ac85ed1 100755 --- a/lubuntu/oem/calamares-launch-oem +++ b/lubuntu/oem/calamares-launch-oem @@ -29,7 +29,7 @@ if kdialog --warningyesno "${msg}"; then sed -i "/- welcome$/a \ \ - oemid" /etc/calamares/settings.conf; # Enable OEM prep module - sed -i "/- pkgselectprocess$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; + sed -i "/- packages$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; # Fix OEM UID sed -i "/- shellprocess@oemprep$/a \ \ - shellprocess@fix-oem-uid" /etc/calamares/settings.conf; diff --git a/lubuntu/settings.conf b/lubuntu/settings.conf index 391d3a8..7f895b8 100644 --- a/lubuntu/settings.conf +++ b/lubuntu/settings.conf @@ -2,12 +2,12 @@ modules-search: [ local ] instances: +- id: before_bootloader_mkdirs + module: contextualprocess + config: before_bootloader_mkdirs_context.conf - id: before_bootloader module: contextualprocess config: before_bootloader_context.conf -- id: copy_vmlinuz_shellprocess - module: shellprocess - config: copy_vmlinuz_shellprocess.conf - id: logs module: shellprocess config: shellprocess_logs.conf @@ -17,6 +17,12 @@ instances: - id: add386arch module: shellprocess config: shellprocess_add386arch.conf +- id: pkgselect_action + module: contextualprocess + config: pkgselect_context.conf +- id: pkgselect_snap_action + module: contextualprocess + config: pkgselect_snap_context.conf - id: oemprep module: shellprocess config: shellprocess_oemprep.conf @@ -53,11 +59,10 @@ sequence: - displaymanager - networkcfg - hwclock + - contextualprocess@before_bootloader_mkdirs - automirror - - pkgselectprocess - dracutlukscfg - dracut - - shellprocess@copy_vmlinuz_shellprocess - shellprocess@bug-LP#1829805 - shellprocess@fixconkeys_part1 - shellprocess@fixconkeys_part2 @@ -65,6 +70,9 @@ sequence: - contextualprocess@before_bootloader - grubcfg - bootloader + - packages + - contextualprocess@pkgselect_action + - contextualprocess@pkgselect_snap_action - shellprocess@logs - umount - show: diff --git a/ubuntuunity/modules/packages.conf b/ubuntuunity/modules/packages.conf new file mode 100644 index 0000000..8ec8c47 --- /dev/null +++ b/ubuntuunity/modules/packages.conf @@ -0,0 +1,15 @@ +update_db: true +backend: apt +operations: + - remove: + - "^live-*" + - calamares-settings-ubuntu-unity + - calamares + - cifs-utils + - try_install: + - language-pack-$LOCALE + - language-pack-gnome-$LOCALE + - language-pack-kde-$LOCALE + - hunspell-$LOCALE + - libreoffice-help-$LOCALE + - libreoffice-l10n-$LOCALE diff --git a/ubuntuunity/modules/pkgselect.conf b/ubuntuunity/modules/pkgselect.conf deleted file mode 100644 index 2533796..0000000 --- a/ubuntuunity/modules/pkgselect.conf +++ /dev/null @@ -1,48 +0,0 @@ ---- -packages: - additional_packages: - - id: "element-desktop" - name: "Element" - description: "Matrix-based end-to-end encrypted messenger and secure collaboration app." - snap: true - - id: "thunderbird" - name: "Thunderbird" - description: "Email, newsfeed, chat, and calendaring client." - snap: true - - id: "krita" - name: "Krita" - description: "Graphics editor designed primarily for digital art and 2D animation." - snap: true - minimal_remove_packages: - - snapd aisleriot - - atril - - cheese - - simple-scan - - gdebi - - gparted - - "*kvantum*" - - "libreoffice*" - - gnome-mahjongg - - gnome-mines - - remmina - - rhythmbox - - shotwell - - gnome-sudoku - - synaptic - - transmission-gtk - - vlc - - stacer - installer_remove_packages: - - "^live-*" - - calamares-settings-ubuntu-unity - - calamares - - cifs-utils - regular_install_packages: - - language-pack-$LOCALE - - language-pack-gnome-$LOCALE - - language-pack-kde-$LOCALE - - hunspell-$LOCALE - - libreoffice-help-$LOCALE - - libreoffice-l10n-$LOCALE - refresh_snaps: - - "firefox" diff --git a/ubuntuunity/modules/pkgselect_context.conf b/ubuntuunity/modules/pkgselect_context.conf new file mode 100644 index 0000000..a0718db --- /dev/null +++ b/ubuntuunity/modules/pkgselect_context.conf @@ -0,0 +1,19 @@ +--- +dontChroot: false +timeout: 10800 +"packages.minimalButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get -y --purge remove snapd aisleriot atril cheese simple-scan gdebi gparted *kvantum* libreoffice* gnome-mahjongg gnome-mines remmina rhythmbox shotwell gnome-sudoku synaptic transmission-gtk vlc stacer" + - "apt-get -y autoremove" +"packages.partyButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install ubuntu-restricted-addons unrar" +"packages.updatesButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confnew' full-upgrade" +"packages.virtmanagerButton": + true: + - "DEBIAN_FRONTEND=noninteractive apt-get update" + - "DEBIAN_FRONTEND=noninteractive apt-get -y install virt-manager" diff --git a/ubuntuunity/modules/pkgselect_snap_context.conf b/ubuntuunity/modules/pkgselect_snap_context.conf new file mode 100644 index 0000000..d75cd6c --- /dev/null +++ b/ubuntuunity/modules/pkgselect_snap_context.conf @@ -0,0 +1,9 @@ +--- +dontChroot: true +timeout: 10800 +"packages.elementButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed element-desktop" +"packages.kritaButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed krita" +"packages.thunderbirdButton": + true: "snap-seed-glue-emb --seed ${ROOT}/var/lib/snapd/seed thunderbird" diff --git a/ubuntuunity/oem/calamares-launch-oem b/ubuntuunity/oem/calamares-launch-oem index 02cbff8..a5d6b74 100755 --- a/ubuntuunity/oem/calamares-launch-oem +++ b/ubuntuunity/oem/calamares-launch-oem @@ -26,7 +26,7 @@ if zenity --question --text="${msg}"; then sed -i "/- welcome$/a \ \ - oemid" /etc/calamares/settings.conf; # Enable OEM prep module - sed -i "/- pkgselectprocess$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; + sed -i "/- packages$/a \ \ - shellprocess@oemprep" /etc/calamares/settings.conf; # Fix OEM UID sed -i "/- shellprocess@oemprep$/a \ \ - shellprocess@fix-oem-uid" /etc/calamares/settings.conf; diff --git a/ubuntuunity/settings.conf b/ubuntuunity/settings.conf index 25748dd..5dcd994 100644 --- a/ubuntuunity/settings.conf +++ b/ubuntuunity/settings.conf @@ -2,12 +2,12 @@ modules-search: [ local ] instances: +- id: before_bootloader_mkdirs + module: contextualprocess + config: before_bootloader_mkdirs_context.conf - id: before_bootloader module: contextualprocess config: before_bootloader_context.conf -- id: copy_vmlinuz_shellprocess - module: shellprocess - config: copy_vmlinuz_shellprocess.conf - id: logs module: shellprocess config: shellprocess_logs.conf @@ -17,6 +17,12 @@ instances: - id: add386arch module: shellprocess config: shellprocess_add386arch.conf +- id: pkgselect_action + module: contextualprocess + config: pkgselect_context.conf +- id: pkgselect_snap_action + module: contextualprocess + config: pkgselect_snap_context.conf - id: oemprep module: shellprocess config: shellprocess_oemprep.conf @@ -53,7 +59,7 @@ sequence: - displaymanager - networkcfg - hwclock - - shellprocess@copy_vmlinuz_shellprocess + - contextualprocess@before_bootloader_mkdirs - shellprocess@bug-LP#1829805 - shellprocess@fixconkeys_part1 - shellprocess@fixconkeys_part2 @@ -64,7 +70,9 @@ sequence: - bootloader - shellprocess@add386arch - automirror - - pkgselectprocess + - packages + - contextualprocess@pkgselect_action + - contextualprocess@pkgselect_snap_action - shellprocess@logs - umount - show: