mirror of
https://github.com/parchlinux/calamares.git
synced 2025-02-23 10:25:45 -05:00
Merge pull request #1879 from dalto8/pkgchooser-netinstall
Allow the packagechooser module to modify the netinstall module
This commit is contained in:
commit
6a2e80a0b7
10 changed files with 263 additions and 4 deletions
|
@ -15,6 +15,7 @@
|
|||
#include "PackageModel.h"
|
||||
#include "ui_page_netinst.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "network/Manager.h"
|
||||
|
@ -62,4 +63,19 @@ void
|
|||
NetInstallPage::onActivate()
|
||||
{
|
||||
ui->groupswidget->setFocus();
|
||||
|
||||
// The NetInstallSelect global storage value can be used to make additional items selected by default
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
const QStringList selectNames = gs->value( "netinstallSelect" ).toStringList();
|
||||
if ( !selectNames.isEmpty() )
|
||||
{
|
||||
m_config->model()->setSelections( selectNames );
|
||||
}
|
||||
|
||||
// If NetInstallAdd is found in global storage, add those items to the tree
|
||||
const QVariantList groups = gs->value( "netinstallAdd" ).toList();
|
||||
if ( !groups.isEmpty() )
|
||||
{
|
||||
m_config->model()->appendModelData( groups );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,53 @@
|
|||
#include "utils/Variant.h"
|
||||
#include "utils/Yaml.h"
|
||||
|
||||
/** @brief Appends groups to the tree
|
||||
*
|
||||
* Uses the data from @p groupList to add elements to the
|
||||
* existing tree that m_rootItem points to. If m_rootItem
|
||||
* is not valid, it does nothing
|
||||
*
|
||||
* Before adding anything to the model, it ensures that there
|
||||
* is no existing data from the same source. If there is, that
|
||||
* data is pruned first
|
||||
*
|
||||
*/
|
||||
static void
|
||||
setSelections2( const QStringList& selectNames, PackageTreeItem* item )
|
||||
{
|
||||
for ( int i = 0; i < item->childCount(); i++ )
|
||||
{
|
||||
auto* child = item->child( i );
|
||||
setSelections2( selectNames, child );
|
||||
}
|
||||
if ( item->isGroup() && selectNames.contains( item->name() ) )
|
||||
{
|
||||
item->setSelected( Qt::CheckState::Checked );
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Collects all the "source" values from @p groupList
|
||||
*
|
||||
* Iterates over @p groupList and returns all nonempty "source"
|
||||
* values from the maps.
|
||||
*
|
||||
*/
|
||||
static QStringList
|
||||
collectSources( const QVariantList& groupList )
|
||||
{
|
||||
QStringList sources;
|
||||
for ( const QVariant& group : groupList )
|
||||
{
|
||||
QVariantMap groupMap = group.toMap();
|
||||
if ( !groupMap[ "source" ].toString().isEmpty() )
|
||||
{
|
||||
sources.append( groupMap[ "source" ].toString() );
|
||||
}
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
PackageModel::PackageModel( QObject* parent )
|
||||
: QAbstractItemModel( parent )
|
||||
{
|
||||
|
@ -170,6 +217,15 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
void
|
||||
PackageModel::setSelections( const QStringList& selectNames )
|
||||
{
|
||||
if ( m_rootItem )
|
||||
{
|
||||
setSelections2( selectNames, m_rootItem );
|
||||
}
|
||||
}
|
||||
|
||||
PackageTreeItem::List
|
||||
PackageModel::getPackages() const
|
||||
{
|
||||
|
@ -303,9 +359,43 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa
|
|||
void
|
||||
PackageModel::setupModelData( const QVariantList& l )
|
||||
{
|
||||
emit beginResetModel();
|
||||
Q_EMIT beginResetModel();
|
||||
delete m_rootItem;
|
||||
m_rootItem = new PackageTreeItem();
|
||||
setupModelData( l, m_rootItem );
|
||||
emit endResetModel();
|
||||
Q_EMIT endResetModel();
|
||||
}
|
||||
|
||||
void
|
||||
PackageModel::appendModelData( const QVariantList& groupList )
|
||||
{
|
||||
if ( m_rootItem )
|
||||
{
|
||||
Q_EMIT beginResetModel();
|
||||
|
||||
const QStringList sources = collectSources( groupList );
|
||||
|
||||
if ( !sources.isEmpty() )
|
||||
{
|
||||
// Prune any existing data from the same source
|
||||
QList< int > removeList;
|
||||
for ( int i = 0; i < m_rootItem->childCount(); i++ )
|
||||
{
|
||||
PackageTreeItem* child = m_rootItem->child( i );
|
||||
if ( sources.contains( child->source() ) )
|
||||
{
|
||||
removeList.insert( 0, i );
|
||||
}
|
||||
}
|
||||
for ( const int& item : qAsConst( removeList ) )
|
||||
{
|
||||
m_rootItem->removeChild( item );
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new data to the model
|
||||
setupModelData( groupList, m_rootItem );
|
||||
|
||||
Q_EMIT endResetModel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,9 +54,22 @@ public:
|
|||
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||
int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||
|
||||
/** @brief Sets the checked flag on matching groups in the tree
|
||||
*
|
||||
* Recursively traverses the tree pointed to by m_rootItem and
|
||||
* checks if a group name matches any of the items in @p selectNames.
|
||||
* If a match is found, set check the box for that group and it's children.
|
||||
*
|
||||
* Individual packages will not be matched.
|
||||
*
|
||||
*/
|
||||
void setSelections(const QStringList &selectNames );
|
||||
|
||||
PackageTreeItem::List getPackages() const;
|
||||
PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const;
|
||||
|
||||
void appendModelData(const QVariantList& groupList);
|
||||
|
||||
private:
|
||||
friend class ItemTests;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ PackageTreeItem::PackageTreeItem( const QVariantMap& groupData, GroupTag&& paren
|
|||
, m_description( CalamaresUtils::getString( groupData, "description" ) )
|
||||
, m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) )
|
||||
, m_postScript( CalamaresUtils::getString( groupData, "post-install" ) )
|
||||
, m_source( CalamaresUtils::getString( groupData, "source" ) )
|
||||
, m_isGroup( true )
|
||||
, m_isCritical( parentCriticality( groupData, parent.parent ) )
|
||||
, m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) )
|
||||
|
@ -248,6 +249,19 @@ PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected )
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageTreeItem::removeChild( int row )
|
||||
{
|
||||
if ( row < m_childItems.count() )
|
||||
{
|
||||
m_childItems.removeAt( row );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Attempt to remove invalid child in removeChild() at row " << row;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PackageTreeItem::type() const
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
QString description() const { return m_description; }
|
||||
QString preScript() const { return m_preScript; }
|
||||
QString postScript() const { return m_postScript; }
|
||||
QString source() const { return m_source; }
|
||||
|
||||
/** @brief Is this item a group-item?
|
||||
*
|
||||
|
@ -124,6 +125,8 @@ public:
|
|||
void setSelected( Qt::CheckState isSelected );
|
||||
void setChildrenSelected( Qt::CheckState isSelected );
|
||||
|
||||
void removeChild( int row );
|
||||
|
||||
/** @brief Update selectedness based on the children's states
|
||||
*
|
||||
* This only makes sense for groups, which might have packages
|
||||
|
@ -157,6 +160,7 @@ private:
|
|||
QString m_description;
|
||||
QString m_preScript;
|
||||
QString m_postScript;
|
||||
QString m_source;
|
||||
bool m_isGroup = false;
|
||||
bool m_isCritical = false;
|
||||
bool m_isHidden = false;
|
||||
|
|
|
@ -27,6 +27,29 @@
|
|||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
/** @brief This removes any values from @p groups that match @p source
|
||||
*
|
||||
* This is used to remove duplicates from the netinstallAdd structure
|
||||
* It iterates over @p groups and for each map in the list, if the
|
||||
* "source" element matches @p source, it is removed from the returned
|
||||
* list.
|
||||
*/
|
||||
static QVariantList
|
||||
pruneNetinstallAdd( const QString& source, const QVariant& groups )
|
||||
{
|
||||
QVariantList newGroupList;
|
||||
const QVariantList groupList = groups.toList();
|
||||
for ( const QVariant& group : groupList )
|
||||
{
|
||||
QVariantMap groupMap = group.toMap();
|
||||
if ( groupMap.value( "source", "" ).toString() != source )
|
||||
{
|
||||
newGroupList.append( groupMap );
|
||||
}
|
||||
}
|
||||
return newGroupList;
|
||||
}
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >&
|
||||
packageChooserModeNames()
|
||||
{
|
||||
|
@ -55,6 +78,8 @@ PackageChooserMethodNames()
|
|||
{ "custom", PackageChooserMethod::Legacy },
|
||||
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||
{ "packages", PackageChooserMethod::Packages },
|
||||
{ "netinstall-add", PackageChooserMethod::NetAdd },
|
||||
{ "netinstall-select", PackageChooserMethod::NetSelect },
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
@ -121,6 +146,47 @@ Config::updateGlobalStorage( const QStringList& selected ) const
|
|||
CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
||||
}
|
||||
else if ( m_method == PackageChooserMethod::NetAdd )
|
||||
{
|
||||
QVariantList netinstallDataList = m_model->getNetinstallDataForNames( selected );
|
||||
if ( netinstallDataList.isEmpty() )
|
||||
{
|
||||
cWarning() << "No netinstall information found for " << selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
if ( gs->contains( "netinstallAdd" ) )
|
||||
{
|
||||
netinstallDataList
|
||||
+= pruneNetinstallAdd( QStringLiteral( "packageChooser" ), gs->value( "netinstallAdd" ) );
|
||||
}
|
||||
gs->insert( "netinstallAdd", netinstallDataList );
|
||||
}
|
||||
}
|
||||
else if ( m_method == PackageChooserMethod::NetSelect )
|
||||
{
|
||||
cDebug() << m_defaultId << "groups to select in netinstall" << selected;
|
||||
QStringList newSelected = selected;
|
||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
|
||||
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||
if ( gs->contains( "netinstallSelect" ) )
|
||||
{
|
||||
auto selectedOrig = gs->value( "netinstallSelect" );
|
||||
if ( selectedOrig.canConvert( QVariant::StringList ) )
|
||||
{
|
||||
newSelected += selectedOrig.toStringList();
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Invalid NetinstallSelect data in global storage. Earlier selections purged";
|
||||
}
|
||||
gs->remove( "netinstallSelect" );
|
||||
}
|
||||
gs->insert( "netinstallSelect", newSelected );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||
|
|
|
@ -33,6 +33,8 @@ enum class PackageChooserMethod
|
|||
{
|
||||
Legacy, // use contextualprocess or other custom
|
||||
Packages, // use the packages module
|
||||
NetAdd, // adds packages to the netinstall module
|
||||
NetSelect, // makes selections in the netinstall module
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||
|
|
|
@ -15,6 +15,16 @@
|
|||
|
||||
#include <QFileInfo>
|
||||
|
||||
/** @brief A wrapper for CalamaresUtils::getSubMap that excludes the success param
|
||||
*/
|
||||
static QVariantMap
|
||||
getSubMap( const QVariantMap& map, const QString& key )
|
||||
{
|
||||
bool success;
|
||||
|
||||
return CalamaresUtils::getSubMap( map, key, success );
|
||||
}
|
||||
|
||||
static QPixmap
|
||||
loadScreenshot( const QString& path )
|
||||
{
|
||||
|
@ -51,12 +61,13 @@ PackageItem::PackageItem( const QString& a_id,
|
|||
{
|
||||
}
|
||||
|
||||
PackageItem::PackageItem::PackageItem( const QVariantMap& item_map )
|
||||
PackageItem::PackageItem( const QVariantMap& item_map )
|
||||
: id( CalamaresUtils::getString( item_map, "id" ) )
|
||||
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
||||
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
||||
, screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) )
|
||||
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
||||
, netinstallData( getSubMap( item_map, "netinstall" ) )
|
||||
{
|
||||
if ( name.isEmpty() && id.isEmpty() )
|
||||
{
|
||||
|
@ -125,6 +136,25 @@ PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
|||
return l;
|
||||
}
|
||||
|
||||
QVariantList
|
||||
PackageListModel::getNetinstallDataForNames( const QStringList& ids ) const
|
||||
{
|
||||
QVariantList l;
|
||||
for ( auto& p : m_packages )
|
||||
{
|
||||
if ( ids.contains( p.id ) )
|
||||
{
|
||||
if ( !p.netinstallData.isEmpty() )
|
||||
{
|
||||
QVariantMap newData = p.netinstallData;
|
||||
newData[ "source" ] = QStringLiteral( "packageChooser" );
|
||||
l.append( newData );
|
||||
}
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ struct PackageItem
|
|||
CalamaresUtils::Locale::TranslatedString description;
|
||||
QPixmap screenshot;
|
||||
QStringList packageNames;
|
||||
QVariantMap netinstallData;
|
||||
|
||||
/// @brief Create blank PackageItem
|
||||
PackageItem();
|
||||
|
@ -111,6 +112,14 @@ public:
|
|||
*/
|
||||
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
||||
|
||||
/** @brief Does a name lookup (based on id) and returns the netinstall data
|
||||
*
|
||||
* If there is a package with an id in @p ids, returns their netinstall data
|
||||
*
|
||||
* returns a list of netinstall data or an emply list if none is found
|
||||
*/
|
||||
QVariantList getNetinstallDataForNames( const QStringList& ids ) const;
|
||||
|
||||
enum Roles : int
|
||||
{
|
||||
NameRole = Qt::DisplayRole,
|
||||
|
|
|
@ -33,6 +33,15 @@ mode: required
|
|||
# in the `exec` section. These package settings will then be handed
|
||||
# off to whatever package manager is configured there.
|
||||
#
|
||||
# - "netinstall-select"
|
||||
# When this is set, the id(s) selected are passed to the netinstall module.
|
||||
# Any id that matches a group name in that module is set to checked
|
||||
#
|
||||
# - "netinstall-add"
|
||||
# With this method, the packagechooser module is used to add groups to the
|
||||
# netinstall module. For this to hav=e any effect. You must set netinstall,
|
||||
# which is described below.
|
||||
#
|
||||
# There is no need to put this module in the `exec` section. There
|
||||
# are no jobs that this module provides. You should put **other**
|
||||
# modules, either *contextualprocess* or *packages* or some custom
|
||||
|
@ -101,13 +110,19 @@ labels:
|
|||
# an additional attempt is made to load the image from the **branding**
|
||||
# directory.
|
||||
#
|
||||
# The following field is **optional** for an item:
|
||||
# The following fields are **optional** for an item:
|
||||
#
|
||||
# - *packages* :
|
||||
# List of package names for the product. If using the *method*
|
||||
# "packages", consider this item mandatory (because otherwise
|
||||
# selecting the item would install no packages).
|
||||
#
|
||||
# - *netinstall* :
|
||||
# The data in this field should follow the format of a group
|
||||
# from the netinstall module documented in
|
||||
# src/modules/netinstall/netinstall.conf. This is only used
|
||||
# when method is set to "netinstall-add"
|
||||
#
|
||||
# # AppData Items #
|
||||
#
|
||||
# For data provided by AppData XML: the item has an *appdata*
|
||||
|
|
Loading…
Add table
Reference in a new issue