Merge branch 'master' into issue-1152

This commit is contained in:
Adriaan de Groot 2019-06-16 13:11:03 +02:00
commit 075f0787f9
46 changed files with 864 additions and 561 deletions

View file

@ -16,27 +16,27 @@
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QDesktopWidget>
#include "CalamaresApplication.h"
#include "CalamaresConfig.h"
#include "CalamaresWindow.h"
#include "CalamaresVersion.h"
#include "progresstree/ProgressTreeView.h"
#include "CalamaresWindow.h"
#include "progresstree/ProgressTreeModel.h"
#include "progresstree/ProgressTreeView.h"
#include "Branding.h"
#include "JobQueue.h"
#include "Settings.h"
#include "ViewManager.h"
#include "modulesystem/ModuleManager.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "JobQueue.h"
#include "Branding.h"
#include "Settings.h"
#include "viewpages/ViewStep.h"
#include "ViewManager.h"
#include <QDesktopWidget>
#include <QDir>
#include <QFileInfo>
@ -77,12 +77,11 @@ CalamaresApplication::init()
initSettings();
initBranding();
setWindowIcon( QIcon( Calamares::Branding::instance()->
imagePath( Calamares::Branding::ProductIcon ) ) );
setWindowIcon( QIcon( Calamares::Branding::instance()->imagePath( Calamares::Branding::ProductIcon ) ) );
cDebug() << "STARTUP: initQmlPath, initSettings, initBranding done";
initModuleManager(); //also shows main window
initModuleManager(); //also shows main window
cDebug() << "STARTUP: initModuleManager: module init started";
}
@ -91,15 +90,7 @@ CalamaresApplication::init()
CalamaresApplication::~CalamaresApplication()
{
cDebug( Logger::LOGVERBOSE ) << "Shutting down Calamares...";
// if ( JobQueue::instance() )
// JobQueue::instance()->stop();
// delete m_mainwindow;
// delete JobQueue::instance();
cDebug( Logger::LOGVERBOSE ) << "Finished shutdown.";
cDebug( Logger::LOGVERBOSE ) << Logger::SubEntry << "Finished shutdown.";
}
@ -138,14 +129,20 @@ qmlDirCandidates( bool assumeBuilddir )
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 );
}
@ -160,14 +157,20 @@ settingsFileCandidates( bool assumeBuilddir )
QStringList settingsPaths;
if ( CalamaresUtils::isAppDataDirOverridden() )
{
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
else
{
if ( assumeBuilddir )
{
settingsPaths << QDir::current().absoluteFilePath( settings );
}
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraConfigDirs() )
{
settingsPaths << ( s + settings );
}
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
@ -181,16 +184,22 @@ brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
{
QStringList brandingPaths;
if ( CalamaresUtils::isAppDataDirOverridden() )
{
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename );
}
else
{
if ( assumeBuilddir )
{
brandingPaths << ( QDir::currentPath() + QStringLiteral( "/src/" ) + brandingFilename );
}
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraDataDirs() )
{
brandingPaths << ( s + brandingFilename );
}
brandingPaths << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename);
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename );
}
return brandingPaths;
@ -218,11 +227,15 @@ CalamaresApplication::initQmlPath()
if ( !found || !importPath.exists() || !importPath.isReadable() )
{
cError() << "Cowardly refusing to continue startup without a QML directory."
<< Logger::DebugList( qmlDirCandidatesByPriority );
<< 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 );
}
@ -253,11 +266,15 @@ CalamaresApplication::initSettings()
if ( !found || !settingsFile.exists() || !settingsFile.isReadable() )
{
cError() << "Cowardly refusing to continue startup without settings."
<< Logger::DebugList( settingsFileCandidatesByPriority );
<< Logger::DebugList( settingsFileCandidatesByPriority );
if ( CalamaresUtils::isAppDataDirOverridden() )
{
cError() << "FATAL: explicitly configured application data directory is missing settings.conf";
}
else
{
cError() << "FATAL: none of the expected configuration file paths exist.";
}
::exit( EXIT_FAILURE );
}
@ -281,7 +298,7 @@ CalamaresApplication::initBranding()
}
QString brandingDescriptorSubpath = QString( "branding/%1/branding.desc" ).arg( brandingComponentName );
QStringList brandingFileCandidatesByPriority = brandingFileCandidates( isDebug(), brandingDescriptorSubpath);
QStringList brandingFileCandidatesByPriority = brandingFileCandidates( isDebug(), brandingDescriptorSubpath );
QFileInfo brandingFile;
bool found = false;
@ -300,11 +317,15 @@ CalamaresApplication::initBranding()
if ( !found || !brandingFile.exists() || !brandingFile.isReadable() )
{
cError() << "Cowardly refusing to continue startup without branding."
<< Logger::DebugList( brandingFileCandidatesByPriority );
<< Logger::DebugList( brandingFileCandidatesByPriority );
if ( CalamaresUtils::isAppDataDirOverridden() )
{
cError() << "FATAL: explicitly configured application data directory is missing" << brandingComponentName;
}
else
{
cError() << "FATAL: none of the expected branding descriptor file paths exist.";
}
::exit( EXIT_FAILURE );
}
@ -315,10 +336,8 @@ CalamaresApplication::initBranding()
void
CalamaresApplication::initModuleManager()
{
m_moduleManager = new Calamares::ModuleManager(
Calamares::Settings::instance()->modulesSearchPaths(), this );
connect( m_moduleManager, &Calamares::ModuleManager::initDone,
this, &CalamaresApplication::initView );
m_moduleManager = new Calamares::ModuleManager( Calamares::Settings::instance()->modulesSearchPaths(), this );
connect( m_moduleManager, &Calamares::ModuleManager::initDone, this, &CalamaresApplication::initView );
m_moduleManager->init();
}
@ -330,18 +349,14 @@ CalamaresApplication::initView()
initJobQueue();
cDebug() << "STARTUP: initJobQueue done";
m_mainwindow = new CalamaresWindow(); //also creates ViewManager
m_mainwindow = new CalamaresWindow(); //also creates ViewManager
connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded,
this, &CalamaresApplication::initViewSteps );
connect( m_moduleManager, &Calamares::ModuleManager::modulesFailed,
this, &CalamaresApplication::initFailed );
connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded, this, &CalamaresApplication::initViewSteps );
connect( m_moduleManager, &Calamares::ModuleManager::modulesFailed, this, &CalamaresApplication::initFailed );
m_moduleManager->loadModules();
m_mainwindow->move(
this->desktop()->availableGeometry().center() -
m_mainwindow->rect().center() );
m_mainwindow->move( this->desktop()->availableGeometry().center() - m_mainwindow->rect().center() );
cDebug() << "STARTUP: CalamaresWindow created; loadModules started";
}
@ -358,7 +373,9 @@ CalamaresApplication::initViewSteps()
m_mainwindow->showMaximized();
}
else
{
m_mainwindow->show();
}
ProgressTreeModel* m = new ProgressTreeModel( nullptr );
ProgressTreeView::instance()->setModel( m );
@ -368,11 +385,13 @@ CalamaresApplication::initViewSteps()
cDebug() << Logger::SubEntry << steps.count() << "view steps loaded.";
// Tell the first view that it's been shown.
if ( steps.count() > 0 )
steps[0]->onActivate();
{
steps[ 0 ]->onActivate();
}
}
void
CalamaresApplication::initFailed(const QStringList& l)
CalamaresApplication::initFailed( const QStringList& l )
{
cError() << "STARTUP: failed modules are" << l;
m_mainwindow->show();

View file

@ -82,4 +82,4 @@ private:
bool m_debugMode;
};
#endif //CALAMARESAPPLICATION_H
#endif // CALAMARESAPPLICATION_H

