Merge branch 'master' of https://github.com/calamares/calamares into development
This commit is contained in:
commit
49c17942d0
@ -32,6 +32,9 @@
|
|||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Dirs.h"
|
#include "utils/Dirs.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#ifdef WITH_QML
|
||||||
|
#include "utils/Qml.h"
|
||||||
|
#endif
|
||||||
#include "utils/Retranslator.h"
|
#include "utils/Retranslator.h"
|
||||||
#include "viewpages/ViewStep.h"
|
#include "viewpages/ViewStep.h"
|
||||||
|
|
||||||
@ -117,34 +120,6 @@ CalamaresApplication::mainWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static QStringList
|
|
||||||
qmlDirCandidates( bool assumeBuilddir )
|
|
||||||
{
|
|
||||||
static const char QML[] = "qml";
|
|
||||||
|
|
||||||
QStringList qmlDirs;
|
|
||||||
if ( CalamaresUtils::isAppDataDirOverridden() )
|
|
||||||
{
|
|
||||||
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( assumeBuilddir )
|
|
||||||
{
|
|
||||||
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir
|
|
||||||
}
|
|
||||||
if ( CalamaresUtils::haveExtraDirs() )
|
|
||||||
for ( auto s : CalamaresUtils::extraDataDirs() )
|
|
||||||
{
|
|
||||||
qmlDirs << ( s + QML );
|
|
||||||
}
|
|
||||||
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
|
|
||||||
}
|
|
||||||
|
|
||||||
return qmlDirs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static QStringList
|
static QStringList
|
||||||
brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
|
brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
|
||||||
{
|
{
|
||||||
@ -175,38 +150,12 @@ brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
|
|||||||
void
|
void
|
||||||
CalamaresApplication::initQmlPath()
|
CalamaresApplication::initQmlPath()
|
||||||
{
|
{
|
||||||
QDir importPath; // Right now, current-dir
|
#ifdef WITH_QML
|
||||||
QStringList qmlDirCandidatesByPriority = qmlDirCandidates( isDebug() );
|
if ( !CalamaresUtils::initQmlModulesDir() )
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
foreach ( const QString& path, qmlDirCandidatesByPriority )
|
|
||||||
{
|
{
|
||||||
QDir dir( path );
|
|
||||||
if ( dir.exists() && dir.isReadable() )
|
|
||||||
{
|
|
||||||
importPath = dir;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !found || !importPath.exists() || !importPath.isReadable() )
|
|
||||||
{
|
|
||||||
cError() << "Cowardly refusing to continue startup without a QML directory."
|
|
||||||
<< Logger::DebugList( qmlDirCandidatesByPriority );
|
|
||||||
if ( CalamaresUtils::isAppDataDirOverridden() )
|
|
||||||
{
|
|
||||||
cError() << "FATAL: explicitly configured application data directory is missing qml/";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cError() << "FATAL: none of the expected QML paths exist.";
|
|
||||||
}
|
|
||||||
::exit( EXIT_FAILURE );
|
::exit( EXIT_FAILURE );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
cDebug() << "Using Calamares QML directory" << importPath.absolutePath();
|
|
||||||
CalamaresUtils::setQmlModulesDir( importPath );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ CalamaresWindow::getWidgetNavigation( QWidget* parent )
|
|||||||
QWidget*
|
QWidget*
|
||||||
CalamaresWindow::getQmlSidebar( QWidget* parent, int )
|
CalamaresWindow::getQmlSidebar( QWidget* parent, int )
|
||||||
{
|
{
|
||||||
CalamaresUtils::registerCalamaresModels();
|
CalamaresUtils::registerQmlModels();
|
||||||
QQuickWidget* w = new QQuickWidget( parent );
|
QQuickWidget* w = new QQuickWidget( parent );
|
||||||
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||||
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
||||||
@ -220,7 +220,7 @@ CalamaresWindow::getQmlSidebar( QWidget* parent, int )
|
|||||||
QWidget*
|
QWidget*
|
||||||
CalamaresWindow::getQmlNavigation( QWidget* parent )
|
CalamaresWindow::getQmlNavigation( QWidget* parent )
|
||||||
{
|
{
|
||||||
CalamaresUtils::registerCalamaresModels();
|
CalamaresUtils::registerQmlModels();
|
||||||
QQuickWidget* w = new QQuickWidget( parent );
|
QQuickWidget* w = new QQuickWidget( parent );
|
||||||
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||||
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
||||||
|
@ -22,18 +22,22 @@
|
|||||||
* bindings.
|
* bindings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "modulesystem/Module.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
#include "utils/Yaml.h"
|
|
||||||
|
|
||||||
#include "Branding.h"
|
#include "Branding.h"
|
||||||
|
#include "CppJob.h"
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "Job.h"
|
#include "Job.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "ViewManager.h"
|
#include "ViewManager.h"
|
||||||
|
#include "modulesystem/Module.h"
|
||||||
#include "modulesystem/ModuleManager.h"
|
#include "modulesystem/ModuleManager.h"
|
||||||
|
#include "modulesystem/ViewModule.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#ifdef WITH_QML
|
||||||
|
#include "utils/Qml.h"
|
||||||
|
#endif
|
||||||
|
#include "utils/Yaml.h"
|
||||||
|
#include "viewpages/ExecutionViewStep.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCommandLineOption>
|
#include <QCommandLineOption>
|
||||||
@ -42,6 +46,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -80,6 +85,8 @@ handle_args( QCoreApplication& a )
|
|||||||
"src/branding/default/branding.desc" );
|
"src/branding/default/branding.desc" );
|
||||||
QCommandLineOption uiOption( QStringList() << QStringLiteral( "U" ) << QStringLiteral( "ui" ),
|
QCommandLineOption uiOption( QStringList() << QStringLiteral( "U" ) << QStringLiteral( "ui" ),
|
||||||
QStringLiteral( "Enable UI" ) );
|
QStringLiteral( "Enable UI" ) );
|
||||||
|
QCommandLineOption slideshowOption( QStringList() << QStringLiteral( "s" ) << QStringLiteral( "slideshow" ),
|
||||||
|
QStringLiteral( "Run slideshow module" ) );
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription( "Calamares module tester" );
|
parser.setApplicationDescription( "Calamares module tester" );
|
||||||
@ -92,13 +99,14 @@ handle_args( QCoreApplication& a )
|
|||||||
parser.addOption( langOption );
|
parser.addOption( langOption );
|
||||||
parser.addOption( brandOption );
|
parser.addOption( brandOption );
|
||||||
parser.addOption( uiOption );
|
parser.addOption( uiOption );
|
||||||
|
parser.addOption( slideshowOption );
|
||||||
parser.addPositionalArgument( "module", "Path or name of module to run." );
|
parser.addPositionalArgument( "module", "Path or name of module to run." );
|
||||||
parser.addPositionalArgument( "job.yaml", "Path of job settings document to use.", "[job.yaml]" );
|
parser.addPositionalArgument( "job.yaml", "Path of job settings document to use.", "[job.yaml]" );
|
||||||
|
|
||||||
parser.process( a );
|
parser.process( a );
|
||||||
|
|
||||||
const QStringList args = parser.positionalArguments();
|
const QStringList args = parser.positionalArguments();
|
||||||
if ( args.isEmpty() )
|
if ( args.isEmpty() && !parser.isSet( slideshowOption ) )
|
||||||
{
|
{
|
||||||
cError() << "Missing <module> path.\n";
|
cError() << "Missing <module> path.\n";
|
||||||
parser.showHelp();
|
parser.showHelp();
|
||||||
@ -116,20 +124,161 @@ handle_args( QCoreApplication& a )
|
|||||||
jobSettings = args.at( 1 );
|
jobSettings = args.at( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModuleConfig { args.first(),
|
return ModuleConfig { parser.isSet( slideshowOption ) ? QStringLiteral( "-" ) : args.first(),
|
||||||
jobSettings,
|
jobSettings,
|
||||||
parser.value( globalOption ),
|
parser.value( globalOption ),
|
||||||
parser.value( langOption ),
|
parser.value( langOption ),
|
||||||
parser.value( brandOption ),
|
parser.value( brandOption ),
|
||||||
parser.isSet( uiOption ) };
|
parser.isSet( slideshowOption ) || parser.isSet( uiOption ) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Bogus Job for --slideshow option
|
||||||
|
*
|
||||||
|
* Generally one would use DummyCppJob for this kind of dummy
|
||||||
|
* job, but that class lives in a module so isn't available
|
||||||
|
* in this test application.
|
||||||
|
*
|
||||||
|
* This bogus job just sleeps for 3.
|
||||||
|
*/
|
||||||
|
class ExecViewJob : public Calamares::CppJob
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ExecViewJob( const QString& name, unsigned long t = 3 )
|
||||||
|
: m_name( name )
|
||||||
|
, m_delay( t )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~ExecViewJob() override;
|
||||||
|
|
||||||
|
QString prettyName() const override { return m_name; }
|
||||||
|
|
||||||
|
Calamares::JobResult exec() override
|
||||||
|
{
|
||||||
|
QThread::sleep( m_delay );
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& ) override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
unsigned long m_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecViewJob::~ExecViewJob() {}
|
||||||
|
|
||||||
|
/** @brief Bogus module for --slideshow option
|
||||||
|
*
|
||||||
|
* Normally the slideshow -- displayed by ExecutionViewStep -- is not
|
||||||
|
* associated with any particular module in the Calamares configuration.
|
||||||
|
* It is added internally by the module manager. For the module-loader
|
||||||
|
* testing application, we need something that pretends to be the
|
||||||
|
* module for the ExecutionViewStep.
|
||||||
|
*/
|
||||||
|
class ExecViewModule : public Calamares::Module
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExecViewModule();
|
||||||
|
~ExecViewModule() override;
|
||||||
|
|
||||||
|
void loadSelf() override;
|
||||||
|
|
||||||
|
virtual Type type() const override;
|
||||||
|
virtual Interface interface() const override;
|
||||||
|
|
||||||
|
virtual Calamares::JobList jobs() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initFrom( const QVariantMap& ) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecViewModule::ExecViewModule()
|
||||||
|
: Calamares::Module()
|
||||||
|
{
|
||||||
|
// Normally the module-loader gives the module an instance key
|
||||||
|
// (out of the settings file, or the descriptor of the module).
|
||||||
|
// We don't have one, so build one -- this gives us "x@x".
|
||||||
|
QVariantMap m;
|
||||||
|
m.insert( "name", "x" );
|
||||||
|
Calamares::Module::initFrom( m, "x" );
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecViewModule::~ExecViewModule() {}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecViewModule::initFrom( const QVariantMap& )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecViewModule::loadSelf()
|
||||||
|
{
|
||||||
|
auto* viewStep = new Calamares::ExecutionViewStep();
|
||||||
|
viewStep->setModuleInstanceKey( instanceKey() );
|
||||||
|
viewStep->setConfigurationMap( m_configurationMap );
|
||||||
|
viewStep->appendJobModuleInstanceKey( instanceKey().toString() );
|
||||||
|
Calamares::ViewManager::instance()->addViewStep( viewStep );
|
||||||
|
m_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::Module::Type
|
||||||
|
ExecViewModule::type() const
|
||||||
|
{
|
||||||
|
return Module::Type::View;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Calamares::Module::Interface
|
||||||
|
ExecViewModule::interface() const
|
||||||
|
{
|
||||||
|
return Module::Interface::QtPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobList
|
||||||
|
ExecViewModule::jobs() const
|
||||||
|
{
|
||||||
|
Calamares::JobList l;
|
||||||
|
const auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( gs && gs->contains( "jobs" ) )
|
||||||
|
{
|
||||||
|
QVariantList joblist = gs->value( "jobs" ).toList();
|
||||||
|
for ( const auto& jd : joblist )
|
||||||
|
{
|
||||||
|
QVariantMap jobdescription = jd.toMap();
|
||||||
|
if ( jobdescription.contains( "name" ) && jobdescription.contains( "delay" ) )
|
||||||
|
{
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( jobdescription.value( "name" ).toString(),
|
||||||
|
jobdescription.value( "delay" ).toULongLong() ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( l.count() > 0 )
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step 1" ) ) ) );
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step two" ) ) ) );
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "locking mutexes" ), 20 ) ) );
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "unlocking mutexes" ), 1 ) ) );
|
||||||
|
for ( const QString& s : QStringList { "Harder", "Better", "Faster", "Stronger" } )
|
||||||
|
{
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( s, 0 ) ) );
|
||||||
|
}
|
||||||
|
l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "cleaning up" ), 20 ) ) );
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
static Calamares::Module*
|
static Calamares::Module*
|
||||||
load_module( const ModuleConfig& moduleConfig )
|
load_module( const ModuleConfig& moduleConfig )
|
||||||
{
|
{
|
||||||
QString moduleName = moduleConfig.moduleName();
|
QString moduleName = moduleConfig.moduleName();
|
||||||
|
if ( moduleName == "-" )
|
||||||
|
{
|
||||||
|
return new ExecViewModule;
|
||||||
|
}
|
||||||
|
|
||||||
QFileInfo fi;
|
QFileInfo fi;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@ -188,6 +337,18 @@ load_module( const ModuleConfig& moduleConfig )
|
|||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_ui_option( const char* s )
|
||||||
|
{
|
||||||
|
return !qstrcmp( s, "--ui" ) || !qstrcmp( s, "-U" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_slideshow_option( const char* s )
|
||||||
|
{
|
||||||
|
return !qstrcmp( s, "--slideshow" ) || !qstrcmp( s, "-s" );
|
||||||
|
}
|
||||||
|
|
||||||
/** @brief Create the right kind of QApplication
|
/** @brief Create the right kind of QApplication
|
||||||
*
|
*
|
||||||
* Does primitive parsing of argv[] to find the --ui option and returns
|
* Does primitive parsing of argv[] to find the --ui option and returns
|
||||||
@ -202,7 +363,7 @@ createApplication( int& argc, char* argv[] )
|
|||||||
{
|
{
|
||||||
for ( int i = 1; i < argc; ++i )
|
for ( int i = 1; i < argc; ++i )
|
||||||
{
|
{
|
||||||
if ( !qstrcmp( argv[ i ], "--ui" ) || !qstrcmp( argv[ i ], "-U" ) )
|
if ( is_slideshow_option( argv[ i ] ) || is_ui_option( argv[ i ] ) )
|
||||||
{
|
{
|
||||||
auto* aw = new QApplication( argc, argv );
|
auto* aw = new QApplication( argc, argv );
|
||||||
aw->setQuitOnLastWindowClosed( true );
|
aw->setQuitOnLastWindowClosed( true );
|
||||||
@ -241,6 +402,10 @@ main( int argc, char* argv[] )
|
|||||||
gs->insert( "localeConf", vm );
|
gs->insert( "localeConf", vm );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_QML
|
||||||
|
CalamaresUtils::initQmlModulesDir(); // don't care if failed
|
||||||
|
#endif
|
||||||
|
|
||||||
cDebug() << "Calamares module-loader testing" << module.moduleName();
|
cDebug() << "Calamares module-loader testing" << module.moduleName();
|
||||||
Calamares::Module* m = load_module( module );
|
Calamares::Module* m = load_module( module );
|
||||||
if ( !m )
|
if ( !m )
|
||||||
@ -252,6 +417,10 @@ main( int argc, char* argv[] )
|
|||||||
cDebug() << " .. got" << m->name() << m->typeString() << m->interfaceString();
|
cDebug() << " .. got" << m->name() << m->typeString() << m->interfaceString();
|
||||||
if ( m->type() == Calamares::Module::Type::View )
|
if ( m->type() == Calamares::Module::Type::View )
|
||||||
{
|
{
|
||||||
|
// If we forgot the --ui, any ViewModule will core dump as it
|
||||||
|
// tries to create the widget **which won't be used anyway**.
|
||||||
|
//
|
||||||
|
// To avoid that crash, re-create the QApplication, now with GUI
|
||||||
if ( !qobject_cast< QApplication* >( aw ) )
|
if ( !qobject_cast< QApplication* >( aw ) )
|
||||||
{
|
{
|
||||||
auto* replace_app = new QApplication( argc, argv );
|
auto* replace_app = new QApplication( argc, argv );
|
||||||
@ -261,8 +430,9 @@ main( int argc, char* argv[] )
|
|||||||
mw = module.m_ui ? new QMainWindow() : nullptr;
|
mw = module.m_ui ? new QMainWindow() : nullptr;
|
||||||
|
|
||||||
(void)new Calamares::Branding( module.m_branding );
|
(void)new Calamares::Branding( module.m_branding );
|
||||||
(void)new Calamares::ModuleManager( QStringList(), nullptr );
|
auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr );
|
||||||
(void)Calamares::ViewManager::instance( mw );
|
(void)Calamares::ViewManager::instance( mw );
|
||||||
|
modulemanager->addModule( m );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !m->isLoaded() )
|
if ( !m->isLoaded() )
|
||||||
|
@ -42,7 +42,6 @@ namespace CalamaresUtils
|
|||||||
{
|
{
|
||||||
|
|
||||||
static QDir s_appDataDir( CMAKE_INSTALL_FULL_DATADIR );
|
static QDir s_appDataDir( CMAKE_INSTALL_FULL_DATADIR );
|
||||||
static QDir s_qmlModulesDir( QString( CMAKE_INSTALL_FULL_DATADIR ) + "/qml" );
|
|
||||||
static bool s_isAppDataDirOverridden = false;
|
static bool s_isAppDataDirOverridden = false;
|
||||||
|
|
||||||
static bool s_haveExtraDirs = false;
|
static bool s_haveExtraDirs = false;
|
||||||
@ -79,13 +78,6 @@ isWritableDir( const QDir& dir )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QDir
|
|
||||||
qmlModulesDir()
|
|
||||||
{
|
|
||||||
return s_qmlModulesDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
setAppDataDir( const QDir& dir )
|
setAppDataDir( const QDir& dir )
|
||||||
{
|
{
|
||||||
@ -200,11 +192,4 @@ appLogDir()
|
|||||||
return QDir::temp();
|
return QDir::temp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
setQmlModulesDir( const QDir& dir )
|
|
||||||
{
|
|
||||||
s_qmlModulesDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
namespace CalamaresUtils
|
namespace CalamaresUtils
|
||||||
{
|
{
|
||||||
DLLEXPORT QDir qmlModulesDir();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief appDataDir returns the directory with common application data.
|
* @brief appDataDir returns the directory with common application data.
|
||||||
* Defaults to CMAKE_INSTALL_FULL_DATADIR (usually /usr/share/calamares).
|
* Defaults to CMAKE_INSTALL_FULL_DATADIR (usually /usr/share/calamares).
|
||||||
@ -57,8 +55,6 @@ DLLEXPORT QDir systemLibDir();
|
|||||||
DLLEXPORT void setAppDataDir( const QDir& dir );
|
DLLEXPORT void setAppDataDir( const QDir& dir );
|
||||||
DLLEXPORT bool isAppDataDirOverridden();
|
DLLEXPORT bool isAppDataDirOverridden();
|
||||||
|
|
||||||
DLLEXPORT void setQmlModulesDir( const QDir& dir );
|
|
||||||
|
|
||||||
/** @brief Setup extra config and data dirs from the XDG variables.
|
/** @brief Setup extra config and data dirs from the XDG variables.
|
||||||
*/
|
*/
|
||||||
DLLEXPORT void setXdgDirs();
|
DLLEXPORT void setXdgDirs();
|
||||||
|
@ -52,14 +52,14 @@ CppJobModule::loadSelf()
|
|||||||
CalamaresPluginFactory* pf = qobject_cast< CalamaresPluginFactory* >( m_loader->instance() );
|
CalamaresPluginFactory* pf = qobject_cast< CalamaresPluginFactory* >( m_loader->instance() );
|
||||||
if ( !pf )
|
if ( !pf )
|
||||||
{
|
{
|
||||||
cDebug() << Q_FUNC_INFO << m_loader->errorString();
|
cDebug() << "Could not load module:" << m_loader->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CppJob* cppJob = pf->create< Calamares::CppJob >();
|
CppJob* cppJob = pf->create< Calamares::CppJob >();
|
||||||
if ( !cppJob )
|
if ( !cppJob )
|
||||||
{
|
{
|
||||||
cDebug() << Q_FUNC_INFO << m_loader->errorString();
|
cDebug() << "Could not load module:" << m_loader->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// cDebug() << "CppJobModule loading self for instance" << instanceKey()
|
// cDebug() << "CppJobModule loading self for instance" << instanceKey()
|
||||||
|
@ -300,22 +300,12 @@ ModuleManager::loadModules()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !checkModuleDependencies( *thisModule ) )
|
if ( !addModule( thisModule ) )
|
||||||
{
|
{
|
||||||
// Error message is already printed
|
// Error message is already printed
|
||||||
failedModules.append( instanceKey.toString() );
|
failedModules.append( instanceKey.toString() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a ViewModule, it also appends the ViewStep to the ViewManager.
|
|
||||||
thisModule->loadSelf();
|
|
||||||
m_loadedModulesByInstanceKey.insert( instanceKey, thisModule );
|
|
||||||
if ( !thisModule->isLoaded() )
|
|
||||||
{
|
|
||||||
cError() << "Module" << instanceKey.toString() << "loading FAILED.";
|
|
||||||
failedModules.append( instanceKey.toString() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point we most certainly have a pointer to a loaded module in
|
// At this point we most certainly have a pointer to a loaded module in
|
||||||
@ -345,6 +335,40 @@ ModuleManager::loadModules()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ModuleManager::addModule( Module *module )
|
||||||
|
{
|
||||||
|
if ( !module )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !module->instanceKey().isValid() )
|
||||||
|
{
|
||||||
|
cWarning() << "Module" << module->location() << '@' << (void*)module << "has invalid instance key.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !checkModuleDependencies( *module ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !module->isLoaded() )
|
||||||
|
{
|
||||||
|
module->loadSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even if the load failed, we keep the module, so that if it tried to
|
||||||
|
// get loaded **again**, we already know.
|
||||||
|
m_loadedModulesByInstanceKey.insert( module->instanceKey(), module );
|
||||||
|
if ( !module->isLoaded() )
|
||||||
|
{
|
||||||
|
cError() << "Module" << module->instanceKey().toString() << "loading FAILED.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleManager::checkRequirements()
|
ModuleManager::checkRequirements()
|
||||||
{
|
{
|
||||||
@ -414,6 +438,12 @@ ModuleManager::checkDependencies()
|
|||||||
bool
|
bool
|
||||||
ModuleManager::checkModuleDependencies( const Module& m )
|
ModuleManager::checkModuleDependencies( const Module& m )
|
||||||
{
|
{
|
||||||
|
if ( !m_availableDescriptorsByModuleName.contains( m.name() ) )
|
||||||
|
{
|
||||||
|
cWarning() << "Module" << m.name() << "loaded externally, no dependency information.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool allRequirementsFound = true;
|
bool allRequirementsFound = true;
|
||||||
QStringList requiredModules
|
QStringList requiredModules
|
||||||
= m_availableDescriptorsByModuleName[ m.name() ].value( "requiredModules" ).toStringList();
|
= m_availableDescriptorsByModuleName[ m.name() ].value( "requiredModules" ).toStringList();
|
||||||
|
@ -85,6 +85,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
void loadModules();
|
void loadModules();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a single module (loaded by some other means)
|
||||||
|
*
|
||||||
|
* Returns @c true on success (that is, the module's dependencies
|
||||||
|
* are satisfied, it wasn't already loaded, ...).
|
||||||
|
*/
|
||||||
|
bool addModule( Module* );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Starts asynchronous requirements checking for each module.
|
* @brief Starts asynchronous requirements checking for each module.
|
||||||
* When this is done, the signal requirementsComplete is emitted.
|
* When this is done, the signal requirementsComplete is emitted.
|
||||||
|
@ -53,14 +53,14 @@ ViewModule::loadSelf()
|
|||||||
CalamaresPluginFactory* pf = qobject_cast< CalamaresPluginFactory* >( m_loader->instance() );
|
CalamaresPluginFactory* pf = qobject_cast< CalamaresPluginFactory* >( m_loader->instance() );
|
||||||
if ( !pf )
|
if ( !pf )
|
||||||
{
|
{
|
||||||
cWarning() << Q_FUNC_INFO << "No factory:" << m_loader->errorString();
|
cWarning() << "No factory:" << m_loader->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_viewStep = pf->create< Calamares::ViewStep >();
|
m_viewStep = pf->create< Calamares::ViewStep >();
|
||||||
if ( !m_viewStep )
|
if ( !m_viewStep )
|
||||||
{
|
{
|
||||||
cWarning() << Q_FUNC_INFO << "create() failed" << m_loader->errorString();
|
cWarning() << "create() failed" << m_loader->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ ViewModule::loadSelf()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cWarning() << Q_FUNC_INFO << "No view step was created";
|
cWarning() << "No view step was created";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +207,10 @@ unmarginLayout( QLayout* layout )
|
|||||||
int
|
int
|
||||||
defaultFontSize()
|
defaultFontSize()
|
||||||
{
|
{
|
||||||
|
if ( s_defaultFontSize <= 0 )
|
||||||
|
{
|
||||||
|
s_defaultFontSize = QFont().pointSize();
|
||||||
|
}
|
||||||
return s_defaultFontSize;
|
return s_defaultFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
#include "Branding.h"
|
#include "Branding.h"
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
|
#include "Settings.h"
|
||||||
#include "ViewManager.h"
|
#include "ViewManager.h"
|
||||||
|
#include "utils/Dirs.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
@ -30,11 +32,81 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
|
static QDir s_qmlModulesDir( QString( CMAKE_INSTALL_FULL_DATADIR ) + "/qml" );
|
||||||
|
|
||||||
namespace CalamaresUtils
|
namespace CalamaresUtils
|
||||||
{
|
{
|
||||||
|
QDir
|
||||||
|
qmlModulesDir()
|
||||||
|
{
|
||||||
|
return s_qmlModulesDir;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
callQMLFunction( QQuickItem* qmlObject, const char* method )
|
setQmlModulesDir( const QDir& dir )
|
||||||
|
{
|
||||||
|
s_qmlModulesDir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QStringList
|
||||||
|
qmlDirCandidates( bool assumeBuilddir )
|
||||||
|
{
|
||||||
|
static const char QML[] = "qml";
|
||||||
|
|
||||||
|
QStringList qmlDirs;
|
||||||
|
if ( CalamaresUtils::isAppDataDirOverridden() )
|
||||||
|
{
|
||||||
|
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( assumeBuilddir )
|
||||||
|
{
|
||||||
|
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir
|
||||||
|
}
|
||||||
|
if ( CalamaresUtils::haveExtraDirs() )
|
||||||
|
for ( auto s : CalamaresUtils::extraDataDirs() )
|
||||||
|
{
|
||||||
|
qmlDirs << ( s + QML );
|
||||||
|
}
|
||||||
|
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
|
||||||
|
}
|
||||||
|
|
||||||
|
return qmlDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
initQmlModulesDir()
|
||||||
|
{
|
||||||
|
QStringList qmlDirCandidatesByPriority
|
||||||
|
= qmlDirCandidates( Calamares::Settings::instance() && Calamares::Settings::instance()->debugMode() );
|
||||||
|
|
||||||
|
for ( const QString& path : qmlDirCandidatesByPriority )
|
||||||
|
{
|
||||||
|
QDir dir( path );
|
||||||
|
if ( dir.exists() && dir.isReadable() )
|
||||||
|
{
|
||||||
|
cDebug() << "Using Calamares QML directory" << dir.absolutePath();
|
||||||
|
CalamaresUtils::setQmlModulesDir( dir );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cError() << "Cowardly refusing to continue startup without a QML directory."
|
||||||
|
<< Logger::DebugList( qmlDirCandidatesByPriority );
|
||||||
|
if ( CalamaresUtils::isAppDataDirOverridden() )
|
||||||
|
{
|
||||||
|
cError() << "FATAL: explicitly configured application data directory is missing qml/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cError() << "FATAL: none of the expected QML paths exist.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
callQmlFunction( QQuickItem* qmlObject, const char* method )
|
||||||
{
|
{
|
||||||
QByteArray methodSignature( method );
|
QByteArray methodSignature( method );
|
||||||
methodSignature.append( "()" );
|
methodSignature.append( "()" );
|
||||||
@ -149,7 +221,7 @@ qmlSearchNames()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
registerCalamaresModels()
|
registerQmlModels()
|
||||||
{
|
{
|
||||||
static bool done = false;
|
static bool done = false;
|
||||||
if ( !done )
|
if ( !done )
|
||||||
|
@ -24,10 +24,25 @@
|
|||||||
#include "modulesystem/InstanceKey.h"
|
#include "modulesystem/InstanceKey.h"
|
||||||
#include "utils/NamedEnum.h"
|
#include "utils/NamedEnum.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
class QQuickItem;
|
class QQuickItem;
|
||||||
|
|
||||||
namespace CalamaresUtils
|
namespace CalamaresUtils
|
||||||
{
|
{
|
||||||
|
/// @brief the extra directory where Calamares searches for QML files
|
||||||
|
UIDLLEXPORT QDir qmlModulesDir();
|
||||||
|
/// @brief sets specific directory for searching for QML files
|
||||||
|
UIDLLEXPORT void setQmlModulesDir( const QDir& dir );
|
||||||
|
|
||||||
|
/** @brief initialize QML search path with branding directories
|
||||||
|
*
|
||||||
|
* Picks a suitable branding directory (from the build-dir in debug mode,
|
||||||
|
* otherwise based on the branding directory) and adds it to the
|
||||||
|
* QML modules directory; returns @c false if none is found.
|
||||||
|
*/
|
||||||
|
UIDLLEXPORT bool initQmlModulesDir();
|
||||||
|
|
||||||
/** @brief Sets up global Calamares models for QML
|
/** @brief Sets up global Calamares models for QML
|
||||||
*
|
*
|
||||||
* This needs to be called at least once to make the global Calamares
|
* This needs to be called at least once to make the global Calamares
|
||||||
@ -40,7 +55,7 @@ namespace CalamaresUtils
|
|||||||
* Additionally, modules based on QmlViewStep have a context
|
* Additionally, modules based on QmlViewStep have a context
|
||||||
* property `config` referring to that module's configuration (if any).
|
* property `config` referring to that module's configuration (if any).
|
||||||
*/
|
*/
|
||||||
UIDLLEXPORT void registerCalamaresModels();
|
UIDLLEXPORT void registerQmlModels();
|
||||||
|
|
||||||
/** @brief Calls the QML method @p method on @p qmlObject
|
/** @brief Calls the QML method @p method on @p qmlObject
|
||||||
*
|
*
|
||||||
@ -50,7 +65,7 @@ UIDLLEXPORT void registerCalamaresModels();
|
|||||||
*
|
*
|
||||||
* If there is a return value from the QML method, it is logged (but not otherwise used).
|
* If there is a return value from the QML method, it is logged (but not otherwise used).
|
||||||
*/
|
*/
|
||||||
UIDLLEXPORT void callQMLFunction( QQuickItem* qmlObject, const char* method );
|
UIDLLEXPORT void callQmlFunction( QQuickItem* qmlObject, const char* method );
|
||||||
|
|
||||||
/** @brief Search modes for loading Qml files.
|
/** @brief Search modes for loading Qml files.
|
||||||
*
|
*
|
||||||
|
@ -58,7 +58,7 @@ changeQMLState( QMLAction action, QQuickItem* item )
|
|||||||
static const char propertyName[] = "activatedInCalamares";
|
static const char propertyName[] = "activatedInCalamares";
|
||||||
|
|
||||||
bool activate = action == QMLAction::Start;
|
bool activate = action == QMLAction::Start;
|
||||||
CalamaresUtils::callQMLFunction( item, activate ? "onActivate" : "onLeave" );
|
CalamaresUtils::callQmlFunction( item, activate ? "onActivate" : "onLeave" );
|
||||||
|
|
||||||
auto property = item->property( propertyName );
|
auto property = item->property( propertyName );
|
||||||
if ( property.isValid() && ( property.type() == QVariant::Bool ) && ( property.toBool() != activate ) )
|
if ( property.isValid() && ( property.type() == QVariant::Bool ) && ( property.toBool() != activate ) )
|
||||||
@ -76,7 +76,7 @@ QmlViewStep::QmlViewStep( QObject* parent )
|
|||||||
, m_spinner( new WaitingWidget( tr( "Loading ..." ) ) )
|
, m_spinner( new WaitingWidget( tr( "Loading ..." ) ) )
|
||||||
, m_qmlWidget( new QQuickWidget )
|
, m_qmlWidget( new QQuickWidget )
|
||||||
{
|
{
|
||||||
CalamaresUtils::registerCalamaresModels();
|
CalamaresUtils::registerQmlModels();
|
||||||
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
||||||
layout->addWidget( m_spinner );
|
layout->addWidget( m_spinner );
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
#include "Branding.h"
|
#include "Branding.h"
|
||||||
#include "utils/Dirs.h"
|
#include "utils/Dirs.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#ifdef WITH_QML
|
||||||
#include "utils/Qml.h"
|
#include "utils/Qml.h"
|
||||||
|
#endif
|
||||||
#include "utils/Retranslator.h"
|
#include "utils/Retranslator.h"
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@ -50,6 +52,8 @@ SlideshowQML::SlideshowQML( QWidget* parent )
|
|||||||
, m_qmlComponent( nullptr )
|
, m_qmlComponent( nullptr )
|
||||||
, m_qmlObject( nullptr )
|
, m_qmlObject( nullptr )
|
||||||
{
|
{
|
||||||
|
CalamaresUtils::registerQmlModels();
|
||||||
|
|
||||||
m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||||
m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
||||||
m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() );
|
m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() );
|
||||||
@ -121,11 +125,30 @@ SlideshowQML::loadQmlV2Complete()
|
|||||||
if ( isActive() )
|
if ( isActive() )
|
||||||
{
|
{
|
||||||
// We're alreay visible! Must have been slow QML loading, and we
|
// We're alreay visible! Must have been slow QML loading, and we
|
||||||
// passed onActivate already.
|
// passed onActivate already. changeSlideShowState() locks
|
||||||
|
// the same mutex: we could set up a workaround to call
|
||||||
|
// changeSlideShowState() later after destruction of l.
|
||||||
|
//
|
||||||
|
l.unlock();
|
||||||
changeSlideShowState( Slideshow::Start );
|
changeSlideShowState( Slideshow::Start );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( m_qmlObject )
|
||||||
|
{
|
||||||
|
cWarning() << "QML object already created";
|
||||||
|
}
|
||||||
|
else if ( !m_qmlComponent )
|
||||||
|
{
|
||||||
|
cWarning() << "QML component does not exist";
|
||||||
|
}
|
||||||
|
else if ( m_qmlComponent && !m_qmlComponent->isReady() )
|
||||||
|
{
|
||||||
|
cWarning() << "QML component not ready:" << m_qmlComponent->errors();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -144,7 +167,7 @@ SlideshowQML::changeSlideShowState( Action state )
|
|||||||
if ( Branding::instance()->slideshowAPI() == 2 )
|
if ( Branding::instance()->slideshowAPI() == 2 )
|
||||||
{
|
{
|
||||||
// The QML was already loaded in the constructor, need to start it
|
// The QML was already loaded in the constructor, need to start it
|
||||||
CalamaresUtils::callQMLFunction( m_qmlObject, activate ? "onActivate" : "onLeave" );
|
CalamaresUtils::callQmlFunction( m_qmlObject, activate ? "onActivate" : "onLeave" );
|
||||||
}
|
}
|
||||||
else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() )
|
else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -560,7 +560,7 @@ ChoicePage::doAlongsideSetupSplitter( const QModelIndex& current,
|
|||||||
Partition* part = modl->partitionForIndex( current );
|
Partition* part = modl->partitionForIndex( current );
|
||||||
if ( !part )
|
if ( !part )
|
||||||
{
|
{
|
||||||
cDebug() << Q_FUNC_INFO << "Partition not found for index" << current;
|
cDebug() << "Partition not found for index" << current;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,10 +120,10 @@ PartitionSplitterWidget::setSplitPartition( const QString& path,
|
|||||||
qint64 maxSize,
|
qint64 maxSize,
|
||||||
qint64 preferredSize )
|
qint64 preferredSize )
|
||||||
{
|
{
|
||||||
cDebug() << Q_FUNC_INFO << "path:" << path
|
cDebug() << "path:" << path
|
||||||
<< "\nminSize:" << minSize
|
<< Logger::Continuation << "minSize:" << minSize
|
||||||
<< "\nmaxSize:" << maxSize
|
<< Logger::Continuation << "maxSize:" << maxSize
|
||||||
<< "\nprfSize:" << preferredSize;
|
<< Logger::Continuation << "prfSize:" << preferredSize;
|
||||||
|
|
||||||
if ( m_itemToResize && m_itemToResizeNext )
|
if ( m_itemToResize && m_itemToResizeNext )
|
||||||
{
|
{
|
||||||
|
@ -96,7 +96,7 @@ class RawFSItem:
|
|||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
libcalamares.utils.debug("Copying {} to {}".format(self.source, self.destination))
|
libcalamares.utils.debug("Copying {} to {}".format(self.source, self.destination))
|
||||||
if libcalamares.job.configuration["bogus"]:
|
if libcalamares.job.configuration.get("bogus", False):
|
||||||
return
|
return
|
||||||
|
|
||||||
srcsize, srcblksize = get_device_size(self.source)
|
srcsize, srcblksize = get_device_size(self.source)
|
||||||
|
Loading…
Reference in New Issue
Block a user