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

33
.clang-format Normal file
View File

@ -0,0 +1,33 @@
---
BasedOnStyle: WebKit
AlignAfterOpenBracket: Align
AllowAllParametersOfDeclarationOnNextLine: 'false'
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakAfterDefinitionReturnType: All
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: 'false'
BinPackParameters: 'false'
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: 'true'
BreakConstructorInitializers: BeforeComma
ColumnLimit: 120
Cpp11BracedListStyle: 'false'
FixNamespaceComments: 'true'
IncludeBlocks: Preserve
IndentWidth: '4'
MaxEmptyLinesToKeep: '2'
NamespaceIndentation: Inner
PointerAlignment: Left
ReflowComments: 'false'
SortIncludes: 'true'
SpaceAfterCStyleCast: 'false'
SpacesBeforeTrailingComments: '2'
SpacesInAngles: 'true'
SpacesInParentheses: 'true'
SpacesInSquareBrackets: 'true'
Standard: Cpp11
...

30
CHANGES
View File

@ -3,7 +3,31 @@ contributors are listed. Note that Calamares does not have a historical
changelog -- this log starts with version 3.2.0. The release notes on the
website will have to do for older versions.
# 3.2.9 (unreleased) #
# 3.2.10 (unreleased) #
This release contains contributions from (alphabetically by first name):
## Core ##
- With this release, option *WITH_PYTHONQT* changes default to **off**.
There does not seem to be any serious use of the PythonQt API and
the UI opportunities it offers, so begin the process of deprecating
and removing that. Sometime in the future, QML pages will fill the
gap for easily-prototyped-yet-slick UI elements.
- A crash when no *finished* page (or rather, no page at all) is
configured after the last *exec* section of the sequence has been
solved. The *finished* page can be left out (but then you don't get
the restart-now functionality). #1168
## Modules ##
- *partition* Now has its own setting for *requiredStorage*, duplicating
the same setting in the *welcome* module. This is useful for
configurations where no *welcome* module is used, but a minimum
size must be checked anyway. #1169
# 3.2.9 (2019-06-03) #
This release contains contributions from (alphabetically by first name):
- Kevin Kofler
@ -21,7 +45,9 @@ milestone for details.
- *branding* allows the use of FreeDesktop.org icon names for the
*productLogo* and *productIcon* keys. If a file is named there, then
the file is used, and otherwise the icon is looked up in the current
theme.
theme. #1160
- *packages* On Arch, with the `pacman` package manager, avoid a hang
during system update. #1154
- *welcome* allows a custom image path or icon name to be set for the
language-selection drop-down (instead of the international standard one).

View File

@ -37,7 +37,7 @@
cmake_minimum_required( VERSION 3.2 FATAL_ERROR )
project( CALAMARES
VERSION 3.2.9
VERSION 3.2.10
LANGUAGES C CXX )
set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development
@ -48,7 +48,7 @@ option( INSTALL_CONFIG "Install configuration files" OFF )
option( INSTALL_POLKIT "Install Polkit configuration" ON )
option( BUILD_TESTING "Build the testing tree." ON )
option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON )
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." ON )
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF )
option( WITH_KF5Crash "Enable crash reporting with KCrash." ON )
@ -104,12 +104,12 @@ set( CALAMARES_DESCRIPTION_SUMMARY
# checks for new languages and misspelled ones are done (that is,
# copy these four lines to four backup lines, add "p", and then update
# the original four lines with the current translations).
set( _tx_complete ast ca cs_CZ da de fr hr ja lt pl pt_BR pt_PT
tr_TR zh_TW )
set( _tx_good bg en_GB es es_MX et gl he hi hu id it_IT ro ru sk sq
zh_CN )
set( _tx_ok ar el es_PR eu fi_FI is ko mr nb nl sl sr
sr@latin sv th uk )
set( _tx_complete ca cs_CZ da de fr he hr hu ko lt pt_BR sq tr_TR
zh_TW )
set( _tx_good ast en_GB es es_MX et gl id it_IT ja nl pl pt_PT ro
ru sk zh_CN )
set( _tx_ok ar bg el es_PR eu fi_FI hi is mr nb sl sr sr@latin sv
th uk )
set( _tx_bad be eo fa fr_CH gu kk kn lo mk ne_NP ur uz )

View File

@ -56,7 +56,7 @@ some PEP8 guidelines.
* For pointer and reference variable declarations, put a space before the variable name
and no space between the type and the `*` or `&`, e.g. `int* p`.
* `for`, `if`, `else`, `while` and similar statements put the braces on the next line,
if the following block is more than one statement. Use no braces for single statements.
if the following block is more than one statement. Always use braces.
* Function and class definitions have their braces on separate lines.
* A function implementation's return type is on its own line.
* `CamelCase.{cpp,h}` style file names.
@ -86,9 +86,13 @@ MyClass::myMethod( QStringList list, const QString& name )
}
```
You can use the `ci/calamaresstyle` script to run
[astyle](http://astyle.sf.net) on your code and have it formatted the right
way.
You can use `clang-format` (version 7) to have Calamares sources formatted
the right way. There is a `.clang-format` file that specifies the details.
In general:
```
$ clang-format-7 -i -style=file <files>
```
`
**NOTE:** An .editorconfig file is included to assist with formatting. In
order to take advantage of this functionality you will need to acquire the
@ -179,15 +183,19 @@ connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded, [this]
Debugging
---------
Use `cDebug()` and `cLog()` from `utils/Logger.h`. You can pass a debug-level to
either macro (1 is debugging, higher is less important). Use `cLog()` for warning
messages. It is recommended to add *WARNING* as the first part of a warning
message.
Use `cDebug()` from `utils/Logger.h`. You can pass a debug-level to the
macro (6 is debugging, higher is less important). Use `cWarning()` for warning
messages (equivalent to level 2) and `cError()` for errors (level 1). Warnings
and errors will add relevant text automatically. See `libcalamares/utils/Logger.h`
for details.
For log messages that are continued across multiple calls to `cDebug()`,
in particular listing things, conventional formatting is as follows:
* End the first debug message with ` ..`
* Indent following lines with ` ..`
* Start the next debug message by outputting `Logger::SubEntry`
For single-outputs that need to be split across multiplt lines,
output `Logger::Continuation`.
Commit Messages