View file

@ -21,33 +21,39 @@
#include "CalamaresWindow.h"
#include "Branding.h"
#include "Settings.h"
#include "ViewManager.h"
#include "progresstree/ProgressTreeView.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "utils/DebugWindow.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "Settings.h"
#include "Branding.h"
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
#include <QDesktopWidget>
#include <QLabel>
#include <QTreeView>
#include <QFile>
#include <QFileInfo>
#include <QLabel>
#include <QTreeView>
static inline int
windowDimensionToPixels( const Calamares::Branding::WindowDimension& u )
{
if ( !u.isValid() )
{
return 0;
}
if ( u.unit() == Calamares::Branding::WindowDimensionUnit::Pixies )
{
return u.value();
}
if ( u.unit() == Calamares::Branding::WindowDimensionUnit::Fonties )
{
return u.value() * CalamaresUtils::defaultFontHeight();
}
return 0;
}
@ -58,14 +64,13 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
{
// If we can never cancel, don't show the window-close button
if ( Calamares::Settings::instance()->disableCancel() )
{
setWindowFlag( Qt::WindowCloseButtonHint, false );
}
CALAMARES_RETRANSLATE(
setWindowTitle( Calamares::Settings::instance()->isSetupMode()
? tr( "%1 Setup Program" ).arg( *Calamares::Branding::ProductName )
: tr( "%1 Installer" ).arg( *Calamares::Branding::ProductName )
);
)
CALAMARES_RETRANSLATE( setWindowTitle( Calamares::Settings::instance()->isSetupMode()
? tr( "%1 Setup Program" ).arg( *Calamares::Branding::ProductName )
: tr( "%1 Installer" ).arg( *Calamares::Branding::ProductName ) ); )
const Calamares::Branding* const branding = Calamares::Branding::instance();
@ -75,7 +80,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
using CalamaresUtils::windowPreferredWidth;
// Needs to match what's checked in DebugWindow
this->setObjectName("mainApp");
this->setObjectName( "mainApp" );
QSize availableSize = qApp->desktop()->availableGeometry( this ).size();
QSize minimumSize( qBound( windowMinimumWidth, availableSize.width(), windowPreferredWidth ),
@ -87,7 +92,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
auto brandingSizes = branding->windowSize();
int w = qBound( minimumSize.width(), windowDimensionToPixels( brandingSizes.first ), availableSize.width() );
int h = qBound( minimumSize.height(), windowDimensionToPixels( brandingSizes.second ), availableSize.height() );
int h = qBound( minimumSize.height(), windowDimensionToPixels( brandingSizes.second ), availableSize.height() );
cDebug() << Logger::SubEntry << "Proposed window size:" << w << h;
resize( w, h );
@ -96,25 +101,26 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
setLayout( mainLayout );
QWidget* sideBox = new QWidget( this );
sideBox->setObjectName("sidebarApp");
sideBox->setObjectName( "sidebarApp" );
mainLayout->addWidget( sideBox );
QBoxLayout* sideLayout = new QVBoxLayout;
sideBox->setLayout( sideLayout );
// Set this attribute into qss file
sideBox->setFixedWidth( qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) );
sideBox->setFixedWidth(
qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) );
sideBox->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
QHBoxLayout* logoLayout = new QHBoxLayout;
sideLayout->addLayout( logoLayout );
logoLayout->addStretch();
QLabel* logoLabel = new QLabel( sideBox );
logoLabel->setObjectName("logoApp");
logoLabel->setObjectName( "logoApp" );
//Define all values into qss file
{
QPalette plt = sideBox->palette();
sideBox->setAutoFillBackground( true );
plt.setColor( sideBox->backgroundRole(),branding->styleString( Calamares::Branding::SidebarBackground ) );
plt.setColor( sideBox->backgroundRole(), branding->styleString( Calamares::Branding::SidebarBackground ) );
plt.setColor( sideBox->foregroundRole(), branding->styleString( Calamares::Branding::SidebarText ) );
sideBox->setPalette( plt );
logoLabel->setPalette( plt );
@ -133,22 +139,16 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
{
QPushButton* debugWindowBtn = new QPushButton;
debugWindowBtn->setObjectName( "debugButton" );
CALAMARES_RETRANSLATE(
debugWindowBtn->setText( tr( "Show debug information" ) );
)
CALAMARES_RETRANSLATE( debugWindowBtn->setText( tr( "Show debug information" ) ); )
sideLayout->addWidget( debugWindowBtn );
debugWindowBtn->setFlat( true );
debugWindowBtn->setCheckable( true );
connect( debugWindowBtn, &QPushButton::clicked,
this, [ = ]( bool checked )
{
connect( debugWindowBtn, &QPushButton::clicked, this, [=]( bool checked ) {
if ( checked )
{
m_debugWindow = new Calamares::DebugWindow();
m_debugWindow->show();
connect( m_debugWindow.data(), &Calamares::DebugWindow::closed,
this, [ = ]()
{
connect( m_debugWindow.data(), &Calamares::DebugWindow::closed, this, [=]() {
m_debugWindow->deleteLater();
debugWindowBtn->setChecked( false );
} );
@ -156,7 +156,9 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
else
{
if ( m_debugWindow )
{
m_debugWindow->deleteLater();
}
}
} );
}
@ -166,7 +168,9 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
m_viewManager = Calamares::ViewManager::instance( this );
if ( branding->windowExpands() )
{
connect( m_viewManager, &Calamares::ViewManager::enlarge, this, &CalamaresWindow::enlarge );
}
// NOTE: Although the ViewManager has a signal cancelEnabled() that
// signals when the state of the cancel button changes (in
// particular, to disable cancel during the exec phase),
@ -201,5 +205,7 @@ CalamaresWindow::closeEvent( QCloseEvent* event )
qApp->quit();
}
else
{
event->ignore();
}
}

View file

@ -27,7 +27,7 @@ namespace Calamares
{
class DebugWindow;
class ViewManager;
}
} // namespace Calamares
/**
* @brief The CalamaresWindow class represents the main window of the Calamares UI.
@ -55,4 +55,4 @@ private:
Calamares::ViewManager* m_viewManager;
};
#endif //CALAMARESWINDOW_H
#endif // CALAMARESWINDOW_H

View file

@ -24,11 +24,10 @@
#include "kdsingleapplicationguard/kdsingleapplicationguard.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "CalamaresConfig.h"
#ifdef WITH_KF5Crash
#include <KF5/KCrash/KCrash>
#include <KF5/KCoreAddons/KAboutData>
#include <KF5/KCrash/KCrash>
#endif
#include <QCommandLineParser>
@ -38,14 +37,13 @@
static void
handle_args( CalamaresApplication& a )
{
QCommandLineOption debugOption( QStringList{ "d", "debug"},
QCommandLineOption debugOption( QStringList { "d", "debug" },
"Also look in current directory for configuration. Implies -D8." );
QCommandLineOption debugLevelOption( QStringLiteral("D"),
"Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption configOption( QStringList{ "c", "config"},
"Configuration directory to use, for testing purposes.", "config" );
QCommandLineOption xdgOption( QStringList{"X", "xdg-config"},
"Use XDG_{CONFIG,DATA}_DIRS as well." );
QCommandLineOption debugLevelOption(
QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption configOption(
QStringList { "c", "config" }, "Configuration directory to use, for testing purposes.", "config" );
QCommandLineOption xdgOption( QStringList { "X", "xdg-config" }, "Use XDG_{CONFIG,DATA}_DIRS as well." );
QCommandLineParser parser;
parser.setApplicationDescription( "Distribution-independent installer framework" );
@ -61,22 +59,32 @@ handle_args( CalamaresApplication& a )
a.setDebug( parser.isSet( debugOption ) );
if ( parser.isSet( debugOption ) )
{
Logger::setupLogLevel( Logger::LOGVERBOSE );
}
else if ( parser.isSet( debugLevelOption ) )
{
bool ok = true;
int l = parser.value( debugLevelOption ).toInt( &ok );
unsigned int dlevel = 0;
if ( !ok || ( l < 0 ) )
{
dlevel = Logger::LOGVERBOSE;
}
else
dlevel = static_cast<unsigned int>( l ); // l >= 0
{
dlevel = static_cast< unsigned int >( l ); // l >= 0
}
Logger::setupLogLevel( dlevel );
}
if ( parser.isSet( configOption ) )
{
CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) );
}
if ( parser.isSet( xdgOption ) )
{
CalamaresUtils::setXdgDirs();
}
}
int
@ -118,9 +126,13 @@ main( int argc, char* argv[] )
auto instancelist = guard.instances();
qDebug() << "Calamares is already running, shutting down.";
if ( instancelist.count() > 0 )
{
qDebug() << "Other running Calamares instances:";
}
for ( const auto& i : instancelist )
{
qDebug() << " " << i.isValid() << i.pid() << i.arguments();
}
}
return returnCode;

View file

@ -20,23 +20,28 @@
#include "ProgressTreeDelegate.h"
#include "ProgressTreeModel.h"
#include "Branding.h"
#include "CalamaresApplication.h"
#include "CalamaresWindow.h"
#include "Branding.h"
#include "utils/CalamaresUtilsGui.h"
#include <QPainter>
static constexpr int const item_margin = 8;
static inline int item_fontsize() { return CalamaresUtils::defaultFontSize() + 4; }
static inline int
item_fontsize()
{
return CalamaresUtils::defaultFontSize() + 4;
}
QSize
ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option,
const QModelIndex& index ) const
ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
if ( !index.isValid() )
{
return option.rect.size();
}
QFont font = qApp->font();
@ -51,9 +56,7 @@ ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option,
void
ProgressTreeDelegate::paint( QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
ProgressTreeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QStyleOptionViewItem opt = option;
@ -62,10 +65,9 @@ ProgressTreeDelegate::paint( QPainter* painter,
initStyleOption( &opt, index );
opt.text.clear();
painter->setBrush( QColor( Calamares::Branding::instance()->
styleString( Calamares::Branding::SidebarBackground ) ) );
painter->setPen( QColor( Calamares::Branding::instance()->
styleString( Calamares::Branding::SidebarText ) ) );
painter->setBrush(
QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ) );
painter->setPen( QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarText ) ) );
paintViewStep( painter, opt, index );
@ -89,14 +91,17 @@ ProgressTreeDelegate::paintViewStep( QPainter* painter,
if ( isCurrent )
{
painter->setPen( Calamares::Branding::instance()->
styleString( Calamares::Branding::SidebarTextSelect ) );
QString textHighlight = Calamares::Branding::instance()->
styleString( Calamares::Branding::SidebarTextHighlight );
painter->setPen( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarTextSelect ) );
QString textHighlight
= Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarTextHighlight );
if ( textHighlight.isEmpty() )
{
painter->setBrush( CalamaresApplication::instance()->mainWindow()->palette().background() );
}
else
{
painter->setBrush( QColor( textHighlight ) );
}
}
@ -114,17 +119,19 @@ ProgressTreeDelegate::paintViewStep( QPainter* painter,
shrinkSteps++;
QRectF boundingBox;
painter->drawText( textRect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, index.data().toString(), &boundingBox );
painter->drawText(
textRect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, index.data().toString(), &boundingBox );
// The extra check here is to avoid the changing-font-size if we're not going to use
// it in the next iteration of the loop anyway.
if ( ( shrinkSteps <= maximumShrink ) && (boundingBox.width() > textRect.width() ) )
if ( ( shrinkSteps <= maximumShrink ) && ( boundingBox.width() > textRect.width() ) )
{
font.setPointSize( item_fontsize() - shrinkSteps );
painter->setFont( font );
}
else
{
break; // It fits
}
while ( shrinkSteps <= maximumShrink );
}
} while ( shrinkSteps <= maximumShrink );
}

View file

@ -33,16 +33,11 @@ public:
using QStyledItemDelegate::QStyledItemDelegate;
protected:
QSize sizeHint( const QStyleOptionViewItem& option,
const QModelIndex& index ) const override;
void paint( QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index ) const override;
QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
private:
void paintViewStep( QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index ) const;
void paintViewStep( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
};
#endif // PROGRESSTREEDELEGATE_H
#endif // PROGRESSTREEDELEGATE_H

View file

@ -65,8 +65,9 @@ int
ProgressTreeItem::row() const
{
if ( m_parentItem )
return m_parentItem->m_childItems.indexOf(
const_cast< ProgressTreeItem* >( this ) );
{
return m_parentItem->m_childItems.indexOf( const_cast< ProgressTreeItem* >( this ) );
}
return 0;
}
@ -80,7 +81,8 @@ ProgressTreeItem::parent()
ProgressTreeRoot::ProgressTreeRoot()
: ProgressTreeItem()
{}
{
}
QVariant

View file

@ -57,4 +57,4 @@ public:
virtual QVariant data( int role ) const;
};
#endif // PROGRESSTREEITEM_H
#endif // PROGRESSTREEITEM_H

View file

@ -19,7 +19,8 @@
#include "ProgressTreeModel.h"
#include "progresstree/ViewStepItem.h"
#include "ViewStepItem.h"
#include "ViewManager.h"
ProgressTreeModel::ProgressTreeModel( QObject* parent )
@ -40,7 +41,9 @@ Qt::ItemFlags
ProgressTreeModel::flags( const QModelIndex& index ) const
{
if ( !index.isValid() )
{
return Qt::ItemFlags();
}
return Qt::ItemIsEnabled;
}
@ -50,20 +53,30 @@ QModelIndex
ProgressTreeModel::index( int row, int column, const QModelIndex& parent ) const
{
if ( !hasIndex( row, column, parent ) )
{
return QModelIndex();
}
ProgressTreeItem* parentItem;
if ( !parent.isValid() )
{
parentItem = m_rootItem;
}
else
{
parentItem = static_cast< ProgressTreeItem* >( parent.internalPointer() );
}
ProgressTreeItem* childItem = parentItem->child( row );
if ( childItem )
{
return createIndex( row, column, childItem );
}
else
{
return QModelIndex();
}
}
@ -71,13 +84,17 @@ QModelIndex
ProgressTreeModel::parent( const QModelIndex& index ) const
{
if ( !index.isValid() )
{
return QModelIndex();
}
ProgressTreeItem* childItem = static_cast< ProgressTreeItem* >( index.internalPointer() );
ProgressTreeItem* parentItem = childItem->parent();
if ( parentItem == m_rootItem )
{
return QModelIndex();
}
return createIndex( parentItem->row(), 0, parentItem );
}
@ -87,7 +104,9 @@ QVariant
ProgressTreeModel::data( const QModelIndex& index, int role ) const
{
if ( !index.isValid() )
{
return QVariant();
}
ProgressTreeItem* item = static_cast< ProgressTreeItem* >( index.internalPointer() );
@ -111,12 +130,18 @@ ProgressTreeModel::rowCount( const QModelIndex& parent ) const
{
ProgressTreeItem* parentItem;
if ( parent.column() > 0 )
{
return 0;
}
if ( !parent.isValid() )
{
parentItem = m_rootItem;
}
else
{
parentItem = static_cast< ProgressTreeItem* >( parent.internalPointer() );
}
return parentItem->childCount();
}
@ -126,9 +151,13 @@ int
ProgressTreeModel::columnCount( const QModelIndex& parent ) const
{
if ( parent.isValid() )
{
return static_cast< ProgressTreeItem* >( parent.internalPointer() )->columnCount();
}
else
{
return m_rootItem->columnCount();
}
}
@ -152,7 +181,9 @@ QModelIndex
ProgressTreeModel::indexFromItem( ProgressTreeItem* item )
{
if ( !item || !item->parent() )
{
return QModelIndex();
}
// Reconstructs a QModelIndex from a ProgressTreeItem that is somewhere in the tree.
// Traverses the item to the root node, then rebuilds the qmodelindices from there
@ -172,10 +203,13 @@ ProgressTreeModel::indexFromItem( ProgressTreeItem* item )
**/
QList< int > childIndexList;
ProgressTreeItem* curItem = item;
while ( curItem != m_rootItem ) {
int row = curItem->row(); //relative to its parent
if ( row < 0 ) // something went wrong, bail
while ( curItem != m_rootItem )
{
int row = curItem->row(); //relative to its parent
if ( row < 0 ) // something went wrong, bail
{
return QModelIndex();
}
childIndexList << row;
@ -184,7 +218,7 @@ ProgressTreeModel::indexFromItem( ProgressTreeItem* item )
// Now we rebuild the QModelIndex we need
QModelIndex idx;
for ( int i = childIndexList.size() - 1; i >= 0 ; i-- )
for ( int i = childIndexList.size() - 1; i >= 0; i-- )
{
idx = index( childIndexList[ i ], 0, idx );
}

View file

@ -57,4 +57,4 @@ private:
ProgressTreeRoot* m_rootItem;
};
#endif // PROGRESSTREEMODEL_H
#endif // PROGRESSTREEMODEL_H

View file

@ -19,8 +19,9 @@
#include "ProgressTreeView.h"
#include "ProgressTreeDelegate.h"
#include "ViewManager.h"
#include "Branding.h"
#include "ViewManager.h"
ProgressTreeView* ProgressTreeView::s_instance = nullptr;
@ -33,9 +34,9 @@ ProgressTreeView::instance()
ProgressTreeView::ProgressTreeView( QWidget* parent )
: QTreeView( parent )
{
s_instance = this; //FIXME: should assert when s_instance gets written and it wasn't nullptr
s_instance = this; //FIXME: should assert when s_instance gets written and it wasn't nullptr
this->setObjectName("sidebarMenuApp");
this->setObjectName( "sidebarMenuApp" );
setFrameShape( QFrame::NoFrame );
setContentsMargins( 0, 0, 0, 0 );
@ -55,31 +56,29 @@ ProgressTreeView::ProgressTreeView( QWidget* parent )
setItemDelegate( m_delegate );
QPalette plt = palette();
plt.setColor( QPalette::Base, Calamares::Branding::instance()->
styleString( Calamares::Branding::SidebarBackground ) );
plt.setColor( QPalette::Base,
Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) );
setPalette( plt );
}
ProgressTreeView::~ProgressTreeView()
{
}
ProgressTreeView::~ProgressTreeView() {}
void
ProgressTreeView::setModel( QAbstractItemModel* model )
{
if ( ProgressTreeView::model() )
{
return;
}
QTreeView::setModel( model );
expandAll();
connect( Calamares::ViewManager::instance(),
&Calamares::ViewManager::currentStepChanged,
this, [this]()
{
viewport()->update();
},
Qt::UniqueConnection );
this,
[this]() { viewport()->update(); },
Qt::UniqueConnection );
}

View file

@ -48,4 +48,4 @@ private:
ProgressTreeDelegate* m_delegate;
};
#endif // PROGRESSTREEVIEW_H
#endif // PROGRESSTREEVIEW_H

View file

@ -19,6 +19,7 @@
#include "ViewStepItem.h"
#include "ProgressTreeModel.h"
#include "Settings.h"
#include "ViewManager.h"
#include "viewpages/ViewStep.h"
@ -28,18 +29,17 @@ ViewStepItem::ViewStepItem( std::function< QString() > prettyName,
std::function< const Calamares::ViewStep*() > accessor,
ProgressTreeItem* parent )
: ProgressTreeItem( parent )
, m_accessor( accessor )
, m_prettyName( prettyName )
, m_step( nullptr )
{
m_prettyName = prettyName;
m_accessor = accessor;
}
ViewStepItem::ViewStepItem( const Calamares::ViewStep* step,
ProgressTreeItem* parent )
ViewStepItem::ViewStepItem( const Calamares::ViewStep* step, ProgressTreeItem* parent )
: ProgressTreeItem( parent )
, m_step( step )
{
m_step = step;
}
void
@ -55,8 +55,7 @@ ViewStepItem::data( int role ) const
{
if ( role == Qt::DisplayRole )
{
return m_step ? m_step->prettyName()
: m_prettyName();
return m_step ? m_step->prettyName() : m_prettyName();
}
if ( Calamares::Settings::instance()->debugMode() && role == Qt::ToolTipRole )
{
@ -66,9 +65,9 @@ ViewStepItem::data( int role ) const
toolTip.append( "<br/>Type:\tViewStep" );
toolTip.append( QString( "<br/>Pretty:\t%1" ).arg( m_step->prettyName() ) );
toolTip.append( QString( "<br/>Status:\t%1" ).arg( m_step->prettyStatus() ) );
toolTip.append( QString( "<br/>Source:\t%1" ).arg(
m_step->moduleInstanceKey().isEmpty() ? "built-in"
: m_step->moduleInstanceKey() ) );
toolTip.append(
QString( "<br/>Source:\t%1" )
.arg( m_step->moduleInstanceKey().isEmpty() ? "built-in" : m_step->moduleInstanceKey() ) );
}
else
{
@ -78,8 +77,7 @@ ViewStepItem::data( int role ) const
return toolTip;
}
if ( role == ProgressTreeModel::ProgressTreeItemCurrentRole )
return m_step ?
( Calamares::ViewManager::instance()->currentStep() == m_step ) :
( Calamares::ViewManager::instance()->currentStep() == m_accessor() );
return m_step ? ( Calamares::ViewManager::instance()->currentStep() == m_step )
: ( Calamares::ViewManager::instance()->currentStep() == m_accessor() );
return QVariant();
}

View file

@ -37,18 +37,17 @@ public:
std::function< const Calamares::ViewStep*() > accessor,
ProgressTreeItem* parent = nullptr );
explicit ViewStepItem( const Calamares::ViewStep* step,
ProgressTreeItem* parent = nullptr );
explicit ViewStepItem( const Calamares::ViewStep* step, ProgressTreeItem* parent = nullptr );
void appendChild( ProgressTreeItem* item ) override;
QVariant data( int role ) const override;
private:
std::function< const Calamares::ViewStep*() > m_accessor;
std::function< QString() > m_prettyName;
const Calamares::ViewStep* m_step;
const std::function< const Calamares::ViewStep*() > m_accessor;
const std::function< QString() > m_prettyName;
const Calamares::ViewStep* const m_step;
};
#endif // VIEWSTEPITEM_H
#endif // VIEWSTEPITEM_H

