Merge branch 'master' into usertracking

This commit is contained in:
Adriaan de Groot 2017-11-01 06:58:10 -04:00
commit a90f15081c
216 changed files with 9101 additions and 8842 deletions

View file

@ -8,10 +8,17 @@ componentName: default
# same distribution.
welcomeStyleCalamares: false
# Should the welcome image (productWelcome, below) be scaled
# up beyond its natural size?
welcomeExpandingLogo: true
# These are strings shown to the user in the user interface.
# There is no provision for translating them -- since they
# are names, the string is included as-is.
#
# The four Url strings are the Urls used by the buttons in
# the welcome screen, and are not shown to the user. Clicking
# on the "Support" button, for instance, opens the link supportUrl.
# If a Url is empty, the corresponding button is not shown.
#
# bootloaderEntryName is how this installation / distro is named
# in the boot loader (e.g. in the GRUB menu).
strings:
productName: Generic GNU/Linux
shortProductName: Generic
@ -25,11 +32,33 @@ strings:
knownIssuesUrl: http://calamares.io/about/
releaseNotesUrl: http://calamares.io/about/
# Should the welcome image (productWelcome, below) be scaled
# up beyond its natural size? If false, the image does not grow
# with the window but remains the same size throughout (this
# may have surprising effects on HiDPI monitors).
welcomeExpandingLogo: true
# These images are loaded from the branding module directory.
#
# productIcon is used as the window icon, and will (usually) be used
# by the window manager to represent the application. This image
# should be square, and may be displayed by the window manager
# as small as 16x16 (but possibly larger).
# productLogo is used as the logo at the top of the left-hand column
# which shows the steps to be taken. The image should be square,
# and is displayed at 80x80 pixels (also on HiDPI).
# productWelcome is shown on the welcome page of the application in
# the middle of the window, below the welcome text. It can be
# any size and proportion, and will be scaled to fit inside
# the window. Use `welcomeExpandingLogo` to make it non-scaled.
# Recommended size is 320x150.
images:
productLogo: "squid.png"
productIcon: "squid.png"
productWelcome: "languages.png"
# The slideshow is displayed during execution steps (e.g. when the
# installer is actually writing to disk and doing other slow things).
slideshow: "show.qml"
# Colors for text and background components.

View file