View File

@ -5,7 +5,7 @@ indent=spaces=4
# Brackets
style=break
remove-brackets # Remove brackets on single-line `if` and `for` (requires astyle 2.04)
add-brackets
# Spaces
pad-paren-in

View File

@ -1,6 +1,42 @@
#!/bin/sh
#
# Calls astyle with settings matching Calamares coding style
# Requires astyle >= 2.04
# Requires astyle >= 2.04 and clang-format-7
#
# You can pass in directory names, in which case the files
# in that directory (NOT below it) are processed.
#
set -e
astyle --options=$(dirname $0)/astylerc "$@"
AS=$( which astyle )
CF=$( which clang-format-7 )
test -n "$AS" || { echo "! No astyle found in PATH"; exit 1 ; }
test -n "$CF" || { echo "! No clang-format-7 found in PATH"; exit 1 ; }
test -x "$AS" || { echo "! $AS is not executable."; exit 1 ; }
test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; }
any_dirs=no
for d in "$@"
do
test -d "$d" && any_dirs=yes
done
style_some()
{
$AS --options=$(dirname $0)/astylerc --quiet "$@"
$CF -i -style=file "$@"
}
if test "x$any_dirs" = "xyes" ; then
for d in "$@"
do
if test -d "$@" ; then
style_some $( find "$d" -maxdepth 1 -type f -name '*.cpp' -o -name '*.h' )
else
style_some "$d"
fi
done
else
style_some "$@"
fi

View File

@ -15,12 +15,12 @@ showReleaseNotesUrl: true
# that are checked. They may not match with the actual requirements
# imposed by other modules in the system.
requirements:
# Amount of available disk, in GB. Floating-point is allowed here.
# Amount of available disk, in GiB. Floating-point is allowed here.
# Note that this does not account for *usable* disk, so it is possible
# to pass this requirement, yet have no space to install to.
requiredStorage: 5.5
# Amount of available RAM, in GB. Floating-point is allowed here.
# Amount of available RAM, in GiB. Floating-point is allowed here.
requiredRam: 1.0
# To check for internet connectivity, Calamares does a HTTP GET

View File

@ -854,17 +854,17 @@ El instalador terminará y se perderán todos los cambios.</translation>
<location filename="../src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp" line="34"/>
<location filename="../src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp" line="48"/>
<source>Deactivate volume group named %1.</source>
<translation type="unfinished"/>
<translation>Desactivar el grupo de volúmenes llamado%1.</translation>
</message>
<message>
<location filename="../src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp" line="41"/>
<source>Deactivate volume group named &lt;strong&gt;%1&lt;/strong&gt;.</source>
<translation type="unfinished"/>
<translation>Desactivar el grupo de volúmenes llamado&lt;strong&gt;% 1&lt;/strong&gt;.</translation>
</message>
<message>
<location filename="../src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp" line="61"/>
<source>The installer failed to deactivate a volume group named %1.</source>
<translation type="unfinished"/>
<translation>El instalador no pudo desactivar un grupo de volúmenes llamado%1.</translation>
</message>
</context>
<context>
@ -1098,7 +1098,7 @@ El instalador terminará y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="95"/>
<source>&lt;Restart checkbox tooltip&gt;</source>
<translation type="unfinished"/>
<translation>&lt;Restart checkbox tooltip&gt;</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="98"/>
@ -1108,12 +1108,12 @@ El instalador terminará y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="54"/>
<source>&lt;h1&gt;All done.&lt;/h1&gt;&lt;br/&gt;%1 has been set up on your computer.&lt;br/&gt;You may now start using your new system.</source>
<translation type="unfinished"/>
<translation>&lt;h1&gt;Todo listo.&lt;/h1&gt;&lt;br/&gt;% 1 se ha configurado en su computadora. &lt;br/&gt;Ahora puede comenzar a usar su nuevo sistema.</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="58"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When this box is checked, your system will restart immediately when you click on &lt;span style=&quot;font-style:italic;&quot;&gt;Done&lt;/span&gt; or close the setup program.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"/>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Cuando esta casilla está marcada, su sistema se reiniciará inmediatamente cuando haga clic en &lt;span style=&quot;font-style:italic;&quot;&gt;Listo&lt;/span&gt; o cierre el programa de instalación.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="66"/>