View file

@ -22,9 +22,9 @@
* bindings.
*/
#include "modulesystem/Module.h"
#include "utils/Logger.h"
#include "utils/Yaml.h"
#include "modulesystem/Module.h"
#include "GlobalStorage.h"
#include "Job.h"
@ -40,28 +40,47 @@
struct ModuleConfig
{
QString moduleName() const { return m_module; }
QString configFile() const { return m_jobConfig; }
QString language() const { return m_language; }
QString globalConfigFile() const { return m_globalConfig; }
QString
moduleName() const
{
return m_module;
}
QString
configFile() const
{
return m_jobConfig;
}
QString
language() const
{
return m_language;
}
QString
globalConfigFile() const
{
return m_globalConfig;
}
QString m_module;
QString m_jobConfig;
QString m_globalConfig;
QString m_language;
} ;
};
static ModuleConfig
handle_args( QCoreApplication& a )
{
QCommandLineOption debugLevelOption( QStringLiteral("D"),
"Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption globalOption( QStringList() << QStringLiteral( "g" ) << QStringLiteral( "global "),
QStringLiteral( "Global settings document" ), "global.yaml" );
QCommandLineOption jobOption( QStringList() << QStringLiteral( "j" ) << QStringLiteral( "job"),
QStringLiteral( "Job settings document" ), "job.yaml" );
QCommandLineOption debugLevelOption(
QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption globalOption( QStringList() << QStringLiteral( "g" ) << QStringLiteral( "global " ),
QStringLiteral( "Global settings document" ),
"global.yaml" );
QCommandLineOption jobOption( QStringList() << QStringLiteral( "j" ) << QStringLiteral( "job" ),
QStringLiteral( "Job settings document" ),
"job.yaml" );
QCommandLineOption langOption( QStringList() << QStringLiteral( "l" ) << QStringLiteral( "language" ),
QStringLiteral( "Language (global)" ), "languagecode" );
QStringLiteral( "Language (global)" ),
"languagecode" );
QCommandLineParser parser;
parser.setApplicationDescription( "Calamares module tester" );
@ -73,7 +92,7 @@ handle_args( QCoreApplication& a )
parser.addOption( jobOption );
parser.addOption( langOption );
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 );
@ -83,9 +102,13 @@ handle_args( QCoreApplication& a )
unsigned int l = parser.value( debugLevelOption ).toUInt( &ok );
unsigned int dlevel = 0;
if ( !ok )
{
dlevel = Logger::LOGVERBOSE;
}
else
{
dlevel = l;
}
Logger::setupLogLevel( dlevel );
}
@ -104,9 +127,11 @@ handle_args( QCoreApplication& a )
{
QString jobSettings( parser.value( jobOption ) );
if ( jobSettings.isEmpty() && ( args.size() == 2 ) )
jobSettings = args.at(1);
{
jobSettings = args.at( 1 );
}
return ModuleConfig{ args.first(), jobSettings, parser.value( globalOption ), parser.value( langOption ) };
return ModuleConfig { args.first(), jobSettings, parser.value( globalOption ), parser.value( langOption ) };
}
}
@ -120,14 +145,18 @@ load_module( const ModuleConfig& moduleConfig )
bool ok = false;
QVariantMap descriptor;
for ( const QString& prefix : QStringList{ "./", "src/modules/", "modules/" } )
for ( const QString& prefix : QStringList { "./", "src/modules/", "modules/" } )
{
// Could be a complete path, eg. src/modules/dummycpp/module.desc
fi = QFileInfo( prefix + moduleName );
if ( fi.exists() && fi.isFile() )
{
descriptor = CalamaresUtils::loadYaml( fi, &ok );
}
if ( ok )
{
break;
}
// Could be a path without module.desc
fi = QFileInfo( prefix + moduleName );
@ -135,8 +164,13 @@ load_module( const ModuleConfig& moduleConfig )
{
fi = QFileInfo( prefix + moduleName + "/module.desc" );
if ( fi.exists() && fi.isFile() )
{
descriptor = CalamaresUtils::loadYaml( fi, &ok );
if ( ok ) break;
}
if ( ok )
{
break;
}
}
}
@ -154,15 +188,12 @@ load_module( const ModuleConfig& moduleConfig )
}
QString moduleDirectory = fi.absolutePath();
QString configFile(
moduleConfig.configFile().isEmpty()
? moduleDirectory + '/' + name + ".conf"
: moduleConfig.configFile() );
QString configFile( moduleConfig.configFile().isEmpty() ? moduleDirectory + '/' + name + ".conf"
: moduleConfig.configFile() );
cDebug() << "Module" << moduleName << "job-configuration:" << configFile;
Calamares::Module* module = Calamares::Module::fromDescriptor(
descriptor, name, configFile, moduleDirectory );
Calamares::Module* module = Calamares::Module::fromDescriptor( descriptor, name, configFile, moduleDirectory );
return module;
}
@ -174,14 +205,18 @@ main( int argc, char* argv[] )
ModuleConfig module = handle_args( a );
if ( module.moduleName().isEmpty() )
{
return 1;
}
std::unique_ptr< Calamares::Settings > settings_p( new Calamares::Settings( QString(), true ) );
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
auto gs = jobqueue_p->globalStorage();
if ( !module.globalConfigFile().isEmpty() )
{
gs->loadYaml( module.globalConfigFile() );
}
if ( !module.language().isEmpty() )
{
QVariantMap vm;
@ -199,7 +234,9 @@ main( int argc, char* argv[] )
}
if ( !m->isLoaded() )
{
m->loadSelf();
}
if ( !m->isLoaded() )
{
@ -207,12 +244,10 @@ main( int argc, char* argv[] )
return 1;
}
using TR = Logger::DebugRow<const char*, const QString>;
using TR = Logger::DebugRow< const char*, const QString >;
cDebug() << "Module metadata"
<< TR( "name", m->name() )
<< TR( "type", m->typeString() )
<< TR( "interface", m->interfaceString() );
cDebug() << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() )
<< TR( "interface", m->interfaceString() );
cDebug() << "Job outputs:";
Calamares::JobList jobList = m->jobs();
@ -224,11 +259,11 @@ main( int argc, char* argv[] )
Calamares::JobResult r = p->exec();
if ( !r )
{
cError() << "Job #" << count << "failed"
<< TR( "summary", r.message() )
<< TR( "details", r.details() );
cError() << "Job #" << count << "failed" << TR( "summary", r.message() ) << TR( "details", r.details() );
if ( r.errorCode() > 0 )
{
++failure_count;
}
}
++count;
}