@ -96,7 +96,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
logoLabel->setAlignment( Qt::AlignCenter );
logoLabel->setFixedSize( 80, 80 );
logoLabel->setPixmap( Calamares::Branding::instance()->
image( Calamares::Branding::ProductIcon,
image( Calamares::Branding::ProductLogo,
logoLabel->size() ) );
logoLayout->addWidget( logoLabel );
logoLayout->addStretch();

View file

@ -72,9 +72,10 @@ calamares_add_library( calamaresui
EXPORT_MACRO UIDLLEXPORT_PRO
LINK_PRIVATE_LIBRARIES
${YAMLCPP_LIBRARY}
${OPTIONAL_PRIVATE_LIBRARIES}
LINK_LIBRARIES
Qt5::Svg
Qt5::QuickWidgets
${OPTIONAL_PRIVATE_LIBRARIES}
RESOURCES libcalamaresui.qrc
EXPORT CalamaresLibraryDepends
VERSION ${CALAMARES_VERSION_SHORT}

View file

@ -26,11 +26,9 @@
#include "qjsonitem.h"
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
: mParent( parent )
, mType( QJsonValue::Type::Null )
{
mParent = parent;
}
QJsonTreeItem::~QJsonTreeItem()

View file

@ -33,14 +33,19 @@
QJsonModel::QJsonModel(QObject *parent) :
QAbstractItemModel(parent)
, mRootItem( new QJsonTreeItem )
{
mRootItem = new QJsonTreeItem;
mHeaders.append("key");
mHeaders.append("value");
}
QJsonModel::~QJsonModel()
{
delete mRootItem;
}
bool QJsonModel::load(const QString &fileName)
{
QFile file(fileName);
@ -66,6 +71,7 @@ bool QJsonModel::loadJson(const QByteArray &json)
if (!mDocument.isNull())
{
beginResetModel();
delete mRootItem;
if (mDocument.isArray()) {
mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.array()));
} else {

View file

@ -17,6 +17,7 @@ class QJsonModel : public QAbstractItemModel
Q_OBJECT
public:
explicit QJsonModel(QObject *parent = 0);
~QJsonModel();
bool load(const QString& fileName);
bool load(QIODevice * device);
bool loadJson(const QByteArray& json);

View file

@ -21,13 +21,13 @@
#include <QApplication>
ClickableLabel::ClickableLabel( QWidget* parent, Qt::WindowFlags f )
: QLabel( parent, f )
ClickableLabel::ClickableLabel( QWidget* parent )
: QLabel( parent )
{}
ClickableLabel::ClickableLabel( const QString& text, QWidget* parent, Qt::WindowFlags f )
: QLabel( text, parent, f )
ClickableLabel::ClickableLabel( const QString& text, QWidget* parent )
: QLabel( text, parent )
{}

View file

@ -27,8 +27,8 @@ class ClickableLabel : public QLabel
{
Q_OBJECT
public:
explicit ClickableLabel( QWidget* parent = nullptr, Qt::WindowFlags f = 0 );
explicit ClickableLabel( const QString& text, QWidget* parent = nullptr, Qt::WindowFlags f = 0 );
explicit ClickableLabel( QWidget* parent = nullptr );
explicit ClickableLabel( const QString& text, QWidget* parent = nullptr );
virtual ~ClickableLabel() override;
signals:

View file

@ -1,5 +1,10 @@
include( CMakeColors )
if( BUILD_TESTING )
add_executable( test_conf test_conf.cpp )
target_link_libraries( test_conf ${YAMLCPP_LIBRARY} )
endif()
file( GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" )
string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" )
foreach( SUBDIRECTORY ${SUBDIRECTORIES} )

View file

@ -8,11 +8,12 @@
# Copyright 2014, Daniel Hillenbrand <codeworkx@bbqlinux.org>
# Copyright 2014, Benjamin Vaudour <benjamin.vaudour@yahoo.fr>
# Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
# Copyright 2015, Philip Mueller <philm@manjaro.org>
# Copyright 2015-2017, Philip Mueller <philm@manjaro.org>
# Copyright 2016-2017, Teo Mrnjavac <teo@kde.org>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
# Copyright 2017, Adriaan de Groot <groot@kde.org>
# Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
# Copyright 2017, Ben Green <Bezzy1999@hotmail.com>
#
# Calamares is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -235,10 +236,18 @@ def install_grub(efi_directory, fw_type):
# if the kernel is older than 4.0, the UEFI bitness likely isn't
# exposed to the userspace so we assume a 64 bit UEFI here
efi_bitness = "64"
bitness_translate = {"32": "--target=i386-efi",
"64": "--target=x86_64-efi"}
if efi_bitness == "32":
efi_target = "i386-efi"
efi_grub_file = "grubia32.efi"
efi_boot_file = "bootia32.efi"
elif efi_bitness == "64":
efi_target = "x86_64-efi"
efi_grub_file = "grubx64.efi"
efi_boot_file = "bootx64.efi"
check_target_env_call([libcalamares.job.configuration["grubInstall"],
bitness_translate[efi_bitness],
"--target=" + efi_target,
"--efi-directory=" + efi_directory,
"--bootloader-id=" + efi_bootloader_id,
"--force"])
@ -260,13 +269,13 @@ def install_grub(efi_directory, fw_type):
os.makedirs(install_efi_boot_directory)
# Workaround for some UEFI firmwares
efi_file_source = {"32": os.path.join(install_efi_directory_firmware,
efi_bootloader_id,
"grubia32.efi"),
"64": os.path.join(install_efi_directory_firmware,
efi_bootloader_id,
"grubx64.efi")}
shutil.copy2(efi_file_source[efi_bitness], install_efi_boot_directory)
efi_file_source = os.path.join(install_efi_directory_firmware,
efi_bootloader_id,
efi_grub_file)
efi_file_target = os.path.join(install_efi_boot_directory,
efi_boot_file)
shutil.copy2(efi_file_source, efi_file_target)
else:
print("Bootloader: grub (bios)")
if libcalamares.globalstorage.value("bootLoader") is None:

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-04 08:16-0400\n"
"POT-Creation-Date: 2017-09-28 10:34-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: pavelrz <pavel@rzehak.cz>, 2016\n"
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n"
@ -20,7 +20,7 @@ msgstr ""
#: src/modules/dummypythonqt/main.py:84
msgid "Click me!"
msgstr "Klikni na mě!"
msgstr "Klikněte na mě!"
#: src/modules/dummypythonqt/main.py:94
msgid "A new QLabel."
@ -36,7 +36,7 @@ msgstr "Testovací úloha PythonQt"
#: src/modules/dummypythonqt/main.py:186
msgid "This is the Dummy PythonQt Job. The dummy job says: {}"
msgstr "Toto je testovací úloha PythonQt. Testovací úloha říká: {}"
msgstr "Toto je testovací úloha PythonQt. Testovací úloha sděluje: {}"
#: src/modules/dummypythonqt/main.py:190
msgid "A status message for Dummy PythonQt Job."

View file

@ -8,12 +8,12 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-04 08:16-0400\n"
"POT-Creation-Date: 2017-09-28 10:34-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"

View file

@ -8,8 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-04 08:16-0400\n"
"POT-Creation-Date: 2017-09-28 10:34-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Paul Combal <abonnementspaul@gmail.com>, 2017\n"
"Language-Team: French (https://www.transifex.com/calamares/teams/20061/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -19,11 +20,11 @@ msgstr ""
#: src/modules/dummypythonqt/main.py:84
msgid "Click me!"
msgstr ""
msgstr "Cliquez-moi!"
#: src/modules/dummypythonqt/main.py:94
msgid "A new QLabel."
msgstr ""
msgstr "Un nouveau QLabel."
#: src/modules/dummypythonqt/main.py:97
msgid "Dummy PythonQt ViewStep"

View file

@ -178,7 +178,7 @@ FinishedViewStep::setConfigurationMap( const QVariantMap& configurationMap )
configurationMap.value( "restartNowCommand" ).type() == QVariant::String )
m_widget->setRestartNowCommand( configurationMap.value( "restartNowCommand" ).toString() );
else
m_widget->setRestartNowCommand( "systemctl -i reboot" );
m_widget->setRestartNowCommand( "shutdown -r now" );
}
}
if ( configurationMap.contains( "notifyOnFinished" ) &&

View file

@ -1,14 +1,18 @@
Configuration for the "finished" page, which is usually shown only at
the end of the installation (successful or not).
# Configuration for the "finished" page, which is usually shown only at
# the end of the installation (successful or not).
---
# The finished page can hold a "restart system now" checkbox.
# If this is false, no checkbox is show and the system is not restarted
# If this is false, no checkbox is shown and the system is not restarted
# when Calamares exits.
restartNowEnabled: true
# Initial state of the checkbox "restart now".
# Initial state of the checkbox "restart now". Only relevant when the
# checkbox is shown by restartNowEnabled.
restartNowChecked: false
# If the checkbox is shown, and the checkbox is checked, then when
# Calamares exits from the finished-page it will run this command.
# If not set, falls back to "shutdown -r now".
restartNowCommand: "systemctl -i reboot"
# When the last page is (successfully) reached, send a DBus notification

View file

@ -24,6 +24,8 @@
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
import libcalamares
import inspect
import os
import shutil

View file

@ -21,6 +21,7 @@ calamares_add_plugin( interactiveterminal
InteractiveTerminalPage.cpp
LINK_PRIVATE_LIBRARIES
calamaresui
LINK_LIBRARIES
KF5::Service
KF5::Parts
SHARED_LIB

View file

@ -1,3 +1,5 @@
# NOTE: you must have ckbcomp installed and runnable
# on the live system, for keyboard layout previews.
---
# The name of the file to write X11 keyboard settings to
# The default value is the name used by upstream systemd-localed.

View file

@ -20,6 +20,7 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils/Logger.h"
#include "keyboardpreview.h"
KeyBoardPreview::KeyBoardPreview( QWidget* parent )
@ -113,10 +114,16 @@ bool KeyBoardPreview::loadCodes() {
process.setEnvironment(QStringList() << "LANG=C" << "LC_MESSAGES=C");
process.start("ckbcomp", param);
if (!process.waitForStarted())
{
cDebug() << "WARNING: ckbcomp not found , keyboard preview disabled";
return false;
}
if (!process.waitForFinished())
{
cDebug() << "WARNING: ckbcomp failed, keyboard preview disabled";
return false;
}
// Clear codes
codes.clear();

View file

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
*
* Originally from the Manjaro Installation Framework
* by Roland Singer <roland@manjaro.org>
@ -20,61 +21,70 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath>
#include "timezonewidget.h"
TimeZoneWidget::TimeZoneWidget(QWidget* parent) :
QWidget(parent)
constexpr double MATH_PI = 3.14159265;
TimeZoneWidget::TimeZoneWidget( QWidget* parent ) :
QWidget( parent )
{
setMouseTracking(false);
setCursor(Qt::PointingHandCursor);
setMouseTracking( false );
setCursor( Qt::PointingHandCursor );
// Font
font.setPointSize(12);
font.setBold(false);
font.setPointSize( 12 );
font.setBold( false );
// Images
background = QImage(":/images/bg.png").scaled(X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
pin = QImage(":/images/pin.png");
background = QImage( ":/images/bg.png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
pin = QImage( ":/images/pin.png" );
// Set size
setMinimumSize(background.size());
setMaximumSize(background.size());
setMinimumSize( background.size() );
setMaximumSize( background.size() );
// Zone images
QStringList zones = QString(ZONES).split(" ", QString::SkipEmptyParts);
for (int i = 0; i < zones.size(); ++i)
timeZoneImages.append(QImage(":/images/timezone_" + zones.at(i) + ".png").scaled(X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
QStringList zones = QString( ZONES ).split( " ", QString::SkipEmptyParts );
for ( int i = 0; i < zones.size(); ++i )
timeZoneImages.append( QImage( ":/images/timezone_" + zones.at( i ) + ".png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
}
void TimeZoneWidget::setCurrentLocation(QString region, QString zone) {
void TimeZoneWidget::setCurrentLocation( QString region, QString zone )
{
QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
if (!hash.contains(region))
if ( !hash.contains( region ) )
return;
QList<LocaleGlobal::Location> locations = hash.value(region);
for (int i = 0; i < locations.size(); ++i) {
if (locations.at(i).zone == zone) {
setCurrentLocation(locations.at(i));
QList<LocaleGlobal::Location> locations = hash.value( region );
for ( int i = 0; i < locations.size(); ++i )
{
if ( locations.at( i ).zone == zone )
{
setCurrentLocation( locations.at( i ) );
break;
}
}
}
void TimeZoneWidget::setCurrentLocation(LocaleGlobal::Location location) {
void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
{
currentLocation = location;
// Set zone
QPoint pos = getLocationPosition(currentLocation.longitude, currentLocation.latitude);
QPoint pos = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
for (int i = 0; i < timeZoneImages.size(); ++i) {
for ( int i = 0; i < timeZoneImages.size(); ++i )
{
QImage zone = timeZoneImages[i];
// If not transparent set as current
if (zone.pixel(pos) != RGB_TRANSPARENT) {
if ( zone.pixel( pos ) != RGB_TRANSPARENT )
{
currentZoneImage = zone;
break;
}
@ -91,74 +101,87 @@ void TimeZoneWidget::setCurrentLocation(LocaleGlobal::Location location) {
//###
QPoint TimeZoneWidget::getLocationPosition(double longitude, double latitude) {
QPoint TimeZoneWidget::getLocationPosition( double longitude, double latitude )
{
const int width = this->width();
const int height = this->height();
double x = (width / 2.0 + (width / 2.0) * longitude / 180.0) + MAP_X_OFFSET * width;
double y = (height / 2.0 - (height / 2.0) * latitude / 90.0) + MAP_Y_OFFSET * height;
double x = ( width / 2.0 + ( width / 2.0 ) * longitude / 180.0 ) + MAP_X_OFFSET * width;
double y = ( height / 2.0 - ( height / 2.0 ) * latitude / 90.0 ) + MAP_Y_OFFSET * height;
if (x < 0)
//Far north, the MAP_Y_OFFSET no longer holds, cancel the Y offset; it's noticeable
// from 62 degrees north, so scale those 28 degrees as if the world is flat south
// of there, and we have a funny "rounded" top of the world. In practice the locations
// of the different cities / regions looks ok -- at least Thule ends up in the right
// country, and Inuvik isn't in the ocean.
if ( latitude > 62.0 )
y -= sin( MATH_PI * ( latitude - 62.0 ) / 56.0 ) * MAP_Y_OFFSET * height;
// Antarctica isn't shown on the map, but you could try clicking there
if ( latitude < -60 )
y = height - 1;
if ( x < 0 )
x = width+x;
if (x >= width)
if ( x >= width )
x -= width;
if (y < 0)
if ( y < 0 )
y = height+y;
if (y >= height)
if ( y >= height )
y -= height;
return QPoint((int)x, (int)y);
return QPoint( int(x), int(y) );
}
void TimeZoneWidget::paintEvent(QPaintEvent*) {
void TimeZoneWidget::paintEvent( QPaintEvent* )
{
const int width = this->width();
const int height = this->height();
QFontMetrics fontMetrics(font);
QPainter painter(this);
QFontMetrics fontMetrics( font );
QPainter painter( this );
painter.setRenderHint(QPainter::Antialiasing);
painter.setFont(font);
painter.setRenderHint( QPainter::Antialiasing );
painter.setFont( font );
// Draw background
painter.drawImage(0, 0, background);
painter.drawImage( 0, 0, background );
// Draw zone image
painter.drawImage(0, 0, currentZoneImage);
painter.drawImage( 0, 0, currentZoneImage );
// Draw pin
QPoint point = getLocationPosition(currentLocation.longitude, currentLocation.latitude);
painter.drawImage(point.x() - pin.width()/2, point.y() - pin.height()/2, pin);
QPoint point = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
painter.drawImage( point.x() - pin.width()/2, point.y() - pin.height()/2, pin );
// Draw text and box
const int textWidth = fontMetrics.width(LocaleGlobal::Location::pretty(currentLocation.zone));
const int textWidth = fontMetrics.width( LocaleGlobal::Location::pretty( currentLocation.zone ) );
const int textHeight = fontMetrics.height();
QRect rect = QRect(point.x() - textWidth/2 - 5, point.y() - textHeight - 8, textWidth + 10, textHeight - 2);
QRect rect = QRect( point.x() - textWidth/2 - 5, point.y() - textHeight - 8, textWidth + 10, textHeight - 2 );
if (rect.x() <= 5)
rect.moveLeft(5);
if (rect.right() >= width-5)
rect.moveRight(width - 5);
if (rect.y() <= 5)
rect.moveTop(5);
if (rect.y() >= height-5)
rect.moveBottom(height-5);
if ( rect.x() <= 5 )
rect.moveLeft( 5 );
if ( rect.right() >= width-5 )
rect.moveRight( width - 5 );
if ( rect.y() <= 5 )
rect.moveTop( 5 );
if ( rect.y() >= height-5 )
rect.moveBottom( height-5 );
painter.setPen(QPen()); // no pen
painter.setBrush(QColor(40, 40, 40));
painter.drawRoundedRect(rect, 3, 3);
painter.setPen(Qt::white);
painter.drawText(rect.x() + 5, rect.bottom() - 4, LocaleGlobal::Location::pretty(currentLocation.zone));
painter.setPen( QPen() ); // no pen
painter.setBrush( QColor( 40, 40, 40 ) );
painter.drawRoundedRect( rect, 3, 3 );
painter.setPen( Qt::white );
painter.drawText( rect.x() + 5, rect.bottom() - 4, LocaleGlobal::Location::pretty( currentLocation.zone ) );
painter.end();
}
void TimeZoneWidget::mousePressEvent(QMouseEvent* event) {
if (event->button() != Qt::LeftButton)
void TimeZoneWidget::mousePressEvent( QMouseEvent* event )
{
if ( event->button() != Qt::LeftButton )
return;
// Set nearest location
@ -167,14 +190,17 @@ void TimeZoneWidget::mousePressEvent(QMouseEvent* event) {
QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
QHash<QString, QList<LocaleGlobal::Location> >::iterator iter = hash.begin();
while (iter != hash.end()) {
while ( iter != hash.end() )
{
QList<LocaleGlobal::Location> locations = iter.value();
for (int i = 0; i < locations.size(); ++i) {
for ( int i = 0; i < locations.size(); ++i )
{
LocaleGlobal::Location loc = locations[i];
QPoint locPos = getLocationPosition(loc.longitude, loc.latitude);
QPoint locPos = getLocationPosition( loc.longitude, loc.latitude );
if ((abs(mX - locPos.x()) + abs(mY - locPos.y()) < abs(mX - nX) + abs(mY - nY))) {
if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() ) < abs( mX - nX ) + abs( mY - nY ) ) )
{
currentLocation = loc;
nX = locPos.x();
nY = locPos.y();
@ -185,8 +211,8 @@ void TimeZoneWidget::mousePressEvent(QMouseEvent* event) {
}
// Set zone image and repaint widget
setCurrentLocation(currentLocation);
setCurrentLocation( currentLocation );
// Emit signal
emit locationChanged(currentLocation);
emit locationChanged( currentLocation );
}

View file

@ -48,14 +48,17 @@ class TimeZoneWidget : public QWidget
{
Q_OBJECT
public:
explicit TimeZoneWidget(QWidget* parent = 0);
explicit TimeZoneWidget( QWidget* parent = nullptr );
LocaleGlobal::Location getCurrentLocation() { return currentLocation; }
void setCurrentLocation(QString region, QString zone);
void setCurrentLocation(LocaleGlobal::Location location);
LocaleGlobal::Location getCurrentLocation()
{
return currentLocation;
}
void setCurrentLocation( QString region, QString zone );
void setCurrentLocation( LocaleGlobal::Location location );
signals:
void locationChanged(LocaleGlobal::Location location);
void locationChanged( LocaleGlobal::Location location );
private:
QFont font;
@ -63,10 +66,14 @@ private:
QList<QImage> timeZoneImages;
LocaleGlobal::Location currentLocation;
QPoint getLocationPosition(double longitude, double latitude);
QPoint getLocationPosition( const LocaleGlobal::Location& l )
{
return getLocationPosition( l.longitude, l.latitude );
}
QPoint getLocationPosition( double longitude, double latitude );
void paintEvent(QPaintEvent* event);
void mousePressEvent(QMouseEvent* event);
void paintEvent( QPaintEvent* event );
void mousePressEvent( QMouseEvent* event );
};
#endif // TIMEZONEWIDGET_H

View file

@ -3,6 +3,7 @@
* Copyright 2016, Lisa Vitolo <shainer@chakraos.org>
* Copyright 2017, Kyle Robbertze <krobbertze@gmail.com>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.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
@ -77,7 +78,7 @@ NetInstallPage::readGroups( const QByteArray& yamlData )
m_groups = new PackageModel( groups );
CALAMARES_RETRANSLATE(
m_groups->setHeaderData( 0, Qt::Horizontal, tr( "Name" ) );
m_groups->setHeaderData( 0, Qt::Horizontal, tr( "Description" ) ); )
m_groups->setHeaderData( 1, Qt::Horizontal, tr( "Description" ) ); )
return true;
}
@ -101,7 +102,7 @@ NetInstallPage::dataIsHere( QNetworkReply* reply )
if ( !readGroups( reply->readAll() ) )
{
cDebug() << "Netinstall groups data was received, but invalid.";
ui->netinst_status->setText( tr( "Network Installation. (Disabled: Unable to fetch package lists, check your network connection)" ) );
ui->netinst_status->setText( tr( "Network Installation. (Disabled: Received invalid groups data)" ) );
reply->deleteLater();
return;
}

View file

@ -126,18 +126,26 @@ NetInstallViewStep::onLeave()
cDebug() << "Leaving netinstall, adding packages to be installed"
<< "to global storage";
QMap<QString, QVariant> packagesWithOperation;
QList<PackageTreeItem::ItemData> packages = m_widget->selectedPackages();
QVariantList installPackages;
QVariantList tryInstallPackages;
cDebug() << "Processing";
QVariantList packageOperations;
cDebug() << "Processing" << packages.length() << "packages from netinstall.";
for ( auto package : packages )
{
QMap<QString, QVariant> details;
details.insert( "pre-script", package.preScript );
details.insert( "package", package.packageName );
details.insert( "post-script", package.postScript );
QVariant details( package.packageName );
// If it's a package with a pre- or post-script, replace
// with the more complicated datastructure.
if (!package.preScript.isEmpty() || !package.postScript.isEmpty())
{
QMap<QString, QVariant> sdetails;
sdetails.insert( "pre-script", package.preScript );
sdetails.insert( "package", package.packageName );
sdetails.insert( "post-script", package.postScript );
details = sdetails;
}
if ( package.isCritical )
installPackages.append( details );
else
@ -145,14 +153,24 @@ NetInstallViewStep::onLeave()
}
if ( !installPackages.empty() )
packagesWithOperation.insert( "install", QVariant( installPackages ) );
{
QMap<QString, QVariant> op;
op.insert( "install", QVariant( installPackages ) );
packageOperations.append(op);
cDebug() << " .." << installPackages.length() << "critical packages.";
}
if ( !tryInstallPackages.empty() )
packagesWithOperation.insert( "try_install", QVariant( tryInstallPackages ) );
{
QMap<QString, QVariant> op;
op.insert( "try_install", QVariant( tryInstallPackages ) );
packageOperations.append(op);
cDebug() << " .." << tryInstallPackages.length() << "non-critical packages.";
}
if ( !packagesWithOperation.isEmpty() )
if ( !packageOperations.isEmpty() )
{
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
gs->insert( "packageOperations", QVariant( packagesWithOperation ) );
gs->insert( "packageOperations", QVariant( packageOperations ) );
}
}

View file

@ -6,6 +6,7 @@ At installation time, the user is presented with the choice to install groups of
Calamares will then invoke the correct backend to install the packages.
## Configuration of the packages
Every distribution can choose which groups to display and which packages should be in the groups.
The *netinstall.conf* file should have this format:
@ -48,7 +49,8 @@ If you set both *hidden* and *selected* for a group, you are basically creating
which will always be installed in the user's system.
## Configuration of the module
Here is the set of instructions to have the module work in your Calamares. As of July 2016, this has been successfully
Here is the set of instructions to have the module work in your Calamares. As of July 2016, this has been successfully
tested using the live installation of Chakra Fermi.
First, if the module is used, we need to require a working Internet connection, otherwise the module will be
@ -63,7 +65,8 @@ If not present, add the **packages** job in the **exec** list. This is the job t
to install packages. Make sure it is configured to use the correct package manager for your distribution; this
is configured in src/modules/packages/packages.conf.
The exec list should be:
The **exec** list in *settings.conf* should contain the following items in
order (it's ok for other jobs to be listed inbetween them, though):
- unpackfs
- networkcfg
@ -74,10 +77,10 @@ structure; **networkcfg** set ups a working network in the chroot; and finally *
in the chroot.
## Common issues
If launching the package manager command returns you negative exit statuses and nothing is actually invoked, this
is likely an error in the setup of the chroot; check that the parameter **rootMountPoint** is set to the correct
value in the Calamares configuration.
If the command is run, but exits with error, check that the network is working in the chroot. Make sure /etc/resolv.conf
exists and that it's not empty.

View file

@ -344,10 +344,18 @@ def subst_locale(plist):
def run_operations(pkgman, entry):
"""
Call package manager with given parameters.
Call package manager with suitable parameters for the given
package actions.
:param pkgman:
:param entry:
:param pkgman: PackageManager
This is the manager that does the actual work.
:param entry: dict
Keys are the actions -- e.g. "install" -- to take, and the values
are the (list of) packages to apply the action to. The actions are
not iterated in a specific order, so it is recommended to use only
one action per dictionary. The list of packages may be package
names (strings) or package information dictionaries with pre-
and post-scripts.
"""
global group_packages, completed_packages, mode_packages

View file

@ -8,11 +8,26 @@ find_package( KF5 REQUIRED CoreAddons )
# These are needed because KPMcore links publicly against ConfigCore, I18n, IconThemes, KIOCore and Service
find_package( KF5 REQUIRED Config I18n IconThemes KIO Service )
# Compatibility: KPMCore 3.2 has a different API, so detect it
# first and add a define for it; otherwise we need 3.0.3 for NVMe
# support; 3.0.2 works as well, but is buggy (#697)
find_package( KPMcore 3.1.50 QUIET )
if ( ${KPMcore_FOUND} )
if ( KPMcore_FOUND )
add_definitions(-DWITH_KPMCORE22)
endif()
find_package( KPMcore 3.0.3 REQUIRED )
find_package( KPMcore 3.0.3 QUIET )
# 3.0.3 and newer has fixes for NVMe support; allow 3.0.2, but warn
# about it .. needs to use a different feature name because it otherwise
# gets reported as KPMcore (the package).
if ( KPMcore_FOUND )
message( STATUS "KPMCore supports NVMe operations" )
add_feature_info( KPMcoreNVMe KPMcore_FOUND "KPMcore with NVMe support" )
else()
find_package( KPMcore 3.0.2 REQUIRED )
message( WARNING "KPMCore 3.0.2 is known to have bugs with NVMe devices" )
add_feature_info( KPMcoreNVMe KPMcore_FOUND "Older KPMcore with no NVMe support" )
endif()
find_library( atasmart_LIB atasmart )
find_library( blkid_LIB blkid )
if( NOT atasmart_LIB )
@ -58,7 +73,6 @@ calamares_add_plugin( partition
gui/PrettyRadioButton.cpp
gui/ScanningDialog.cpp
gui/ReplaceWidget.cpp
jobs/CheckFileSystemJob.cpp
jobs/ClearMountsJob.cpp
jobs/ClearTempMountsJob.cpp
jobs/CreatePartitionJob.cpp
@ -66,7 +80,6 @@ calamares_add_plugin( partition
jobs/DeletePartitionJob.cpp
jobs/FillGlobalStorageJob.cpp
jobs/FormatPartitionJob.cpp
jobs/MoveFileSystemJob.cpp
jobs/PartitionJob.cpp
jobs/ResizePartitionJob.cpp
jobs/SetPartitionFlagsJob.cpp

View file

@ -24,6 +24,7 @@
// KPMcore
#include <kpmcore/core/partition.h>
#include <kpmcore/fs/luks.h>
// Qt
#include <QColor>
@ -86,9 +87,19 @@ colorForPartition( Partition* partition )
return EXTENDED_COLOR;
if ( partition->fileSystem().supportGetUUID() != FileSystem::cmdSupportNone &&
!partition->fileSystem().uuid().isEmpty() &&
s_partitionColorsCache.contains( partition->fileSystem().uuid() ) )
return s_partitionColorsCache[ partition->fileSystem().uuid() ];
!partition->fileSystem().uuid().isEmpty() )
{
if ( partition->fileSystem().type() == FileSystem::Luks )
{
FS::luks& luksFs = dynamic_cast< FS::luks& >( partition->fileSystem() );
if ( !luksFs.outerUuid().isEmpty() &&
s_partitionColorsCache.contains( luksFs.outerUuid() ) )
return s_partitionColorsCache[ luksFs.outerUuid() ];
}
if ( s_partitionColorsCache.contains( partition->fileSystem().uuid() ) )
return s_partitionColorsCache[ partition->fileSystem().uuid() ];
}
// No partition-specific color needed, pick one from our list, but skip
// free space: we don't want a partition to change colors if space before
@ -119,8 +130,20 @@ colorForPartition( Partition* partition )
if ( partition->fileSystem().supportGetUUID() != FileSystem::cmdSupportNone &&
!partition->fileSystem().uuid().isEmpty() )
s_partitionColorsCache.insert( partition->fileSystem().uuid(),
PARTITION_COLORS[ colorIdx % NUM_PARTITION_COLORS ] );
{
if ( partition->fileSystem().type() == FileSystem::Luks )
{
FS::luks& luksFs = dynamic_cast< FS::luks& >( partition->fileSystem() );
if ( !luksFs.outerUuid().isEmpty() )
{
s_partitionColorsCache.insert( luksFs.outerUuid(),
PARTITION_COLORS[ colorIdx % NUM_PARTITION_COLORS ] );
}
}
else
s_partitionColorsCache.insert( partition->fileSystem().uuid(),
PARTITION_COLORS[ colorIdx % NUM_PARTITION_COLORS ] );
}
return PARTITION_COLORS[ colorIdx % NUM_PARTITION_COLORS ];
}

View file

@ -1,83 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2016, Teo Mrnjavac <teo@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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jobs/CheckFileSystemJob.h"
#include <utils/Logger.h>
// KPMcore
#include <kpmcore/core/partition.h>
#include <kpmcore/fs/filesystem.h>
#include <kpmcore/util/report.h>
#include <QThread>
CheckFileSystemJob::CheckFileSystemJob( Partition* partition )
: PartitionJob( partition )
{}
QString
CheckFileSystemJob::prettyName() const
{
QString path = partition()->partitionPath();
return tr( "Checking file system on partition %1." ).arg( path );
}
QString
CheckFileSystemJob::prettyStatusMessage() const
{
return prettyName();
}
Calamares::JobResult
CheckFileSystemJob::exec()
{
FileSystem& fs = partition()->fileSystem();
// if we cannot check, assume everything is fine
if ( fs.supportCheck() != FileSystem::cmdSupportFileSystem )
return Calamares::JobResult::ok();
Report report( nullptr );
bool ok = fs.check( report, partition()->partitionPath() );
int retries = 0;
const int MAX_RETRIES = 10;
while ( !ok )
{
cDebug() << "Partition" << partition()->partitionPath()
<< "might not be ready yet, retrying (" << ++retries
<< "/" << MAX_RETRIES << ") ...";
QThread::sleep( 2 /*seconds*/ );
ok = fs.check( report, partition()->partitionPath() );
if ( retries == MAX_RETRIES )
break;
}
if ( !ok )
return Calamares::JobResult::error(
tr( "The file system check on partition %1 failed." )
.arg( partition()->partitionPath() ),
report.toText()
);
return Calamares::JobResult::ok();
}

View file

@ -1,38 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHECKFILESYSTEMJOB_H
#define CHECKFILESYSTEMJOB_H
#include <jobs/PartitionJob.h>
/**
* Runs a file system check on an existing partition.
*/
class CheckFileSystemJob : public PartitionJob
{
Q_OBJECT
public:
CheckFileSystemJob( Partition* partition );
QString prettyName() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
};
#endif /* CHECKFILESYSTEMJOB_H */

View file

@ -1,239 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
// This class is heavily based on the MoveFileSystemJob class from KDE Partition
// Manager.
// The copyBlock functions come from Partition Manager Job class.
// Original copyright follow:
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include <jobs/MoveFileSystemJob.h>
#include <utils/Logger.h>
// KPMcore
#include <kpmcore/core/copysourcedevice.h>
#include <kpmcore/core/copytargetdevice.h>
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/fs/filesystem.h>
#include <kpmcore/util/report.h>
MoveFileSystemJob::MoveFileSystemJob( Device* device, Partition* partition, qint64 oldFirstSector, qint64 newFirstSector, qint64 length )
: PartitionJob( partition )
, m_device( device )
, m_oldFirstSector( oldFirstSector )
, m_newFirstSector( newFirstSector )
, m_length( length )
{}
QString
MoveFileSystemJob::prettyName() const
{
return tr( "Move file system of partition %1." ).arg( partition()->partitionPath() );
}
Calamares::JobResult
MoveFileSystemJob::exec()
{
Report report( nullptr );
QString partitionPath = partition()->partitionPath();
CopySourceDevice moveSource( *m_device, m_oldFirstSector, m_oldFirstSector + m_length - 1 );
CopyTargetDevice moveTarget( *m_device, m_newFirstSector, m_newFirstSector + m_length - 1 );
if ( !moveSource.open() )
return Calamares::JobResult::error(
QString(),
tr( "Could not open file system on partition %1 for moving." ).arg( partitionPath )
);
if ( !moveTarget.open() )
return Calamares::JobResult::error(
QString(),
tr( "Could not create target for moving file system on partition %1." ).arg( partitionPath )
);
bool ok = copyBlocks( report, moveTarget, moveSource );
if ( !ok )
{
if ( rollbackCopyBlocks( report, moveTarget, moveSource ) )
return Calamares::JobResult::error(
QString(),
tr( "Moving of partition %1 failed, changes have been rolled back." ).arg( partitionPath )
+ '\n' + report.toText()
);
else
return Calamares::JobResult::error(
QString(),
tr( "Moving of partition %1 failed. Roll back of the changes have failed." ).arg( partitionPath )
+ '\n' + report.toText()
);
}
FileSystem& fs = partition()->fileSystem();
fs.setFirstSector( m_newFirstSector );
fs.setLastSector( m_newFirstSector + m_length - 1 );
if ( !fs.updateBootSector( report, partitionPath ) )
return Calamares::JobResult::error(
QString(),
tr( "Updating boot sector after the moving of partition %1 failed." ).arg( partitionPath )
+ '\n' + report.toText()
);
return Calamares::JobResult::ok();
}
bool
MoveFileSystemJob::copyBlocks( Report& report, CopyTargetDevice& target, CopySourceDevice& source )
{
/** @todo copyBlocks() assumes that source.sectorSize() == target.sectorSize(). */
if ( source.sectorSize() != target.sectorSize() )
{
report.line() << tr( "The logical sector sizes in the source and target for copying are not the same. This is currently unsupported." );
return false;
}
bool rval = true;
const qint64 blockSize = 16065 * 8; // number of sectors per block to copy
const qint64 blocksToCopy = source.length() / blockSize;
qint64 readOffset = source.firstSector();
qint64 writeOffset = target.firstSector();
qint32 copyDir = 1;
if ( target.firstSector() > source.firstSector() )
{
readOffset = source.firstSector() + source.length() - blockSize;
writeOffset = target.firstSector() + source.length() - blockSize;
copyDir = -1;
}
qint64 blocksCopied = 0;
Q_ASSERT( blockSize > 0 );
Q_ASSERT( source.sectorSize() > 0 );
Q_ASSERT( blockSize * source.sectorSize() > 0 );
void* buffer = malloc( size_t( blockSize * source.sectorSize() ) );
qint64 percent = 0;
while ( blocksCopied < blocksToCopy )
{
rval = source.readSectors( buffer, readOffset + blockSize * blocksCopied * copyDir, blockSize );
if ( !rval )
break;
rval = target.writeSectors( buffer, writeOffset + blockSize * blocksCopied * copyDir, blockSize );
if ( !rval )
break;
if ( ++blocksCopied * 100 / blocksToCopy != percent )
{
percent = blocksCopied * 100 / blocksToCopy;
progress( percent / 100. );
}
}
const qint64 lastBlock = source.length() % blockSize;
// copy the remainder
if ( rval && lastBlock > 0 )
{
Q_ASSERT( lastBlock < blockSize );
const qint64 lastBlockReadOffset = copyDir > 0 ? readOffset + blockSize * blocksCopied : source.firstSector();
const qint64 lastBlockWriteOffset = copyDir > 0 ? writeOffset + blockSize * blocksCopied : target.firstSector();
rval = source.readSectors( buffer, lastBlockReadOffset, lastBlock );
if ( rval )
rval = target.writeSectors( buffer, lastBlockWriteOffset, lastBlock );
if ( rval )
emit progress( 1.0 );
}
free( buffer );
return rval;
}
bool
MoveFileSystemJob::rollbackCopyBlocks( Report& report, CopyTargetDevice& origTarget, CopySourceDevice& origSource )
{
if ( !origSource.overlaps( origTarget ) )
{
report.line() << tr( "Source and target for copying do not overlap: Rollback is not required." );
return true;
}
// default: use values as if we were copying from front to back.
qint64 undoSourceFirstSector = origTarget.firstSector();
qint64 undoSourceLastSector = origTarget.firstSector() + origTarget.sectorsWritten() - 1;
qint64 undoTargetFirstSector = origSource.firstSector();
qint64 undoTargetLastSector = origSource.firstSector() + origTarget.sectorsWritten() - 1;
if ( origTarget.firstSector() > origSource.firstSector() )
{
// we were copying from back to front
undoSourceFirstSector = origTarget.firstSector() + origSource.length() - origTarget.sectorsWritten();
undoSourceLastSector = origTarget.firstSector() + origSource.length() - 1;
undoTargetFirstSector = origSource.lastSector() - origTarget.sectorsWritten() + 1;
undoTargetLastSector = origSource.lastSector();
}
CopySourceDevice undoSource( origTarget.device(), undoSourceFirstSector, undoSourceLastSector );
if ( !undoSource.open() )
{
report.line() << tr( "Could not open device %1 to rollback copying." )
.arg( origTarget.device().deviceNode() );
return false;
}
CopyTargetDevice undoTarget( origSource.device(), undoTargetFirstSector, undoTargetLastSector );
if ( !undoTarget.open() )
{
report.line() << tr( "Could not open device %1 to rollback copying." )
.arg( origSource.device().deviceNode() );
return false;
}
return copyBlocks( report, undoTarget, undoSource );
}

View file

@ -1,76 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
// This class is heavily based on the MoveFileSystemJob class from KDE Partition
// Manager. Original copyright follow:
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef MOVEFILESYSTEMJOB_H
#define MOVEFILESYSTEMJOB_H
#include <jobs/PartitionJob.h>
class CopySourceDevice;
class CopyTargetDevice;
class Device;
class Partition;
class Report;
/**
* This job moves the data of a filesystem from one position on the disk to
* another.
*
* It is used by the ResizePartitionJob.
*/
class MoveFileSystemJob : public PartitionJob
{
Q_OBJECT
public:
MoveFileSystemJob( Device* device, Partition* partition, qint64 oldFirstSector, qint64 newFirstSector, qint64 length );
QString prettyName() const override;
Calamares::JobResult exec() override;
private:
Device* m_device;
qint64 m_oldFirstSector;
qint64 m_newFirstSector;
qint64 m_length;
bool copyBlocks( Report& report, CopyTargetDevice& target, CopySourceDevice& source );
bool rollbackCopyBlocks( Report& report, CopyTargetDevice& origTarget, CopySourceDevice& origSource );
};
#endif /* MOVEFILESYSTEMJOB_H */

View file

@ -2,6 +2,7 @@
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Andrius Štikonas <andrius@stikonas.eu>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -17,156 +18,12 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
// This class is heavily based on the ResizeOperation class from KDE Partition
// Manager. Original copyright follow:
/***************************************************************************
* Copyright (C) 2008,2012 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "jobs/ResizePartitionJob.h"
#include "jobs/CheckFileSystemJob.h"
#include "jobs/MoveFileSystemJob.h"
#include "utils/Logger.h"
// KPMcore
#include <kpmcore/backend/corebackend.h>
#include <kpmcore/backend/corebackendmanager.h>
#include <kpmcore/backend/corebackenddevice.h>
#include <kpmcore/backend/corebackendpartition.h>
#include <kpmcore/backend/corebackendpartitiontable.h>
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/util/report.h>
// Qt
#include <QScopedPointer>
//- ResizeFileSystemJob --------------------------------------------------------
class ResizeFileSystemJob : public Calamares::Job
{
Q_OBJECT
public:
ResizeFileSystemJob( Device* device, CoreBackendPartitionTable* backendPartitionTable, Partition* partition, qint64 length )
: m_device( device )
, m_backendPartitionTable( backendPartitionTable )
, m_partition( partition )
, m_length( length )
{}
QString prettyName() const override
{
QString path = m_partition->partitionPath();
return tr( "Resize file system on partition %1." ).arg( path );
}
Calamares::JobResult exec() override
{
Report report( nullptr );
FileSystem& fs = m_partition->fileSystem();
FileSystem::CommandSupportType support = m_length < fs.length() ? fs.supportShrink() : fs.supportGrow();
switch ( support )
{
case FileSystem::cmdSupportBackend:
if ( !backendResize( &report ) )
return Calamares::JobResult::error(
QString(),
tr( "Parted failed to resize filesystem." ) + '\n' + report.toText()
);
break;
case FileSystem::cmdSupportFileSystem:
{
qint64 byteLength = m_device->logicalSize() * m_length;
bool ok = fs.resize( report, m_partition->partitionPath(), byteLength );
if ( !ok )
return Calamares::JobResult::error(
QString(),
tr( "Failed to resize filesystem." ) + '\n' + report.toText()
);
break;
}
default:
break;
}
fs.setLastSector( fs.firstSector() + m_length - 1 );
return Calamares::JobResult::ok();
}
private:
Device* m_device;
CoreBackendPartitionTable* m_backendPartitionTable;
Partition* m_partition;
qint64 m_length;
bool backendResize( Report* report )
{
bool ok = m_backendPartitionTable->resizeFileSystem( *report, *m_partition, m_length );
if ( !ok )
return false;
m_backendPartitionTable->commit();
return true;
}
};
//- SetPartGeometryJob ---------------------------------------------------------
class SetPartGeometryJob : public Calamares::Job
{
Q_OBJECT
public:
SetPartGeometryJob( CoreBackendPartitionTable* backendPartitionTable, Partition* partition, qint64 firstSector, qint64 length )
: m_backendPartitionTable( backendPartitionTable )
, m_partition( partition )
, m_firstSector( firstSector )
, m_length( length )
{}
QString prettyName() const override
{
QString path = m_partition->partitionPath();
return tr( "Update geometry of partition %1." ).arg( path );
}
Calamares::JobResult exec() override
{
Report report( nullptr );
qint64 lastSector = m_firstSector + m_length - 1;
bool ok = m_backendPartitionTable->updateGeometry( report, *m_partition, m_firstSector, lastSector );
if ( !ok )
{
return Calamares::JobResult::error(
QString(),
tr( "Failed to change the geometry of the partition." ) + '\n' + report.toText() );
}
m_partition->setFirstSector( m_firstSector );
m_partition->setLastSector( lastSector );
m_backendPartitionTable->commit();
return Calamares::JobResult::ok();
}
private:
CoreBackendPartitionTable* m_backendPartitionTable;
Partition* m_partition;
qint64 m_firstSector;
qint64 m_length;
};
#include <core/device.h>
#include <ops/resizeoperation.h>
#include <util/report.h>
//- ResizePartitionJob ---------------------------------------------------------
ResizePartitionJob::ResizePartitionJob( Device* device, Partition* partition, qint64 firstSector, qint64 lastSector )
@ -194,7 +51,7 @@ ResizePartitionJob::prettyDescription() const
return tr( "Resize <strong>%2MB</strong> partition <strong>%1</strong> to "
"<strong>%3MB</strong>." )
.arg( partition()->partitionPath() )
.arg( ( m_oldLastSector - m_oldFirstSector ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_oldLastSector - m_oldFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_newLastSector - m_newFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 );
}
@ -205,7 +62,7 @@ ResizePartitionJob::prettyStatusMessage() const
return tr( "Resizing %2MB partition %1 to "
"%3MB." )
.arg( partition()->partitionPath() )
.arg( ( m_oldLastSector - m_oldFirstSector ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_oldLastSector - m_oldFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_newLastSector - m_newFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 );
}
@ -213,64 +70,21 @@ ResizePartitionJob::prettyStatusMessage() const
Calamares::JobResult
ResizePartitionJob::exec()
{
qint64 oldLength = m_oldLastSector - m_oldFirstSector + 1;
qint64 newLength = m_newLastSector - m_newFirstSector + 1;
// Assuming updatePreview() has been called, `partition` uses its new
// position and size. Reset it to the old values: part of the libparted
// backend relies on this (for example:
// LibPartedPartitionTable::updateGeometry())
// The jobs are responsible for updating the partition back when they are
// done.
Report report (nullptr);
// Restore partition sectors that were modified for preview
m_partition->setFirstSector( m_oldFirstSector );
m_partition->setLastSector( m_oldLastSector );
ResizeOperation op(*m_device, *m_partition, m_newFirstSector, m_newLastSector);
op.setStatus(Operation::StatusRunning);
connect(&op, &Operation::progress, [&](int percent) { emit progress(percent / 100.0); } );
CoreBackend* backend = CoreBackendManager::self()->backend();
QScopedPointer<CoreBackendDevice> backendDevice( backend->openDevice( m_device->deviceNode() ) );
if ( !backendDevice.data() )
{
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
return Calamares::JobResult::error(
errorMessage,
tr( "Could not open device '%1'." ).arg( m_device->deviceNode() )
);
}
QScopedPointer<CoreBackendPartitionTable> backendPartitionTable( backendDevice->openPartitionTable() );
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
if (op.execute(report))
return Calamares::JobResult::ok();
// Create jobs
QList< Calamares::job_ptr > jobs;
jobs << Calamares::job_ptr( new CheckFileSystemJob( partition() ) );
if ( m_partition->roles().has( PartitionRole::Extended ) )
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, newLength ) );
else
{
bool shrink = newLength < oldLength;
bool grow = newLength > oldLength;
bool moveRight = m_newFirstSector > m_oldFirstSector;
bool moveLeft = m_newFirstSector < m_oldFirstSector;
if ( shrink )
{
jobs << Calamares::job_ptr( new ResizeFileSystemJob( m_device, backendPartitionTable.data(), m_partition, newLength ) );
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_oldFirstSector, newLength ) );
}
if ( moveRight || moveLeft )
{
// At this point, we need to set the partition's length to either the resized length, if it has already been
// shrunk, or to the original length (it may or may not then later be grown, we don't care here)
const qint64 length = shrink ? newLength : oldLength;
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, length ) );
jobs << Calamares::job_ptr( new MoveFileSystemJob( m_device, m_partition, m_oldFirstSector, m_newFirstSector, length ) );
}
if ( grow )
{
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, newLength ) );
jobs << Calamares::job_ptr( new ResizeFileSystemJob( m_device, backendPartitionTable.data(), m_partition, newLength ) );
}
}
jobs << Calamares::job_ptr( new CheckFileSystemJob( partition() ) );
return execJobList( jobs );
return Calamares::JobResult::error(errorMessage, report.toText());
}
void
@ -290,31 +104,3 @@ ResizePartitionJob::device() const
{
return m_device;
}
Calamares::JobResult
ResizePartitionJob::execJobList( const QList< Calamares::job_ptr >& jobs )
{
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
int nbJobs = jobs.size();
int count = 0;
for ( Calamares::job_ptr job : jobs )
{
cLog() << "- " + job->prettyName();
Calamares::JobResult result = job->exec();
if ( !result )
{
if ( result.message().isEmpty() )
result.setMessage( errorMessage );
return result;
}
++count;
progress( qreal( count ) / nbJobs );
}
return Calamares::JobResult::ok();
}
#include "ResizePartitionJob.moc"

View file

@ -51,8 +51,6 @@ private:
qint64 m_oldLastSector;
qint64 m_newFirstSector;
qint64 m_newLastSector;
Calamares::JobResult execJobList( const QList< Calamares::job_ptr >& jobs );
};
#endif /* RESIZEPARTITIONJOB_H */

View file

@ -26,9 +26,16 @@ drawNestedPartitions: false
# Show/hide partition labels on manual partitioning page.
alwaysShowPartitionLabels: true
# Default filesystem type, pre-selected in the "Create Partition" dialog.
# The filesystem type selected here is also used for automated install
# modes (Erase, Replace and Alongside).
# Default filesystem type, used when a "new" partition is made.
#
# When replacing a partition, the existing filesystem inside the
# partition is retained. In other cases, e.g. Erase and Alongside,
# as well as when using manual partitioning and creating a new
# partition, this filesystem type is pre-selected. Note that
# editing a partition in manual-creation mode will not automatically
# change the filesystem type to this default value -- it is not
# creating a new partition.
#
# Suggested values: ext2, ext3, ext4, reiser, xfs, jfs, btrfs
# If nothing is specified, Calamares defaults to "ext4".
defaultFileSystemType: "ext4"

View file

@ -9,11 +9,9 @@ set( partitionjobtests_SRCS
${PartitionModule_SOURCE_DIR}/core/KPMHelpers.cpp
${PartitionModule_SOURCE_DIR}/core/PartitionInfo.cpp
${PartitionModule_SOURCE_DIR}/core/PartitionIterator.cpp
${PartitionModule_SOURCE_DIR}/jobs/CheckFileSystemJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionTableJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/DeletePartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/MoveFileSystemJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/PartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/ResizePartitionJob.cpp
PartitionJobTests.cpp

66
src/modules/test_conf.cpp Normal file
View file

@ -0,0 +1,66 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This is a test-application that just checks the YAML config-file
* shipped with each module for correctness -- well, for parseability.
*/
#include <iostream>
#include <yaml-cpp/yaml.h>
using std::cerr;
int main(int argc, char** argv)
{
if (argc != 2)
{
cerr << "Usage: test_conf <file.conf>\n";
return 1;
}
try
{
YAML::Node doc = YAML::LoadFile( argv[1] );
if ( doc.IsNull() )
{
// Special case: empty config files are valid,
// but aren't a map. For the example configs,
// this is still an error.
cerr << "WARNING:" << argv[1] << '\n';
cerr << "WARNING: empty YAML\n";
return 1;
}
if ( !doc.IsMap() )
{
cerr << "WARNING:" << argv[1] << '\n';
cerr << "WARNING: not-a-YAML-map\n";
return 1;
}
}
catch ( YAML::Exception& e )
{
cerr << "WARNING:" << argv[1] << '\n';
cerr << "WARNING: YAML parser error " << e.what() << '\n';
return 1;
}
return 0;
}

View file

@ -18,6 +18,15 @@
#
# You should have received a copy of the GNU General Public License
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
"""
Testing tool to run a single Python module; optionally a
global configuration and module configuration can be read
from YAML files. Give a full path to the module-directory,
and also full paths to the configuration files. An empty
configuration file name, or "-" (a single dash) is used
to indicate that no file should be read -- useful to load
a module configuratioon file without a global configuration.
"""
import argparse
import os
@ -57,26 +66,10 @@ class Job:
print("Job set progress to {}%.".format(progress * 100))
def main():
"""
def test_module(moduledir, globalconfigfilename, moduleconfigfilename, lang):
print("Testing module in: " + moduledir)
:return:
"""
parser = argparse.ArgumentParser()
parser.add_argument("moduledir",
help="Dir containing the Python module.")
parser.add_argument("globalstorage_yaml", nargs="?",
help="A yaml file to initialize GlobalStorage.")
parser.add_argument("configuration_yaml", nargs="?",
help="A yaml file to initialize the Job.")
parser.add_argument("--lang", "-l", nargs="?", default=None,
help="Set translation language.")
args = parser.parse_args()
print("Testing module in: " + args.moduledir)
confpath = os.path.join(args.moduledir, "module.desc")
confpath = os.path.join(moduledir, "module.desc")
with open(confpath) as f:
doc = yaml.load(f)
@ -87,27 +80,33 @@ def main():
# Parameter None creates a new, empty GlobalStorage
libcalamares.globalstorage = libcalamares.GlobalStorage(None)
libcalamares.globalstorage.insert("testing", True)
if args.lang:
libcalamares.globalstorage.insert("locale", args.lang)
libcalamares.globalstorage.insert("localeConf", {"LANG": args.lang})
if lang:
libcalamares.globalstorage.insert("locale", lang)
libcalamares.globalstorage.insert("localeConf", {"LANG": lang})
# if a file for simulating globalStorage contents is provided, load it
if args.globalstorage_yaml:
with open(args.globalstorage_yaml) as f:
if globalconfigfilename:
with open(globalconfigfilename) as f:
gs_doc = yaml.load(f)
for key, value in gs_doc.items():
libcalamares.globalstorage.insert(key, value)
print("Global configuration '" + globalconfigfilename + "' loaded.")
else:
print("No global configuration loaded.")
cfg_doc = dict()
if args.configuration_yaml:
with open(args.configuration_yaml) as f:
if moduleconfigfilename:
with open(moduleconfigfilename) as f:
cfg_doc = yaml.load(f)
print("Local configuration '" + moduleconfigfilename + "' loaded.")
else:
print("No module configuration loaded.")
libcalamares.job = Job(args.moduledir, doc, cfg_doc)
libcalamares.job = Job(moduledir, doc, cfg_doc)
scriptpath = os.path.abspath(args.moduledir)
scriptpath = os.path.abspath(moduledir)
sys.path.append(scriptpath)
import main
import main # Assumed to import main from module itself
print("Output from module:")
print(main.run())
@ -115,5 +114,33 @@ def main():
return 0
def munge_filename(filename):
"""
Maps files "" (empty) and "-" (just a dash) to None,
to simplify processing elsewhere.
"""
if not filename or filename == "-":
return None
return filename
def main():
parser = argparse.ArgumentParser(description=globals()["__doc__"])
parser.add_argument("moduledir",
help="Dir containing the Python module.")
parser.add_argument("globalstorage_yaml", nargs="?",
help="A yaml file to initialize GlobalStorage.")
parser.add_argument("configuration_yaml", nargs="?",
help="A yaml file to initialize the Job.")
parser.add_argument("--lang", "-l", nargs="?", default=None,
help="Set translation language.")
args = parser.parse_args()
return test_module(args.moduledir,
munge_filename(args.globalstorage_yaml),
munge_filename(args.configuration_yaml),
args.lang)
if __name__ == "__main__":
sys.exit(main())

View file

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.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
@ -131,6 +132,7 @@ UsersViewStep::setConfigurationMap( const QVariantMap& configurationMap )
}
else
{
cDebug() << "WARNING: Using fallback groups. Please check defaultGroups in users.conf";
m_defaultGroups = QStringList{ "lp", "video", "network", "storage", "wheel", "audio" };
}

View file

@ -11,6 +11,8 @@
# These globalconfig keys are set when the jobs for this module
# are created.
---
# Used as default groups for the created user.
# Adjust to your Distribution defaults.
defaultGroups:
- users
- lp
@ -19,13 +21,32 @@ defaultGroups:
- storage
- wheel
- audio
# Some Distributions require a 'autologin' group for the user.
# Autologin causes a user to become automatically logged in to
# the desktop environment on boot.
# Disable when your Distribution does not require such a group.
autologinGroup: autologin
# You can control the initial state for the 'autologin checkbox' in UsersViewStep here.
# Possible values are: true to enable or false to disable the checkbox by default
doAutologin: true
# remove the following line to avoid creating /etc/sudoers.d/10-installer
# When set to a non-empty string, Calamares creates a sudoers file for the user.
# /etc/sudoers.d/10-installer
# Remember to add sudoersGroup to defaultGroups.
#
# If your Distribution already sets up a group of sudoers in its packaging,
# remove this setting (delete or comment out the line below). Otherwise,
# the setting will be duplicated in the /etc/sudoers.d/10-installer file,
# potentially confusing users.
sudoersGroup: wheel
# Setting this to false , causes the root account to be disabled.
setRootPassword: true
# You can control the initial state for the 'root password checkbox' in UsersViewStep here.
# Possible values are: true to enable or false to disable the checkbox by default.
# When enabled the user password is used for the root account too.
# NOTE: doReusePassword requires setRootPassword to be enabled.
doReusePassword: true
# These are optional password-requirements that a distro can enforce

View file

@ -12,7 +12,7 @@ set( CHECKER_SOURCES
checker/partman_devices.c
)
set( CHECKER_LINK_LIBRARIES
${LIBPARTED_LIBS}
${LIBPARTED_LIBRARY}
Qt5::DBus
Qt5::Network
)

View file

@ -2,6 +2,7 @@
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.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
@ -99,8 +100,12 @@ RequirementsChecker::RequirementsChecker( QObject* parent )
if ( m_entriesToCheck.contains( "root" ) )
isRoot = checkIsRoot();
cDebug() << "enoughStorage, enoughRam, hasPower, hasInternet, isRoot: "
<< enoughStorage << enoughRam << hasPower << hasInternet << isRoot;
cDebug() << "RequirementsChecker output:"
<< " enoughStorage:" << enoughStorage
<< " enoughRam:" << enoughRam
<< " hasPower:" << hasPower
<< " hasInternet:" << hasInternet
<< " isRoot:" << isRoot;
QList< PrepareEntry > checkEntries;
foreach ( const QString& entry, m_entriesToCheck )