File diff suppressed because it is too large Load Diff

View File

@ -347,7 +347,7 @@ msgstr ""
#: src/modules/openrcdmcryptcfg/main.py:34
msgid "Configuring OpenRC dmcrypt service."
msgstr ""
msgstr "Configurando'l serviciu dmcrypt d'OpenRC."
#: src/modules/luksbootkeyfile/main.py:35
msgid "Configuring LUKS key file."

View File

@ -88,25 +88,27 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
msgstr ""
msgstr "Irrota tiedostojärjestelmät käytöstä."
#: src/modules/unpackfs/main.py:41
msgid "Filling up filesystems."
msgstr ""
msgstr "Paikannetaan tiedostojärjestelmiä."
#: src/modules/unpackfs/main.py:159
msgid "rsync failed with error code {}."
msgstr ""
msgstr "rsync epäonnistui virhekoodilla {}."
#: src/modules/unpackfs/main.py:220 src/modules/unpackfs/main.py:238
msgid "Failed to unpack image \"{}\""
msgstr ""
msgstr "Kuvan purkaminen epäonnistui \"{}\""
#: src/modules/unpackfs/main.py:221
msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed"
msgstr ""
"Ei löytynyt unsquashfs, varmista, että sinulla on squashfs-tools paketti "
"asennettuna"
#: src/modules/unpackfs/main.py:320
msgid "No mount point for root partition"
@ -118,7 +120,7 @@ msgstr ""
#: src/modules/unpackfs/main.py:326
msgid "Bad mount point for root partition"
msgstr ""
msgstr "Huono kiinnityspiste root-osioon"
#: src/modules/unpackfs/main.py:327
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
@ -127,7 +129,7 @@ msgstr ""
#: src/modules/unpackfs/main.py:340 src/modules/unpackfs/main.py:347
#: src/modules/unpackfs/main.py:352
msgid "Bad unsquash configuration"
msgstr ""
msgstr "Huono epäpuhdas kokoonpano"
#: src/modules/unpackfs/main.py:341
msgid "The filesystem for \"{}\" ({}) is not supported"
@ -167,19 +169,19 @@ msgstr ""
#: src/modules/displaymanager/main.py:602
msgid "Cannot configure LightDM"
msgstr ""
msgstr "LightDM määritysvirhe"
#: src/modules/displaymanager/main.py:603
msgid "No LightDM greeter installed."
msgstr ""
msgstr "LightDM ei ole asennettu."
#: src/modules/displaymanager/main.py:634
msgid "Cannot write SLIM configuration file"
msgstr ""
msgstr "SLIM-määritystiedostoa ei voi kirjoittaa"
#: src/modules/displaymanager/main.py:635
msgid "SLIM config file {!s} does not exist"
msgstr ""
msgstr "SLIM-määritystiedostoa {!s} ei ole olemassa"
#: src/modules/displaymanager/main.py:750
msgid "No display managers selected for the displaymanager module."
@ -193,11 +195,11 @@ msgstr ""
#: src/modules/displaymanager/main.py:831
msgid "Display manager configuration was incomplete"
msgstr ""
msgstr "Näytönhallinnan kokoonpano oli puutteellinen"
#: src/modules/initcpiocfg/main.py:36
msgid "Configuring mkinitcpio."
msgstr ""
msgstr "Määritetään mkinitcpio."
#: src/modules/initcpiocfg/main.py:192
#: src/modules/luksopenswaphookcfg/main.py:100
@ -213,7 +215,7 @@ msgstr ""
#: src/modules/initcpio/main.py:47
msgid "Process Failed"
msgstr ""
msgstr "Prosessi epäonnistui"
#: src/modules/initcpio/main.py:48
msgid ""
@ -227,7 +229,7 @@ msgstr ""
#: src/modules/rawfs/main.py:35
msgid "Installing data."
msgstr ""
msgstr "Asennetaan tietoja."
#: src/modules/services-openrc/main.py:38
msgid "Configure OpenRC services"

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