View file

@ -44,7 +44,7 @@ public:
}
virtual ~JobThread() override;
void setJobs( const JobList& jobs )
{
m_jobs = jobs;
@ -157,6 +157,14 @@ JobQueue::JobQueue( QObject* parent )
JobQueue::~JobQueue()
{
if ( m_thread->isRunning() )
{
m_thread->terminate();
if ( !m_thread->wait(300) )
cError() << "Could not terminate job thread (expect a crash now).";
delete m_thread;
}
delete m_storage;
}

View file

@ -48,10 +48,8 @@ ProcessJob::~ProcessJob()
QString
ProcessJob::prettyName() const
{
//TODO: show something more meaningful
return tr( "Run command %1 %2" )
.arg( m_command )
.arg( m_runInChroot ? "in chroot." : " ." );
return ( m_runInChroot ? tr( "Run command '%1' in target system." ) : tr( " Run command '%1'." ) )
.arg( m_command );
}
@ -67,83 +65,23 @@ ProcessJob::prettyStatusMessage() const
JobResult
ProcessJob::exec()
{
int ec = 0;
QString output;
using CalamaresUtils::System;
if ( m_runInChroot )
ec = CalamaresUtils::System::instance()->
targetEnvOutput( m_command,
output,
return CalamaresUtils::System::instance()->
targetEnvCommand( { m_command },
m_workingPath,
QString(),
m_timeoutSec );
m_timeoutSec )
.explainProcess( m_command, m_timeoutSec );
else
ec = callOutput( m_command,
output,
m_workingPath,
QString(),
m_timeoutSec );
return CalamaresUtils::ProcessResult::explainProcess( ec, m_command, output, m_timeoutSec );
}
int
ProcessJob::callOutput( const QString& command,
QString& output,
const QString& workingPath,
const QString& stdInput,
int timeoutSec )
{
output.clear();
QProcess process;
process.setProgram( "/bin/sh" );
process.setArguments( { "-c", command } );
process.setProcessChannelMode( QProcess::MergedChannels );
if ( !workingPath.isEmpty() )
{
if ( QDir( workingPath ).exists() )
process.setWorkingDirectory( QDir( workingPath ).absolutePath() );
else
{
cWarning() << "Invalid working directory:" << workingPath;
return -3;
}
}
cDebug() << "Running" << command;
process.start();
if ( !process.waitForStarted() )
{
cWarning() << "Process failed to start" << process.error();
return -2;
}
if ( !stdInput.isEmpty() )
{
process.write( stdInput.toLocal8Bit() );
process.closeWriteChannel();
}
if ( !process.waitForFinished( timeoutSec ? ( timeoutSec * 1000 ) : -1 ) )
{
cWarning() << "Timed out. output so far:";
output.append( QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed() );
cWarning() << output;
return -4;
}
output.append( QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed() );
if ( process.exitStatus() == QProcess::CrashExit )
{
cWarning() << "Process crashed";
return -1;
}
cDebug() << "Finished. Exit code:" << process.exitCode();
return process.exitCode();
return
System::runCommand( System::RunLocation::RunInHost,
{ "/bin/sh", "-c", m_command },
m_workingPath,
QString(),
m_timeoutSec )
.explainProcess( m_command, m_timeoutSec );
}
} // namespace Calamares

