[merge] upstream
This commit is contained in:
commit
90ee4cdb4c
13
CHANGES
13
CHANGES
@ -10,9 +10,11 @@ website will have to do for older versions.
|
||||
# 3.2.40 (unreleased) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Anubhav Choudhary (SoK success!)
|
||||
- Erik Dubois
|
||||
- Jerrod Frost (new contributor! welcome!)
|
||||
- Joe Kamprad
|
||||
- Lisa Vitolo
|
||||
- Lisa Vitolo (blast from the past!)
|
||||
|
||||
## Core ##
|
||||
- The CMake modules for consumption by external modules (e.g. the
|
||||
@ -23,11 +25,20 @@ This release contains contributions from (alphabetically by first name):
|
||||
libcalamares to systematically mark filesystem (types) as "in use"
|
||||
or not. This, in turn, means that modules can depend on that information
|
||||
for other work (e.g. removing drivers for unused filesystems). #1635
|
||||
- The "upload log file" now has a configurable log-file-size. (Thanks Anubhav)
|
||||
|
||||
## Modules ##
|
||||
- *displaymanager* example configuration has been shuffled around a bit,
|
||||
for better results when the live image is running XFCE. Also lists
|
||||
more potential display managers. #1205 (Thanks Erik)
|
||||
- The *netinstall* module can now fall back to alternative URLs when
|
||||
loading groups data. The first URL to yield a non-empty groups
|
||||
collection is accepted. No changes are needed in the configuration. #1673
|
||||
- *packagechooser* can now integrate with the *packages* module; that
|
||||
means you can specify package names to install for a given selection,
|
||||
and the regular package-installation mechanism will take care of it.
|
||||
Legacy configurations that use *contextualprocess* are still supported.
|
||||
See the `packagechooser.conf` file for details. #1550
|
||||
- A long-neglected pull request from Lisa Vitolo for the *partition*
|
||||
module -- allowing to set filesystem labels during manual partitioning --
|
||||
has been revived and merged.
|
||||
|
@ -220,13 +220,19 @@ slideshowAPI: 2
|
||||
|
||||
|
||||
# These options are to customize online uploading of logs to pastebins:
|
||||
# - type : Defines the kind of pastebin service to be used. Currently
|
||||
# it accepts two values:
|
||||
# - none : disables the pastebin functionality
|
||||
# - fiche : use fiche pastebin server
|
||||
# - url : Defines the address of pastebin service to be used.
|
||||
# Takes string as input. Important bits are the host and port,
|
||||
# the scheme is not used.
|
||||
# - type : Defines the kind of pastebin service to be used. Currently
|
||||
# it accepts two values:
|
||||
# - none : disables the pastebin functionality
|
||||
# - fiche : use fiche pastebin server
|
||||
# - url : Defines the address of pastebin service to be used.
|
||||
# Takes string as input. Important bits are the host and port,
|
||||
# the scheme is not used.
|
||||
# - sizeLimit : Defines maximum size limit (in KiB) of log file to be pasted.
|
||||
# Takes integer as input. If < 0, no limit will be forced,
|
||||
# else only last (approximately) 'n' KiB of log file will be pasted.
|
||||
# Please note that upload size may be slightly over the limit (due
|
||||
# to last minute logging), so provide a suitable value.
|
||||
uploadServer :
|
||||
type : "fiche"
|
||||
url : "http://termbin.com:9999"
|
||||
sizeLimit : -1
|
||||
|
@ -215,10 +215,49 @@ calamares_add_test(
|
||||
${geoip_src}
|
||||
)
|
||||
|
||||
function ( calamares_qrc_translations basename )
|
||||
set( NAME ${ARGV0} )
|
||||
set( options "" )
|
||||
set( oneValueArgs SUBDIRECTORY OUTPUT_VARIABLE )
|
||||
set( multiValueArgs LANGUAGES )
|
||||
cmake_parse_arguments( _qrt "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
|
||||
if( NOT _qrt_OUTPUT_VARIABLE )
|
||||
set( _qrt_OUTPUT_VARIABLE "qrc_translations_${basename}" )
|
||||
endif()
|
||||
|
||||
set( translations_qrc_infile ${CMAKE_CURRENT_BINARY_DIR}/${basename}.qrc )
|
||||
set( translations_qrc_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${basename}.cxx )
|
||||
|
||||
# Must use this variable name because of the @ substitution
|
||||
set( calamares_i18n_qrc_content "" )
|
||||
set( calamares_i18n_ts_filelist "" )
|
||||
foreach( lang ${_qrt_LANGUAGES} )
|
||||
string( APPEND calamares_i18n_qrc_content "<file>${basename}_${lang}.qm</file>" )
|
||||
list( APPEND calamares_i18n_ts_filelist "${CMAKE_CURRENT_SOURCE_DIR}/${_qrt_SUBDIRECTORY}/${basename}_${lang}.ts" )
|
||||
endforeach()
|
||||
|
||||
configure_file( ${CMAKE_SOURCE_DIR}/lang/calamares_i18n.qrc.in ${translations_qrc_infile} @ONLY )
|
||||
qt5_add_translation(QM_FILES ${calamares_i18n_ts_filelist})
|
||||
|
||||
# Run the resource compiler (rcc_options should already be set)
|
||||
add_custom_command(
|
||||
OUTPUT ${translations_qrc_outfile}
|
||||
COMMAND "${Qt5Core_RCC_EXECUTABLE}"
|
||||
ARGS ${rcc_options} --format-version 1 -name ${basename} -o ${translations_qrc_outfile} ${translations_qrc_infile}
|
||||
MAIN_DEPENDENCY ${translations_qrc_infile}
|
||||
DEPENDS ${QM_FILES}
|
||||
)
|
||||
|
||||
set( ${_qrt_OUTPUT_VARIABLE} ${translations_qrc_outfile} PARENT_SCOPE )
|
||||
endfunction()
|
||||
|
||||
calamares_qrc_translations( localetest OUTPUT_VARIABLE localetest_qrc SUBDIRECTORY testdata LANGUAGES nl )
|
||||
calamares_add_test(
|
||||
libcalamareslocaletest
|
||||
SOURCES
|
||||
locale/Tests.cpp
|
||||
${localetest_qrc}
|
||||
)
|
||||
|
||||
calamares_add_test(
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "CalamaresVersion.h"
|
||||
#include "GlobalStorage.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
@ -33,6 +34,7 @@ private Q_SLOTS:
|
||||
void testTranslatableLanguages();
|
||||
void testTranslatableConfig1();
|
||||
void testTranslatableConfig2();
|
||||
void testTranslatableConfigContext();
|
||||
void testLanguageScripts();
|
||||
|
||||
void testEsperanto();
|
||||
@ -246,6 +248,32 @@ LocaleTests::testTranslatableConfig2()
|
||||
QCOMPARE( ts3.count(), 1 ); // The empty string
|
||||
}
|
||||
|
||||
void
|
||||
LocaleTests::testTranslatableConfigContext()
|
||||
{
|
||||
using TS = CalamaresUtils::Locale::TranslatedString;
|
||||
|
||||
const QString original( "Quit" );
|
||||
TS quitUntranslated( original );
|
||||
TS quitTranslated( original, metaObject()->className() );
|
||||
|
||||
QCOMPARE( quitUntranslated.get(), original );
|
||||
QCOMPARE( quitTranslated.get(), original );
|
||||
|
||||
// Load translation data from QRC
|
||||
QVERIFY( QFile::exists( ":/lang/localetest_nl.qm" ) );
|
||||
QTranslator t;
|
||||
QVERIFY( t.load( QString( ":/lang/localetest_nl" ) ) );
|
||||
QCoreApplication::installTranslator( &t );
|
||||
|
||||
// Translation doesn't affect the one without context
|
||||
QCOMPARE( quitUntranslated.get(), original );
|
||||
// But the translation **does** affect this class' context
|
||||
QCOMPARE( quitTranslated.get(), QStringLiteral( "Ophouden" ) );
|
||||
QCOMPARE( tr( "Quit" ), QStringLiteral( "Ophouden" ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocaleTests::testRegions()
|
||||
{
|
||||
|
@ -23,9 +23,15 @@ namespace CalamaresUtils
|
||||
{
|
||||
namespace Locale
|
||||
{
|
||||
TranslatedString::TranslatedString( const QString& string )
|
||||
TranslatedString::TranslatedString( const QString& key, const char* context )
|
||||
: m_context( context )
|
||||
{
|
||||
m_strings[ QString() ] = key;
|
||||
}
|
||||
|
||||
TranslatedString::TranslatedString( const QString& string )
|
||||
: TranslatedString( string, nullptr )
|
||||
{
|
||||
m_strings[ QString() ] = string;
|
||||
}
|
||||
|
||||
TranslatedString::TranslatedString( const QVariantMap& map, const QString& key, const char* context )
|
||||
|
@ -50,11 +50,23 @@ public:
|
||||
* metaObject()->className() as context (from a QObject based class)
|
||||
* to give the TranslatedString the same context as other calls
|
||||
* to tr() within that class.
|
||||
*
|
||||
* The @p context, if any, should point to static data; it is
|
||||
* **not** owned by the TranslatedString.
|
||||
*/
|
||||
TranslatedString( const QVariantMap& map, const QString& key, const char* context = nullptr );
|
||||
/** @brief Not-actually-translated string.
|
||||
*/
|
||||
TranslatedString( const QString& string );
|
||||
/** @brief Proxy for calling QObject::tr()
|
||||
*
|
||||
* This is like the two constructors above, with an empty map an a
|
||||
* non-null context. It will end up calling tr() with that context.
|
||||
*
|
||||
* The @p context, if any, should point to static data; it is
|
||||
* **not** owned by the TranslatedString.
|
||||
*/
|
||||
TranslatedString( const QString& key, const char* context );
|
||||
/// @brief Empty string
|
||||
TranslatedString()
|
||||
: TranslatedString( QString() )
|
||||
|
@ -12,11 +12,11 @@
|
||||
#include "GlobalStorage.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
bool
|
||||
CalamaresUtils::Packages::setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
const Calamares::ModuleSystem::InstanceKey& module,
|
||||
const QVariantList& installPackages,
|
||||
const QVariantList& tryInstallPackages )
|
||||
static bool
|
||||
additions( Calamares::GlobalStorage* gs,
|
||||
const QString& key,
|
||||
const QVariantList& installPackages,
|
||||
const QVariantList& tryInstallPackages )
|
||||
{
|
||||
static const char PACKAGEOP[] = "packageOperations";
|
||||
|
||||
@ -25,8 +25,6 @@ CalamaresUtils::Packages::setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
QVariantList packageOperations = gs->contains( PACKAGEOP ) ? gs->value( PACKAGEOP ).toList() : QVariantList();
|
||||
cDebug() << "Existing package operations length" << packageOperations.length();
|
||||
|
||||
const QString key = module.toString();
|
||||
|
||||
// Clear out existing operations for this module, going backwards:
|
||||
// Sometimes we remove an item, and we don't want the index to
|
||||
// fall off the end of the list.
|
||||
@ -66,3 +64,25 @@ CalamaresUtils::Packages::setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CalamaresUtils::Packages::setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
const Calamares::ModuleSystem::InstanceKey& module,
|
||||
const QVariantList& installPackages,
|
||||
const QVariantList& tryInstallPackages )
|
||||
{
|
||||
return additions( gs, module.toString(), installPackages, tryInstallPackages );
|
||||
}
|
||||
|
||||
bool
|
||||
CalamaresUtils::Packages::setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
const Calamares::ModuleSystem::InstanceKey& module,
|
||||
const QStringList& installPackages )
|
||||
{
|
||||
QVariantList l;
|
||||
for ( const auto& s : installPackages )
|
||||
{
|
||||
l << s;
|
||||
}
|
||||
return additions( gs, module.toString(), l, QVariantList() );
|
||||
}
|
||||
|
@ -28,6 +28,14 @@ bool setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
const Calamares::ModuleSystem::InstanceKey& module,
|
||||
const QVariantList& installPackages,
|
||||
const QVariantList& tryInstallPackages );
|
||||
/** @brief Sets the install-packages GS keys for the given module
|
||||
*
|
||||
* This replaces previously-set install-packages lists. Use this with
|
||||
* plain lists of package names. It does not support try-install.
|
||||
*/
|
||||
bool setGSPackageAdditions( Calamares::GlobalStorage* gs,
|
||||
const Calamares::ModuleSystem::InstanceKey& module,
|
||||
const QStringList& installPackages );
|
||||
// void setGSPackageRemovals( const Calamares::ModuleSystem::InstanceKey& key, const QVariantList& removePackages );
|
||||
} // namespace Packages
|
||||
} // namespace CalamaresUtils
|
||||
|
@ -24,7 +24,15 @@ private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void testEmpty();
|
||||
void testAdd_data();
|
||||
/** @brief Test various add calls, for a "clean" GS
|
||||
*
|
||||
* Check that adding through the variant- and the stringlist-API
|
||||
* does the same thing.
|
||||
*/
|
||||
void testAdd();
|
||||
/// Test replacement and mixing string-list with variant calls
|
||||
void testAddMixed();
|
||||
};
|
||||
|
||||
void
|
||||
@ -46,38 +54,179 @@ PackagesTests::testEmpty()
|
||||
// Adding nothing at all does nothing
|
||||
QVERIFY( !CalamaresUtils::Packages::setGSPackageAdditions( &gs, k, QVariantList(), QVariantList() ) );
|
||||
QVERIFY( !gs.contains( topKey ) );
|
||||
|
||||
QVERIFY( !CalamaresUtils::Packages::setGSPackageAdditions( &gs, k, QStringList() ) );
|
||||
QVERIFY( !gs.contains( topKey ) );
|
||||
}
|
||||
|
||||
void
|
||||
PackagesTests::testAdd_data()
|
||||
{
|
||||
QTest::addColumn< QStringList >( "packages" );
|
||||
|
||||
QTest::newRow( "one" ) << QStringList { QString( "vim" ) };
|
||||
QTest::newRow( "two" ) << QStringList { QString( "vim" ), QString( "emacs" ) };
|
||||
QTest::newRow( "one-again" ) << QStringList { QString( "nano" ) };
|
||||
QTest::newRow( "six" ) << QStringList { QString( "vim" ), QString( "emacs" ), QString( "nano" ),
|
||||
QString( "kate" ), QString( "gedit" ), QString( "sublime" ) };
|
||||
// There is no "de-duplication" so this will insert "cim" twice
|
||||
QTest::newRow( "dups" ) << QStringList { QString( "cim" ), QString( "vim" ), QString( "cim" ) };
|
||||
}
|
||||
|
||||
void
|
||||
PackagesTests::testAdd()
|
||||
{
|
||||
Calamares::GlobalStorage gs;
|
||||
|
||||
const QString extraEditor( "notepad++" );
|
||||
const QString topKey( "packageOperations" );
|
||||
Calamares::ModuleSystem::InstanceKey k( "this", "that" );
|
||||
Calamares::ModuleSystem::InstanceKey otherInstance( "this", "other" );
|
||||
|
||||
QVERIFY( !gs.contains( topKey ) );
|
||||
QVERIFY(
|
||||
CalamaresUtils::Packages::setGSPackageAdditions( &gs, k, QVariantList { QString( "vim" ) }, QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 1 );
|
||||
cDebug() << op;
|
||||
QFETCH( QStringList, packages );
|
||||
QVERIFY( !packages.contains( extraEditor ) );
|
||||
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
&gs, k, QVariantList { QString( "vim" ), QString( "emacs" ) }, QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 2 );
|
||||
QCOMPARE( action[ "source" ].toString(), k.toString() );
|
||||
cDebug() << op;
|
||||
{
|
||||
QVERIFY( !gs.contains( topKey ) );
|
||||
QVERIFY(
|
||||
CalamaresUtils::Packages::setGSPackageAdditions( &gs, k, QVariant( packages ).toList(), QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), packages.length() );
|
||||
for ( const auto& s : qAsConst( packages ) )
|
||||
{
|
||||
QVERIFY( op.contains( s ) );
|
||||
}
|
||||
cDebug() << op;
|
||||
}
|
||||
{
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions( &gs, otherInstance, packages ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 2 ); // One for each instance key!
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
auto secondaction = actionList[ 1 ].toMap();
|
||||
auto op = action[ "install" ].toList();
|
||||
auto secondop = secondaction[ "install" ].toList();
|
||||
QCOMPARE( op, secondop );
|
||||
}
|
||||
|
||||
{
|
||||
// Replace one and expect differences
|
||||
packages << extraEditor;
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions( &gs, otherInstance, packages ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 2 ); // One for each instance key!
|
||||
for ( const auto& actionVariant : qAsConst( actionList ) )
|
||||
{
|
||||
auto action = actionVariant.toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
QVERIFY( action.contains( "source" ) );
|
||||
if ( action[ "source" ].toString() == otherInstance.toString() )
|
||||
{
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), packages.length() ); // changed from original length, though
|
||||
for ( const auto& s : qAsConst( packages ) )
|
||||
{
|
||||
QVERIFY( op.contains( s ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the "original" instance, so it's missing extraEditor
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), packages.length()-1 ); // changed from original length
|
||||
QVERIFY( !op.contains( extraEditor ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackagesTests::testAddMixed()
|
||||
{
|
||||
Calamares::GlobalStorage gs;
|
||||
|
||||
const QString extraEditor( "notepad++" );
|
||||
const QString topKey( "packageOperations" );
|
||||
Calamares::ModuleSystem::InstanceKey k( "this", "that" );
|
||||
Calamares::ModuleSystem::InstanceKey otherInstance( "this", "other" );
|
||||
|
||||
// Just one
|
||||
{
|
||||
QVERIFY( !gs.contains( topKey ) );
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
&gs, k, QVariantList { QString( "vim" ) }, QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 1 );
|
||||
QCOMPARE( op[ 0 ], QString( "vim" ) );
|
||||
cDebug() << op;
|
||||
}
|
||||
|
||||
// Replace with two packages
|
||||
{
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
&gs, k, QVariantList { QString( "vim" ), QString( "emacs" ) }, QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 2 );
|
||||
QCOMPARE( action[ "source" ].toString(), k.toString() );
|
||||
QVERIFY( op.contains( QString( "vim" ) ) );
|
||||
QVERIFY( op.contains( QString( "emacs" ) ) );
|
||||
cDebug() << op;
|
||||
}
|
||||
|
||||
// Replace with one (different) package
|
||||
{
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
&gs, k, QVariantList { QString( "nano" ) }, QVariantList() ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 1 );
|
||||
auto action = actionList[ 0 ].toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 1 );
|
||||
QCOMPARE( action[ "source" ].toString(), k.toString() );
|
||||
QCOMPARE( op[ 0 ], QString( "nano" ) );
|
||||
cDebug() << op;
|
||||
}
|
||||
|
||||
// Now we have two sources
|
||||
{
|
||||
QVERIFY( CalamaresUtils::Packages::setGSPackageAdditions( &gs, otherInstance, QStringList( extraEditor ) ) );
|
||||
QVERIFY( gs.contains( topKey ) );
|
||||
auto actionList = gs.value( topKey ).toList();
|
||||
QCOMPARE( actionList.length(), 2 );
|
||||
|
||||
for ( const auto& actionVariant : qAsConst( actionList ) )
|
||||
{
|
||||
auto action = actionVariant.toMap();
|
||||
QVERIFY( action.contains( "install" ) );
|
||||
QVERIFY( action.contains( "source" ) );
|
||||
if ( action[ "source" ].toString() == otherInstance.toString() )
|
||||
{
|
||||
auto op = action[ "install" ].toList();
|
||||
QCOMPARE( op.length(), 1 );
|
||||
QVERIFY(
|
||||
op.contains( action[ "source" ] == otherInstance.toString() ? extraEditor : QString( "nano" ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
15
src/libcalamares/testdata/localetest_nl.ts
vendored
Normal file
15
src/libcalamares/testdata/localetest_nl.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- SPDX-FileCopyrightText: no
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
<!DOCTYPE TS>
|
||||
<TS language="nl" version="2.1">
|
||||
<context>
|
||||
<name>LocaleTests</name>
|
||||
<message>
|
||||
<location filename="Tests.cpp" line="22"/>
|
||||
<source>Quit</source>
|
||||
<translation>Ophouden</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
@ -174,6 +174,22 @@ struct NamedEnumTable
|
||||
return table.begin()->second;
|
||||
}
|
||||
|
||||
/** @brief Find a name @p s in the table.
|
||||
*
|
||||
* Searches case-insensitively.
|
||||
*
|
||||
* If the name @p s is not found, the value @p d is returned as
|
||||
* a default. Otherwise the value corresponding to @p s is returned.
|
||||
* This is a shortcut over find() using a bool to distinguish
|
||||
* successful and unsuccesful lookups.
|
||||
*/
|
||||
enum_t find( const string_t& s, enum_t d ) const
|
||||
{
|
||||
bool ok = false;
|
||||
enum_t e = find( s, ok );
|
||||
return ok ? e : d;
|
||||
}
|
||||
|
||||
/** @brief Find a value @p s in the table and return its name.
|
||||
*
|
||||
* If @p s is an enum value in the table, return the corresponding
|
||||
|
@ -113,7 +113,7 @@ BrandingLoader::tryLoad( QTranslator* translator )
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "Branding using default, system locale not found:" << m_localeName;
|
||||
cDebug() << Logger::SubEntry << "Branding no translation for" << m_localeName << "using default (en)";
|
||||
// TODO: this loads something completely different
|
||||
return translator->load( m_prefix + "en" );
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "utils/ImageRegistry.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
#include "utils/Units.h"
|
||||
#include "utils/Yaml.h"
|
||||
|
||||
#include <QDir>
|
||||
@ -153,15 +154,18 @@ uploadServerFromMap( const QVariantMap& map )
|
||||
|
||||
QString typestring = map[ "type" ].toString();
|
||||
QString urlstring = map[ "url" ].toString();
|
||||
qint64 sizeLimitKiB = map[ "sizeLimit" ].toLongLong();
|
||||
|
||||
if ( typestring.isEmpty() || urlstring.isEmpty() )
|
||||
{
|
||||
return Branding::UploadServerInfo( Branding::UploadServerType::None, QUrl() );
|
||||
return Branding::UploadServerInfo( Branding::UploadServerType::None, QUrl(), 0 );
|
||||
}
|
||||
|
||||
bool bogus = false; // we don't care about type-name lookup success here
|
||||
return Branding::UploadServerInfo( names.find( typestring, bogus ),
|
||||
QUrl( urlstring, QUrl::ParsingMode::StrictMode ) );
|
||||
return Branding::UploadServerInfo(
|
||||
names.find( typestring, bogus ),
|
||||
QUrl( urlstring, QUrl::ParsingMode::StrictMode ),
|
||||
sizeLimitKiB >= 0 ? CalamaresUtils::KiBtoBytes( static_cast< unsigned long long >( sizeLimitKiB ) ) : -1 );
|
||||
}
|
||||
|
||||
/** @brief Load the @p map with strings from @p config
|
||||
|
@ -223,10 +223,11 @@ public:
|
||||
|
||||
/** @brief Upload server configuration
|
||||
*
|
||||
* This is both the type (which may be none, in which case the URL
|
||||
* is irrelevant and usually empty) and the URL for the upload.
|
||||
* This object has 3 items : the type (which may be none, in which case the URL
|
||||
* is irrelevant and usually empty), the URL for the upload and the size limit of upload
|
||||
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
|
||||
*/
|
||||
using UploadServerInfo = QPair< UploadServerType, QUrl >;
|
||||
using UploadServerInfo = std::tuple< UploadServerType, QUrl, qint64 >;
|
||||
UploadServerInfo uploadServer() const { return m_uploadServer; }
|
||||
|
||||
/**
|
||||
|
@ -143,8 +143,9 @@ ViewManager::insertViewStep( int before, ViewStep* step )
|
||||
void
|
||||
ViewManager::onInstallationFailed( const QString& message, const QString& details )
|
||||
{
|
||||
bool shouldOfferWebPaste
|
||||
= Calamares::Branding::instance()->uploadServer().first != Calamares::Branding::UploadServerType::None;
|
||||
bool shouldOfferWebPaste = std::get< 0 >( Calamares::Branding::instance()->uploadServer() )
|
||||
!= Calamares::Branding::UploadServerType::None
|
||||
and std::get< 2 >( Calamares::Branding::instance()->uploadServer() ) != 0;
|
||||
|
||||
cError() << "Installation failed:" << message;
|
||||
cDebug() << Logger::SubEntry << "- message:" << message;
|
||||
|
@ -30,8 +30,12 @@ using namespace CalamaresUtils::Units;
|
||||
* Returns an empty QByteArray() on any kind of error.
|
||||
*/
|
||||
STATICTEST QByteArray
|
||||
logFileContents()
|
||||
logFileContents( const qint64 sizeLimitBytes )
|
||||
{
|
||||
if ( sizeLimitBytes != -1 )
|
||||
{
|
||||
cDebug() << "Log upload size limit was limited to" << sizeLimitBytes << "bytes";
|
||||
}
|
||||
const QString name = Logger::logFile();
|
||||
QFile pasteSourceFile( name );
|
||||
if ( !pasteSourceFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
@ -39,12 +43,18 @@ logFileContents()
|
||||
cWarning() << "Could not open log file" << name;
|
||||
return QByteArray();
|
||||
}
|
||||
QFileInfo fi( pasteSourceFile );
|
||||
if ( fi.size() > 16_KiB )
|
||||
if ( sizeLimitBytes == -1 )
|
||||
{
|
||||
pasteSourceFile.seek( fi.size() - 16_KiB );
|
||||
return pasteSourceFile.readAll();
|
||||
}
|
||||
return pasteSourceFile.read( 16_KiB );
|
||||
QFileInfo fi( pasteSourceFile );
|
||||
if ( fi.size() > sizeLimitBytes )
|
||||
{
|
||||
cDebug() << "Only last" << sizeLimitBytes << "bytes of log file (sized" << fi.size() << "bytes) uploaded";
|
||||
fi.refresh();
|
||||
pasteSourceFile.seek( fi.size() - sizeLimitBytes );
|
||||
}
|
||||
return pasteSourceFile.read( sizeLimitBytes );
|
||||
}
|
||||
|
||||
|
||||
@ -101,7 +111,7 @@ ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* par
|
||||
QString
|
||||
CalamaresUtils::Paste::doLogUpload( QObject* parent )
|
||||
{
|
||||
auto [ type, serverUrl ] = Calamares::Branding::instance()->uploadServer();
|
||||
auto [ type, serverUrl, sizeLimitBytes ] = Calamares::Branding::instance()->uploadServer();
|
||||
if ( !serverUrl.isValid() )
|
||||
{
|
||||
cWarning() << "Upload configure with invalid URL";
|
||||
@ -113,7 +123,7 @@ CalamaresUtils::Paste::doLogUpload( QObject* parent )
|
||||
return QString();
|
||||
}
|
||||
|
||||
QByteArray pasteData = logFileContents();
|
||||
QByteArray pasteData = logFileContents( sizeLimitBytes );
|
||||
if ( pasteData.isEmpty() )
|
||||
{
|
||||
// An error has already been logged
|
||||
@ -165,6 +175,6 @@ CalamaresUtils::Paste::doLogUploadUI( QWidget* parent )
|
||||
bool
|
||||
CalamaresUtils::Paste::isEnabled()
|
||||
{
|
||||
auto [ type, serverUrl ] = Calamares::Branding::instance()->uploadServer();
|
||||
auto [ type, serverUrl, sizeLimitBytes ] = Calamares::Branding::instance()->uploadServer();
|
||||
return type != Calamares::Branding::UploadServerType::None;
|
||||
}
|
||||
|
@ -10,13 +10,14 @@
|
||||
*/
|
||||
|
||||
#include "Paste.h"
|
||||
#include "network/Manager.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
extern QByteArray logFileContents();
|
||||
extern QByteArray logFileContents( qint64 sizeLimitBytes );
|
||||
extern QString ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* parent );
|
||||
|
||||
class TestPaste : public QObject
|
||||
@ -30,6 +31,7 @@ public:
|
||||
private Q_SLOTS:
|
||||
void testGetLogFile();
|
||||
void testFichePaste();
|
||||
void testUploadSize();
|
||||
};
|
||||
|
||||
void
|
||||
@ -37,14 +39,18 @@ TestPaste::testGetLogFile()
|
||||
{
|
||||
QFile::remove( Logger::logFile() );
|
||||
// This test assumes nothing **else** has set up logging yet
|
||||
QByteArray contentsOfLogfileBefore = logFileContents();
|
||||
QVERIFY( contentsOfLogfileBefore.isEmpty() );
|
||||
QByteArray logLimitedBefore = logFileContents( 16 );
|
||||
QVERIFY( logLimitedBefore.isEmpty() );
|
||||
QByteArray logUnlimitedBefore = logFileContents( -1 );
|
||||
QVERIFY( logUnlimitedBefore.isEmpty() );
|
||||
|
||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||
Logger::setupLogfile();
|
||||
|
||||
QByteArray contentsOfLogfileAfterSetup = logFileContents();
|
||||
QVERIFY( !contentsOfLogfileAfterSetup.isEmpty() );
|
||||
QByteArray logLimitedAfter = logFileContents( 16 );
|
||||
QVERIFY( !logLimitedAfter.isEmpty() );
|
||||
QByteArray logUnlimitedAfter = logFileContents( -1 );
|
||||
QVERIFY( !logUnlimitedAfter.isEmpty() );
|
||||
}
|
||||
|
||||
void
|
||||
@ -60,7 +66,19 @@ TestPaste::testFichePaste()
|
||||
QVERIFY( !s.isEmpty() );
|
||||
}
|
||||
|
||||
void
|
||||
TestPaste::testUploadSize()
|
||||
{
|
||||
QByteArray logContent = logFileContents( 100 );
|
||||
QString s = ficheLogUpload( logContent, QUrl( "http://termbin.com:9999" ), nullptr );
|
||||
|
||||
QVERIFY( !s.isEmpty() );
|
||||
|
||||
QUrl url( s );
|
||||
QByteArray returnedData = CalamaresUtils::Network::Manager::instance().synchronousGet( url );
|
||||
|
||||
QCOMPARE( returnedData.size(), 100 );
|
||||
}
|
||||
QTEST_GUILESS_MAIN( TestPaste )
|
||||
|
||||
#include "utils/moc-warnings.h"
|
||||
|
@ -392,7 +392,7 @@ ItemTests::testUrlFallback()
|
||||
QVERIFY( map.count() > 0 );
|
||||
c.setConfigurationMap( map );
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
catch ( YAML::Exception& )
|
||||
{
|
||||
bool badYaml = true;
|
||||
QVERIFY( !badYaml );
|
||||
|
@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
derp
|
||||
derp
|
||||
herpa-derp: no
|
||||
|
@ -15,7 +15,7 @@ option( WITH_APPDATA "Support appdata: items in PackageChooser (requires QtXml)"
|
||||
if ( WITH_APPDATA )
|
||||
find_package(Qt5 COMPONENTS Xml)
|
||||
if ( Qt5Xml_FOUND )
|
||||
add_definitions( -DHAVE_XML )
|
||||
add_definitions( -DHAVE_APPDATA )
|
||||
list( APPEND _extra_libraries Qt5::Xml )
|
||||
list( APPEND _extra_src ItemAppData.cpp )
|
||||
endif()
|
||||
@ -45,6 +45,7 @@ calamares_add_plugin( packagechooser
|
||||
TYPE viewmodule
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
Config.cpp
|
||||
PackageChooserPage.cpp
|
||||
PackageChooserViewStep.cpp
|
||||
PackageModel.cpp
|
||||
|
231
src/modules/packagechooser/Config.cpp
Normal file
231
src/modules/packagechooser/Config.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#ifdef HAVE_APPDATA
|
||||
#include "ItemAppData.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
#include "ItemAppStream.h"
|
||||
#include <AppStreamQt/pool.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "packages/Globals.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >&
|
||||
packageChooserModeNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMode > names {
|
||||
{ "optional", PackageChooserMode::Optional },
|
||||
{ "required", PackageChooserMode::Required },
|
||||
{ "optionalmultiple", PackageChooserMode::OptionalMultiple },
|
||||
{ "requiredmultiple", PackageChooserMode::RequiredMultiple },
|
||||
// and a bunch of aliases
|
||||
{ "zero-or-one", PackageChooserMode::Optional },
|
||||
{ "radio", PackageChooserMode::Required },
|
||||
{ "one", PackageChooserMode::Required },
|
||||
{ "set", PackageChooserMode::OptionalMultiple },
|
||||
{ "zero-or-more", PackageChooserMode::OptionalMultiple },
|
||||
{ "multiple", PackageChooserMode::RequiredMultiple },
|
||||
{ "one-or-more", PackageChooserMode::RequiredMultiple }
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >&
|
||||
PackageChooserMethodNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMethod > names {
|
||||
{ "legacy", PackageChooserMethod::Legacy },
|
||||
{ "custom", PackageChooserMethod::Legacy },
|
||||
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||
{ "packages", PackageChooserMethod::Packages },
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
Config::Config( QObject* parent )
|
||||
: Calamares::ModuleSystem::Config( parent )
|
||||
, m_model( new PackageListModel( this ) )
|
||||
, m_mode( PackageChooserMode::Required )
|
||||
{
|
||||
}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
const PackageItem&
|
||||
Config::introductionPackage() const
|
||||
{
|
||||
for ( int i = 0; i < m_model->packageCount(); ++i )
|
||||
{
|
||||
const auto& package = m_model->packageData( i );
|
||||
if ( package.isNonePackage() )
|
||||
{
|
||||
return package;
|
||||
}
|
||||
}
|
||||
|
||||
static PackageItem* defaultIntroduction = nullptr;
|
||||
if ( !defaultIntroduction )
|
||||
{
|
||||
const auto name = QT_TR_NOOP( "Package Selection" );
|
||||
const auto description
|
||||
= QT_TR_NOOP( "Please pick a product from the list. The selected product will be installed." );
|
||||
defaultIntroduction = new PackageItem( QString(), name, description );
|
||||
defaultIntroduction->screenshot = QPixmap( QStringLiteral( ":/images/no-selection.png" ) );
|
||||
defaultIntroduction->name = CalamaresUtils::Locale::TranslatedString( name, metaObject()->className() );
|
||||
defaultIntroduction->description
|
||||
= CalamaresUtils::Locale::TranslatedString( description, metaObject()->className() );
|
||||
}
|
||||
return *defaultIntroduction;
|
||||
}
|
||||
|
||||
void
|
||||
Config::updateGlobalStorage( const QStringList& selected ) const
|
||||
{
|
||||
if ( m_method == PackageChooserMethod::Legacy )
|
||||
{
|
||||
QString value = selected.join( ',' );
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( m_id, value );
|
||||
cDebug() << m_id<< "selected" << value;
|
||||
}
|
||||
else if ( m_method == PackageChooserMethod::Packages )
|
||||
{
|
||||
QStringList packageNames = m_model->getInstallPackagesForNames( selected );
|
||||
cDebug() << m_defaultId << "packages to install" << packageNames;
|
||||
CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fillModel( PackageListModel* model, const QVariantList& items )
|
||||
{
|
||||
if ( items.isEmpty() )
|
||||
{
|
||||
cWarning() << "No *items* for PackageChooser module.";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
std::unique_ptr< AppStream::Pool > pool;
|
||||
bool poolOk = false;
|
||||
#endif
|
||||
|
||||
cDebug() << "Loading PackageChooser model items from config";
|
||||
int item_index = 0;
|
||||
for ( const auto& item_it : items )
|
||||
{
|
||||
++item_index;
|
||||
QVariantMap item_map = item_it.toMap();
|
||||
if ( item_map.isEmpty() )
|
||||
{
|
||||
cWarning() << "PackageChooser entry" << item_index << "is not valid.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item_map.contains( "appdata" ) )
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
model->addPackage( fromAppData( item_map ) );
|
||||
#else
|
||||
cWarning() << "Loading AppData XML is not supported.";
|
||||
#endif
|
||||
}
|
||||
else if ( item_map.contains( "appstream" ) )
|
||||
{
|
||||
#ifdef HAVE_APPSTREAM
|
||||
if ( !pool )
|
||||
{
|
||||
pool = std::make_unique< AppStream::Pool >();
|
||||
pool->setLocale( QStringLiteral( "ALL" ) );
|
||||
poolOk = pool->load();
|
||||
}
|
||||
if ( pool && poolOk )
|
||||
{
|
||||
model->addPackage( fromAppStream( *pool, item_map ) );
|
||||
}
|
||||
#else
|
||||
cWarning() << "Loading AppStream data is not supported.";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
model->addPackage( PackageItem( item_map ) );
|
||||
}
|
||||
}
|
||||
cDebug() << Logger::SubEntry << "Loaded PackageChooser with" << model->packageCount() << "entries.";
|
||||
}
|
||||
|
||||
void
|
||||
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_mode = packageChooserModeNames().find( CalamaresUtils::getString( configurationMap, "mode" ),
|
||||
PackageChooserMode::Required );
|
||||
m_method = PackageChooserMethodNames().find( CalamaresUtils::getString( configurationMap, "method" ),
|
||||
PackageChooserMethod::Legacy );
|
||||
|
||||
if ( m_method == PackageChooserMethod::Legacy )
|
||||
{
|
||||
const QString configId = CalamaresUtils::getString( configurationMap, "id" );
|
||||
const QString base = QStringLiteral( "packagechooser_" );
|
||||
if ( configId.isEmpty() )
|
||||
{
|
||||
if ( m_defaultId.id().isEmpty() )
|
||||
{
|
||||
// We got nothing to work with
|
||||
m_id = base;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_id = base + m_defaultId.id();
|
||||
}
|
||||
cDebug() << "Using default ID" << m_id << "from" << m_defaultId.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_id = base + configId;
|
||||
cDebug() << "Using configured ID" << m_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( configurationMap.contains( "items" ) )
|
||||
{
|
||||
fillModel( m_model, configurationMap.value( "items" ).toList() );
|
||||
}
|
||||
|
||||
QString default_item_id = CalamaresUtils::getString( configurationMap, "default" );
|
||||
if ( !default_item_id.isEmpty() )
|
||||
{
|
||||
for ( int item_n = 0; item_n < m_model->packageCount(); ++item_n )
|
||||
{
|
||||
QModelIndex item_idx = m_model->index( item_n, 0 );
|
||||
QVariant item_id = m_model->data( item_idx, PackageListModel::IdRole );
|
||||
|
||||
if ( item_id.toString() == default_item_id )
|
||||
{
|
||||
m_defaultModelIndex = item_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
src/modules/packagechooser/Config.h
Normal file
92
src/modules/packagechooser/Config.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PACKAGECHOOSER_CONFIG_H
|
||||
#define PACKAGECHOOSER_CONFIG_H
|
||||
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include "modulesystem/Config.h"
|
||||
#include "modulesystem/InstanceKey.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
enum class PackageChooserMode
|
||||
{
|
||||
Optional, // zero or one
|
||||
Required, // exactly one
|
||||
OptionalMultiple, // zero or more
|
||||
RequiredMultiple // one or more
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >& packageChooserModeNames();
|
||||
|
||||
enum class PackageChooserMethod
|
||||
{
|
||||
Legacy, // use contextualprocess or other custom
|
||||
Packages, // use the packages module
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||
|
||||
class Config : public Calamares::ModuleSystem::Config
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Config( QObject* parent = nullptr );
|
||||
~Config() override;
|
||||
|
||||
/** @brief Sets the default Id for this Config
|
||||
*
|
||||
* The default Id is the (owning) module identifier for the config,
|
||||
* and it is used when the Id read from the config file is empty.
|
||||
* The **usual** configuration when using method *packages* is
|
||||
* to rely on the default Id.
|
||||
*/
|
||||
void setDefaultId( const Calamares::ModuleSystem::InstanceKey& defaultId ) { m_defaultId = defaultId; }
|
||||
void setConfigurationMap( const QVariantMap& ) override;
|
||||
|
||||
PackageChooserMode mode() const { return m_mode; }
|
||||
PackageListModel* model() const { return m_model; }
|
||||
QModelIndex defaultSelectionIndex() const { return m_defaultModelIndex; }
|
||||
|
||||
/** @brief Returns an "introductory package" which describes packagechooser
|
||||
*
|
||||
* If the model contains a "none" package, returns that one on
|
||||
* the assumption that it is one to describe the whole; otherwise
|
||||
* returns a totally generic description.
|
||||
*/
|
||||
const PackageItem& introductionPackage() const;
|
||||
|
||||
/** @brief Write selection to global storage
|
||||
*
|
||||
* Updates the GS keys for this packagechooser, marking all
|
||||
* (and only) the packages in @p selected as selected.
|
||||
*/
|
||||
void updateGlobalStorage( const QStringList& selected ) const;
|
||||
/// As updateGlobalStorage() with an empty selection list
|
||||
void updateGlobalStorage() const { updateGlobalStorage( QStringList() ); }
|
||||
|
||||
private:
|
||||
PackageListModel* m_model = nullptr;
|
||||
QModelIndex m_defaultModelIndex;
|
||||
|
||||
/// Selection mode for this module
|
||||
PackageChooserMode m_mode = PackageChooserMode::Optional;
|
||||
/// How this module stores to GS
|
||||
PackageChooserMethod m_method = PackageChooserMethod::Legacy;
|
||||
/// Id (used to identify settings from this module in GS)
|
||||
QString m_id;
|
||||
/// Value to use for id if none is set in the config file
|
||||
Calamares::ModuleSystem::InstanceKey m_defaultId;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@
|
||||
#ifndef PACKAGECHOOSERPAGE_H
|
||||
#define PACKAGECHOOSERPAGE_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
@ -9,20 +9,12 @@
|
||||
|
||||
#include "PackageChooserViewStep.h"
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#include "ItemAppData.h"
|
||||
#endif
|
||||
#ifdef HAVE_APPSTREAM
|
||||
#include "ItemAppStream.h"
|
||||
#include <AppStreamQt/pool.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
#include "Config.h"
|
||||
#include "PackageChooserPage.h"
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "locale/TranslatableConfiguration.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
@ -35,9 +27,8 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( PackageChooserViewStepFactory, registerPlug
|
||||
|
||||
PackageChooserViewStep::PackageChooserViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_config( new Config( this ) )
|
||||
, m_widget( nullptr )
|
||||
, m_model( nullptr )
|
||||
, m_mode( PackageChooserMode::Required )
|
||||
, m_stepName( nullptr )
|
||||
{
|
||||
emit nextStatusChanged( false );
|
||||
@ -50,7 +41,6 @@ PackageChooserViewStep::~PackageChooserViewStep()
|
||||
{
|
||||
m_widget->deleteLater();
|
||||
}
|
||||
delete m_model;
|
||||
delete m_stepName;
|
||||
}
|
||||
|
||||
@ -67,19 +57,11 @@ PackageChooserViewStep::widget()
|
||||
{
|
||||
if ( !m_widget )
|
||||
{
|
||||
m_widget = new PackageChooserPage( m_mode, nullptr );
|
||||
m_widget = new PackageChooserPage( m_config->mode(), nullptr );
|
||||
connect( m_widget, &PackageChooserPage::selectionChanged, [=]() {
|
||||
emit nextStatusChanged( this->isNextEnabled() );
|
||||
} );
|
||||
|
||||
if ( m_model )
|
||||
{
|
||||
hookupModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "PackageChooser Widget created before model.";
|
||||
}
|
||||
hookupModel();
|
||||
}
|
||||
return m_widget;
|
||||
}
|
||||
@ -88,18 +70,13 @@ PackageChooserViewStep::widget()
|
||||
bool
|
||||
PackageChooserViewStep::isNextEnabled() const
|
||||
{
|
||||
if ( !m_model )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !m_widget )
|
||||
{
|
||||
// No way to have changed anything
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( m_mode )
|
||||
switch ( m_config->mode() )
|
||||
{
|
||||
case PackageChooserMode::Optional:
|
||||
case PackageChooserMode::OptionalMultiple:
|
||||
@ -139,22 +116,14 @@ PackageChooserViewStep::onActivate()
|
||||
{
|
||||
if ( !m_widget->hasSelection() )
|
||||
{
|
||||
m_widget->setSelection( m_defaultIdx );
|
||||
m_widget->setSelection( m_config->defaultSelectionIndex() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::onLeave()
|
||||
{
|
||||
QString key = QStringLiteral( "packagechooser_%1" ).arg( m_id );
|
||||
QString value;
|
||||
if ( m_widget->hasSelection() )
|
||||
{
|
||||
value = m_widget->selectedPackageIds().join( ',' );
|
||||
}
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( key, value );
|
||||
|
||||
cDebug() << "PackageChooser" << key << "selected" << value;
|
||||
m_config->updateGlobalStorage( m_widget->selectedPackageIds() );
|
||||
}
|
||||
|
||||
Calamares::JobList
|
||||
@ -167,23 +136,8 @@ PackageChooserViewStep::jobs() const
|
||||
void
|
||||
PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
QString mode = CalamaresUtils::getString( configurationMap, "mode" );
|
||||
bool mode_ok = false;
|
||||
if ( !mode.isEmpty() )
|
||||
{
|
||||
m_mode = roleNames().find( mode, mode_ok );
|
||||
}
|
||||
if ( !mode_ok )
|
||||
{
|
||||
m_mode = PackageChooserMode::Required;
|
||||
}
|
||||
|
||||
m_id = CalamaresUtils::getString( configurationMap, "id" );
|
||||
if ( m_id.isEmpty() )
|
||||
{
|
||||
// Not set, so use the instance id
|
||||
m_id = moduleInstanceKey().id();
|
||||
}
|
||||
m_config->setDefaultId( moduleInstanceKey() );
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
|
||||
bool labels_ok = false;
|
||||
auto labels = CalamaresUtils::getSubMap( configurationMap, "labels", labels_ok );
|
||||
@ -195,117 +149,22 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap
|
||||
}
|
||||
}
|
||||
|
||||
QString default_item_id = CalamaresUtils::getString( configurationMap, "default" );
|
||||
m_defaultIdx = QModelIndex();
|
||||
|
||||
bool first_time = !m_model;
|
||||
if ( configurationMap.contains( "items" ) )
|
||||
{
|
||||
fillModel( configurationMap.value( "items" ).toList() );
|
||||
}
|
||||
|
||||
if ( first_time && m_widget && m_model )
|
||||
if ( m_widget )
|
||||
{
|
||||
hookupModel();
|
||||
}
|
||||
|
||||
// find default item
|
||||
if ( first_time && m_model && !default_item_id.isEmpty() )
|
||||
{
|
||||
for ( int item_n = 0; item_n < m_model->packageCount(); ++item_n )
|
||||
{
|
||||
QModelIndex item_idx = m_model->index( item_n, 0 );
|
||||
QVariant item_id = m_model->data( item_idx, PackageListModel::IdRole );
|
||||
|
||||
if ( item_id.toString() == default_item_id )
|
||||
{
|
||||
m_defaultIdx = item_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::fillModel( const QVariantList& items )
|
||||
{
|
||||
if ( !m_model )
|
||||
{
|
||||
m_model = new PackageListModel( nullptr );
|
||||
}
|
||||
|
||||
if ( items.isEmpty() )
|
||||
{
|
||||
cWarning() << "No *items* for PackageChooser module.";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
std::unique_ptr< AppStream::Pool > pool;
|
||||
bool poolOk = false;
|
||||
#endif
|
||||
|
||||
cDebug() << "Loading PackageChooser model items from config";
|
||||
int item_index = 0;
|
||||
for ( const auto& item_it : items )
|
||||
{
|
||||
++item_index;
|
||||
QVariantMap item_map = item_it.toMap();
|
||||
if ( item_map.isEmpty() )
|
||||
{
|
||||
cWarning() << "PackageChooser entry" << item_index << "is not valid.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item_map.contains( "appdata" ) )
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
m_model->addPackage( fromAppData( item_map ) );
|
||||
#else
|
||||
cWarning() << "Loading AppData XML is not supported.";
|
||||
#endif
|
||||
}
|
||||
else if ( item_map.contains( "appstream" ) )
|
||||
{
|
||||
#ifdef HAVE_APPSTREAM
|
||||
if ( !pool )
|
||||
{
|
||||
pool = std::make_unique< AppStream::Pool >();
|
||||
pool->setLocale( QStringLiteral( "ALL" ) );
|
||||
poolOk = pool->load();
|
||||
}
|
||||
if ( pool && poolOk )
|
||||
{
|
||||
m_model->addPackage( fromAppStream( *pool, item_map ) );
|
||||
}
|
||||
#else
|
||||
cWarning() << "Loading AppStream data is not supported.";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model->addPackage( PackageItem( item_map ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::hookupModel()
|
||||
{
|
||||
if ( !m_model || !m_widget )
|
||||
if ( !m_config->model() || !m_widget )
|
||||
{
|
||||
cError() << "Can't hook up model until widget and model both exist.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_widget->setModel( m_model );
|
||||
for ( int i = 0; i < m_model->packageCount(); ++i )
|
||||
{
|
||||
const auto& package = m_model->packageData( i );
|
||||
if ( package.id.isEmpty() )
|
||||
{
|
||||
m_widget->setIntroduction( package );
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_widget->setModel( m_config->model() );
|
||||
m_widget->setIntroduction( m_config->introductionPackage() );
|
||||
}
|
||||
|
@ -15,12 +15,9 @@
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QVariantMap>
|
||||
|
||||
class Config;
|
||||
class PackageChooserPage;
|
||||
|
||||
class PLUGINDLLEXPORT PackageChooserViewStep : public Calamares::ViewStep
|
||||
@ -49,17 +46,11 @@ public:
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
private:
|
||||
void fillModel( const QVariantList& items );
|
||||
void hookupModel();
|
||||
|
||||
Config* m_config;
|
||||
PackageChooserPage* m_widget;
|
||||
PackageListModel* m_model;
|
||||
|
||||
// Configuration
|
||||
PackageChooserMode m_mode;
|
||||
QString m_id;
|
||||
CalamaresUtils::Locale::TranslatedString* m_stepName; // As it appears in the sidebar
|
||||
QModelIndex m_defaultIdx;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PackageChooserViewStepFactory )
|
||||
|
@ -12,46 +12,20 @@
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >&
|
||||
roleNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMode > names {
|
||||
{ "optional", PackageChooserMode::Optional },
|
||||
{ "required", PackageChooserMode::Required },
|
||||
{ "optionalmultiple", PackageChooserMode::OptionalMultiple },
|
||||
{ "requiredmultiple", PackageChooserMode::RequiredMultiple },
|
||||
// and a bunch of aliases
|
||||
{ "zero-or-one", PackageChooserMode::Optional },
|
||||
{ "radio", PackageChooserMode::Required },
|
||||
{ "one", PackageChooserMode::Required },
|
||||
{ "set", PackageChooserMode::OptionalMultiple },
|
||||
{ "zero-or-more", PackageChooserMode::OptionalMultiple },
|
||||
{ "multiple", PackageChooserMode::RequiredMultiple },
|
||||
{ "one-or-more", PackageChooserMode::RequiredMultiple }
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
PackageItem::PackageItem() {}
|
||||
|
||||
PackageItem::PackageItem( const QString& a_id,
|
||||
const QString& a_package,
|
||||
const QString& a_name,
|
||||
const QString& a_description )
|
||||
PackageItem::PackageItem( const QString& a_id, const QString& a_name, const QString& a_description )
|
||||
: id( a_id )
|
||||
, package( a_package )
|
||||
, name( a_name )
|
||||
, description( a_description )
|
||||
{
|
||||
}
|
||||
|
||||
PackageItem::PackageItem( const QString& a_id,
|
||||
const QString& a_package,
|
||||
const QString& a_name,
|
||||
const QString& a_description,
|
||||
const QString& screenshotPath )
|
||||
: id( a_id )
|
||||
, package( a_package )
|
||||
, name( a_name )
|
||||
, description( a_description )
|
||||
, screenshot( screenshotPath )
|
||||
@ -60,10 +34,10 @@ PackageItem::PackageItem( const QString& a_id,
|
||||
|
||||
PackageItem::PackageItem::PackageItem( const QVariantMap& item_map )
|
||||
: id( CalamaresUtils::getString( item_map, "id" ) )
|
||||
, package( CalamaresUtils::getString( item_map, "package" ) )
|
||||
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
||||
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
||||
, screenshot( CalamaresUtils::getString( item_map, "screenshot" ) )
|
||||
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
||||
{
|
||||
if ( name.isEmpty() && id.isEmpty() )
|
||||
{
|
||||
@ -105,6 +79,33 @@ PackageListModel::addPackage( PackageItem&& p )
|
||||
}
|
||||
}
|
||||
|
||||
QStringList
|
||||
PackageListModel::getInstallPackagesForName( const QString& id ) const
|
||||
{
|
||||
for ( const auto& p : qAsConst( m_packages ) )
|
||||
{
|
||||
if ( p.id == id )
|
||||
{
|
||||
return p.packageNames;
|
||||
}
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList
|
||||
PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
||||
{
|
||||
QStringList l;
|
||||
for ( const auto& p : qAsConst( m_packages ) )
|
||||
{
|
||||
if ( ids.contains( p.id ) )
|
||||
{
|
||||
l.append( p.packageNames );
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||
{
|
||||
|
@ -18,24 +18,14 @@
|
||||
#include <QPixmap>
|
||||
#include <QVector>
|
||||
|
||||
enum class PackageChooserMode
|
||||
{
|
||||
Optional, // zero or one
|
||||
Required, // exactly one
|
||||
OptionalMultiple, // zero or more
|
||||
RequiredMultiple // one or more
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >& roleNames();
|
||||
|
||||
struct PackageItem
|
||||
{
|
||||
QString id;
|
||||
// FIXME: unused
|
||||
QString package;
|
||||
CalamaresUtils::Locale::TranslatedString name;
|
||||
CalamaresUtils::Locale::TranslatedString description;
|
||||
QPixmap screenshot;
|
||||
QStringList packageNames;
|
||||
|
||||
/// @brief Create blank PackageItem
|
||||
PackageItem();
|
||||
@ -44,7 +34,7 @@ struct PackageItem
|
||||
* This constructor sets all the text members,
|
||||
* but leaves the screenshot blank. Set that separately.
|
||||
*/
|
||||
PackageItem( const QString& id, const QString& package, const QString& name, const QString& description );
|
||||
PackageItem( const QString& id, const QString& name, const QString& description );
|
||||
|
||||
/** @brief Creates a PackageItem from given strings.
|
||||
*
|
||||
@ -52,17 +42,21 @@ struct PackageItem
|
||||
* @p screenshotPath, which may be a QRC path (:/path/in/qrc) or
|
||||
* a filesystem path, whatever QPixmap understands.
|
||||
*/
|
||||
PackageItem( const QString& id,
|
||||
const QString& package,
|
||||
const QString& name,
|
||||
const QString& description,
|
||||
const QString& screenshotPath );
|
||||
PackageItem( const QString& id, const QString& name, const QString& description, const QString& screenshotPath );
|
||||
|
||||
/** @brief Creates a PackageItem from a QVariantMap
|
||||
*
|
||||
* This is intended for use when loading PackageItems from a
|
||||
* configuration map. It will look up the various keys in the map
|
||||
* and handle translation strings as well.
|
||||
*
|
||||
* The following keys are used:
|
||||
* - *id*: the identifier for this item; if it is the empty string
|
||||
* then this is the special "no-package".
|
||||
* - *name* (and *name[lang]*): for the name and its translations
|
||||
* - *description* (and *description[lang]*)
|
||||
* - *screenshot*: a path to a screenshot for this package
|
||||
* - *packages*: a list of package names
|
||||
*/
|
||||
PackageItem( const QVariantMap& map );
|
||||
|
||||
@ -104,6 +98,19 @@ public:
|
||||
/// @brief Direct (non-abstract) count of package data
|
||||
int packageCount() const { return m_packages.count(); }
|
||||
|
||||
/** @brief Does a name lookup (based on id) and returns the packages member
|
||||
*
|
||||
* If there is a package with the given @p id, returns its packages
|
||||
* (e.g. the names of underlying packages to install for it); returns
|
||||
* an empty list if the id is not found.
|
||||
*/
|
||||
QStringList getInstallPackagesForName( const QString& id ) const;
|
||||
/** @brief Name-lookup all the @p ids and returns the packages members
|
||||
*
|
||||
* Concatenates installPackagesForName() for each id in @p ids.
|
||||
*/
|
||||
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
||||
|
||||
enum Roles : int
|
||||
{
|
||||
NameRole = Qt::DisplayRole,
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "Tests.h"
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#ifdef HAVE_APPDATA
|
||||
#include "ItemAppData.h"
|
||||
#endif
|
||||
#ifdef HAVE_APPSTREAM
|
||||
|
@ -3,26 +3,47 @@
|
||||
#
|
||||
# Configuration for the low-density software chooser
|
||||
---
|
||||
# The packagechooser writes a GlobalStorage value for the choice that
|
||||
# has been made. The key is *packagechooser_<id>*. If *id* is set here,
|
||||
# it is substituted into the key name. If it is not set, the module's
|
||||
# instance name is used; see the *instances* section of `settings.conf`.
|
||||
# If there is just one packagechooser module, and no *id* is set,
|
||||
# resulting GS key is probably *packagechooser_packagechooser*.
|
||||
#
|
||||
# The GS value is a comma-separated list of the IDs of the selected
|
||||
# packages, or an empty string if none is selected.
|
||||
#
|
||||
# id: ""
|
||||
|
||||
# Software selection mode, to set whether the software packages
|
||||
# can be chosen singly, or multiply.
|
||||
#
|
||||
# Possible modes are "optional", "required" (for zero or one)
|
||||
# Possible modes are "optional", "required" (for zero-or-one or exactly-one)
|
||||
# or "optionalmultiple", "requiredmultiple" (for zero-or-more
|
||||
# or one-or-more).
|
||||
mode: required
|
||||
|
||||
# Software installation method:
|
||||
#
|
||||
# - "legacy" or "custom" or "contextualprocess"
|
||||
# When set to "legacy", writes a GlobalStorage value for the choice that
|
||||
# has been made. The key is *packagechooser_<id>*. Normally, the module's
|
||||
# instance name is used; see the *instances* section of `settings.conf`.
|
||||
# If there is just one packagechooser module, and no special instance is set,
|
||||
# resulting GS key is probably *packagechooser@packagechooser*.
|
||||
# You can set *id* to change that, but it is not recommended.
|
||||
#
|
||||
# The GS value is a comma-separated list of the IDs of the selected
|
||||
# packages, or an empty string if none is selected.
|
||||
#
|
||||
# With "legacy" installation, you should have a contextualprocess or similar
|
||||
# module somewhere in the `exec` phase to process the GlobalStorage key
|
||||
# and actually **do** something for the packages.
|
||||
#
|
||||
# - "packages"
|
||||
# When set to "packages", writes GlobalStorage values suitable for
|
||||
# consumption by the *packages* module (which should appear later
|
||||
# in the `exec` section. These package settings will then be handed
|
||||
# off to whatever package manager is configured there.
|
||||
# The *id* key is not used.
|
||||
#
|
||||
# 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
|
||||
# module, in the `exec` section to do the actual work.
|
||||
method: legacy
|
||||
# The *id* key is used only in "legacy" mode
|
||||
# id: ""
|
||||
|
||||
|
||||
# Human-visible strings in this module. These are all optional.
|
||||
# The following translated keys are used:
|
||||
# - *step*, used in the overall progress view (left-hand pane)
|
||||
@ -49,27 +70,45 @@ labels:
|
||||
# as a source for the data.
|
||||
#
|
||||
# For data provided by the list: the item has an id, which is used in
|
||||
# setting the value of *packagechooser_<module-id>*. The following fields
|
||||
# are mandatory:
|
||||
# setting the value of *packagechooser_<module-id>*. The following field
|
||||
# is mandatory:
|
||||
#
|
||||
# - *id* : ID for the product. The ID "" is special, and is used for
|
||||
# "no package selected". Only include this if the mode allows
|
||||
# selecting none.
|
||||
# - *package* : Package name for the product. While mandatory, this is
|
||||
# not actually used anywhere.
|
||||
# - *name* : Human-readable name of the product. To provide translations,
|
||||
# add a *[lang]* decoration as part of the key name,
|
||||
# e.g. `name[nl]` for Dutch.
|
||||
# The list of usable languages can be found in
|
||||
# `CMakeLists.txt` or as part of the debug output of Calamares.
|
||||
# - *description* : Human-readable description. These can be translated
|
||||
# as well.
|
||||
# - *screenshot* : Path to a single screenshot of the product. May be
|
||||
# a filesystem path or a QRC path,
|
||||
# e.g. ":/images/no-selection.png".
|
||||
# - *id*
|
||||
# ID for the product. The ID "" is special, and is used for
|
||||
# "no package selected". Only include this if the mode allows
|
||||
# selecting none. The name and description given for the "no package
|
||||
# selected" item are displayed when the module starts.
|
||||
#
|
||||
# Use the empty string "" as ID / key for the "no selection" item if
|
||||
# you want to customize the display of that item as well.
|
||||
# Each item must adhere to one of three "styles" of item. Which styles
|
||||
# are supported depends on compile-time dependencies of Calamares.
|
||||
# Both AppData and AppStream may **optionally** be available.
|
||||
#
|
||||
# # Generic Items #
|
||||
#
|
||||
# These items are always supported. They require the most configuration
|
||||
# **in this file** and duplicate information that may be available elsewhere
|
||||
# (e.g. in AppData or AppStream), but do not require any additional
|
||||
# dependencies. These items have the following **mandatory** fields:
|
||||
#
|
||||
# - *name*
|
||||
# Human-readable name of the product. To provide translations,
|
||||
# add a *[lang]* decoration as part of the key name, e.g. `name[nl]`
|
||||
# for Dutch. The list of usable languages can be found in
|
||||
# `CMakeLists.txt` or as part of the debug output of Calamares.
|
||||
# - *description*
|
||||
# Human-readable description. These can be translated as well.
|
||||
# - *screenshot*
|
||||
# Path to a single screenshot of the product. May be a filesystem
|
||||
# path or a QRC path, e.g. ":/images/no-selection.png".
|
||||
#
|
||||
# The following field is **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).
|
||||
#
|
||||
# # AppData Items #
|
||||
#
|
||||
# For data provided by AppData XML: the item has an *appdata*
|
||||
# key which points to an AppData XML file in the local filesystem.
|
||||
@ -84,6 +123,8 @@ labels:
|
||||
# **may** specify an ID or screenshot path, as above. This will override
|
||||
# the settings from AppData.
|
||||
#
|
||||
# # AppStream Items #
|
||||
#
|
||||
# For data provided by AppStream cache: the item has an *appstream*
|
||||
# key which matches the AppStream identifier in the cache (e.g.
|
||||
# *org.kde.kwrite.desktop*). Data is retrieved from the AppStream
|
||||
|
@ -256,6 +256,23 @@ class PMEntropy(PackageManager):
|
||||
pass
|
||||
|
||||
|
||||
class PMLuet(PackageManager):
|
||||
backend = "luet"
|
||||
|
||||
def install(self, pkgs, from_local=False):
|
||||
check_target_env_call(["luet", "install", "-y"] + pkgs)
|
||||
|
||||
def remove(self, pkgs):
|
||||
check_target_env_call(["luet", "uninstall", "-y"] + pkgs)
|
||||
|
||||
def update_db(self):
|
||||
# Luet checks for DB update everytime its ran.
|
||||
pass
|
||||
|
||||
def update_system(self):
|
||||
check_target_env_call(["luet", "upgrade", "-y"])
|
||||
|
||||
|
||||
class PMPackageKit(PackageManager):
|
||||
backend = "packagekit"
|
||||
|
||||
|
@ -1,13 +1,30 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
# The configuration for the package manager starts with the
|
||||
# *backend* key, which picks one of the backends to use.
|
||||
# In `main.py` there is a base class `PackageManager`.
|
||||
# Implementations must subclass that and set a (class-level)
|
||||
# property *backend* to the name of the backend (e.g. "dummy").
|
||||
# That property is used to match against the *backend* key here.
|
||||
#
|
||||
# You will have to add such a class for your package manager.
|
||||
# It is fairly simple Python code. The API is described in the
|
||||
# abstract methods in class `PackageManager`. Mostly, the only
|
||||
# trick is to figure out the correct commands to use, and in particular,
|
||||
# whether additional switches are required or not. Some package managers
|
||||
# have more installer-friendly defaults than others, e.g., DNF requires
|
||||
# passing --disablerepo=* -C to allow removing packages without Internet
|
||||
# connectivity, and it also returns an error exit code if the package did
|
||||
# not exist to begin with.
|
||||
---
|
||||
#
|
||||
# Which package manager to use, options are:
|
||||
# - apk - Alpine Linux package manager
|
||||
# - apt - APT frontend for DEB and RPM
|
||||
# - dnf - DNF, the new RPM frontend
|
||||
# - entropy - Sabayon package manager
|
||||
# - entropy - Sabayon package manager (is being deprecated)
|
||||
# - luet - Sabayon package manager (next-gen)
|
||||
# - packagekit - PackageKit CLI tool
|
||||
# - pacman - Pacman
|
||||
# - pamac - Manjaro package manager
|
||||
|
@ -13,6 +13,7 @@ properties:
|
||||
- apt
|
||||
- dnf
|
||||
- entropy
|
||||
- luet
|
||||
- packagekit
|
||||
- pacman
|
||||
- pamac
|
||||
|
@ -264,7 +264,8 @@ FillGlobalStorageJob::prettyDescription() const
|
||||
"<strong>%2</strong>%4." )
|
||||
.arg( path )
|
||||
.arg( mountPoint )
|
||||
.arg( fsType ) );
|
||||
.arg( fsType )
|
||||
.arg( QString() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user