View file

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2017-2019, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -40,11 +40,6 @@ public:
JobResult exec() override;
private:
int callOutput( const QString& command,
QString& output,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
int timeoutSec = 0 );
QString m_command;
QString m_workingPath;
bool m_runInChroot;

View file

@ -18,9 +18,12 @@
#include "Tests.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include "utils/Yaml.h"
#include <QTemporaryFile>
#include <QtTest/QtTest>
QTEST_GUILESS_MAIN( LibCalamaresTests )
@ -113,3 +116,45 @@ LibCalamaresTests::testLoadSaveYamlExtended()
}
QFile::remove( "out.yaml" );
}
void
LibCalamaresTests::testCommands()
{
using CalamaresUtils::System;
auto r = System::runCommand(
System::RunLocation::RunInHost,
{ "/bin/ls", "/tmp" }
);
QVERIFY( r.getExitCode() == 0 );
QTemporaryFile tf( "/tmp/calamares-test-XXXXXX" );
QVERIFY( tf.open() );
QVERIFY( !tf.fileName().isEmpty() );
QFileInfo tfn( tf.fileName() );
QVERIFY( !r.getOutput().contains( tfn.fileName() ) );
// Run ls again, now that the file exists
r = System::runCommand(
System::RunLocation::RunInHost,
{ "/bin/ls", "/tmp" }
);
QVERIFY( r.getOutput().contains( tfn.fileName() ) );
// .. and without a working directory set, assume builddir != /tmp
r = System::runCommand(
System::RunLocation::RunInHost,
{ "/bin/ls" }
);
QVERIFY( !r.getOutput().contains( tfn.fileName() ) );
r = System::runCommand(
System::RunLocation::RunInHost,
{ "/bin/ls" },
"/tmp"
);
QVERIFY( r.getOutput().contains( tfn.fileName() ) );
}

View file

@ -34,6 +34,8 @@ private Q_SLOTS:
void testLoadSaveYaml(); // Just settings.conf
void testLoadSaveYamlExtended(); // Do a find() in the src dir
void testCommands();
};
#endif

View file

@ -114,14 +114,24 @@ System::mount( const QString& devicePath,
const QString& options )
{
if ( devicePath.isEmpty() || mountPoint.isEmpty() )
return -3;
{
if ( devicePath.isEmpty() )
cWarning() << "Can't mount an empty device.";
if ( mountPoint.isEmpty() )
cWarning() << "Can't mount on an empty mountpoint.";
return static_cast<int>(ProcessResult::Code::NoWorkingDirectory);
}
QDir mountPointDir( mountPoint );
if ( !mountPointDir.exists() )
{
bool ok = mountPointDir.mkpath( mountPoint );
if ( !ok )
return -3;
{
cWarning() << "Could not create mountpoint" << mountPoint;
return static_cast<int>(ProcessResult::Code::NoWorkingDirectory);
}
}
QString program( "mount" );
@ -146,15 +156,13 @@ System::runCommand(
{
QString output;
if ( !Calamares::JobQueue::instance() )
return -3;
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
if ( ( location == System::RunLocation::RunInTarget ) &&
( !gs || !gs->contains( "rootMountPoint" ) ) )
{
cWarning() << "No rootMountPoint in global storage";
return -3;
return ProcessResult::Code::NoWorkingDirectory;
}
QProcess process;
@ -167,7 +175,7 @@ System::runCommand(
if ( !QDir( destDir ).exists() )
{
cWarning() << "rootMountPoint points to a dir which does not exist";
return -3;
return ProcessResult::Code::NoWorkingDirectory;
}
program = "chroot";
@ -189,8 +197,10 @@ System::runCommand(
if ( QDir( workingPath ).exists() )
process.setWorkingDirectory( QDir( workingPath ).absolutePath() );
else
{
cWarning() << "Invalid working directory:" << workingPath;
return -3;
return ProcessResult::Code::NoWorkingDirectory;
}
}
cDebug() << "Running" << program << RedactedList( arguments );
@ -198,20 +208,20 @@ System::runCommand(
if ( !process.waitForStarted() )
{
cWarning() << "Process failed to start" << process.error();
return -2;
return ProcessResult::Code::FailedToStart;
}
if ( !stdInput.isEmpty() )
{
process.write( stdInput.toLocal8Bit() );
process.closeWriteChannel();
}
process.closeWriteChannel();
if ( !process.waitForFinished( timeoutSec ? ( timeoutSec * 1000 ) : -1 ) )
{
cWarning().noquote().nospace() << "Timed out. Output so far:\n" <<
process.readAllStandardOutput();
return -4;
return ProcessResult::Code::TimedOut;
}
output.append( QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed() );
@ -219,12 +229,13 @@ System::runCommand(
if ( process.exitStatus() == QProcess::CrashExit )
{
cWarning().noquote().nospace() << "Process crashed. Output so far:\n" << output;
return -1;
return ProcessResult::Code::Crashed;
}
auto r = process.exitCode();
cDebug() << "Finished. Exit code:" << r;
if ( ( r != 0 ) || Calamares::Settings::instance()->debugMode() )
bool showDebug = ( !Calamares::Settings::instance() ) || ( Calamares::Settings::instance()->debugMode() );
if ( ( r != 0 ) || showDebug )
{
cDebug() << "Target cmd:" << RedactedList( args );
cDebug().noquote().nospace() << "Target output:\n" << output;
@ -306,22 +317,22 @@ ProcessResult::explainProcess( int ec, const QString& command, const QString& ou
? QCoreApplication::translate( "ProcessResult", "\nThere was no output from the command.")
: (QCoreApplication::translate( "ProcessResult", "\nOutput:\n") + output);
if ( ec == -1 ) //Crash!
if ( ec == static_cast<int>(ProcessResult::Code::Crashed) ) //Crash!
return JobResult::error( QCoreApplication::translate( "ProcessResult", "External command crashed." ),
QCoreApplication::translate( "ProcessResult", "Command <i>%1</i> crashed." )
.arg( command )
+ outputMessage );
if ( ec == -2 )
if ( ec == static_cast<int>(ProcessResult::Code::FailedToStart) )
return JobResult::error( QCoreApplication::translate( "ProcessResult", "External command failed to start." ),
QCoreApplication::translate( "ProcessResult", "Command <i>%1</i> failed to start." )
.arg( command ) );
if ( ec == -3 )
if ( ec == static_cast<int>(ProcessResult::Code::NoWorkingDirectory) )
return JobResult::error( QCoreApplication::translate( "ProcessResult", "Internal error when starting command." ),
QCoreApplication::translate( "ProcessResult", "Bad parameters for process job call." ) );
if ( ec == -4 )
if ( ec == static_cast<int>(ProcessResult::Code::TimedOut) )
return JobResult::error( QCoreApplication::translate( "ProcessResult", "External command failed to finish." ),
QCoreApplication::translate( "ProcessResult", "Command <i>%1</i> failed to finish in %2 seconds." )
.arg( command )

View file

@ -32,8 +32,16 @@ namespace CalamaresUtils
class ProcessResult : public QPair< int, QString >
{
public:
enum class Code : int
{
Crashed = -1, // Must match special return values from QProcess
FailedToStart = -2, // Must match special return values from QProcess
NoWorkingDirectory = -3,
TimedOut = -4
} ;
/** @brief Implicit one-argument constructor has no output, only a return code */
ProcessResult( int r ) : QPair< int, QString >( r, QString() ) {}
ProcessResult( Code r ) : QPair< int, QString >( static_cast<int>(r), QString() ) {}
ProcessResult( int r, QString s ) : QPair< int, QString >( r, s ) {}
int getExitCode() const { return first; }
@ -93,9 +101,9 @@ public:
* @param filesystemName the name of the filesystem (optional).
* @param options any additional options as passed to mount -o (optional).
* @returns the program's exit code, or:
* -1 = QProcess crash
* -2 = QProcess cannot start
* -3 = bad arguments
* Crashed = QProcess crash
* FailedToStart = QProcess cannot start
* NoWorkingDirectory = bad arguments
*/
DLLEXPORT int mount( const QString& devicePath,
const QString& mountPoint,
@ -120,10 +128,10 @@ public:
*
* @returns the program's exit code and its output (if any). Special
* exit codes (which will never have any output) are:
* -1 = QProcess crash
* -2 = QProcess cannot start
* -3 = bad arguments
* -4 = QProcess timeout
* Crashed = QProcess crash
* FailedToStart = QProcess cannot start
* NoWorkingDirectory = bad arguments
* TimedOut = QProcess timeout
*/
static DLLEXPORT ProcessResult runCommand(
RunLocation location,

View file

@ -78,6 +78,11 @@ constexpr int BytesToMiB( qint64 b )
return int( b / 1024 / 1024 );
}
constexpr int BytesToGiB( qint64 b )
{
return int( b / 1024 / 1024 / 1024 );
}
constexpr qint64 alignBytesToBlockSize( qint64 bytes, qint64 blocksize )
{
qint64 blocks = bytes / blocksize;

View file

@ -283,18 +283,35 @@ ViewManager::next()
}
m_currentStep++;
m_stack->setCurrentIndex( m_currentStep );
m_stack->setCurrentIndex( m_currentStep ); // Does nothing if out of range
step->onLeave();
m_steps.at( m_currentStep )->onActivate();
executing = qobject_cast< ExecutionViewStep* >( m_steps.at( m_currentStep ) ) != nullptr;
emit currentStepChanged();
if ( m_currentStep < m_steps.count() )
{
m_steps.at( m_currentStep )->onActivate();
executing = qobject_cast< ExecutionViewStep* >( m_steps.at( m_currentStep ) ) != nullptr;
emit currentStepChanged();
}
else
{
// Reached the end in a weird state (e.g. no finished step after an exec)
executing = false;
m_next->setEnabled( false );
m_back->setEnabled( false );
}
updateCancelEnabled( !settings->disableCancel() && !(executing && settings->disableCancelDuringExec() ) );
}
else
{
step->next();
}
m_next->setEnabled( !executing && m_steps.at( m_currentStep )->isNextEnabled() );
m_back->setEnabled( !executing && m_steps.at( m_currentStep )->isBackEnabled() );
if ( m_currentStep < m_steps.count() )
{
m_next->setEnabled( !executing && m_steps.at( m_currentStep )->isNextEnabled() );
m_back->setEnabled( !executing && m_steps.at( m_currentStep )->isBackEnabled() );
}
updateButtonLabels();
}
@ -320,7 +337,7 @@ ViewManager::updateButtonLabels()
else
m_next->setText( tr( "&Next" ) );
if ( m_currentStep == m_steps.count() -1 && m_steps.last()->isAtEnd() )
if ( isAtVeryEnd() )
{
m_quit->setText( tr( "&Done" ) );
m_quit->setToolTip( complete );
@ -368,7 +385,7 @@ bool ViewManager::confirmCancelInstallation()
const auto* const settings = Calamares::Settings::instance();
// When we're at the very end, then it's always OK to exit.
if ( m_currentStep == m_steps.count() -1 && m_steps.last()->isAtEnd() )
if ( isAtVeryEnd() )
return true;
// Not at the very end, cancel/quit might be disabled

View file

@ -130,7 +130,12 @@ private:
void insertViewStep( int before, ViewStep* step );
void updateButtonLabels();
void updateCancelEnabled( bool enabled );
bool isAtVeryEnd() const
{
return ( m_currentStep >= m_steps.count() ) || ( m_currentStep == m_steps.count() - 1 && m_steps.last()->isAtEnd() );
}
static ViewManager* s_instance;
ViewStepList m_steps;

View file

@ -4,16 +4,16 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Zmicer Turok <zmicerturok@gmail.com>, 2018
# Zmicer Turok <nashtlumach@gmail.com>, 2018
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-05 11:34-0400\n"
"POT-Creation-Date: 2019-05-10 19:18-0400\n"
"PO-Revision-Date: 2016-12-16 12:18+0000\n"
"Last-Translator: Zmicer Turok <zmicerturok@gmail.com>, 2018\n"
"Last-Translator: Zmicer Turok <nashtlumach@gmail.com>, 2018\n"
"Language-Team: Belarusian (https://www.transifex.com/calamares/teams/20061/be/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View file

@ -83,13 +83,14 @@ size: 100%
atleast: 600MiB
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( j.name().isEmpty() );
QVERIFY( !j.name().isEmpty() );
QCOMPARE( j.name(), QString("/") );
QCOMPARE( j.size().unit(), SizeUnit::Percent );
QCOMPARE( j.minimumSize().unit(), SizeUnit::MiB );
QCOMPARE( j.size().value(), 100 );
QCOMPARE( j.minimumSize().value(), 600 );
// Silly config
// Silly config has bad atleast value
doc0 = YAML::Load( R"(---
fs: /
dev: /dev/m00
@ -98,12 +99,27 @@ atleast: 127 %
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( !j.name().isEmpty() );
QCOMPARE( j.name(), QString("/") );
QCOMPARE( j.size().unit(), SizeUnit::MiB );
QCOMPARE( j.minimumSize().unit(), SizeUnit::None );
QCOMPARE( j.size().value(), 72 );
QCOMPARE( j.minimumSize().value(), 0 );
// Silly config
// Silly config has bad atleast value
doc0 = YAML::Load( R"(---
dev: /dev/m00
size: 72 MiB
atleast: 127 %
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( !j.name().isEmpty() );
QCOMPARE( j.name(), QString("/dev/m00") );
QCOMPARE( j.size().unit(), SizeUnit::MiB );
QCOMPARE( j.minimumSize().unit(), SizeUnit::None );
QCOMPARE( j.size().value(), 72 );
QCOMPARE( j.minimumSize().value(), 0 );
// Normal config
doc0 = YAML::Load( R"(---
fs: /
# dev: /dev/m00
@ -111,7 +127,8 @@ size: 71MiB
# atleast: 127%
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( j.name().isEmpty() );
QVERIFY( !j.name().isEmpty() );
QCOMPARE( j.name(), QString("/") );
QCOMPARE( j.size().unit(), SizeUnit::MiB );
QCOMPARE( j.minimumSize().unit(), SizeUnit::None );
QCOMPARE( j.size().value(), 71 );

View file

@ -62,37 +62,55 @@ convenienceName( const Partition* const candidate )
return p;
}
/** @brief Get the globalStorage setting for required space. */
static double
getRequiredStorageGiB( bool& ok )
{
return Calamares::JobQueue::instance()->globalStorage()->value( "requiredStorageGiB" ).toDouble( &ok );
}
bool
canBeReplaced( Partition* candidate )
{
if ( !candidate )
{
cDebug() << "Partition* is NULL";
return false;
}
cDebug() << "Checking if" << convenienceName( candidate ) << "can be replaced.";
if ( candidate->isMounted() )
{
cDebug() << Logger::SubEntry << "NO, it is mounted.";
return false;
}
bool ok = false;
double requiredStorageGB = Calamares::JobQueue::instance()
->globalStorage()
->value( "requiredStorageGiB" )
.toDouble( &ok );
double requiredStorageGiB = getRequiredStorageGiB( ok );
if ( !ok )
{
cDebug() << Logger::SubEntry << "NO, requiredStorageGiB is not set correctly.";
return false;
}
qint64 availableStorageB = candidate->capacity();
qint64 requiredStorageB = ( requiredStorageGB + 0.5 ) * 1024 * 1024 * 1024;
cDebug() << "Required storage B:" << requiredStorageB
<< QString( "(%1GB)" ).arg( requiredStorageB / 1024 / 1024 / 1024 );
cDebug() << "Storage capacity B:" << availableStorageB
<< QString( "(%1GB)" ).arg( availableStorageB / 1024 / 1024 / 1024 )
<< "for" << convenienceName( candidate ) << " length:" << candidate->length();
qint64 requiredStorageB = CalamaresUtils::GiBtoBytes( requiredStorageGiB + 0.5 );
if ( ok &&
availableStorageB > requiredStorageB )
if ( availableStorageB > requiredStorageB )
{
cDebug() << "Partition" << convenienceName( candidate ) << "authorized for replace install.";
return true;
}
return false;
else
{
Logger::CDebug deb;
deb << Logger::SubEntry << "NO, insufficient storage";
deb << Logger::Continuation << "Required storage B:" << requiredStorageB
<< QString( "(%1GiB)" ).arg( requiredStorageGiB );
deb << Logger::Continuation << "Available storage B:" << availableStorageB
<< QString( "(%1GiB)" ).arg( CalamaresUtils::BytesToGiB( availableStorageB ) );
return false;
}
}
@ -144,40 +162,35 @@ canBeResized( Partition* candidate )
}
bool ok = false;
double requiredStorageGB = Calamares::JobQueue::instance()
->globalStorage()
->value( "requiredStorageGiB" )
.toDouble( &ok );
double requiredStorageGiB = getRequiredStorageGiB( ok );
if ( !ok )
{
cDebug() << Logger::SubEntry << "NO, requiredStorageGiB is not set correctly.";
return false;
}
// We require a little more for partitioning overhead and swap file
double advisedStorageGB = requiredStorageGB + 0.5 + 2.0;
double advisedStorageGiB = requiredStorageGiB + 0.5 + 2.0;
qint64 availableStorageB = candidate->available();
qint64 advisedStorageB = CalamaresUtils::GiBtoBytes( advisedStorageGiB );
qint64 advisedStorageB = CalamaresUtils::GiBtoBytes( advisedStorageGB );
if ( ok &&
availableStorageB > advisedStorageB )
if ( availableStorageB > advisedStorageB )
{
cDebug() << "Partition" << convenienceName( candidate ) << "authorized for resize + autopartition install.";
return true;
}
else if ( ok )
else
{
Logger::CDebug deb;
deb << Logger::SubEntry << "NO, insufficient storage";
deb << Logger::Continuation << "Required storage B:" << advisedStorageB
<< QString( "(%1GB)" ).arg( advisedStorageGB );
<< QString( "(%1GiB)" ).arg( advisedStorageGiB );
deb << Logger::Continuation << "Available storage B:" << availableStorageB
<< QString( "(%1GB)" ).arg( availableStorageB / 1024 / 1024 / 1024 )
<< QString( "(%1GiB)" ).arg( CalamaresUtils::BytesToGiB( availableStorageB ) )
<< "for" << convenienceName( candidate ) << "length:" << candidate->length()
<< "sectorsUsed:" << candidate->sectorsUsed() << "fsType:" << candidate->fileSystem().name();
return false;
}
else
{
cDebug() << Logger::SubEntry << "NO, requiredStorageGB is not set correctly.";
return false;
}
}

View file

@ -69,6 +69,7 @@ PartitionViewStep::PartitionViewStep( QObject* parent )
, m_widget( new QStackedWidget() )
, m_choicePage( nullptr )
, m_manualPartitionPage( nullptr )
, m_requiredStorageGiB( 0.0 )
{
m_widget->setContentsMargins( 0, 0, 0, 0 );
@ -371,6 +372,14 @@ PartitionViewStep::isAtEnd() const
void
PartitionViewStep::onActivate()
{
// If there's no setting (e.g. from the welcome page) for required storage
// then use ours, if it was set.
auto* gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
if ( m_requiredStorageGiB >= 0.0 && gs && !gs->contains( "requiredStorageGiB" ) )
{
gs->insert( "requiredStorageGiB", m_requiredStorageGiB );
}
// if we're coming back to PVS from the next VS
if ( m_widget->currentWidget() == m_choicePage &&
m_choicePage->currentChoice() == ChoicePage::Alongside )
@ -564,6 +573,9 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
m_swapChoices = choices;
// Settings that overlap with the Welcome module
m_requiredStorageGiB = CalamaresUtils::getDouble( configurationMap, "requiredStorage", -1.0 );
// These gs settings seem to be unused (in upstream Calamares) outside of
// the partition module itself.
gs->insert( "ensureSuspendToDisk", ensureSuspendToDisk );

View file

@ -86,6 +86,8 @@ private:
QFutureWatcher<void>* m_future;
QSet< PartitionActions::Choices::SwapChoice > m_swapChoices;
qreal m_requiredStorageGiB; // May duplicate setting in the welcome module
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( PartitionViewStepFactory )

View file

@ -120,3 +120,15 @@ defaultFileSystemType: "ext4"
# % of the available drive space if a '%' is appended to the value
# - minSize: minimum partition size (optional parameter)
# - maxSize: maximum partition size (optional parameter)
# Checking for available storage
#
# This overlaps with the setting of the same name in the welcome module's
# requirements section. If nothing is set by the welcome module, this
# value is used instead. It is still a problem if there is no required
# size set at all, and the replace and resize options will not be offered
# if no required size is set.
#
# The value is in Gibibytes (GiB).
#
# requiredStorage: 3.5