[release] v3.2.2

This commit is contained in:
Philip Müller 2018-09-05 20:09:25 +02:00
commit 1031ba1084
98 changed files with 4143 additions and 1595 deletions

125
CHANGES Normal file
View File

@ -0,0 +1,125 @@
This is the changelog for Calamares. For each release, the major changes and
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.2 (2018-09-04) =
This release contains contributions from (alphabetically by first name):
- Andrius Štikonas
- artoo@cromnix.org
- Caio Carvalho
- Harald Sitter
- Philip Müller
- Simon Quigley
- Walter Lapchynski
== Core ==
* Example configurations are **no longer installed** by default.
The default setting for *INSTALL_CONFIG* has changed. Distributions
are strongly encouraged to write their own configuration files and
not rely on the example configuration files. Example configurations
may change unpredictably.
* It is now possible to express module dependencies through the
*requiredModules* key in `module.desc`. All of the required modules
for a given module must occur in the sequence **before** the module
requiring them. None of the core modules use this facility.
* The search paths for QML files, branding descriptors and module
descriptors have been revamped and now self-document in the log.
* A new `ci/RELEASE.sh` script has been added to streamline releases;
it is not guaranteed to work anywhere in particular though.
== Modules ==
* When multiple modules are mutually exclusive, or don't make sense
to enable concurrectly, a new `USE_<foo>` framework has been added
to CMake to simplify the selection of modules. This is in addition
to the existing `SKIP_MODULES` mechanism.
* Various off-by-one-sector errors in the automatic partitioning
mode have been corrected. In addition, swap space is calculated
a little more conservatively.
* A new module has been added to the core which can configure openrc
services. To make services configuration consistent:
- The *services* module has been **renamed** *services-systemd*,
- The openrc module is named *services-openrc*,
- At CMake time, it is possible to select all of the services modules,
or one specific one, by setting the *USE_services* CMake variable.
By default, all of the modules are built and installed.
* The systemd-services module can now disable targets and mask both
targets and services (which will allow you to break the system with
a bad configuration). The configuration is a little more flexible
because a service (or target) name can be used on its own with
sensible defaults.
* The displaymanager module has been entirely revamped. A long-standing
bug which ignored the settings for default desktop has been fixed
(thanks to Walter Lapchynski). Translations have been added to the
error messages. Each DM now has an implementation class for doing
all the configuration steps it needs. This groups the code needed for
a specific DM (and presumably, per-distro) in one place.
Distro's are **strongly advised** to re-test their DM configuration
and installation with the revamped code.
**3.2.1** (2018-06-25)
This release contains contributions from (alphabetically by first name):
- Bill Auguer
- Gabriel Craciunescu
- Phil Mueller
- Raul Rodrigo Segura
== Core ==
* Qt 5.7 is now the minimum required Qt version. Because KPMCore
(a fairly fundamental dependency) requires Qt 5.7, Calamares
has followed suit.
* New testing application `loadmodule` for loading and running a
single Calamares module.
* New translations Belarussian and Korean.
* Jobs can now be *emergency jobs* which run even after a failure.
* Improved debugging when modules fail to load.
* Bad configuration files will now cause the user-interface of
Calamares to display an error message, rather than silently
ignoring some configuration errors. This will certainly cause
problems for distributions with sloppy configurations.
== Modules ==
* New module preservefiles, keeps (log) files around after install;
this duplicates functionality with the unmount module, but unmount
is very late, rather limited, and fragile.
* Interactiveterminal module now disables itself if build requirements
are not met, rather than blocking the build.
* Fixes in the timezone map data make the southern hemisphere more
usable and put Reykjavik in its place.
* The packages module can now update the target system if explicitly
told to do so.
* More paths and executables are configurable in the bootloader module.
* Distributions are advised to review the `users.conf` setup **again**,
as some changes in version 3.2.0 caused regressions downstream.
* Distributions are advised to review their `locale.gen` files
**again**. Previous changes were too restrictive, matching only
the specific format Chakra Linux uses. Calamares now preserves
all the comment-lines in the file and writes enabled locales
at the end, with a descriptive comment.
**3.2.0** (2018-05-17)
This release contains contributions from (alphabetically by first name):
- Alf Gaida
- AlmAck
- Caio Carvalho
- Frede H
== Modules ==
* UI annoyances in the partitioning module were fixed; the
mount-point selector is now more obvious when no mount-point
has been chosen, and the mount-point and flags are preserved
when (re)editing partitions.
* The handling of `@@ROOT@@` substitution in shellprocesses was
backwards; this has been fixed (the substitution is made when
running in the **host**).
* The user shell is no longer hard-coded to `/bin/bash`,
but follows the default setting for useradd(8), e.g.
those set in `/etc/default/useradd`.

View File

@ -28,6 +28,9 @@
# Example usage:
#
# cmake . -DSKIP_MODULES="partition luksbootkeycfg"
#
# One special target is "show-version", which can be built
# to obtain the version number from here.
project( calamares C CXX )
@ -36,13 +39,30 @@ cmake_minimum_required( VERSION 3.2 )
### OPTIONS
#
option( INSTALL_CONFIG "Install configuration files" ON )
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_KF5Crash "Enable crash reporting with KCrash." ON )
### USE_*
#
# By convention, when there are multiple modules that implement similar
# functionality, and it only makes sense to have **at most one** of them
# enabled at any time, those modules are named <foo>-<implementation>.
# For example, services-systemd and services-openrc.
#
# Setting up SKIP_MODULES to ignore "the ones you don't want" can be
# annoying and error-prone (e.g. if a new module shows up). The USE_*
# modules provide a way to do automatic selection. To pick exactly
# one of the implementations from group <foo>, set USE_<foo> to the
# name of the implementation. If USE_<foo> is unset, or empty, then
# all the implementations are enabled (this just means they are
# **available** to `settings.conf`, not that they are used).
#
# Currently, no USE_<foo> variables exist.
set( USE_services "" CACHE STRING "Select the services module to use" )
### Calamares application info
#
@ -54,10 +74,9 @@ set( CALAMARES_DESCRIPTION_SUMMARY
set( CALAMARES_VERSION_MAJOR 3 )
set( CALAMARES_VERSION_MINOR 2 )
set( CALAMARES_VERSION_PATCH 1 )
set( CALAMARES_VERSION_PATCH 2 )
set( CALAMARES_VERSION_RC 0 )
### Transifex (languages) info
#
# complete = 100% translated,
@ -377,6 +396,15 @@ if( NOT BUILD_RELEASE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git/" )
endif()
endif()
# Special target for not-RC (e.g. might-be-release) builds.
# This is used by the release script to get the version.
if ( CALAMARES_VERSION_RC EQUAL 0 )
add_custom_target(show-version
${CMAKE_COMMAND} -E echo CALAMARES_VERSION=${CALAMARES_VERSION_SHORT}
USES_TERMINAL
)
endif()
# enforce using constBegin, constEnd for const-iterators
add_definitions( "-DQT_STRICT_ITERATORS" )

View File

@ -85,9 +85,11 @@ function( calamares_add_module_subdirectory )
configure_file( ${SUBDIRECTORY}/${MODULE_FILE} ${SUBDIRECTORY}/${MODULE_FILE} COPYONLY )
get_filename_component( FLEXT ${MODULE_FILE} EXT )
if( "${FLEXT}" STREQUAL ".conf" AND INSTALL_CONFIG)
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
DESTINATION ${MODULE_DATA_DESTINATION} )
if( "${FLEXT}" STREQUAL ".conf" )
if( INSTALL_CONFIG )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
DESTINATION ${MODULE_DATA_DESTINATION} )
endif()
list( APPEND MODULE_CONFIG_FILES ${MODULE_FILE} )
else()
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
@ -102,10 +104,11 @@ function( calamares_add_module_subdirectory )
message( " ${Green}MODULE_DESTINATION:${ColorReset} ${MODULE_DESTINATION}" )
if( MODULE_CONFIG_FILES )
if ( INSTALL_CONFIG )
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => ${MODULE_DATA_DESTINATION}" )
set( _destination "${MODULE_DATA_DESTINATION}" )
else()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => [Skipping installation]" )
set( _destination "[Build directory only]" )
endif()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => ${_destination}" )
endif()
message( "" )
endif()

View File

@ -66,17 +66,18 @@ function( calamares_add_plugin )
message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" )
message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" )
message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
# message( " ${Green}SOURCES:${ColorReset} ${PLUGIN_SOURCES}" )
# message( " ${Green}UI:${ColorReset} ${PLUGIN_UI}" )
# message( " ${Green}EXPORT_MACRO:${ColorReset} ${PLUGIN_EXPORT_MACRO}" )
# message( " ${Green}NO_INSTALL:${ColorReset} ${PLUGIN_NO_INSTALL}" )
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
if( PLUGIN_CONFIG_FILES )
set( _destination "(unknown)" )
if ( INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL )
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${PLUGIN_DATA_DESTINATION}" )
set( _destination "${PLUGIN_DATA_DESTINATION}" )
elseif( NOT PLUGIN_NO_INSTALL )
# Not INSTALL_CONFIG
set( _destination "[Build directory only]" )
else()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => [Skipping installation]" )
set( _destination "[Skipping installation]" )
endif()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${_destination}" )
endif()
if( PLUGIN_RESOURCES )
message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" )
@ -147,12 +148,13 @@ function( calamares_add_plugin )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
DESTINATION ${PLUGIN_DESTINATION} )
if ( INSTALL_CONFIG )
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE}
DESTINATION ${PLUGIN_DATA_DESTINATION} )
endforeach()
endif()
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
if ( INSTALL_CONFIG )
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE}
DESTINATION ${PLUGIN_DATA_DESTINATION} )
endif()
endforeach()
endif()
endfunction()

View File

@ -2,6 +2,9 @@
#
# Sets PYTHONQT_FOUND, PYTHONQT_INCLUDE_DIR, PYTHONQT_LIBRARY, PYTHONQT_LIBRARIES
#
# Also sets PYTHONQT_INCLUDE_DIRS to add whatever directories
# that are needed for extensions.
#
# Python is required
find_package(PythonLibs)
@ -24,22 +27,38 @@ string(REGEX REPLACE
)
if(NOT EXISTS "${PYTHONQT_INSTALL_DIR}")
find_path(PYTHONQT_INSTALL_DIR include/PythonQt/PythonQt.h DOC "Directory where PythonQt was installed.")
find_path(PYTHONQT_INSTALL_DIR
NAMES
include/PythonQt/PythonQt.h
include/PythonQt5/PythonQt.h
DOC "Directory where PythonQt was installed.")
endif()
# XXX Since PythonQt 3.0 is not yet cmakeified, depending
# on how PythonQt is built, headers will not always be
# installed in "include/PythonQt". That is why "src"
# is added as an option. See [1] for more details.
# [1] https://github.com/commontk/CTK/pull/538#issuecomment-86106367
find_path(PYTHONQT_INCLUDE_DIR PythonQt.h
PATHS "${PYTHONQT_INSTALL_DIR}/include/PythonQt"
PATHS
"${PYTHONQT_INSTALL_DIR}/include/PythonQt"
"${PYTHONQT_INSTALL_DIR}/include/PythonQt5"
"${PYTHONQT_INSTALL_DIR}/src"
DOC "Path to the PythonQt include directory")
DOC "Path to the PythonQt include directory")
find_path(PYTHONQT_ALL_INCLUDE_DIR PythonQt_QtAll.h
PATHS
"${PYTHONQT_INCLUDE_DIR}"
"${PYTHONQT_INSTALL_DIR}"
PATH_SUFFIXES
"extensions/PythonQt_QtAll"
"src"
DOC "Path to the PythonQt 'all' header")
if ( NOT PythonQt_FIND_QUIETLY )
message( STATUS "Searching for PythonQt (PythonLibs ${PYTHONLIBS_MAJMIN}) .." )
if ( PYTHONQT_INCLUDE_DIR )
message( STATUS " .. found include ${PYTHONQT_INCLUDE_DIR}" )
message( STATUS " .. found all include ${PYTHONQT_ALL_INCLUDE_DIR}" )
endif()
endif()
@ -139,6 +158,10 @@ if(PYTHONQT_INCLUDE_DIR AND PYTHONQT_LIBRARY AND PYTHONQT_QTALL_LIBRARY)
set(PYTHONQT_FOUND 1)
set(PythonQt_FOUND ${PYTHONQT_FOUND})
set(PYTHONQT_LIBRARIES ${PYTHONQT_LIBRARY} ${PYTHONQT_LIBUTIL} ${PYTHONQT_QTALL_LIBRARY})
set(PYTHONQT_INCLUDE_DIRS ${PYTHONQT_INCLUDE_DIR})
if(PYTHONQT_ALL_INCLUDE_DIR)
list(APPEND PYTHONQT_INCLUDE_DIRS ${PYTHONQT_ALL_INCLUDE_DIR})
endif()
elseif(NOT PythonQt_FIND_QUIETLY)
set(_missing "")
if (NOT PYTHONQT_INCLUDE_DIR)

View File

@ -57,9 +57,10 @@ GenericName[fr]=Installateur système
Comment[fr]=Calamares - Installateur système
Name[fr]=Installer le système
Name[gl]=Instalación do Sistema
Icon[he]=קלמארס
Icon[he]=calamares
GenericName[he]=אשף התקנה
Comment[he]=קלמארס - אשף התקנה
Comment[he]=Calamares - אשף התקנה
Name[he]=התקנת מערכת
Icon[hi]=calamares
GenericName[hi]=ि
Comment[hi]=Calamares ि
@ -144,6 +145,8 @@ GenericName[sv]=Systeminstallerare
Comment[sv]=Calamares Systeminstallerare
Name[sv]=Installera system
Name[th]=
GenericName[uk]=Встановлювач системи
Comment[uk]=Calamares - Встановлювач системи
Name[uk]=Встановити Систему
Icon[zh_CN]=calamares
GenericName[zh_CN]=

93
ci/RELEASE.sh Normal file
View File

@ -0,0 +1,93 @@
#! /bin/sh
#
# Release script for Calamares
#
# This attempts to perform the different steps of the RELEASE.md
# document automatically. It's not tested on other machines or
# setups other than [ade]'s development VM.
#
# Assumes that the version in CMakeLists.txt has been bumped,
# and that a release of that version is desired.
#
# None of the "update stuff" is done by this script; in preparation
# for the release, you should have already done:
# - updating the version
# - pulling translations
# - updating the language list
# - switching to the right branch
test -d .git || { echo "Not at top-level." ; exit 1 ; }
test -d src/modules || { echo "No src/modules." ; exit 1 ; }
which cmake > /dev/null 2>&1 || { echo "No cmake(1) available." ; exit 1 ; }
### Build with default compiler
#
#
BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.)
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR" || { echo "Could not create build directory." ; exit 1 ; }
( cd "$BUILDDIR" && cmake .. && make -j4 ) || { echo "Could not perform test-build." ; exit 1 ; }
( cd "$BUILDDIR" && make test ) || { echo "Tests failed." ; exit 1 ; }
### Build with clang
#
#
if which clang++ > /dev/null 2>&1 ; then
# Do build again with clang
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR" || { echo "Could not create build directory." ; exit 1 ; }
( cd "$BUILDDIR" && CC=clang CXX=clang++ cmake .. && make -j4 ) || { echo "Could not perform test-build." ; exit 1 ; }
( cd "$BUILDDIR" && make test ) || { echo "Tests failed." ; exit 1 ; }
fi
### Get version number for this release
#
#
V=$( cd "$BUILDDIR" && make show-version | grep ^CALAMARES_VERSION | sed s/^[A-Z_]*=// )
test -n "$V" || { echo "Could not obtain version." ; exit 1 ; }
### Create signed tag
#
# This is the signing key ID associated with the GitHub account adriaandegroot,
# which is used to create all "verified" tags in the Calamares repo.
KEY_ID="128F00873E05AF1D"
git tag -u "$KEY_ID" -m "Release v$V" "v$V" || { echo "Could not sign tag v$V." ; exit 1 ; }
### Create the tarball
#
#
TAR_V="calamares-$V"
TAR_FILE="$TAR_V.tar.gz"
git archive -o "$TAR_FILE" --prefix "$TAR_V/" "v$V" || { echo "Could not create tarball." ; exit 1 ; }
test -f "$TAR_FILE" || { echo "Tarball was not created." ; exit 1 ; }
SHA256=$(sha256sum "$TAR_FILE" | cut -d" " -f1)
### Build the tarball
#
#
D=$(date +%Y%m%d-%H%M%S)
TMPDIR=$(mktemp -d --suffix="-calamares-$D")
test -d "$TMPDIR" || { echo "Could not create tarball-build directory." ; exit 1 ; }
tar xzf "$TAR_FILE" -C "$TMPDIR" || { echo "Could not unpack tarball." ; exit 1 ; }
test -d "$TMPDIR/$TAR_V" || { echo "Tarball did not contain source directory." ; exit 1 ; }
( cd "$TMPDIR/$TAR_V" && cmake . && make -j4 && make test ) || { echo "Tarball build failed." ; exit 1 ; }
### Cleanup
#
rm -rf "$BUILDDIR" # From test-builds
rm -rf "$TMPDIR" # From tarball
### Print subsequent instructions
#
#
cat <<EOF
# Next steps for this release:
git push --tags
gpg -s -u $KEY_ID --detach --armor $TAR_FILE # Sign the tarball
# Upload tarball $TAR_FILE and the signature $TAR_FILE.asc
# Announce via https://github.com/calamares/calamares/releases/new
# SHA256: $SHA256
EOF
exit 0

12
ci/travis-config.sh Normal file
View File

@ -0,0 +1,12 @@
# Build configuration on Travis.
#
# Defines a CMAKE_ARGS variable for use with cmake
#
# This file is sourced by travis.sh, and exports the variables
# to the environment.
CMAKE_ARGS="\
-DWEBVIEW_FORCE_WEBKIT=1 \
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON \
-DWITH_PYTHONQT=OFF"
export CMAKE_ARGS

View File

@ -3,13 +3,34 @@
# Travis CI script for use on every-commit:
# - build and install Calamares
#
test -n "$BUILDDIR" || exit 1
test -n "$SRCDIR" || exit 1
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
test -n "$SRCDIR" || { echo "! \$SRCDIR not set" ; exit 1 ; }
test -d $BUILDDIR || exit 1
test -d $SRCDIR || exit 1
test -f $SRCDIR/CMakeLists.txt || exit 1
test -d $BUILDDIR || { echo "! $BUILDDIR not a directory" ; exit 1 ; }
test -d $SRCDIR || { echo "! $SRCDIR not a directory" ; exit 1 ; }
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
cd $BUILDDIR || exit 1
cmake -DWEBVIEW_FORCE_WEBKIT=1 -DKDE_INSTALL_USE_QT_SYS_PATHS=ON $SRCDIR && make -j2 && make install DESTDIR=/build/INSTALL_ROOT
echo "###"
echo "### cmake $CMAKE_ARGS $SRCDIR"
echo "###"
cmake $CMAKE_ARGS $SRCDIR || { echo "! CMake failed" ; exit 1 ; }
echo -e "###\n### make\n###"
make -j2 || { make -j1 VERBOSE=1 ; echo "! Make failed" ; exit 1 ; }
echo -e "###\n### make install\n###"
echo "# Build results"
find "$BUILDDIR" -name '*.so'
echo "# Install"
DESTDIR=/build/INSTALL_ROOT
mkdir -p "$DESTDIR"
result=true
make install VERBOSE=1 DESTDIR="$DESTDIR" || result=false
echo "# Install results"
find "$DESTDIR" -type f
$result # Result of make install, above

View File

@ -3,13 +3,13 @@
# Travis CI script for weekly (cron) use:
# - use the coverity tool to build and and upload results
#
test -n "$COVERITY_SCAN_TOKEN" || exit 1
test -n "$BUILDDIR" || exit 1
test -n "$SRCDIR" || exit 1
test -n "$COVERITY_SCAN_TOKEN" || { echo "! Missing Coverity token" ; exit 1 ; }
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
test -n "$SRCDIR" || { echo "! \$SRCDIR not set" ; exit 1 ; }
test -d $BUILDDIR || exit 1
test -d $SRCDIR || exit 1
test -f $SRCDIR/CMakeLists.txt || exit 1
test -d $BUILDDIR || { echo "! $BUILDDIR not a directory" ; exit 1 ; }
test -d $SRCDIR || { echo "! $SRCDIR not a directory" ; exit 1 ; }
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
cd $BUILDDIR || exit 1
@ -20,8 +20,8 @@ mkdir "$BUILDDIR/coveritytool"
tar xvf coverity_tool.tar.gz -C "$BUILDDIR/coveritytool" --strip-components 2
export PATH="$BUILDDIR/coveritytool/bin:$PATH"
cmake -DCMAKE_BUILD_TYPE=Debug -DWEBVIEW_FORCE_WEBKIT=1 -DKDE_INSTALL_USE_QT_SYS_PATHS=ON $SRCDIR || exit 1
echo "# cmake -DCMAKE_BUILD_TYPE=Debug $CMAKE_ARGS $SRCDIR"
cmake -DCMAKE_BUILD_TYPE=Debug $CMAKE_ARGS $SRCDIR || exit 1
cov-build --dir cov-int make -j2
tar caf calamares-ci.tar.xz cov-int

View File

@ -8,9 +8,11 @@
# intensive than the coverity add-on, but works on master.
#
D=`dirname "$0"`
test -d "$D" || exit 1
test -x "$D/travis-continuous.sh" || exit 1
test -x "$D/travis-coverity.sh" || exit 1
test -d "$D" || { echo "! No directory $D" ; exit 1 ; }
test -x "$D/travis-continuous.sh" || { echo "! Missing -continuous" ; exit 1 ; }
test -x "$D/travis-coverity.sh" || { echo "! Missing -coverity" ; exit 1 ; }
test -f "$D/travis-config.sh" && . "$D/travis-config.sh"
if test "$TRAVIS_EVENT_TYPE" = "cron" ; then
exec "$D/travis-coverity.sh"

View File

@ -579,7 +579,7 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="72"/>
<source>En&amp;crypt</source>
<translation>&amp;Xifra</translation>
<translation>En&amp;cripta</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="151"/>
@ -788,7 +788,7 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/dracutlukscfg/DracutLuksCfgJob.cpp" line="133"/>
<source>Skip writing LUKS configuration for Dracut: &quot;/&quot; partition is not encrypted</source>
<translation>Omet l&apos;escriptura de la configuració de LUKS per a Dracut: la partició &quot;/&quot; no està xifrada</translation>
<translation>Omet l&apos;escriptura de la configuració de LUKS per a Dracut: la partició &quot;/&quot; no està encriptada</translation>
</message>
<message>
<location filename="../src/modules/dracutlukscfg/DracutLuksCfgJob.cpp" line="149"/>
@ -872,7 +872,7 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/partition/gui/EncryptWidget.ui" line="32"/>
<source>En&amp;crypt system</source>
<translation>&amp;Xifra el sistema</translation>
<translation>En&amp;cripta el sistema</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/EncryptWidget.ui" line="42"/>
@ -948,7 +948,7 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="51"/>
<source>&lt;h1&gt;All done.&lt;/h1&gt;&lt;br/&gt;%1 has been installed on your computer.&lt;br/&gt;You may now restart into your new system, or continue using the %2 Live environment.</source>
<translation>&lt;h1&gt;Tot fet.&lt;/h1&gt;&lt;br/&gt;%1 s&apos;ha instal·lat al vostre ordinador.&lt;br/&gt;Ara podeu reiniciar-lo per tal d&apos;accedir al sistema operatiu nou o continuar utilitzant l&apos;entorn autònom de %2.</translation>
<translation>&lt;h1&gt;Tot fet.&lt;/h1&gt;&lt;br/&gt;%1 s&apos;ha instal·lat a l&apos;ordinador.&lt;br/&gt;Ara podeu reiniciar-lo per tal d&apos;accedir al sistema operatiu nou o continuar utilitzant l&apos;entorn autònom de %2.</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="109"/>
@ -1786,12 +1786,12 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/partition/gui/PartitionViewStep.cpp" line="450"/>
<source>Boot partition not encrypted</source>
<translation>Partició d&apos;arrencada sense xifrar</translation>
<translation>Partició d&apos;arrencada sense encriptar</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionViewStep.cpp" line="451"/>
<source>A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.&lt;br/&gt;&lt;br/&gt;There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.&lt;br/&gt;You may continue if you wish, but filesystem unlocking will happen later during system startup.&lt;br/&gt;To encrypt the boot partition, go back and recreate it, selecting &lt;strong&gt;Encrypt&lt;/strong&gt; in the partition creation window.</source>
<translation>S&apos;ha establert una partició d&apos;arrencada separada conjuntament amb una partició d&apos;arrel encriptada, però la partició d&apos;arrencada no està encriptada.&lt;br/&gt;&lt;br/&gt;Hi ha aspectes de seguretat amb aquest tipus de configuració, perquè hi ha fitxers del sistema importants en una partició no encriptada.&lt;br/&gt;Podeu continuar, si així ho desitgeu, però el desbloqueig del sistema de fitxers succeirà després, durant l&apos;inici del sistema.&lt;br/&gt;Per encriptar la partició d&apos;arrencada, torneu enrere i torneu-la a crear seleccionant &lt;strong&gt;Encripta&lt;/strong&gt; a la finestra de creació de la partició.</translation>
<translation>S&apos;ha establert una partició d&apos;arrencada separada conjuntament amb una partició d&apos;arrel encriptada, però la partició d&apos;arrencada no està encriptada.&lt;br/&gt;&lt;br/&gt;Hi ha assumptes de seguretat amb aquest tipus de configuració, perquè hi ha fitxers del sistema importants en una partició no encriptada.&lt;br/&gt;Podeu continuar, si així ho desitgeu, però el desbloqueig del sistema de fitxers succeirà després, durant l&apos;inici del sistema.&lt;br/&gt;Per encriptar la partició d&apos;arrencada, torneu enrere i torneu-la a crear seleccionant &lt;strong&gt;Encripta&lt;/strong&gt; a la finestra de creació de la partició.</translation>
</message>
</context>
<context>
@ -1839,7 +1839,7 @@ L&apos;instal·lador es tancarà i tots els canvis es perdran.</translation>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation>Desament dels fitxers per a més tard...</translation>
<translation>Desament de fitxers per a més tard...</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
@ -2292,12 +2292,12 @@ Sortida:
<message>
<location filename="../src/modules/users/SetPasswordJob.cpp" line="113"/>
<source>rootMountPoint is %1</source>
<translation>El punt de muntatge d&apos;arrel és %1</translation>
<translation>El punt de muntatge de l&apos;arrel és %1</translation>
</message>
<message>
<location filename="../src/modules/users/SetPasswordJob.cpp" line="123"/>
<source>Cannot disable root account.</source>
<translation>No es pot inhabilitar el compte de root.</translation>
<translation>No es pot inhabilitar el compte d&apos;arrel.</translation>
</message>
<message>
<location filename="../src/modules/users/SetPasswordJob.cpp" line="124"/>
@ -2528,7 +2528,7 @@ Sortida:
<message>
<location filename="../src/modules/users/UsersPage.cpp" line="345"/>
<source>Your hostname contains invalid characters. Only letters, numbers and dashes are allowed.</source>
<translation>El nom d&apos;amfitrió conté caràcters no vàlids. Només s&apos;admeten lletres, números i guions.</translation>
<translation>El nom d&apos;amfitrió conté caràcters no vàlids. Només s&apos;hi admeten lletres, números i guions.</translation>
</message>
<message>
<location filename="../src/modules/users/UsersPage.cpp" line="373"/>
@ -2585,7 +2585,7 @@ Sortida:
<message>
<location filename="../src/modules/welcome/WelcomePage.cpp" line="60"/>
<source>&lt;h1&gt;Welcome to the Calamares installer for %1.&lt;/h1&gt;</source>
<translation>&lt;h1&gt;Benvingut a l&apos;instal·lador Calamares per a %1.&lt;/h1&gt;</translation>
<translation>&lt;h1&gt;Us donem la benvinguda a l&apos;instal·lador Calamares per a %1.&lt;/h1&gt;</translation>
</message>
<message>
<location filename="../src/modules/welcome/WelcomePage.cpp" line="73"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Κενή Σελίδα</translation>
</message>
</context>
<context>
@ -192,7 +192,7 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Η αρχικοποίηση του Calamares απέτυχε</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
@ -207,7 +207,7 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
<source>&amp;Install</source>
<translation type="unfinished"/>
<translation>&amp;Εγκατάσταση</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="325"/>
@ -249,17 +249,17 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="243"/>
<source>&amp;Install now</source>
<translation>Ε&amp;γκατάσταση τώρα</translation>
<translation>&amp;Εγκατάσταση τώρα</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="244"/>
<source>Go &amp;back</source>
<translation>Μετάβαση πί&amp;σω</translation>
<translation>Μετάβαση &amp;πίσω</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="283"/>
<source>&amp;Done</source>
<translation type="unfinished"/>
<translation>&amp;Ολοκληρώθηκε</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="284"/>
@ -2087,7 +2087,7 @@ Output:
<message>
<location filename="../src/modules/welcome/checker/RequirementsChecker.cpp" line="163"/>
<source>The screen is too small to display the installer.</source>
<translation type="unfinished"/>
<translation>Η οθόνη είναι πολύ μικρή για να απεικονίσει το πρόγραμμα εγκατάστασης</translation>
</message>
</context>
<context>
@ -2173,17 +2173,17 @@ Output:
<location filename="../src/modules/keyboard/SetKeyboardLayoutJob.cpp" line="323"/>
<location filename="../src/modules/keyboard/SetKeyboardLayoutJob.cpp" line="329"/>
<source>Failed to write to %1</source>
<translation type="unfinished"/>
<translation>Αδυναμία εγγραφής στο %1</translation>
</message>
<message>
<location filename="../src/modules/keyboard/SetKeyboardLayoutJob.cpp" line="322"/>
<source>Failed to write keyboard configuration for X11.</source>
<translation type="unfinished"/>
<translation>Αδυναμία εγγραφής στοιχείων διαμόρφωσης πληκτρολογίου για Χ11</translation>
</message>
<message>
<location filename="../src/modules/keyboard/SetKeyboardLayoutJob.cpp" line="328"/>
<source>Failed to write keyboard configuration to existing /etc/default directory.</source>
<translation type="unfinished"/>
<translation>Αδυναμία εγγραφής στοιχείων διαμόρφωσης πληκτρολογίου στον υπάρχων κατάλογο /etc/default</translation>
</message>
</context>
<context>

View File

@ -51,7 +51,7 @@ Para configurar el arranque desde un entorno BIOS, este instalador debe instalar
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Página Blanca</translation>
</message>
</context>
<context>
@ -193,22 +193,22 @@ Para configurar el arranque desde un entorno BIOS, este instalador debe instalar
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>La inicialización de Calamares falló</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 no se pudo instalar. Calamares no fue capaz de cargar todos los módulos configurados. Esto es un problema con la forma en que Calamares es usado por la distribución</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>Los siguientes módulos no se pudieron cargar:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
<source>&amp;Install</source>
<translation type="unfinished"/>
<translation>&amp;Instalar</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="325"/>
@ -509,12 +509,12 @@ Saldrá del instalador y se perderán todos los cambios.</translation>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="128"/>
<source>The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined.</source>
<translation type="unfinished"/>
<translation>El comando corre en el ambiente anfitrión y necesita saber el directorio raiz, pero no está definido el punto de montaje de la raiz</translation>
</message>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/>
<source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/>
<translation>El comando necesita saber el nombre de usuario, pero no hay nombre de usuario definido.</translation>
</message>
</context>
<context>
@ -1664,7 +1664,7 @@ Saldrá del instalador y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Cre&amp;ar</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>
@ -1689,12 +1689,12 @@ Saldrá del instalador y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="195"/>
<source>Can not create new partition</source>
<translation type="unfinished"/>
<translation>No se puede crear una partición nueva</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/>
<source>The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead.</source>
<translation type="unfinished"/>
<translation>La tabla de particiones en %1 tiene %2 particiones primarias y no se pueden agregar más. Por favor remueva una partición primaria y agregue una partición extendida en su reemplazo.</translation>
</message>
</context>
<context>
@ -1824,7 +1824,7 @@ Saldrá del instalador y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/plasmalnf/PlasmaLnfPage.cpp" line="67"/>
<source>Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is installed. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel.</source>
<translation type="unfinished"/>
<translation>Elija una apariencia para KDE Plasma Desktop. También puede omitir este paso y configurar el aspecto una vez que el sistema está instalado. Al hacer clic en una selección de apariencia, obtendrá una vista previa en vivo de esa apariencia.</translation>
</message>
</context>
<context>
@ -1840,17 +1840,17 @@ Saldrá del instalador y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation type="unfinished"/>
<translation>Guardando archivos para después ...</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
<source>No files configured to save for later.</source>
<translation type="unfinished"/>
<translation>No hay archivos configurados para guardarlos para después.</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/>
<source>Not all of the configured files could be preserved.</source>
<translation type="unfinished"/>
<translation>No todos los archivos de configuración se pudieron preservar.</translation>
</message>
</context>
<context>
@ -2368,7 +2368,7 @@ Salida:
<location filename="../src/qml/calamares/slideshow/SlideCounter.qml" line="36"/>
<source>%L1 / %L2</source>
<extracomment>slide counter, %1 of %2 (numeric)</extracomment>
<translation type="unfinished"/>
<translation>%L1 / %L2</translation>
</message>
</context>
<context>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Página en blanco</translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>La inicialización de Calamares ha fallado</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 no pudo ser instalado. Calamares no pudo cargar todos los módulos configurados. Este es un problema con la forma en que Calamares esta siendo usada por la distribución.</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;Los siguientes módulos no pudieron ser cargados:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -1664,7 +1664,7 @@ El instalador terminará y se perderán todos los cambios.</translation>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Cre&amp;ar</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Auð síða</translation>
</message>
</context>
<context>
@ -356,7 +356,7 @@ Uppsetningarforritið mun hætta og allar breytingar tapast.</translation>
<message>
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="235"/>
<source>&lt;strong&gt;Manual partitioning&lt;/strong&gt;&lt;br/&gt;You can create or resize partitions yourself.</source>
<translation>&lt;strong&gt;Handvirk disksneiðing&lt;/strong&gt;&lt;br/&gt;Þú getur búið til eða breytt stærð disksneiða sjálf(ur).</translation>
<translation>&lt;strong&gt;Handvirk disksneiðing&lt;/strong&gt;&lt;br/&gt;Þú getur búið til eða breytt stærð disksneiða sjálft.</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="998"/>
@ -1469,7 +1469,7 @@ Uppsetningarforritið mun hætta og allar breytingar tapast.</translation>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="267"/>
<source>Unknown error</source>
<translation type="unfinished"/>
<translation>Óþekkt villa</translation>
</message>
</context>
<context>
@ -2582,7 +2582,7 @@ Output:
<message>
<location filename="../src/modules/welcome/WelcomePage.cpp" line="60"/>
<source>&lt;h1&gt;Welcome to the Calamares installer for %1.&lt;/h1&gt;</source>
<translation>&lt;h1&gt;Velkomin(n) til Calamares uppsetningar fyrir %1&lt;/h1&gt;</translation>
<translation>&lt;h1&gt;Velkomin til Calamares uppsetningar fyrir %1&lt;/h1&gt;</translation>
</message>
<message>
<location filename="../src/modules/welcome/WelcomePage.cpp" line="73"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Pagina Vuota</translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Inizializzazione di Calamares Fallita</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 non può essere installato. Calamares non è stato in grado di caricare tutti i moduli configurati. Questo è un problema del modo in cui Calamares viene utilizzato dalla distribuzione.</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;Non è stato possibile caricare il seguente modulo:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -1663,7 +1663,7 @@ Il programma d&apos;installazione sarà terminato e tutte le modifiche andranno
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Crea</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Calamares </translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 Calamares Calamares 使</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -508,12 +508,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="128"/>
<source>The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined.</source>
<translation type="unfinished"/>
<translation>rootのパスの情報が必要になりますがroot </translation>
</message>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/>
<source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>
@ -1664,7 +1664,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>&amp;a</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>
@ -1689,12 +1689,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="195"/>
<source>Can not create new partition</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/>
<source>The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead.</source>
<translation type="unfinished"/>
<translation>%1 %2 </translation>
</message>
</context>
<context>
@ -1840,17 +1840,17 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation type="unfinished"/>
<translation>...</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
<source>No files configured to save for later.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/>
<source>Not all of the configured files could be preserved.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>

View File

@ -4,17 +4,17 @@
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="69"/>
<source>The &lt;strong&gt;boot environment&lt;/strong&gt; of this system.&lt;br&gt;&lt;br&gt;Older x86 systems only support &lt;strong&gt;BIOS&lt;/strong&gt;.&lt;br&gt;Modern systems usually use &lt;strong&gt;EFI&lt;/strong&gt;, but may also show up as BIOS if started in compatibility mode.</source>
<translation type="unfinished"/>
<translation> &lt;strong&gt; &lt;/strong&gt;. &lt;br&gt; &lt;br&gt; x86 &lt;strong&gt;BIOS&lt;/strong&gt; . &lt;br&gt; &lt;strong&gt;EFI&lt;/strong&gt;() , BIOS .</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="79"/>
<source>This system was started with an &lt;strong&gt;EFI&lt;/strong&gt; boot environment.&lt;br&gt;&lt;br&gt;To configure startup from an EFI environment, this installer must deploy a boot loader application, like &lt;strong&gt;GRUB&lt;/strong&gt; or &lt;strong&gt;systemd-boot&lt;/strong&gt; on an &lt;strong&gt;EFI System Partition&lt;/strong&gt;. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own.</source>
<translation type="unfinished"/>
<translation> &lt;strong&gt;EFI&lt;/strong&gt; . &lt;br&gt; &lt;br&gt; EFI , &lt;strong&gt;EFI &lt;/strong&gt; &lt;strong&gt;GRUB&lt;/strong&gt; &lt;strong&gt;systemd-boot&lt;/strong&gt; . . , , EFI .</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="91"/>
<source>This system was started with a &lt;strong&gt;BIOS&lt;/strong&gt; boot environment.&lt;br&gt;&lt;br&gt;To configure startup from a BIOS environment, this installer must install a boot loader, like &lt;strong&gt;GRUB&lt;/strong&gt;, either at the beginning of a partition or on the &lt;strong&gt;Master Boot Record&lt;/strong&gt; near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own.</source>
<translation type="unfinished"/>
<translation> &lt;strong&gt;BIOS &lt;/strong&gt; . &lt;br&gt; &lt;br&gt; BIOS , () &lt;strong&gt; &lt;/strong&gt; &lt;strong&gt;GRUB&lt;/strong&gt; . . , , .</translation>
</message>
</context>
<context>
@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation> </translation>
</message>
</context>
<context>
@ -58,7 +58,7 @@
<message>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="24"/>
@ -84,7 +84,7 @@
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="64"/>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="78"/>
<source>none</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="71"/>
@ -123,12 +123,12 @@
<message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="52"/>
<source>Run command %1 %2</source>
<translation type="unfinished"/>
<translation> %1 %2 </translation>
</message>
<message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="61"/>
<source>Running command %1 %2</source>
<translation type="unfinished"/>
<translation> %1 %2 </translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Calamares </translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 () . Calamares가 . Calamares가 .</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation> :</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -244,7 +244,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="238"/>
<source>The %1 installer is about to make changes to your disk in order to install %2.&lt;br/&gt;&lt;strong&gt;You will not be able to undo these changes.&lt;/strong&gt;</source>
<translation type="unfinished"/>
<translation>%1 %2 . &lt;br/&gt; &lt;strong&gt; .&lt;/strong&gt;</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="243"/>
@ -346,7 +346,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/ChoicePage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/ChoicePage.cpp" line="128"/>
@ -867,7 +867,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/EncryptWidget.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/EncryptWidget.ui" line="32"/>
@ -933,7 +933,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="95"/>
@ -1072,7 +1072,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/license/LicensePage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/license/LicensePage.cpp" line="89"/>
@ -1477,7 +1477,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/keyboard/KeyboardPage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/keyboard/KeyboardPage.ui" line="70"/>
@ -1495,7 +1495,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/page_usersetup.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/users/page_usersetup.ui" line="36"/>
@ -1643,7 +1643,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="22"/>
@ -1813,7 +1813,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/plasmalnf/page_plasmalnf.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/plasmalnf/page_plasmalnf.ui" line="20"/>
@ -1965,7 +1965,7 @@ Output:
<message>
<location filename="../src/modules/partition/gui/ReplaceWidget.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/ReplaceWidget.cpp" line="134"/>
@ -2443,7 +2443,7 @@ Output:
<message>
<location filename="../src/modules/tracking/page_trackingstep.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/tracking/page_trackingstep.ui" line="24"/>
@ -2550,7 +2550,7 @@ Output:
<message>
<location filename="../src/modules/welcome/WelcomePage.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/welcome/WelcomePage.ui" line="75"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Pusta strona</translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Błąd inicjacji programu Calamares</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 nie może zostać zainstalowany. Calamares nie mógł wczytać wszystkich skonfigurowanych modułów. Jest to problem ze sposobem, w jaki Calamares jest używany przez dystrybucję.</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;Następujące moduły nie mogły zostać wczytane:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -1663,7 +1663,7 @@ Instalator zostanie zamknięty i wszystkie zmiany zostaną utracone.</translatio
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Ut_wórz</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Página em Branco</translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Falha na inicialização do Calamares</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>%1 não pôde ser instalado. O Calamares não conseguiu carregar todos os módulos configurados. Este é um problema com o modo em que o Calamares está sendo utilizado pela distribuição.</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;Os seguintes módulos não puderam ser carregados:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -259,7 +259,7 @@ O instalador será fechado e todas as alterações serão perdidas.</translation
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="283"/>
<source>&amp;Done</source>
<translation>Completa&amp;do</translation>
<translation>Concluí&amp;do</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="284"/>
@ -318,14 +318,12 @@ O instalador será fechado e todas as alterações serão perdidas.</translation
<message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="96"/>
<source>This computer does not satisfy the minimum requirements for installing %1.&lt;br/&gt;Installation cannot continue. &lt;a href=&quot;#details&quot;&gt;Details...&lt;/a&gt;</source>
<translation>Este computador não satisfaz os requisitos mínimos para instalar %1.
A instalação não pode continuar.&lt;a href=&quot;#details&quot;&gt;Detalhes...&lt;/a&gt;</translation>
<translation>Este computador não satisfaz os requisitos mínimos para instalar %1.&lt;br/&gt;A instalação não pode continuar. &lt;a href=&quot;#details&quot;&gt;Detalhes...&lt;/a&gt;</translation>
</message>
<message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="113"/>
<source>This computer does not satisfy some of the recommended requirements for installing %1.&lt;br/&gt;Installation can continue, but some features might be disabled.</source>
<translation>Este computador não satisfaz alguns dos requisitos recomendados para instalar %1.
A instalação pode continuar, mas alguns recursos podem ser desativados.</translation>
<translation>Este computador não satisfaz alguns dos requisitos recomendados para instalar %1.&lt;br/&gt;A instalação pode continuar, mas alguns recursos podem ser desativados.</translation>
</message>
<message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="151"/>
@ -515,7 +513,7 @@ A instalação pode continuar, mas alguns recursos podem ser desativados.</trans
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/>
<source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/>
<translation>O comando precisa saber do nome do usuário, mas nenhum nome de usuário foi definido.</translation>
</message>
</context>
<context>
@ -912,7 +910,7 @@ A instalação pode continuar, mas alguns recursos podem ser desativados.</trans
<message>
<location filename="../src/modules/partition/jobs/FillGlobalStorageJob.cpp" line="159"/>
<source>Install %2 on %3 system partition &lt;strong&gt;%1&lt;/strong&gt;.</source>
<translation>Instalar %2 em partição %3 do sistema &lt;strong&gt;%1&lt;/strong&gt;.</translation>
<translation>Instalar %2 na partição %3 do sistema &lt;strong&gt;%1&lt;/strong&gt;.</translation>
</message>
<message>
<location filename="../src/modules/partition/jobs/FillGlobalStorageJob.cpp" line="164"/>
@ -1519,7 +1517,7 @@ A instalação pode continuar, mas alguns recursos podem ser desativados.</trans
<message>
<location filename="../src/modules/users/page_usersetup.ui" line="200"/>
<source>&lt;small&gt;If more than one person will use this computer, you can set up multiple accounts after installation.&lt;/small&gt;</source>
<translation>&lt;small&gt;Se mais de uma pessoa utilizará este computador, você pode definir múltiplas contas após a instalação.&lt;/small&gt;</translation>
<translation>&lt;small&gt;Se mais de uma pessoa utilizará este computador, você pode definir múltiplas contas após a instalação.&lt;/small&gt;</translation>
</message>
<message>
<location filename="../src/modules/users/page_usersetup.ui" line="335"/>
@ -1665,7 +1663,7 @@ A instalação pode continuar, mas alguns recursos podem ser desativados.</trans
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Cri&amp;ar</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>
@ -1841,17 +1839,17 @@ A instalação pode continuar, mas alguns recursos podem ser desativados.</trans
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation type="unfinished"/>
<translation>Salvando arquivos para mais tarde...</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
<source>No files configured to save for later.</source>
<translation type="unfinished"/>
<translation>Nenhum arquivo configurado para ser salvo mais tarde.</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/>
<source>Not all of the configured files could be preserved.</source>
<translation type="unfinished"/>
<translation>Nem todos os arquivos configurados puderam ser preservados.</translation>
</message>
</context>
<context>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Пустая страница</translation>
</message>
</context>
<context>
@ -192,17 +192,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Ошибка инициализации Calamares</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>Не удалось установить %1. Calamares не удалось загрузить все сконфигурированные модули. Эта проблема вызвана тем, как ваш дистрибутив использует Calamares.</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;Не удалось загрузить следующие модули:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -507,12 +507,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="128"/>
<source>The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined.</source>
<translation type="unfinished"/>
<translation>Команда выполняется в окружении установщика, и ей необходимо знать путь корневого раздела, но rootMountPoint не определено.</translation>
</message>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/>
<source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/>
<translation>Команде необходимо знать имя пользователя, но оно не задано.</translation>
</message>
</context>
<context>
@ -558,7 +558,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="151"/>
<source>LVM LV name</source>
<translation type="unfinished"/>
<translation>Имя LV LVM</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="188"/>
@ -937,7 +937,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="95"/>
<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 installer.&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;Если этот флажок установлен, ваша система будет перезагружена сразу после нажатия кнопки &lt;span style=&quot; font-style:italic;&quot;&gt;Готово&lt;/span&gt; или закрытия инсталлятора.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="98"/>
@ -952,7 +952,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="109"/>
<source>&lt;h1&gt;Installation Failed&lt;/h1&gt;&lt;br/&gt;%1 has not been installed on your computer.&lt;br/&gt;The error message was: %2.</source>
<translation type="unfinished"/>
<translation>&lt;h1&gt;Сбой установки&lt;/h1&gt;&lt;br/&gt;Не удалось установить %1 на ваш компьютер.&lt;br/&gt;Сообщение об ошибке: %2.</translation>
</message>
</context>
<context>
@ -1063,7 +1063,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/locale/LCLocaleDialog.cpp" line="67"/>
<source>&amp;OK</source>
<translation type="unfinished"/>
<translation>&amp;ОК</translation>
</message>
</context>
<context>
@ -1217,7 +1217,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/netinstall/NetInstallPage.cpp" line="96"/>
<source>Network Installation. (Disabled: Received invalid groups data)</source>
<translation type="unfinished"/>
<translation>Установка по сети. (Отключено: получены неверные сведения о группах)</translation>
</message>
</context>
<context>
@ -1248,12 +1248,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="158"/>
<source>Memory allocation error when setting &apos;%1&apos;</source>
<translation type="unfinished"/>
<translation>Ошибка выделения памяти при установке «%1»</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="162"/>
<source>Memory allocation error</source>
<translation type="unfinished"/>
<translation>Ошибка выделения памяти</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="164"/>
@ -1343,7 +1343,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="198"/>
<source>The password is just rotated old one</source>
<translation type="unfinished"/>
<translation>Новый пароль это просто перевёрнутый старый</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="201"/>
@ -1413,12 +1413,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="231"/>
<source>Unknown setting - %1</source>
<translation type="unfinished"/>
<translation>Неизвестная настройка - %1</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="235"/>
<source>Unknown setting</source>
<translation type="unfinished"/>
<translation>Неизвестная настройка</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="239"/>
@ -1428,27 +1428,27 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="243"/>
<source>Bad integer value</source>
<translation type="unfinished"/>
<translation>Недопустимое целое значение</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="247"/>
<source>Setting %1 is not of integer type</source>
<translation type="unfinished"/>
<translation>Настройка %1 не является целым числом</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="251"/>
<source>Setting is not of integer type</source>
<translation type="unfinished"/>
<translation>Настройка не является целым числом</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="255"/>
<source>Setting %1 is not of string type</source>
<translation type="unfinished"/>
<translation>Настройка %1 не является строкой</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="259"/>
<source>Setting is not of string type</source>
<translation type="unfinished"/>
<translation>Настройка не является строкой</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="261"/>
@ -1458,12 +1458,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="263"/>
<source>The configuration file is malformed</source>
<translation type="unfinished"/>
<translation>Ошибка в структуре конфигурационного файла</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="265"/>
<source>Fatal failure</source>
<translation type="unfinished"/>
<translation>Фатальный сбой</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="267"/>
@ -1662,7 +1662,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation>Со&amp;здать</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>
@ -1804,7 +1804,7 @@ The installer will quit and all changes will be lost.</source>
<location filename="../src/modules/plasmalnf/PlasmaLnfJob.cpp" line="73"/>
<location filename="../src/modules/plasmalnf/PlasmaLnfJob.cpp" line="74"/>
<source>Could not select KDE Plasma Look-and-Feel package</source>
<translation type="unfinished"/>
<translation>Не удалось выбрать пакет внешнего вида для KDE Plasma</translation>
</message>
</context>
<context>
@ -1822,7 +1822,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/plasmalnf/PlasmaLnfPage.cpp" line="67"/>
<source>Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is installed. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel.</source>
<translation type="unfinished"/>
<translation>Выберите внешний вид окружения KDE Plasma. Вы можете пропустить этот шаг, и настроить его после установки системы. Щелкните на выборе внешнего вида, чтобы увидеть, как он будет выглядеть.</translation>
</message>
</context>
<context>
@ -1830,7 +1830,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/plasmalnf/PlasmaLnfViewStep.cpp" line="68"/>
<source>Look-and-Feel</source>
<translation type="unfinished"/>
<translation>Внешний вид</translation>
</message>
</context>
<context>
@ -1906,7 +1906,7 @@ Output:
<message>
<location filename="../src/libcalamares/utils/CalamaresUtilsSystem.cpp" line="291"/>
<source>Command &lt;i&gt;%1&lt;/i&gt; failed to finish in %2 seconds.</source>
<translation type="unfinished"/>
<translation>Команда &lt;i&gt;%1&lt;/i&gt; не завершилась за %2 с.</translation>
</message>
<message>
<location filename="../src/libcalamares/utils/CalamaresUtilsSystem.cpp" line="297"/>
@ -2404,7 +2404,7 @@ Output:
<message>
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="89"/>
<source>HTTP request timed out.</source>
<translation type="unfinished"/>
<translation>Тайм-аут запроса HTTP.</translation>
</message>
</context>
<context>
@ -2428,12 +2428,12 @@ Output:
<message>
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="134"/>
<source>Could not configure machine feedback correctly, script error %1.</source>
<translation type="unfinished"/>
<translation>Не удалось настроить отзывы о компьютере, ошибка сценария %1.</translation>
</message>
<message>
<location filename="../src/modules/tracking/TrackingJobs.cpp" line="137"/>
<source>Could not configure machine feedback correctly, Calamares error %1.</source>
<translation type="unfinished"/>
<translation>Не удалось настроить отзывы о компьютере, ошибка Calamares %1.</translation>
</message>
</context>
<context>
@ -2451,7 +2451,7 @@ Output:
<message>
<location filename="../src/modules/tracking/page_trackingstep.ui" line="72"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By selecting this, you will send &lt;span style=&quot; font-weight:600;&quot;&gt;no information at all&lt;/span&gt; about your installation.&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;Если вы это выберете, то не будет отправлено &lt;span style=&quot; font-weight:600;&quot;&gt;никаких&lt;/span&gt; сведений об установке.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../src/modules/tracking/page_trackingstep.ui" line="123"/>
@ -2470,12 +2470,12 @@ Output:
<message>
<location filename="../src/modules/tracking/page_trackingstep.ui" line="271"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;placeholder&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;Click here for more information about user feedback&lt;/span&gt;&lt;/a&gt;&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;&lt;a href=&quot;placeholder&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;Щелкните здесь чтобы узнать больше об отзывах пользователей&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../src/modules/tracking/TrackingPage.cpp" line="44"/>
<source>Install tracking helps %1 to see how many users they have, what hardware they install %1 to and (with the last two options below), get continuous information about preferred applications. To see what will be sent, please click the help icon next to each area.</source>
<translation type="unfinished"/>
<translation>Отслеживание установок позволяет %1 узнать, сколько у них пользователей, на каком оборудовании устанавливается %1, и (с двумя последними опциями) постоянно получать сведения о предпочитаемых приложениях. Чтобы увидеть, что будет отправлено, щелкните по значку справки рядом с каждой областью.</translation>
</message>
<message>
<location filename="../src/modules/tracking/TrackingPage.cpp" line="45"/>
@ -2498,7 +2498,7 @@ Output:
<message>
<location filename="../src/modules/tracking/TrackingViewStep.cpp" line="59"/>
<source>Feedback</source>
<translation type="unfinished"/>
<translation>Отзывы</translation>
</message>
</context>
<context>

View File

@ -1007,7 +1007,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/interactiveterminal/InteractiveTerminalPage.cpp" line="54"/>
<source>Please install KDE Konsole and try again!</source>
<translation type="unfinished"/>
<translation>Будь ласка встановіть KDE Konsole і спробуйте знову!</translation>
</message>
<message>
<location filename="../src/modules/interactiveterminal/InteractiveTerminalPage.cpp" line="116"/>
@ -1244,7 +1244,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="151"/>
<source>Password is too weak</source>
<translation type="unfinished"/>
<translation>Пароль надто ненадійний</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="158"/>
@ -1254,12 +1254,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="162"/>
<source>Memory allocation error</source>
<translation type="unfinished"/>
<translation>Помилка виділення пам&apos;яті</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="164"/>
<source>The password is the same as the old one</source>
<translation type="unfinished"/>
<translation>Цей пароль такий же як і старий</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="166"/>
@ -1274,17 +1274,18 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="170"/>
<source>The password is too similar to the old one</source>
<translation type="unfinished"/>
<translation>Цей пароль надто схожий на попередній</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="172"/>
<source>The password contains the user name in some form</source>
<translation type="unfinished"/>
<translation>Цей пароль якимось чином містить ім&apos;я користувача
</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="174"/>
<source>The password contains words from the real name of the user in some form</source>
<translation type="unfinished"/>
<translation>Цей пароль містить слова зі справжнього імені користувача в якійсь із форм</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="176"/>
@ -1294,12 +1295,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="179"/>
<source>The password contains less than %1 digits</source>
<translation type="unfinished"/>
<translation>Цей пароль містить менше ніж %1 символ</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="180"/>
<source>The password contains too few digits</source>
<translation type="unfinished"/>
<translation>Цей пароль містить замало символів</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="183"/>
@ -1339,7 +1340,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="196"/>
<source>The password is too short</source>
<translation type="unfinished"/>
<translation>Цей пароль занадто короткий</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="198"/>
@ -1464,12 +1465,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="265"/>
<source>Fatal failure</source>
<translation type="unfinished"/>
<translation>Фатальна помилка</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="267"/>
<source>Unknown error</source>
<translation type="unfinished"/>
<translation>Невідома помилка</translation>
</message>
</context>
<context>
@ -1839,7 +1840,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation type="unfinished"/>
<translation>Збереження файлів на потім ...</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>

Binary file not shown.

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: strel, 2017\n"
"Last-Translator: Francisco Sánchez López de Lerma <fslopezlerma@gmail.com>, 2018\n"
"Language-Team: Spanish (https://www.transifex.com/calamares/teams/20061/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -20,7 +20,7 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
msgstr ""
msgstr "Desmontar sistemas de archivos."
#: src/modules/dummypython/main.py:44
msgid "Dummy python job."

Binary file not shown.

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Eli Shleifer <eligator@gmail.com>, 2017\n"
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>, 2017\n"
"Language-Team: Hebrew (https://www.transifex.com/calamares/teams/20061/he/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -20,7 +20,7 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
msgstr ""
msgstr "ניתוק עיגון מערכות קבצים."
#: src/modules/dummypython/main.py:44
msgid "Dummy python job."
@ -32,31 +32,31 @@ msgstr "צעד דמה של Python {}"
#: src/modules/machineid/main.py:35
msgid "Generate machine-id."
msgstr "חולל מספר סידורי של המכונה."
msgstr "לייצר מספר סידורי של המכונה."
#: src/modules/packages/main.py:62
#, python-format
msgid "Processing packages (%(count)d / %(total)d)"
msgstr "מעבד חבילות (%(count)d/%(total)d)"
msgstr "החבילות מעובדות (%(count)d/%(total)d)"
#: src/modules/packages/main.py:64 src/modules/packages/main.py:74
msgid "Install packages."
msgstr "התקן חבילות."
msgstr "התקנת חבילות."
#: src/modules/packages/main.py:67
#, python-format
msgid "Installing one package."
msgid_plural "Installing %(num)d packages."
msgstr[0] "מתקין חבילה אחת."
msgstr[1] "מתקין %(num)d חבילות."
msgstr[2] "מתקין %(num)d חבילות."
msgstr[3] "מתקין %(num)d חבילות."
msgstr[0] "מותקנת חבילה אחת."
msgstr[1] "מותקנות %(num)d חבילות."
msgstr[2] "מותקנות %(num)d חבילות."
msgstr[3] "מותקנות %(num)d חבילות."
#: src/modules/packages/main.py:70
#, python-format
msgid "Removing one package."
msgid_plural "Removing %(num)d packages."
msgstr[0] "מסיר חבילה אחת."
msgstr[1] "מסיר %(num)d חבילות."
msgstr[2] "מסיר %(num)d חבילות."
msgstr[3] "מסיר %(num)d חבילות."
msgstr[0] "מתבצעת הסרה של חבילה אחת."
msgstr[1] "מתבצעת הסרה של %(num)d חבילות."
msgstr[2] "מתבצעת הסרה של %(num)d חבילות."
msgstr[3] "מתבצעת הסרה של %(num)d חבילות."

Binary file not shown.

View File

@ -20,19 +20,19 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
msgstr ""
msgstr "Aftengja skráarkerfi."
#: src/modules/dummypython/main.py:44
msgid "Dummy python job."
msgstr "Dummy python job."
msgstr ""
#: src/modules/dummypython/main.py:97
msgid "Dummy python step {}"
msgstr "Dummy python step {}"
msgstr ""
#: src/modules/machineid/main.py:35
msgid "Generate machine-id."
msgstr "Generate machine-id."
msgstr ""
#: src/modules/packages/main.py:62
#, python-format

Binary file not shown.

View File

@ -10,6 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Володимир Братко <Yamaha373@outlook.com>, 2018\n"
"Language-Team: Ukrainian (https://www.transifex.com/calamares/teams/20061/uk/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -40,7 +41,7 @@ msgstr ""
#: src/modules/packages/main.py:64 src/modules/packages/main.py:74
msgid "Install packages."
msgstr ""
msgstr "Встановити пакети."
#: src/modules/packages/main.py:67
#, python-format

View File

@ -70,39 +70,39 @@ modules-search: [ local ]
#
# YAML: list of lists of strings.
sequence:
- show:
- welcome
- locale
- keyboard
- partition
- users
- summary
- exec:
- partition
- mount
- unpackfs
- machineid
- fstab
- locale
- keyboard
- localecfg
- luksopenswaphookcfg
- luksbootkeyfile
- plymouthcfg
- initcpiocfg
- initcpio
- users
- displaymanager
- mhwdcfg
- networkcfg
- hwclock
- services
- grubcfg
- bootloader
- postcfg
- umount
- show:
- finished
- show:
- welcome
- locale
- keyboard
- partition
- users
- summary
- exec:
- partition
- mount
- unpackfs
- machineid
- fstab
- locale
- keyboard
- localecfg
- luksopenswaphookcfg
- luksbootkeyfile
- plymouthcfg
- initcpiocfg
- initcpio
- users
- displaymanager
- mhwdcfg
- networkcfg
- hwclock
- services-systemd
- grubcfg
- bootloader
- postcfg
- umount
- show:
- finished
# A branding component is a directory, either in SHARE/calamares/branding or
# in /etc/calamares/branding (the latter takes precedence). The directory must

View File

@ -44,6 +44,15 @@ file) should be enclosed in this form for translations
text: qsTr("This is an example text.")
```
If you use CMake for preparing branding for packaging, the macro
`calamares_add_branding_subdirectory()`` (see also *Project Layout*,
below) will convert the source `.ts` files to their compiled form).
If you are packaging the branding by hand, use
```
lrelease file_en.ts [file_en_GB.ts ..]
```
with all the language suffixes to *file*.
## Presentation
The default QML classes provided by Calamares can be used for a simple
@ -105,13 +114,6 @@ will have a top-level `CMakeLists.txt` that includes some boilerplate
to find Calamares, and then adds a subdirectory which contains the
actual branding component.
Adding the subdirectory can be done as follows:
- If the directory contains files only, and optionally has a single
subdirectory lang/ which contains the translation files for the
component, then `calamares_add_branding_subdirectory()` can be
used, which takes only the name of the subdirectory.
The file layout in a typical branding component repository is:
```
@ -127,9 +129,19 @@ The file layout in a typical branding component repository is:
...
```
Adding the subdirectory can be done as follows:
- If the directory contains files only, and optionally has a single
subdirectory lang/ which contains the translation files for the
component, then `calamares_add_branding_subdirectory()` can be
used, which takes only the name of the subdirectory.
- If the branding component has many files which are organized into
subdirectories, use the SUBDIRECTORIES argument to the CMake function
to additionally install files from those subdirectories. For example,
if the component places all of its images in an `img/` subdirectory,
then call `calamares_add_branding_subdirectory( ... SUBDIRECTORIES img)`.
It is a bad idea to include `lang/` in the SUBDIRECTORIES list.
- The `.ts` files from the `lang/` subdirectory need be be compiled
to `.qm` files before being installed. The CMake macro's do this
automatically. For manual packaging, use `lrelease` to compile
the files.

View File

@ -133,60 +133,93 @@ CalamaresApplication::mainWindow()
}
static QStringList
qmlDirCandidates( bool assumeBuilddir )
{
static const char QML[] = "qml";
QStringList qmlDirs;
if ( CalamaresUtils::isAppDataDirOverridden() )
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
else
{
if ( assumeBuilddir )
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
}
return qmlDirs;
}
static QStringList
settingsFileCandidates( bool assumeBuilddir )
{
static const char settings[] = "settings.conf";
QStringList settingsPaths;
if ( CalamaresUtils::isAppDataDirOverridden() )
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
else
{
if ( assumeBuilddir )
settingsPaths << QDir::current().absoluteFilePath( settings );
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
return settingsPaths;
}
static QStringList
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 );
brandingPaths << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename);
}
return brandingPaths;
}
void
CalamaresApplication::initQmlPath()
{
QDir importPath;
QDir importPath; // Right now, current-dir
QStringList qmlDirCandidatesByPriority = qmlDirCandidates( isDebug() );
bool found = false;
QString subpath( "qml" );
if ( CalamaresUtils::isAppDataDirOverridden() )
foreach ( const QString& path, qmlDirCandidatesByPriority )
{
importPath = QDir( CalamaresUtils::appDataDir()
.absoluteFilePath( subpath ) );
if ( !importPath.exists() || !importPath.isReadable() )
QDir dir( path );
if ( dir.exists() && dir.isReadable() )
{
cError() << "FATAL: explicitly configured application data directory"
<< CalamaresUtils::appDataDir().absolutePath()
<< "does not contain a valid QML modules directory at"
<< importPath.absolutePath()
<< "\nCowardly refusing to continue startup without the QML directory.";
::exit( EXIT_FAILURE );
}
}
else
{
QStringList qmlDirCandidatesByPriority;
if ( isDebug() )
{
qmlDirCandidatesByPriority.append(
QDir::current().absoluteFilePath(
QString( "src/%1" )
.arg( subpath ) ) );
}
qmlDirCandidatesByPriority.append( CalamaresUtils::appDataDir()
.absoluteFilePath( subpath ) );
foreach ( const QString& path, qmlDirCandidatesByPriority )
{
QDir dir( path );
if ( dir.exists() && dir.isReadable() )
{
importPath = dir;
break;
}
}
if ( !importPath.exists() || !importPath.isReadable() )
{
cError() << "FATAL: none of the expected QML paths ("
<< qmlDirCandidatesByPriority.join( ", " )
<< ") exist."
<< "\nCowardly refusing to continue startup without the QML directory.";
::exit( EXIT_FAILURE );
importPath = dir;
found = true;
break;
}
}
if ( !found || !importPath.exists() || !importPath.isReadable() )
{
cError() << "Cowardly refusing to continue startup without a QML directory."
<< Logger::DebugList( qmlDirCandidatesByPriority );
if ( CalamaresUtils::isAppDataDirOverridden() )
cError() << "FATAL: explicitly configured application data directory is missing qml/";
else
cError() << "FATAL: none of the expected QML paths exist.";
::exit( EXIT_FAILURE );
}
cDebug() << "Using Calamares QML directory" << importPath.absolutePath();
CalamaresUtils::setQmlModulesDir( importPath );
}
@ -194,51 +227,31 @@ CalamaresApplication::initQmlPath()
void
CalamaresApplication::initSettings()
{
QStringList settingsFileCandidatesByPriority = settingsFileCandidates( isDebug() );
QFileInfo settingsFile;
if ( CalamaresUtils::isAppDataDirOverridden() )
bool found = false;
foreach ( const QString& path, settingsFileCandidatesByPriority )
{
settingsFile = QFileInfo( CalamaresUtils::appDataDir().absoluteFilePath( "settings.conf" ) );
if ( !settingsFile.exists() || !settingsFile.isReadable() )
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
cError() << "FATAL: explicitly configured application data directory"
<< CalamaresUtils::appDataDir().absolutePath()
<< "does not contain a valid settings.conf file."
<< "\nCowardly refusing to continue startup without settings.";
::exit( EXIT_FAILURE );
settingsFile = pathFi;
found = true;
break;
}
}
else
if ( !found || !settingsFile.exists() || !settingsFile.isReadable() )
{
QStringList settingsFileCandidatesByPriority;
if ( isDebug() )
{
settingsFileCandidatesByPriority.append(
QDir::currentPath() +
QDir::separator() +
"settings.conf" );
}
settingsFileCandidatesByPriority.append( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf" );
settingsFileCandidatesByPriority.append( CalamaresUtils::appDataDir()
.absoluteFilePath( "settings.conf" ) );
foreach ( const QString& path, settingsFileCandidatesByPriority )
{
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
settingsFile = pathFi;
break;
}
}
if ( !settingsFile.exists() || !settingsFile.isReadable() )
{
cError() << "FATAL: none of the expected configuration file paths ("
<< settingsFileCandidatesByPriority.join( ", " )
<< ") contain a valid settings.conf file."
<< "\nCowardly refusing to continue startup without settings.";
::exit( EXIT_FAILURE );
}
cError() << "Cowardly refusing to continue startup without settings."
<< 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 );
}
new Calamares::Settings( settingsFile.absoluteFilePath(), isDebug(), this );
@ -255,59 +268,32 @@ CalamaresApplication::initBranding()
::exit( EXIT_FAILURE );
}
QString brandingDescriptorSubpath = QString( "branding/%1/branding.desc" )
.arg( brandingComponentName );
QString brandingDescriptorSubpath = QString( "branding/%1/branding.desc" ).arg( brandingComponentName );
QStringList brandingFileCandidatesByPriority = brandingFileCandidates( isDebug(), brandingDescriptorSubpath);
QFileInfo brandingFile;
if ( CalamaresUtils::isAppDataDirOverridden() )
bool found = false;
foreach ( const QString& path, brandingFileCandidatesByPriority )
{
brandingFile = QFileInfo( CalamaresUtils::appDataDir()
.absoluteFilePath( brandingDescriptorSubpath ) );
if ( !brandingFile.exists() || !brandingFile.isReadable() )
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
cError() << "FATAL: explicitly configured application data directory"
<< CalamaresUtils::appDataDir().absolutePath()
<< "does not contain a valid branding component descriptor at"
<< brandingFile.absoluteFilePath()
<< "\nCowardly refusing to continue startup without branding.";
::exit( EXIT_FAILURE );
brandingFile = pathFi;
found = true;
break;
}
}
else
if ( !found || !brandingFile.exists() || !brandingFile.isReadable() )
{
QStringList brandingFileCandidatesByPriority;
if ( isDebug() )
{
brandingFileCandidatesByPriority.append(
QDir::currentPath() +
QDir::separator() +
"src" +
QDir::separator() +
brandingDescriptorSubpath );
}
brandingFileCandidatesByPriority.append( QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" )
.absoluteFilePath( brandingDescriptorSubpath ) );
brandingFileCandidatesByPriority.append( CalamaresUtils::appDataDir()
.absoluteFilePath( brandingDescriptorSubpath ) );
foreach ( const QString& path, brandingFileCandidatesByPriority )
{
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
brandingFile = pathFi;
break;
}
}
if ( !brandingFile.exists() || !brandingFile.isReadable() )
{
cError() << "FATAL: none of the expected branding descriptor file paths ("
<< brandingFileCandidatesByPriority.join( ", " )
<< ") contain a valid branding.desc file."
<< "\nCowardly refusing to continue startup without branding.";
::exit( EXIT_FAILURE );
}
cError() << "Cowardly refusing to continue startup without branding."
<< 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 );
}
new Calamares::Branding( brandingFile.absoluteFilePath(), this );

View File

@ -108,7 +108,14 @@ main( int argc, char* argv[] )
returnCode = a.exec();
}
else
{
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

@ -212,7 +212,7 @@ Settings::customModuleInstances() const
}
QList< QPair< ModuleAction, QStringList > >
Settings::ModuleSequence
Settings::modulesSequence() const
{
return m_modulesSequence;

View File

@ -47,7 +47,8 @@ public:
using InstanceDescriptionList = QList< InstanceDescription >;
InstanceDescriptionList customModuleInstances() const;
QList< QPair< ModuleAction, QStringList > > modulesSequence() const;
using ModuleSequence = QList< QPair< ModuleAction, QStringList > >;
ModuleSequence modulesSequence() const;
QString brandingComponentName() const;
@ -63,7 +64,7 @@ private:
QStringList m_modulesSearchPaths;
InstanceDescriptionList m_customModuleInstances;
QList< QPair< ModuleAction, QStringList > > m_modulesSequence;
ModuleSequence m_modulesSequence;
QString m_brandingComponentName;

View File

@ -48,7 +48,8 @@ endif()
if( WITH_PYTHONQT )
include_directories(${PYTHON_INCLUDE_DIRS})
include_directories(${PYTHONQT_INCLUDE_DIR})
# *_DIRS because we also use extensions
include_directories(${PYTHONQT_INCLUDE_DIRS})
list( APPEND calamaresui_SOURCES
modulesystem/PythonQtViewModule.cpp

View File

@ -44,14 +44,6 @@
#include <QString>
// Example module.desc
/*
---
type: "view" #job or view
name: "foo" #the module name. must be unique and same as the parent directory
interface: "qtplugin" #can be: qtplugin, python, process, ...
*/
static const char EMERGENCY[] = "emergency";
namespace Calamares
@ -144,34 +136,29 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
}
static QStringList
moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, const QString& configFileName )
{
QStringList paths;
if ( CalamaresUtils::isAppDataDirOverridden() )
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
else
{
if ( assumeBuildDir )
paths << QDir().absoluteFilePath(QString( "src/modules/%1/%2" ).arg( moduleName ).arg( configFileName ) );
paths << QString( "/etc/calamares/modules/%1" ).arg( configFileName );
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
}
return paths;
}
void
Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception
{
QStringList configFilesByPriority;
if ( CalamaresUtils::isAppDataDirOverridden() )
{
configFilesByPriority.append(
CalamaresUtils::appDataDir().absoluteFilePath(
QString( "modules/%1" ).arg( configFileName ) ) );
}
else
{
if ( Settings::instance()->debugMode() )
{
configFilesByPriority.append(
QDir( QDir::currentPath() ).absoluteFilePath(
QString( "src/modules/%1/%2" ).arg( m_name ).arg( configFileName ) ) );
}
configFilesByPriority.append(
QString( "/etc/calamares/modules/%1" ).arg( configFileName ) );
configFilesByPriority.append(
CalamaresUtils::appDataDir().absoluteFilePath(
QString( "modules/%2" ).arg( configFileName ) ) );
}
foreach ( const QString& path, configFilesByPriority )
foreach ( const QString& path, moduleConfigurationCandidates( Settings::instance()->debugMode(), m_name, configFileName ) )
{
QFile configFile( path );
if ( configFile.exists() && configFile.open( QFile::ReadOnly | QFile::Text ) )
@ -224,13 +211,6 @@ Module::instanceKey() const
}
QStringList
Module::requiredModules() const
{
return m_requiredModules;
}
QString
Module::location() const
{
@ -286,7 +266,6 @@ void
Module::initFrom( const QVariantMap& moduleDescriptor )
{
m_name = moduleDescriptor.value( "name" ).toString();
if ( moduleDescriptor.contains( EMERGENCY ) )
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
}

View File

@ -106,13 +106,6 @@ public:
*/
virtual QString instanceKey() const final;
/**
* @brief requiredModules a list of names of modules required by this one.
* @return the list of names.
* The module dependencies system is currently incomplete and unused.
*/
virtual QStringList requiredModules() const;
/**
* @brief location returns the full path of this module's directory.
* @return the path.
@ -198,7 +191,6 @@ private:
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
QString m_name;
QStringList m_requiredModules;
QString m_directory;
QString m_instanceId;

View File

@ -126,7 +126,6 @@ ModuleManager::doInit()
}
// At this point m_availableModules is filled with whatever was found in the
// search paths.
checkDependencies();
emit initDone();
}
@ -176,11 +175,11 @@ ModuleManager::loadModules()
{
QTimer::singleShot( 0, this, [ this ]()
{
QStringList failedModules;
QStringList failedModules = checkDependencies();
Settings::InstanceDescriptionList customInstances =
Settings::instance()->customModuleInstances();
const auto modulesSequence = Settings::instance()->modulesSequence();
const auto modulesSequence = failedModules.isEmpty() ? Settings::instance()->modulesSequence() : Settings::ModuleSequence();
for ( const auto& modulePhase : modulesSequence )
{
ModuleAction currentAction = modulePhase.first;
@ -262,6 +261,14 @@ ModuleManager::loadModules()
failedModules.append( instanceKey );
continue;
}
if ( !checkDependencies( *thisModule ) )
{
// Error message is already printed
failedModules.append( instanceKey );
continue;
}
// If it's a ViewModule, it also appends the ViewStep to the ViewManager.
thisModule->loadSelf();
m_loadedModulesByInstanceKey.insert( instanceKey, thisModule );
@ -301,24 +308,29 @@ ModuleManager::loadModules()
}
void
QStringList
ModuleManager::checkDependencies()
{
QStringList failed;
// This goes through the map of available modules, and deletes those whose
// dependencies are not met, if any.
bool somethingWasRemovedBecauseOfUnmetDependencies = false;
forever
{
bool somethingWasRemovedBecauseOfUnmetDependencies = false;
for ( auto it = m_availableDescriptorsByModuleName.begin();
it != m_availableDescriptorsByModuleName.end(); ++it )
{
foreach ( const QString& depName,
( *it ).value( "requiredModules" ).toStringList() )
it->value( "requiredModules" ).toStringList() )
{
if ( !m_availableDescriptorsByModuleName.contains( depName ) )
{
QString moduleName = it->value( "name" ).toString();
somethingWasRemovedBecauseOfUnmetDependencies = true;
m_availableDescriptorsByModuleName.erase( it );
failed << moduleName;
cWarning() << "Module" << moduleName << "has unknown requirement" << depName;
break;
}
}
@ -328,7 +340,33 @@ ModuleManager::checkDependencies()
if ( !somethingWasRemovedBecauseOfUnmetDependencies )
break;
}
return failed;
}
bool
ModuleManager::checkDependencies( const Module& m )
{
bool allRequirementsFound = true;
QStringList requiredModules = m_availableDescriptorsByModuleName[ m.name() ].value( "requiredModules" ).toStringList();
for ( const QString& required : requiredModules )
{
bool requirementFound = false;
for( const Module* v : m_loadedModulesByInstanceKey )
if ( required == v->name() )
{
requirementFound = true;
break;
}
if ( !requirementFound )
{
cError() << "Module" << m.name() << "requires" << required << "before it in sequence.";
allRequirementsFound = false;
}
}
return allRequirementsFound;
}
}

View File

@ -90,7 +90,25 @@ private slots:
void doInit();
private:
void checkDependencies();
/**
* Check in a general sense whether the dependencies between
* modules are valid. Returns a list of module names that
* do **not** have their requirements met.
*
* Returns an empty list on success.
*
* Also modifies m_availableDescriptorsByModuleName to remove
* all the entries that fail.
*/
QStringList checkDependencies();
/**
* Check for this specific module if its required modules have
* already been loaded (i.e. are in sequence before it).
*
* Returns true if the requirements are met.
*/
bool checkDependencies( const Module& );
QMap< QString, QVariantMap > m_availableDescriptorsByModuleName;
QMap< QString, QString > m_moduleDirectoriesByModuleName;

View File

@ -31,7 +31,7 @@
#include "JobQueue.h"
#include <PythonQt.h>
#include <extensions/PythonQt_QtAll/PythonQt_QtAll.h>
#include <PythonQt_QtAll.h>
#include <QDir>
#include <QPointer>

View File

@ -15,13 +15,34 @@ string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" )
file( GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" )
list( SORT SUBDIRECTORIES )
set( _use_categories "" )
set( _found_categories "" )
foreach( SUBDIRECTORY ${SUBDIRECTORIES} )
list( FIND SKIP_LIST ${SUBDIRECTORY} DO_SKIP )
set( _skip_reason "user request" )
# Handle the USE_<foo> variables by looking for subdirectories
# with a <foo>-<implementation> kind of name.
if( SUBDIRECTORY MATCHES "^[a-zA-Z0-9_]+-" )
string( REGEX REPLACE "^[^-]+-" "" _implementation ${SUBDIRECTORY} )
string( REGEX REPLACE "-.*" "" _category ${SUBDIRECTORY} )
if( USE_${_category} )
list( APPEND _use_categories ${_category} )
if( "${_implementation}" STREQUAL "${USE_${_category}}" )
list( APPEND _found_categories ${_category} )
else()
list( APPEND SKIP_LIST ${SUBDIRECTORY} )
set( _skip_reason "USE_${_category}=${USE_${_category}}" )
set( DO_SKIP 1 )
endif()
endif()
endif()
if( NOT DO_SKIP EQUAL -1 )
message( "${ColorReset}-- Skipping module ${BoldRed}${SUBDIRECTORY}${ColorReset}." )
message( "" )
list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (user request)" )
list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (${_skip_reason})" )
elseif( ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) AND
( DO_SKIP EQUAL -1 ) )
set( SKIPPED_MODULES )
@ -36,5 +57,12 @@ endforeach()
# both before and after the feature summary.
calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} )
foreach( _category ${_use_categories} )
list( FIND _found_categories ${_category} _found )
if ( _found EQUAL -1 )
message( FATAL_ERROR "USE_${_category} is set to ${USE_${_category}} and no module matches." )
endif()
endforeach()
include( CalamaresAddTranslations )
add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} )

View File

@ -12,8 +12,10 @@ kernel: "_ALL_kver_"
img: "_default_image_"
fallback: "_fallback_image_"
timeout: "10"
# Optionally set the menu entry name and kernel name to use in systemd-boot.
# If not specified here, these settings will be taken from branding.desc.
#
# bootloaderEntryName: "Manjaro"
kernelLine: ", with _manjaro_kernel_"
fallbackKernelLine: ", with _manjaro_kernel_ (fallback initramfs)"

View File

@ -1,3 +1,5 @@
# Configure one or more display managers (e.g. SDDM)
# with a "best effort" approach.
---
#The DM module attempts to set up all the DMs found in this list, in that precise order.
#It also sets up autologin, if the feature is enabled in globalstorage.

View File

@ -3,7 +3,7 @@
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2014-2017, Philip Müller <philm@manjaro.org>
# Copyright 2014-2018, Philip Müller <philm@manjaro.org>
# Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
# Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
@ -23,16 +23,43 @@
# You should have received a copy of the GNU General Public License
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
import abc
import os
import collections
import re
import libcalamares
import configparser
from libcalamares.utils import gettext_path, gettext_languages
import gettext
_translation = gettext.translation("calamares-python",
localedir=gettext_path(),
languages=gettext_languages(),
fallback=True)
_ = _translation.gettext
_n = _translation.ngettext
class DesktopEnvironment:
"""
Desktop Environment -- some utility functions for a desktop
environment (e.g. finding out if it is installed). This
is independent of the *Display Manager*, which is what
we're configuring in this module.
"""
def __init__(self, exec, desktop):
self.executable = exec
self.desktop_file = desktop
def find_desktop_environment(self, root_mount_point):
"""
Check if this environment is installed in the
target system at @p root_mount_point.
"""
return (
os.path.exists("{!s}{!s}".format(root_mount_point, self.executable)) and
os.path.exists("{!s}/usr/share/xsessions/{!s}.desktop".format(root_mount_point, self.desktop_file))
)
DesktopEnvironment = collections.namedtuple(
'DesktopEnvironment', ['executable', 'desktop_file']
)
desktop_environments = [
DesktopEnvironment('/usr/bin/startkde', 'plasma'), # KDE Plasma 5
@ -67,54 +94,80 @@ def find_desktop_environment(root_mount_point):
:return:
"""
for desktop_environment in desktop_environments:
if (os.path.exists("{!s}{!s}".format(
root_mount_point, desktop_environment.executable
)
) and os.path.exists(
"{!s}/usr/share/xsessions/{!s}.desktop".format(
root_mount_point, desktop_environment.desktop_file
)
)):
if desktop_environment.find_desktop_environment(root_mount_point):
return desktop_environment
return None
def have_dm(dm_name, root_mount_point):
class DisplayManager(metaclass=abc.ABCMeta):
"""
Checks if display manager is properly installed.
Display Manager -- a base class for DM configuration.
"""
name = None
executable = None
:param dm_name:
:param root_mount_point:
:return:
"""
bin_path = "{!s}/usr/bin/{!s}".format(root_mount_point, dm_name)
sbin_path = "{!s}/usr/sbin/{!s}".format(root_mount_point, dm_name)
return (os.path.exists(bin_path)
def __init__(self, root_mount_point):
self.root_mount_point = root_mount_point
def have_dm(self):
"""
Is this DM installed in the target system?
The default implementation checks for `executable`
in the target system.
"""
if self.executable is None:
return True
bin_path = "{!s}/usr/bin/{!s}".format(self.root_mount_point, self.executable)
sbin_path = "{!s}/usr/sbin/{!s}".format(self.root_mount_point, self.executable)
return (
os.path.exists(bin_path)
or os.path.exists(sbin_path)
)
# The four abstract methods below are called in the order listed here.
# They must all be implemented by subclasses, but not all of them
# actually do something for all DMs.
def set_autologin(username,
displaymanager,
default_desktop_environment,
root_mount_point):
"""
Enables automatic login for the installed desktop managers.
@abc.abstractmethod
def basic_setup(self):
"""
Do basic setup (e.g. users, groups, directory creation) for this DM.
"""
# Some implementations do nothing
:param username:
:param displaymanager: str
The displaymanager for which to configure autologin.
:param default_desktop_environment:
:param root_mount_point:
"""
do_autologin = True
@abc.abstractmethod
def desktop_environment_setup(self, desktop_environment):
"""
Configure the given @p desktop_environment as the default one, in
the configuration files for this DM.
"""
# Many implementations do nothing
if username is None:
do_autologin = False
@abc.abstractmethod
def greeter_setup(self):
"""
Additional setup for the greeter.
"""
# Most implementations do nothing
if "mdm" == displaymanager:
@abc.abstractmethod
def set_autologin(self, username, do_autologin, default_desktop_environment):
"""
Configure the DM inside the given @p root_mount_point with
autologin (if @p do_autologin is True) for the given @p username.
If the DM supports it, set the default DE to @p default_desktop_environment
as well.
"""
class DMmdm(DisplayManager):
name = "mdm"
executable = "mdm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with MDM as Desktop Manager
mdm_conf_path = os.path.join(root_mount_point, "etc/mdm/custom.conf")
mdm_conf_path = os.path.join(self.root_mount_point, "etc/mdm/custom.conf")
if os.path.exists(mdm_conf_path):
with open(mdm_conf_path, 'r') as mdm_conf:
@ -149,9 +202,58 @@ def set_autologin(username,
else:
mdm_conf.write('AutomaticLoginEnable=False\n')
if "gdm" == displaymanager:
def basic_setup(self):
if libcalamares.utils.target_env_call(
['getent', 'group', 'mdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '128', 'mdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'mdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-c', '"Linux Mint Display Manager"',
'-u', '128',
'-g', 'mdm',
'-d', '/var/lib/mdm',
'-s', '/usr/bin/nologin',
'mdm'
]
)
libcalamares.utils.target_env_call(
['passwd', '-l', 'mdm']
)
libcalamares.utils.target_env_call(
['chown', 'root:mdm', '/var/lib/mdm']
)
libcalamares.utils.target_env_call(
['chmod', '1770', '/var/lib/mdm']
)
def desktop_environment_setup(self, default_desktop_environment):
os.system(
"sed -i \"s|default.desktop|{!s}.desktop|g\" "
"{!s}/etc/mdm/custom.conf".format(
default_desktop_environment.desktop_file,
self.root_mount_point
)
)
def greeter_setup(self):
pass
class DMgdm(DisplayManager):
name = "gdm"
executable = "gdm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with GDM as Desktop Manager
gdm_conf_path = os.path.join(root_mount_point, "etc/gdm/custom.conf")
gdm_conf_path = os.path.join(self.root_mount_point, "etc/gdm/custom.conf")
if os.path.exists(gdm_conf_path):
with open(gdm_conf_path, 'r') as gdm_conf:
@ -185,7 +287,7 @@ def set_autologin(username,
if (do_autologin):
accountservice_dir = "{!s}/var/lib/AccountsService/users".format(
root_mount_point
self.root_mount_point
)
userfile_path = "{!s}/{!s}".format(accountservice_dir, username)
if os.path.exists(accountservice_dir):
@ -198,10 +300,51 @@ def set_autologin(username,
userfile.write("Icon=\n")
if "kdm" == displaymanager:
def basic_setup(self):
if libcalamares.utils.target_env_call(
['getent', 'group', 'gdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '120', 'gdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'gdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-c', '"Gnome Display Manager"',
'-u', '120',
'-g', 'gdm',
'-d', '/var/lib/gdm',
'-s', '/usr/bin/nologin',
'gdm'
]
)
libcalamares.utils.target_env_call(
['passwd', '-l', 'gdm']
)
libcalamares.utils.target_env_call(
['chown', '-R', 'gdm:gdm', '/var/lib/gdm']
)
def desktop_environment_setup(self, desktop_environment):
pass
def greeter_setup(self):
pass
class DMkdm(DisplayManager):
name = "kdm"
executable = "kdm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with KDM as Desktop Manager
kdm_conf_path = os.path.join(
root_mount_point, "usr/share/config/kdm/kdmrc"
self.root_mount_point, "usr/share/config/kdm/kdmrc"
)
# Check which path is in use: SUSE does something else.
# Also double-check the default setting. Pick the first
@ -210,7 +353,7 @@ def set_autologin(username,
"usr/share/config/kdm/kdmrc",
"usr/share/kde4/config/kdm/kdmrc",
):
p = os.path.join(root_mount_point, candidate_kdmrc)
p = os.path.join(self.root_mount_point, candidate_kdmrc)
if os.path.exists(p):
kdm_conf_path = p
break
@ -234,13 +377,51 @@ def set_autologin(username,
kdm_conf.write(line)
else:
return (
"Cannot write KDM configuration file",
"KDM config file {!s} does not exist".format(kdm_conf_path)
_("Cannot write KDM configuration file"),
_("KDM config file {!s} does not exist").format(kdm_conf_path)
)
if "lxdm" == displaymanager:
def basic_setup(self):
if libcalamares.utils.target_env_call(
['getent', 'group', 'kdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '135', 'kdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'kdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-u', '135',
'-g', 'kdm',
'-d', '/var/lib/kdm',
'-s', '/bin/false',
'-r',
'-M',
'kdm'
]
)
libcalamares.utils.target_env_call(
['chown', '-R', '135:135', 'var/lib/kdm']
)
def desktop_environment_setup(self, desktop_environment):
pass
def greeter_setup(self):
pass
class DMlxdm(DisplayManager):
name = "lxdm"
executable = "lxdm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with LXDM as Desktop Manager
lxdm_conf_path = os.path.join(root_mount_point, "etc/lxdm/lxdm.conf")
lxdm_conf_path = os.path.join(self.root_mount_point, "etc/lxdm/lxdm.conf")
text = []
if os.path.exists(lxdm_conf_path):
@ -258,17 +439,52 @@ def set_autologin(username,
lxdm_conf.write(line)
else:
return (
"Cannot write LXDM configuration file",
"LXDM config file {!s} does not exist".format(lxdm_conf_path)
_("Cannot write LXDM configuration file"),
_("LXDM config file {!s} does not exist").format(lxdm_conf_path)
)
if "lightdm" == displaymanager:
def basic_setup(self):
if libcalamares.utils.target_env_call(
['getent', 'group', 'lxdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '--system', 'lxdm']
)
libcalamares.utils.target_env_call(
['chgrp', '-R', 'lxdm', '/var/lib/lxdm']
)
libcalamares.utils.target_env_call(
['chgrp', 'lxdm', '/etc/lxdm/lxdm.conf']
)
libcalamares.utils.target_env_call(
['chmod', '+r', '/etc/lxdm/lxdm.conf']
)
def desktop_environment_setup(self, default_desktop_environment):
os.system(
"sed -i -e \"s|^.*session=.*|session={!s}|\" "
"{!s}/etc/lxdm/lxdm.conf".format(
default_desktop_environment.executable,
self.root_mount_point
)
)
def greeter_setup(self):
pass
class DMlightdm(DisplayManager):
name = "lightdm"
executable = "lightdm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with LightDM as Desktop Manager
# Ideally, we should use configparser for the ini conf file,
# but we just do a simple text replacement for now, as it
# worksforme(tm)
lightdm_conf_path = os.path.join(
root_mount_point, "etc/lightdm/lightdm.conf"
self.root_mount_point, "etc/lightdm/lightdm.conf"
)
text = []
@ -298,15 +514,93 @@ def set_autologin(username,
"#autologin-user=\n")
except FileNotFoundError:
return (
"Cannot write LightDM configuration file",
"LightDM config file {!s} does not exist".format(
lightdm_conf_path
)
_("Cannot write LightDM configuration file"),
_("LightDM config file {!s} does not exist").format(lightdm_conf_path)
)
if "slim" == displaymanager:
def basic_setup(self):
libcalamares.utils.target_env_call(
['mkdir', '-p', '/run/lightdm']
)
if libcalamares.utils.target_env_call(
['getent', 'group', 'lightdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '620', 'lightdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'lightdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd', '-c',
'"LightDM Display Manager"',
'-u', '620',
'-g', 'lightdm',
'-d', '/var/run/lightdm',
'-s', '/usr/bin/nologin',
'lightdm'
]
)
libcalamares.utils.target_env_call(['passwd', '-l', 'lightdm'])
libcalamares.utils.target_env_call(['chown', '-R', 'lightdm:lightdm', '/run/lightdm'])
libcalamares.utils.target_env_call(['chmod', '+r' '/etc/lightdm/lightdm.conf'])
def desktop_environment_setup(self, default_desktop_environment):
os.system(
"sed -i -e \"s/^.*user-session=.*/user-session={!s}/\" "
"{!s}/etc/lightdm/lightdm.conf".format(
default_desktop_environment.desktop_file,
self.root_mount_point
)
)
def greeter_setup(self):
lightdm_conf_path = os.path.join(
self.root_mount_point, "etc/lightdm/lightdm.conf"
)
# configure lightdm-greeter
greeter_path = os.path.join(
self.root_mount_point, "usr/share/xgreeters"
)
if (os.path.exists(greeter_path)):
# configure first found lightdm-greeter
for entry in os.listdir(greeter_path):
if entry.endswith('.desktop'):
greeter = entry.split('.')[0]
libcalamares.utils.debug(
"found greeter {!s}".format(greeter)
)
os.system(
"sed -i -e \"s/^.*greeter-session=.*"
"/greeter-session={!s}/\" {!s}".format(
greeter,
lightdm_conf_path
)
)
libcalamares.utils.debug(
"{!s} configured as greeter.".format(greeter)
)
break
else:
return (
_("Cannot configure LightDM"),
_("No LightDM greeter installed.")
)
class DMslim(DisplayManager):
name = "slim"
executable = "slim"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with Slim as Desktop Manager
slim_conf_path = os.path.join(root_mount_point, "etc/slim.conf")
slim_conf_path = os.path.join(self.root_mount_point, "etc/slim.conf")
text = []
if os.path.exists(slim_conf_path):
@ -327,13 +621,28 @@ def set_autologin(username,
slim_conf.write(line)
else:
return (
"Cannot write SLIM configuration file",
"SLIM config file {!s} does not exist".format(slim_conf_path)
_("Cannot write SLIM configuration file"),
_("SLIM config file {!s} does not exist").format(slim_conf_path)
)
if "sddm" == displaymanager:
def basic_setup(self):
pass
def desktop_environment_setup(self, desktop_environment):
pass
def greeter_setup(self):
pass
class DMsddm(DisplayManager):
name = "sddm"
executable = "sddm"
def set_autologin(self, username, do_autologin, default_desktop_environment):
# Systems with Sddm as Desktop Manager
sddm_conf_path = os.path.join(root_mount_point, "etc/sddm.conf")
sddm_conf_path = os.path.join(self.root_mount_point, "etc/sddm.conf")
sddm_config = configparser.ConfigParser(strict=False)
# Make everything case sensitive
@ -360,7 +669,22 @@ def set_autologin(username,
with open(sddm_conf_path, 'w') as sddm_config_file:
sddm_config.write(sddm_config_file, space_around_delimiters=False)
if "sysconfig" == displaymanager:
def basic_setup(self):
pass
def desktop_environment_setup(self, desktop_environment):
pass
def greeter_setup(self):
pass
class DMsysconfig(DisplayManager):
name = "sysconfig"
executable = None
def set_autologin(self, username, do_autologin, default_desktop_environment):
dmauto = "DISPLAYMANAGER_AUTOLOGIN"
os.system(
@ -368,11 +692,28 @@ def set_autologin(username,
"{!s}/etc/sysconfig/displaymanager".format(
dmauto, dmauto,
username if do_autologin else "",
root_mount_point
self.root_mount_point
)
)
return None
def basic_setup(self):
pass
def desktop_environment_setup(self, desktop_environment):
pass
def greeter_setup(self):
pass
# Collect all the subclasses of DisplayManager defined above,
# and index them based on the name property of each class.
display_managers = [
(c.name, c)
for c in globals().values()
if type(c) is abc.ABCMeta and issubclass(c, DisplayManager) and c.name
]
def run():
@ -386,23 +727,55 @@ def run():
If a displaymanager is in the list but not installed, a debugging message
is printed and the entry ignored.
"""
# Get configuration settings for display managers
displaymanagers = None
if "displaymanagers" in libcalamares.job.configuration:
displaymanagers = libcalamares.job.configuration["displaymanagers"]
if libcalamares.globalstorage.contains("displayManagers"):
displaymanagers = libcalamares.globalstorage.value("displayManagers")
if displaymanagers is None:
if not displaymanagers:
return (
"No display managers selected for the displaymanager module.",
"The displaymanagers list is empty or undefined in both"
"globalstorage and displaymanager.conf."
_("No display managers selected for the displaymanager module."),
_("The displaymanagers list is empty or undefined in both"
"globalstorage and displaymanager.conf.")
)
username = libcalamares.globalstorage.value("autologinUser")
# Get instances that are actually installed
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
dm_impl = []
dm_names = displaymanagers[:]
if ("sysconfigSetup" in libcalamares.job.configuration
and libcalamares.job.configuration["sysconfigSetup"]):
dm_names.append("sysconfig")
for dm in dm_names:
# Find the implementation class
dm_instance = None
impl = [ cls for name, cls in display_managers if name == dm ]
if len(impl) == 1:
dm_instance = impl[0](root_mount_point)
if dm_instance.have_dm():
dm_impl.append(dm_instance)
else:
dm_instance = None
else:
libcalamares.utils.debug("{!s} has {!d} implementation classes.".format(dm).format(len(impl)))
if "default_desktop_environment" in libcalamares.job.configuration:
if dm_instance is None:
libcalamares.utils.debug("{!s} selected but not installed".format(dm))
if dm in displaymanagers:
displaymanagers.remove(dm)
if not dm_impl:
return (
_("No display managers selected for the displaymanager module."),
_("The list is empty after checking for installed display managers.")
)
# Pick up remaining settings
if "defaultDesktopEnvironment" in libcalamares.job.configuration:
entry = libcalamares.job.configuration["defaultDesktopEnvironment"]
default_desktop_environment = DesktopEnvironment(
entry["executable"], entry["desktopFile"]
@ -417,269 +790,34 @@ def run():
else:
enable_basic_setup = False
# Setup slim
if "slim" in displaymanagers:
if not have_dm("slim", root_mount_point):
libcalamares.utils.debug("slim selected but not installed")
displaymanagers.remove("slim")
# Setup sddm
if "sddm" in displaymanagers:
if not have_dm("sddm", root_mount_point):
libcalamares.utils.debug("sddm selected but not installed")
displaymanagers.remove("sddm")
# setup lightdm
if "lightdm" in displaymanagers:
if have_dm("lightdm", root_mount_point):
lightdm_conf_path = os.path.join(
root_mount_point, "etc/lightdm/lightdm.conf"
)
if enable_basic_setup:
libcalamares.utils.target_env_call(
['mkdir', '-p', '/run/lightdm']
)
if libcalamares.utils.target_env_call(
['getent', 'group', 'lightdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '620', 'lightdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'lightdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd', '-c',
'"LightDM Display Manager"',
'-u', '620',
'-g', 'lightdm',
'-d', '/var/run/lightdm',
'-s', '/usr/bin/nologin',
'lightdm'
]
)
libcalamares.utils.target_env_call('passwd', '-l', 'lightdm')
libcalamares.utils.target_env_call(
['chown', '-R', 'lightdm:lightdm', '/run/lightdm']
)
libcalamares.utils.target_env_call(
['chmod', '+r' '/etc/lightdm/lightdm.conf']
)
if default_desktop_environment is not None:
os.system(
"sed -i -e \"s/^.*user-session=.*/user-session={!s}/\" "
"{!s}".format(
default_desktop_environment.desktop_file,
lightdm_conf_path
)
)
# configure lightdm-greeter
greeter_path = os.path.join(
root_mount_point, "usr/share/xgreeters"
)
if (os.path.exists(greeter_path)):
# configure first found lightdm-greeter
for entry in os.listdir(greeter_path):
if entry.endswith('.desktop'):
greeter = entry.split('.')[0]
libcalamares.utils.debug(
"found greeter {!s}".format(greeter)
)
os.system(
"sed -i -e \"s/^.*greeter-session=.*"
"/greeter-session={!s}/\" {!s}".format(
greeter,
lightdm_conf_path
)
)
libcalamares.utils.debug(
"{!s} configured as greeter.".format(greeter)
)
break
else:
return ("No lightdm greeter installed.")
else:
libcalamares.utils.debug("lightdm selected but not installed")
displaymanagers.remove("lightdm")
# Setup gdm
if "gdm" in displaymanagers:
if have_dm("gdm", root_mount_point):
if enable_basic_setup:
if libcalamares.utils.target_env_call(
['getent', 'group', 'gdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '120', 'gdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'gdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-c', '"Gnome Display Manager"',
'-u', '120',
'-g', 'gdm',
'-d', '/var/lib/gdm',
'-s', '/usr/bin/nologin',
'gdm'
]
)
libcalamares.utils.target_env_call(
['passwd', '-l', 'gdm']
)
libcalamares.utils.target_env_call(
['chown', '-R', 'gdm:gdm', '/var/lib/gdm']
)
else:
libcalamares.utils.debug("gdm selected but not installed")
displaymanagers.remove("gdm")
# Setup mdm
if "mdm" in displaymanagers:
if have_dm("mdm", root_mount_point):
if enable_basic_setup:
if libcalamares.utils.target_env_call(
['getent', 'group', 'mdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '128', 'mdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'mdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-c', '"Linux Mint Display Manager"',
'-u', '128',
'-g', 'mdm',
'-d', '/var/lib/mdm',
'-s', '/usr/bin/nologin',
'mdm'
]
)
libcalamares.utils.target_env_call(
['passwd', '-l', 'mdm']
)
libcalamares.utils.target_env_call(
['chown', 'root:mdm', '/var/lib/mdm']
)
libcalamares.utils.target_env_call(
['chmod', '1770', '/var/lib/mdm']
)
if default_desktop_environment is not None:
os.system(
"sed -i \"s|default.desktop|{!s}.desktop|g\" "
"{!s}/etc/mdm/custom.conf".format(
default_desktop_environment.desktop_file,
root_mount_point
)
)
else:
libcalamares.utils.debug("mdm selected but not installed")
displaymanagers.remove("mdm")
# Setup lxdm
if "lxdm" in displaymanagers:
if have_dm("lxdm", root_mount_point):
if enable_basic_setup:
if libcalamares.utils.target_env_call(
['getent', 'group', 'lxdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '--system', 'lxdm']
)
libcalamares.utils.target_env_call(
['chgrp', '-R', 'lxdm', '/var/lib/lxdm']
)
libcalamares.utils.target_env_call(
['chgrp', 'lxdm', '/etc/lxdm/lxdm.conf']
)
libcalamares.utils.target_env_call(
['chmod', '+r', '/etc/lxdm/lxdm.conf']
)
if default_desktop_environment is not None:
os.system(
"sed -i -e \"s|^.*session=.*|session={!s}|\" "
"{!s}/etc/lxdm/lxdm.conf".format(
default_desktop_environment.executable,
root_mount_point
)
)
else:
libcalamares.utils.debug("lxdm selected but not installed")
displaymanagers.remove("lxdm")
# Setup kdm
if "kdm" in displaymanagers:
if have_dm("kdm", root_mount_point):
if enable_basic_setup:
if libcalamares.utils.target_env_call(
['getent', 'group', 'kdm']
) != 0:
libcalamares.utils.target_env_call(
['groupadd', '-g', '135', 'kdm']
)
if libcalamares.utils.target_env_call(
['getent', 'passwd', 'kdm']
) != 0:
libcalamares.utils.target_env_call(
['useradd',
'-u', '135',
'-g', 'kdm',
'-d', '/var/lib/kdm',
'-s', '/bin/false',
'-r',
'-M',
'kdm'
]
)
libcalamares.utils.target_env_call(
['chown', '-R', '135:135', 'var/lib/kdm']
)
else:
libcalamares.utils.debug("kdm selected but not installed")
displaymanagers.remove("kdm")
username = libcalamares.globalstorage.value("autologinUser")
if username is not None:
libcalamares.utils.debug(
"Setting up autologin for user {!s}.".format(username)
)
do_autologin = True
libcalamares.utils.debug("Setting up autologin for user {!s}.".format(username))
else:
do_autologin = False
libcalamares.utils.debug("Unsetting autologin.")
libcalamares.globalstorage.insert("displayManagers", displaymanagers)
# Do the actual configuration and collect messages
dm_setup_message = []
for dm in displaymanagers:
dm_message = set_autologin(
username, dm,
default_desktop_environment,
root_mount_point
)
for dm in dm_impl:
dm_message = None
if enable_basic_setup:
dm_message = dm.basic_setup()
if default_desktop_environment is not None and dm_message is None:
dm_message = dm.desktop_environment_setup(default_desktop_environment)
if dm_message is None:
dm_message = dm.greeter_setup()
if dm_message is None:
dm_message = dm.set_autologin(username, do_autologin, default_desktop_environment)
if dm_message is not None:
dm_setup_message.append("{!s}: {!s}".format(*dm_message))
if ("sysconfigSetup" in libcalamares.job.configuration
and libcalamares.job.configuration["sysconfigSetup"]):
set_autologin(username, "sysconfig", None, root_mount_point)
if dm_setup_message:
return ("Display manager configuration was incomplete",
"\n".join(dm_setup_message))
return (
_("Display manager configuration was incomplete"),
"\n".join(dm_setup_message)
)

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for C++ Jobs.
#
# The code is the documentation for the configuration file.
---
syntax: "YAML map of anything"
example:

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for a Python Job Module.
#
# The code is the documentation for the configuration file.
---
syntax: "YAML map of anything"
example:

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for PythonQt.
#
# The code is the documentation for the configuration file.
---
syntax: "YAML map of anything"
example:

View File

@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-16 11:40-0400\n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Guilherme <guimarcalsilva@gmail.com>, 2017\n"
"Last-Translator: Guilherme Marçal Silva <guimarcalsilva@gmail.com>, 2017\n"
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/calamares/teams/20061/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

@ -1,13 +1,28 @@
# Creates /etc/fstab and /etc/crypttab in the target system.
# Also creates mount points for all the filesystems.
#
# When creating fstab entries for a filesystem, this module
# uses the options for the filesystem type to write to the
# options field of the file.
---
# Mount options to use for all filesystems. If a specific filesystem
# is listed here, use those options, otherwise use the *default*
# options from this mapping.
mountOptions:
default: defaults,noatime
btrfs: defaults,noatime,space_cache,autodefrag
# If a filesystem is on an SSD, add the following options. If a specific
# filesystem is listed here, use those options, otherwise no additional
# options are set (i.e. there is no *default* like in *mountOptions*).
ssdExtraMountOptions:
ext4: discard
jfs: discard
xfs: discard
swap: discard
btrfs: discard,compress=lzo
# Additional options added to each line in /etc/crypttab
crypttabOptions: luks
# For Debian and Debian-based distributions, change the above line to:
# crypttabOptions: luks,keyscript=/bin/cat

View File

@ -1,10 +1,22 @@
# Write lines to /etc/default/grub (in the target system) based
# on calculated values and the values set in the *defaults* key
# in this configuration file.
#
# Calculated values are:
# - GRUB_DISTRIBUTOR, branding module, *bootloaderEntryName*
# - GRUB_ENABLE_CRYPTODISK, based on the presence of filesystems
# that use LUKS
# - GRUB_CMDLINE_LINUX_DEFAULT, adding LUKS setup and plymouth
# support to the kernel.
---
# If set to true, always creates /etc/default/grub from scratch even if the file
# already existed. If set to false, edits the existing file instead.
overwrite: false
# Default entries to write to /etc/default/grub if it does not exist yet or if
# we are overwriting it. Note that in addition, GRUB_CMDLINE_LINUX_DEFAULT and
# GRUB_DISTRIBUTOR will always be written, with automatically detected values.
# we are overwriting it.
#
defaults:
GRUB_TIMEOUT: 5
GRUB_DEFAULT: "saved"

View File

@ -62,6 +62,12 @@ def modify_grub_default(partitions, root_mount_point, distributor):
cryptdevice_params = []
# GRUB needs to decrypt the partition that /boot is on, which may be / or /boot
boot_mountpoint = "/"
for partition in partitions:
if partition["mountPoint"] == "/boot":
boot_mountpoint = "/boot"
if have_dracut:
for partition in partitions:
has_luks = "luksMapperName" in partition
@ -72,7 +78,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
swap_outer_uuid = partition["luksUuid"]
swap_outer_mappername = partition["luksMapperName"]
if (partition["mountPoint"] == "/" and has_luks):
if (partition["mountPoint"] == boot_mountpoint and has_luks):
cryptdevice_params = [
"rd.luks.uuid={!s}".format(partition["luksUuid"])
]
@ -82,7 +88,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
if partition["fs"] == "linuxswap" and not has_luks:
swap_uuid = partition["uuid"]
if (partition["mountPoint"] == "/" and has_luks):
if (partition["mountPoint"] == boot_mountpoint and has_luks):
cryptdevice_params = [
"cryptdevice=UUID={!s}:{!s}".format(
partition["luksUuid"], partition["luksMapperName"]

View File

@ -1,2 +1,3 @@
# Run mkinitcpio(8) with the given preset value
---
kernel: linux312

View File

@ -1,2 +1,4 @@
# Writes an openswap configuration with LUKS settings to the given path
---
# Path of the configuration file to write (in the target system)
configFilePath: /etc/openswap.conf

View File

@ -1,4 +1,18 @@
# Mount filesystems in the target (generally, before treating the
# target as a usable chroot / "live" system). Filesystems are
# automatically mounted from the partitioning module. Filesystems
# listed here are **extra**. The filesystems listed in *extraMounts*
# are mounted in all target systems. The filesystems listed in
# *extraMountsEfi* are mounted in the target system **only** if
# the host machine uses UEFI.
---
# Extra filesystems to mount. The key's value is a list of entries; each
# entry has four keys:
# - device The device node to mount
# - fs The filesystem type to use
# - mountPoint Where to mount the filesystem
# - options (optional) Extra options to pass to mount(8)
#
extraMounts:
- device: proc
fs: proc

View File

@ -12,6 +12,10 @@ set_package_properties(
)
if ( KPMcore_FOUND )
if ( KPMcore_VERSION VERSION_GREATER "3.3.0")
add_definitions(-DWITH_KPMCOREGT33) # kpmcore greater than 3.3
endif()
include_directories( ${KPMCORE_INCLUDE_DIR} )
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
@ -35,9 +39,11 @@ if ( KPMcore_FOUND )
gui/BootInfoWidget.cpp
gui/ChoicePage.cpp
gui/CreatePartitionDialog.cpp
gui/CreateVolumeGroupDialog.cpp
gui/DeviceInfoWidget.cpp
gui/EditExistingPartitionDialog.cpp
gui/EncryptWidget.cpp
gui/ListPhysicalVolumeWidgetItem.cpp
gui/PartitionPage.cpp
gui/PartitionBarsView.cpp
gui/PartitionDialogHelpers.cpp
@ -46,17 +52,23 @@ if ( KPMcore_FOUND )
gui/PartitionSplitterWidget.cpp
gui/PartitionViewStep.cpp
gui/PrettyRadioButton.cpp
gui/ResizeVolumeGroupDialog.cpp
gui/ScanningDialog.cpp
gui/ReplaceWidget.cpp
gui/VolumeGroupBaseDialog.cpp
jobs/ClearMountsJob.cpp
jobs/ClearTempMountsJob.cpp
jobs/CreatePartitionJob.cpp
jobs/CreatePartitionTableJob.cpp
jobs/CreateVolumeGroupJob.cpp
jobs/DeactivateVolumeGroupJob.cpp
jobs/DeletePartitionJob.cpp
jobs/FillGlobalStorageJob.cpp
jobs/FormatPartitionJob.cpp
jobs/PartitionJob.cpp
jobs/RemoveVolumeGroupJob.cpp
jobs/ResizePartitionJob.cpp
jobs/ResizeVolumeGroupJob.cpp
jobs/SetPartitionFlagsJob.cpp
UI
gui/ChoicePage.ui
@ -66,6 +78,7 @@ if ( KPMcore_FOUND )
gui/EncryptWidget.ui
gui/PartitionPage.ui
gui/ReplaceWidget.ui
gui/VolumeGroupBaseDialog.ui
LINK_PRIVATE_LIBRARIES
kpmcore
calamaresui

View File

@ -98,8 +98,7 @@ erase(DeviceList& l, DeviceList::iterator& it)
{
Device* p = *it;
auto r = l.erase( it );
if (p)
delete p;
delete p;
return r;
}

View File

@ -29,6 +29,7 @@
// KF5
#include <KFormat>
#include <QStandardItemModel>
#include <QIcon>
// STL
@ -77,10 +78,18 @@ DeviceModel::data( const QModelIndex& index, int role ) const
if ( device->name().isEmpty() )
return device->deviceNode();
else
return tr( "%1 - %2 (%3)" )
.arg( device->name() )
.arg( KFormat().formatByteSize( device->capacity() ) )
.arg( device->deviceNode() );
{
if ( device->logicalSize() >= 0 && device->totalLogical() >= 0 )
return tr( "%1 - %2 (%3)" )
.arg( device->name() )
.arg( KFormat().formatByteSize( device->capacity() ) )
.arg( device->deviceNode() );
// Newly LVM VGs don't have capacity property yet (i.e. always has 1B capacity), so don't show it for a while
else
return tr( "%1 - (%2)" )
.arg( device->name() )
.arg( device->deviceNode() );
}
case Qt::DecorationRole:
return CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionDisk,
CalamaresUtils::Original,
@ -116,3 +125,31 @@ DeviceModel::swapDevice( Device* oldDevice, Device* newDevice )
emit dataChanged( index( indexOfOldDevice ), index( indexOfOldDevice ) );
}
void
DeviceModel::addDevice( Device *device )
{
beginResetModel();
m_devices << device;
std::sort( m_devices.begin(), m_devices.end(), []( const Device* dev1, const Device* dev2 )
{
return dev1->deviceNode() < dev2->deviceNode();
} );
endResetModel();
}
void
DeviceModel::removeDevice( Device *device )
{
beginResetModel();
m_devices.removeAll( device );
std::sort( m_devices.begin(), m_devices.end(), []( const Device* dev1, const Device* dev2 )
{
return dev1->deviceNode() < dev2->deviceNode();
} );
endResetModel();
}

View File

@ -49,6 +49,10 @@ public:
void swapDevice( Device* oldDevice, Device* newDevice );
void addDevice( Device* device );
void removeDevice( Device* device );
private:
QList< Device* > m_devices;
};

View File

@ -90,17 +90,35 @@ swapSuggestion( const qint64 availableSpaceB )
suggestedSwapSizeB *= overestimationFactor;
// don't use more than 10% of available space
qreal maxSwapDiskRatio = 1.10;
qreal maxSwapDiskRatio = 0.10;
qint64 maxSwapSizeB = availableSpaceB * maxSwapDiskRatio;
if ( suggestedSwapSizeB > maxSwapSizeB )
suggestedSwapSizeB = maxSwapSizeB;
}
cDebug() << "Suggested swap size:" << suggestedSwapSizeB / 1024. / 1024. /1024. << "GiB";
cDebug() << "Suggested swap size:" << suggestedSwapSizeB / 1024. / 1024. / 1024. << "GiB";
return suggestedSwapSizeB;
}
constexpr qint64
alignBytesToBlockSize( qint64 bytes, qint64 blocksize )
{
Q_ASSERT( bytes >= 0 );
Q_ASSERT( blocksize > 0 );
qint64 blocks = bytes / blocksize;
Q_ASSERT( blocks >= 0 );
if ( blocks * blocksize != bytes )
++blocks;
return blocks * blocksize;
}
constexpr qint64
bytesToSectors( qint64 bytes, qint64 blocksize )
{
return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1) ) / blocksize;
}
void
doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPassphrase )
@ -114,25 +132,26 @@ doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPass
defaultFsType = "ext4";
// Partition sizes are expressed in MiB, should be multiples of
// the logical sector size (usually 512B).
int uefisys_part_size = 0;
int empty_space_size = 0;
if ( isEfi )
{
uefisys_part_size = 300;
empty_space_size = 2;
}
else
{
// we start with a 1MiB offset before the first partition
empty_space_size = 1;
}
// the logical sector size (usually 512B). EFI starts with 2MiB
// empty and a 300MiB EFI boot partition, while BIOS starts at
// the 1MiB boundary (usually sector 2048).
int uefisys_part_size = isEfi ? 300 : 0;
int empty_space_size = isEfi ? 2 : 1;
qint64 firstFreeSector = MiBtoBytes(empty_space_size) / dev->logicalSize() + 1;
// Since sectors count from 0, if the space is 2048 sectors in size,
// the first free sector has number 2048 (and there are 2048 sectors
// before that one, numbered 0..2047).
qint64 firstFreeSector = bytesToSectors( MiBtoBytes(empty_space_size), dev->logicalSize() );
if ( isEfi )
{
qint64 lastSector = firstFreeSector + ( MiBtoBytes(uefisys_part_size) / dev->logicalSize() );
qint64 efiSectorCount = bytesToSectors( MiBtoBytes(uefisys_part_size), dev->logicalSize() );
Q_ASSERT( efiSectorCount > 0 );
// Since sectors count from 0, and this partition is created starting
// at firstFreeSector, we need efiSectorCount sectors, numbered
// firstFreeSector..firstFreeSector+efiSectorCount-1.
qint64 lastSector = firstFreeSector + efiSectorCount - 1;
core->createPartitionTable( dev, PartitionTable::gpt );
Partition* efiPartition = KPMHelpers::createNewPartition(
dev->partitionTable(),
@ -141,12 +160,12 @@ doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPass
FileSystem::Fat32,
firstFreeSector,
lastSector,
PartitionTable::FlagEsp
PartitionTable::FlagNone
);
PartitionInfo::setFormat( efiPartition, true );
PartitionInfo::setMountPoint( efiPartition, gs->value( "efiSystemPartition" )
.toString() );
core->createPartition( dev, efiPartition, PartitionTable::FlagEsp | PartitionTable::FlagBoot );
core->createPartition( dev, efiPartition, PartitionTable::FlagEsp );
firstFreeSector = lastSector + 1;
}
else
@ -162,8 +181,11 @@ doAutopartition( PartitionCoreModule* core, Device* dev, const QString& luksPass
{
qint64 availableSpaceB = ( dev->totalLogical() - firstFreeSector ) * dev->logicalSize();
suggestedSwapSizeB = swapSuggestion( availableSpaceB );
// Space required by this installation is what the distro claims is needed
// (via global configuration) plus the swap size plus a fudge factor of
// 0.6GiB (this was 2.1GiB up to Calamares 3.2.2).
qint64 requiredSpaceB =
GiBtoBytes( gs->value( "requiredStorageGB" ).toDouble() + 0.1 + 2.0 ) +
GiBtoBytes( gs->value( "requiredStorageGB" ).toDouble() + 0.6 ) +
suggestedSwapSizeB;
// If there is enough room for ESP + root + swap, create swap, otherwise don't.

View File

@ -34,10 +34,14 @@
#include "jobs/ClearTempMountsJob.h"
#include "jobs/CreatePartitionJob.h"
#include "jobs/CreatePartitionTableJob.h"
#include "jobs/CreateVolumeGroupJob.h"
#include "jobs/DeactivateVolumeGroupJob.h"
#include "jobs/DeletePartitionJob.h"
#include "jobs/FillGlobalStorageJob.h"
#include "jobs/FormatPartitionJob.h"
#include "jobs/RemoveVolumeGroupJob.h"
#include "jobs/ResizePartitionJob.h"
#include "jobs/ResizeVolumeGroupJob.h"
#include "jobs/SetPartitionFlagsJob.h"
#include "Typedefs.h"
@ -45,10 +49,13 @@
// KPMcore
#include <kpmcore/core/device.h>
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/backend/corebackend.h>
#include <kpmcore/backend/corebackendmanager.h>
#include <kpmcore/fs/filesystemfactory.h>
#include <kpmcore/fs/luks.h>
#include <kpmcore/fs/lvm2_pv.h>
// Qt
#include <QStandardItemModel>
@ -57,11 +64,44 @@
#include <QFutureWatcher>
#include <QtConcurrent/QtConcurrent>
PartitionCoreModule::RefreshHelper::RefreshHelper(PartitionCoreModule* module)
: m_module( module )
{
}
PartitionCoreModule::RefreshHelper::~RefreshHelper()
{
m_module->refreshAfterModelChange();
}
class OperationHelper
{
public:
OperationHelper( PartitionModel* model, PartitionCoreModule* core )
: m_coreHelper( core )
, m_modelHelper( model )
{
}
OperationHelper( const OperationHelper& ) = delete;
OperationHelper& operator=( const OperationHelper& ) = delete;
private:
// Keep these in order: first the model needs to finish,
// then refresh is called. Remember that destructors are
// called in *reverse* order of declaration in this class.
PartitionCoreModule::RefreshHelper m_coreHelper;
PartitionModel::ResetHelper m_modelHelper;
} ;
//- DeviceInfo ---------------------------------------------
PartitionCoreModule::DeviceInfo::DeviceInfo( Device* _device )
: device( _device )
, partitionModel( new PartitionModel )
, immutableDevice( new Device( *_device ) )
, isAvailable( true )
{}
PartitionCoreModule::DeviceInfo::~DeviceInfo()
@ -178,6 +218,8 @@ PartitionCoreModule::doInit()
m_bootLoaderModel->init( bootLoaderDevices );
scanForLVMPVs();
//FIXME: this should be removed in favor of
// proper KPM support for EFI
if ( PartUtils::isEfiSystem() )
@ -232,13 +274,11 @@ PartitionCoreModule::createPartitionTable( Device* device, PartitionTable::Table
// keep previous changes
info->forgetChanges();
PartitionModel::ResetHelper helper( partitionModelForDevice( device ) );
OperationHelper helper( partitionModelForDevice( device ), this );
CreatePartitionTableJob* job = new CreatePartitionTableJob( device, type );
job->updatePreview();
info->jobs << Calamares::job_ptr( job );
}
refresh();
}
void
@ -249,7 +289,7 @@ PartitionCoreModule::createPartition( Device* device,
auto deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
PartitionModel::ResetHelper helper( partitionModelForDevice( device ) );
OperationHelper helper( partitionModelForDevice( device ), this );
CreatePartitionJob* job = new CreatePartitionJob( device, partition );
job->updatePreview();
@ -261,8 +301,77 @@ PartitionCoreModule::createPartition( Device* device,
deviceInfo->jobs << Calamares::job_ptr( fJob );
PartitionInfo::setFlags( partition, flags );
}
}
refresh();
void
PartitionCoreModule::createVolumeGroup( QString &vgName,
QVector< const Partition* > pvList,
qint32 peSize )
{
// Appending '_' character in case of repeated VG name
while ( hasVGwithThisName( vgName ) )
vgName.append('_');
CreateVolumeGroupJob* job = new CreateVolumeGroupJob( vgName, pvList, peSize );
job->updatePreview();
LvmDevice* device = new LvmDevice(vgName);
for ( const Partition* p : pvList )
device->physicalVolumes() << p;
DeviceInfo* deviceInfo = new DeviceInfo( device );
deviceInfo->partitionModel->init( device, osproberEntries() );
m_deviceModel->addDevice( device );
m_deviceInfos << deviceInfo;
deviceInfo->jobs << Calamares::job_ptr( job );
refreshAfterModelChange();
}
void
PartitionCoreModule::resizeVolumeGroup( LvmDevice *device, QVector< const Partition* >& pvList )
{
DeviceInfo* deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
ResizeVolumeGroupJob* job = new ResizeVolumeGroupJob( device, pvList );
deviceInfo->jobs << Calamares::job_ptr( job );
refreshAfterModelChange();
}
void
PartitionCoreModule::deactivateVolumeGroup( LvmDevice *device )
{
DeviceInfo* deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
deviceInfo->isAvailable = false;
DeactivateVolumeGroupJob* job = new DeactivateVolumeGroupJob( device );
// DeactivateVolumeGroupJob needs to be immediately called
job->exec();
refreshAfterModelChange();
}
void
PartitionCoreModule::removeVolumeGroup( LvmDevice *device )
{
DeviceInfo* deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
RemoveVolumeGroupJob* job = new RemoveVolumeGroupJob( device );
deviceInfo->jobs << Calamares::job_ptr( job );
refreshAfterModelChange();
}
void
@ -271,7 +380,7 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition )
auto deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
PartitionModel::ResetHelper helper( partitionModelForDevice( device ) );
OperationHelper helper( partitionModelForDevice( device ), this );
if ( partition->roles().has( PartitionRole::Extended ) )
{
@ -339,8 +448,6 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition )
job->updatePreview();
jobs << Calamares::job_ptr( job );
}
refresh();
}
void
@ -348,12 +455,10 @@ PartitionCoreModule::formatPartition( Device* device, Partition* partition )
{
auto deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
PartitionModel::ResetHelper helper( partitionModelForDevice( device ) );
OperationHelper helper( partitionModelForDevice( device ), this );
FormatPartitionJob* job = new FormatPartitionJob( device, partition );
deviceInfo->jobs << Calamares::job_ptr( job );
refresh();
}
void
@ -364,13 +469,11 @@ PartitionCoreModule::resizePartition( Device* device,
{
auto deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
PartitionModel::ResetHelper helper( partitionModelForDevice( device ) );
OperationHelper helper( partitionModelForDevice( device ), this );
ResizePartitionJob* job = new ResizePartitionJob( device, partition, first, last );
job->updatePreview();
deviceInfo->jobs << Calamares::job_ptr( job );
refresh();
}
void
@ -380,13 +483,11 @@ PartitionCoreModule::setPartitionFlags( Device* device,
{
auto deviceInfo = infoForDevice( device );
Q_ASSERT( deviceInfo );
PartitionModel::ResetHelper( partitionModelForDevice( device ) );
OperationHelper( partitionModelForDevice( device ), this );
SetPartFlagsJob* job = new SetPartFlagsJob( device, partition, flags );
deviceInfo->jobs << Calamares::job_ptr( job );
PartitionInfo::setFlags( partition, flags );
refresh();
}
QList< Calamares::job_ptr >
@ -435,6 +536,37 @@ PartitionCoreModule::efiSystemPartitions() const
return m_efiSystemPartitions;
}
QVector< const Partition* >
PartitionCoreModule::lvmPVs() const
{
return m_lvmPVs;
}
bool
PartitionCoreModule::hasVGwithThisName( const QString& name ) const
{
for ( DeviceInfo* d : m_deviceInfos )
if ( dynamic_cast<LvmDevice*>(d->device.data()) &&
d->device.data()->name() == name)
return true;
return false;
}
bool
PartitionCoreModule::isInVG( const Partition *partition ) const
{
for ( DeviceInfo* d : m_deviceInfos )
{
LvmDevice* vg = dynamic_cast<LvmDevice*>( d->device.data() );
if ( vg && vg->physicalVolumes().contains( partition ))
return true;
}
return false;
}
void
PartitionCoreModule::dumpQueue() const
{
@ -462,18 +594,18 @@ PartitionCoreModule::refreshPartition( Device* device, Partition* )
// the loss of the current selection.
auto model = partitionModelForDevice( device );
Q_ASSERT( model );
PartitionModel::ResetHelper helper( model );
refresh();
OperationHelper helper( model, this );
}
void
PartitionCoreModule::refresh()
PartitionCoreModule::refreshAfterModelChange()
{
updateHasRootMountPoint();
updateIsDirty();
m_bootLoaderModel->update();
scanForLVMPVs();
//FIXME: this should be removed in favor of
// proper KPM support for EFI
if ( PartUtils::isEfiSystem() )
@ -526,6 +658,84 @@ PartitionCoreModule::scanForEfiSystemPartitions()
m_efiSystemPartitions = efiSystemPartitions;
}
void
PartitionCoreModule::scanForLVMPVs()
{
m_lvmPVs.clear();
QList< Device* > physicalDevices;
QList< LvmDevice* > vgDevices;
for ( DeviceInfo* deviceInfo : m_deviceInfos )
{
if ( deviceInfo->device.data()->type() == Device::Type::Disk_Device)
physicalDevices << deviceInfo->device.data();
else if ( deviceInfo->device.data()->type() == Device::Type::LVM_Device )
{
LvmDevice* device = dynamic_cast<LvmDevice*>(deviceInfo->device.data());
// Restoring physical volume list
device->physicalVolumes().clear();
vgDevices << device;
}
}
// Update LVM::pvList
LvmDevice::scanSystemLVM( physicalDevices );
#ifdef WITH_KPMCOREGT33
for ( auto p : LVM::pvList::list() )
#else
for ( auto p : LVM::pvList )
#endif
{
m_lvmPVs << p.partition().data();
for ( LvmDevice* device : vgDevices )
if ( p.vgName() == device->name() )
{
// Adding scanned VG to PV list
device->physicalVolumes() << p.partition();
break;
}
}
for ( DeviceInfo* d : m_deviceInfos )
{
for ( auto job : d->jobs )
{
// Including new LVM PVs
CreatePartitionJob* partJob = dynamic_cast<CreatePartitionJob*>( job.data() );
if ( partJob )
{
Partition* p = partJob->partition();
if ( p->fileSystem().type() == FileSystem::Type::Lvm2_PV )
m_lvmPVs << p;
else if ( p->fileSystem().type() == FileSystem::Type::Luks )
{
// Encrypted LVM PVs
FileSystem* innerFS = static_cast<const FS::luks*>(&p->fileSystem())->innerFS();
if ( innerFS && innerFS->type() == FileSystem::Type::Lvm2_PV )
m_lvmPVs << p;
}
#ifdef WITH_KPMCOREGT33
else if ( p->fileSystem().type() == FileSystem::Type::Luks2 )
{
// Encrypted LVM PVs
FileSystem* innerFS = static_cast<const FS::luks*>(&p->fileSystem())->innerFS();
if ( innerFS && innerFS->type() == FileSystem::Type::Lvm2_PV )
m_lvmPVs << p;
}
#endif
}
}
}
}
PartitionCoreModule::DeviceInfo*
PartitionCoreModule::infoForDevice( const Device* device ) const
{
@ -575,9 +785,37 @@ PartitionCoreModule::revert()
void
PartitionCoreModule::revertAllDevices()
{
foreach ( DeviceInfo* devInfo, m_deviceInfos )
revertDevice( devInfo->device.data() );
refresh();
for ( auto it = m_deviceInfos.begin(); it != m_deviceInfos.end(); )
{
// In new VGs device info, there will be always a CreateVolumeGroupJob as the first job in jobs list
if ( dynamic_cast<LvmDevice*>( ( *it )->device.data() ) )
{
( *it )->isAvailable = true;
if ( !( *it )->jobs.empty() )
{
CreateVolumeGroupJob* vgJob = dynamic_cast<CreateVolumeGroupJob*>( ( *it )->jobs[0].data() );
if ( vgJob )
{
vgJob->undoPreview();
( *it )->forgetChanges();
m_deviceModel->removeDevice( ( *it )->device.data() );
it = m_deviceInfos.erase( it );
continue;
}
}
}
revertDevice( ( *it )->device.data() );
++it;
}
refreshAfterModelChange();
}
@ -586,6 +824,7 @@ PartitionCoreModule::revertDevice( Device* dev )
{
QMutexLocker locker( &m_revertMutex );
DeviceInfo* devInfo = infoForDevice( dev );
if ( !devInfo )
return;
devInfo->forgetChanges();
@ -597,12 +836,17 @@ PartitionCoreModule::revertDevice( Device* dev )
m_deviceModel->swapDevice( dev, newDev );
QList< Device* > devices;
foreach ( auto info, m_deviceInfos )
devices.append( info->device.data() );
for ( auto info : m_deviceInfos )
{
if ( info->device.data()->type() != Device::Type::Disk_Device )
continue;
else
devices.append( info->device.data() );
}
m_bootLoaderModel->init( devices );
refresh();
refreshAfterModelChange();
emit deviceReverted( newDev );
}
@ -638,6 +882,16 @@ PartitionCoreModule::isDirty()
return m_isDirty;
}
bool
PartitionCoreModule::isVGdeactivated( LvmDevice *device )
{
for ( DeviceInfo* deviceInfo : m_deviceInfos )
if ( device == deviceInfo->device.data() && !deviceInfo->isAvailable )
return true;
return false;
}
QList< PartitionCoreModule::SummaryInfo >
PartitionCoreModule::createSummaryInfo() const
{

View File

@ -24,6 +24,7 @@
#include "Typedefs.h"
// KPMcore
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/core/partitiontable.h>
// Qt
@ -53,6 +54,25 @@ class PartitionCoreModule : public QObject
{
Q_OBJECT
public:
/**
* This helper class calls refresh() on the module
* on destruction (nothing else). It is used as
* part of the model-consistency objects, along with
* PartitionModel::ResetHelper.
*/
class RefreshHelper
{
public:
RefreshHelper( PartitionCoreModule* module );
~RefreshHelper();
RefreshHelper( const RefreshHelper& ) = delete;
RefreshHelper& operator=( const RefreshHelper& ) = delete;
private:
PartitionCoreModule* m_module;
};
/**
* @brief The SummaryInfo struct is a wrapper for PartitionModel instances for
* a given Device.
@ -111,6 +131,14 @@ public:
void createPartition( Device* device, Partition* partition,
PartitionTable::Flags flags = PartitionTable::FlagNone );
void createVolumeGroup( QString &vgName, QVector< const Partition* > pvList, qint32 peSize );
void resizeVolumeGroup( LvmDevice* device, QVector< const Partition* >& pvList );
void deactivateVolumeGroup( LvmDevice* device );
void removeVolumeGroup( LvmDevice* device );
void deletePartition( Device* device, Partition* partition );
void formatPartition( Device* device, Partition* partition );
@ -132,6 +160,12 @@ public:
QList< Partition* > efiSystemPartitions() const;
QVector< const Partition* > lvmPVs() const;
bool hasVGwithThisName( const QString& name ) const;
bool isInVG( const Partition* partition ) const;
/**
* @brief findPartitionByMountPoint returns a Partition* for a given mount point.
* @param mountPoint the mount point to find a partition for.
@ -151,6 +185,8 @@ public:
bool isDirty(); // true if there are pending changes, otherwise false
bool isVGdeactivated( LvmDevice* device );
/**
* To be called when a partition has been altered, but only for changes
* which do not affect its size, because changes which affect the partition size
@ -175,7 +211,7 @@ Q_SIGNALS:
void deviceReverted( Device* device );
private:
void refresh();
void refreshAfterModelChange();
/**
* Owns the Device, PartitionModel and the jobs
@ -189,11 +225,15 @@ private:
const QScopedPointer< Device > immutableDevice;
QList< Calamares::job_ptr > jobs;
// To check if LVM VGs are deactivated
bool isAvailable;
void forgetChanges();
bool isDirty() const;
};
QList< DeviceInfo* > m_deviceInfos;
QList< Partition* > m_efiSystemPartitions;
QVector< const Partition* > m_lvmPVs;
DeviceModel* m_deviceModel;
BootLoaderModel* m_bootLoaderModel;
@ -205,6 +245,7 @@ private:
void updateHasRootMountPoint();
void updateIsDirty();
void scanForEfiSystemPartitions();
void scanForLVMPVs();
DeviceInfo* infoForDevice( const Device* ) const;

View File

@ -20,6 +20,7 @@
#include "core/PartitionInfo.h"
// KPMcore
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/core/partition.h>
// Qt
@ -80,6 +81,9 @@ reset( Partition* partition )
bool
isDirty( Partition* partition )
{
if ( LvmDevice::s_DirtyPVs.contains( partition ) )
return true;
return !mountPoint( partition ).isEmpty()
|| format( partition )
|| flags( partition ) != partition->activeFlags();

View File

@ -0,0 +1,56 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "CreateVolumeGroupDialog.h"
#include <kpmcore/core/device.h>
#include <kpmcore/core/lvmdevice.h>
#include <QComboBox>
#include <QLineEdit>
#include <QSpinBox>
CreateVolumeGroupDialog::CreateVolumeGroupDialog( QString& vgName,
QVector< const Partition* >& selectedPVs,
QVector< const Partition* > pvList,
qint64& pSize,
QWidget* parent )
: VolumeGroupBaseDialog( vgName, pvList, parent )
, m_selectedPVs( selectedPVs )
, m_peSize( pSize )
{
setWindowTitle( "Create Volume Group" );
peSize()->setValue( pSize );
vgType()->setEnabled( false );
}
void
CreateVolumeGroupDialog::accept()
{
QString& name = vgNameValue();
name = vgName()->text();
m_selectedPVs << checkedItems();
qint64& pe = m_peSize;
pe = peSize()->value();
QDialog::accept();
}

View File

@ -0,0 +1,41 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 CREATEVOLUMEGROUPDIALOG_H
#define CREATEVOLUMEGROUPDIALOG_H
#include "gui/VolumeGroupBaseDialog.h"
class CreateVolumeGroupDialog : public VolumeGroupBaseDialog
{
public:
CreateVolumeGroupDialog( QString& vgName,
QVector< const Partition* >& selectedPVs,
QVector< const Partition* > pvList,
qint64& pSize,
QWidget* parent );
void accept() override;
private:
QVector< const Partition* >& m_selectedPVs;
qint64& m_peSize;
};
#endif // CREATEVOLUMEGROUPDIALOG_H

View File

@ -0,0 +1,36 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "ListPhysicalVolumeWidgetItem.h"
#include <kpmcore/util/capacity.h>
ListPhysicalVolumeWidgetItem::ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked )
: QListWidgetItem(QString("%1 | %2").arg( partition->deviceNode(), Capacity::formatByteSize( partition->capacity() )))
, m_partition(partition)
{
setToolTip( partition->deviceNode() );
setSizeHint( QSize(0, 32) );
setCheckState( checked ? Qt::Checked : Qt::Unchecked );
}
const Partition*
ListPhysicalVolumeWidgetItem::partition() const
{
return m_partition;
}

View File

@ -0,0 +1,37 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 LISTPHYSICALVOLUMEWIDGETITEM_H
#define LISTPHYSICALVOLUMEWIDGETITEM_H
#include <kpmcore/core/partition.h>
#include <QListWidgetItem>
class ListPhysicalVolumeWidgetItem : public QListWidgetItem
{
public:
ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked );
const Partition* partition() const;
private:
const Partition* m_partition;
};
#endif // LISTPHYSICALVOLUMEWIDGETITEM_H

View File

@ -30,7 +30,9 @@
#include "core/PartUtils.h"
#include "core/KPMHelpers.h"
#include "gui/CreatePartitionDialog.h"
#include "gui/CreateVolumeGroupDialog.h"
#include "gui/EditExistingPartitionDialog.h"
#include "gui/ResizeVolumeGroupDialog.h"
#include "gui/ScanningDialog.h"
#include "ui_PartitionPage.h"
@ -45,6 +47,8 @@
// KPMcore
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
#include <kpmcore/ops/removevolumegroupoperation.h>
// Qt
#include <QDebug>
@ -102,6 +106,10 @@ PartitionPage::PartitionPage( PartitionCoreModule* core, QWidget* parent )
connect( m_ui->partitionTreeView, &QAbstractItemView::doubleClicked, this, &PartitionPage::onPartitionViewActivated );
connect( m_ui->revertButton, &QAbstractButton::clicked, this, &PartitionPage::onRevertClicked );
connect( m_ui->newVolumeGroupButton, &QAbstractButton::clicked, this, &PartitionPage::onNewVolumeGroupClicked );
connect( m_ui->resizeVolumeGroupButton, &QAbstractButton::clicked, this, &PartitionPage::onResizeVolumeGroupClicked );
connect( m_ui->deactivateVolumeGroupButton, &QAbstractButton::clicked, this, &PartitionPage::onDeactivateVolumeGroupClicked );
connect( m_ui->removeVolumeGroupButton, &QAbstractButton::clicked, this, &PartitionPage::onRemoveVolumeGroupClicked );
connect( m_ui->newPartitionTableButton, &QAbstractButton::clicked, this, &PartitionPage::onNewPartitionTableClicked );
connect( m_ui->createButton, &QAbstractButton::clicked, this, &PartitionPage::onCreateClicked );
connect( m_ui->editButton, &QAbstractButton::clicked, this, &PartitionPage::onEditClicked );
@ -122,7 +130,8 @@ PartitionPage::~PartitionPage()
void
PartitionPage::updateButtons()
{
bool create = false, createTable = false, edit = false, del = false;
bool create = false, createTable = false, edit = false, del = false, currentDeviceIsVG = false, isDeactivable = false;
bool isRemovable = false, isVGdeactivated = false;
QModelIndex index = m_ui->partitionTreeView->currentIndex();
if ( index.isValid() )
@ -134,6 +143,8 @@ PartitionPage::updateButtons()
bool isFree = KPMHelpers::isPartitionFreeSpace( partition );
bool isExtended = partition->roles().has( PartitionRole::Extended );
bool isInVG = m_core->isInVG( partition );
create = isFree;
// Keep it simple for now: do not support editing extended partitions as
// it does not work with our current edit implementation which is
@ -141,8 +152,9 @@ PartitionPage::updateButtons()
// because they need to be created *before* creating logical partitions
// inside them, so an edit must be applied without altering the job
// order.
// TODO: See if LVM PVs can be edited in Calamares
edit = !isFree && !isExtended;
del = !isFree;
del = !isFree && !isInVG;
}
if ( m_ui->deviceComboBox->currentIndex() >= 0 )
@ -150,12 +162,29 @@ PartitionPage::updateButtons()
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
if ( m_core->deviceModel()->deviceForIndex( deviceIndex )->type() != Device::Type::LVM_Device )
createTable = true;
else
{
currentDeviceIsVG = true;
LvmDevice* lvmDevice = dynamic_cast<LvmDevice*>(m_core->deviceModel()->deviceForIndex( deviceIndex ));
isDeactivable = DeactivateVolumeGroupOperation::isDeactivatable( lvmDevice );
isRemovable = RemoveVolumeGroupOperation::isRemovable( lvmDevice );
isVGdeactivated = m_core->isVGdeactivated( lvmDevice );
if ( isVGdeactivated )
m_ui->revertButton->setEnabled( true );
}
}
m_ui->createButton->setEnabled( create );
m_ui->editButton->setEnabled( edit );
m_ui->deleteButton->setEnabled( del );
m_ui->newPartitionTableButton->setEnabled( createTable );
m_ui->resizeVolumeGroupButton->setEnabled( currentDeviceIsVG && !isVGdeactivated );
m_ui->deactivateVolumeGroupButton->setEnabled( currentDeviceIsVG && isDeactivable && !isVGdeactivated );
m_ui->removeVolumeGroupButton->setEnabled( currentDeviceIsVG && isRemovable );
}
void
@ -204,6 +233,114 @@ PartitionPage::checkCanCreate( Device* device )
return true; // GPT is fine
}
void
PartitionPage::onNewVolumeGroupClicked()
{
QString vgName;
QVector< const Partition* > selectedPVs;
qint64 peSize = 4;
QVector< const Partition* > availablePVs;
for ( const Partition* p : m_core->lvmPVs() )
if ( !m_core->isInVG( p ) )
availablePVs << p;
QPointer< CreateVolumeGroupDialog > dlg = new CreateVolumeGroupDialog( vgName,
selectedPVs,
availablePVs,
peSize,
this );
if ( dlg->exec() == QDialog::Accepted )
{
QModelIndex partitionIndex = m_ui->partitionTreeView->currentIndex();
if ( partitionIndex.isValid() )
{
const PartitionModel* model = static_cast< const PartitionModel* >( partitionIndex.model() );
Q_ASSERT( model );
Partition* partition = model->partitionForIndex( partitionIndex );
Q_ASSERT( partition );
// Disable delete button if current partition was selected to be in VG
// TODO: Should Calamares edit LVM PVs which are in VGs?
if ( selectedPVs.contains( partition ) )
m_ui->deleteButton->setEnabled( false );
}
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
Q_ASSERT( deviceIndex.isValid() );
QVariant previousIndexDeviceData = m_core->deviceModel()->data( deviceIndex, Qt::ToolTipRole );
// Creating new VG
m_core->createVolumeGroup( vgName, selectedPVs, peSize );
// As createVolumeGroup method call resets deviceModel,
// is needed to set the current index in deviceComboBox as the previous one
int previousIndex = m_ui->deviceComboBox->findData( previousIndexDeviceData, Qt::ToolTipRole );
m_ui->deviceComboBox->setCurrentIndex( ( previousIndex < 0 ) ? 0 : previousIndex );
updateFromCurrentDevice();
}
delete dlg;
}
void
PartitionPage::onResizeVolumeGroupClicked()
{
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
LvmDevice* device = dynamic_cast< LvmDevice* >( m_core->deviceModel()->deviceForIndex( deviceIndex ) );
Q_ASSERT( device && device->type() == Device::Type::LVM_Device );
QVector< const Partition* > availablePVs;
QVector< const Partition* > selectedPVs;
for ( const Partition* p : m_core->lvmPVs() )
if ( !m_core->isInVG( p ) )
availablePVs << p;
QPointer< ResizeVolumeGroupDialog > dlg = new ResizeVolumeGroupDialog( device,
availablePVs,
selectedPVs,
this );
if ( dlg->exec() == QDialog::Accepted )
m_core->resizeVolumeGroup( device, selectedPVs );
delete dlg;
}
void
PartitionPage::onDeactivateVolumeGroupClicked()
{
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
LvmDevice* device = dynamic_cast< LvmDevice* >( m_core->deviceModel()->deviceForIndex( deviceIndex ) );
Q_ASSERT( device && device->type() == Device::Type::LVM_Device );
m_core->deactivateVolumeGroup( device );
updateFromCurrentDevice();
PartitionModel* model = m_core->partitionModelForDevice( device );
model->update();
}
void
PartitionPage::onRemoveVolumeGroupClicked()
{
QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 );
LvmDevice* device = dynamic_cast< LvmDevice* >( m_core->deviceModel()->deviceForIndex( deviceIndex ) );
Q_ASSERT( device && device->type() == Device::Type::LVM_Device );
m_core->removeVolumeGroup( device );
}
void
PartitionPage::onCreateClicked()
{
@ -272,7 +409,7 @@ PartitionPage::onRevertClicked()
int oldIndex = m_ui->deviceComboBox->currentIndex();
m_core->revertAllDevices();
m_ui->deviceComboBox->setCurrentIndex( oldIndex );
m_ui->deviceComboBox->setCurrentIndex( ( oldIndex < 0 ) ? 0 : oldIndex );
updateFromCurrentDevice();
} ),
[ this ]{

View File

@ -51,6 +51,10 @@ private:
PartitionCoreModule* m_core;
void updateButtons();
void onNewPartitionTableClicked();
void onNewVolumeGroupClicked();
void onResizeVolumeGroupClicked();
void onDeactivateVolumeGroupClicked();
void onRemoveVolumeGroupClicked();
void onCreateClicked();
void onEditClicked();
void onDeleteClicked();

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>655</width>
<width>684</width>
<height>304</height>
</rect>
</property>
@ -124,6 +124,38 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="newVolumeGroupButton">
<property name="text">
<string>New Volume Group</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="resizeVolumeGroupButton">
<property name="text">
<string>Resize Volume Group</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deactivateVolumeGroupButton">
<property name="text">
<string>Deactivate Volume Group</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeVolumeGroupButton">
<property name="text">
<string>Remove Volume Group</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@ -145,7 +177,7 @@
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Install boot &amp;loader on:</string>
<string>I&amp;nstall boot loader on:</string>
</property>
<property name="buddy">
<cstring>bootLoaderComboBox</cstring>

View File

@ -0,0 +1,62 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "ResizeVolumeGroupDialog.h"
#include "gui/ListPhysicalVolumeWidgetItem.h"
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/util/capacity.h>
#include <QComboBox>
#include <QLineEdit>
#include <QListWidgetItem>
#include <QSpinBox>
ResizeVolumeGroupDialog::ResizeVolumeGroupDialog( LvmDevice *device,
QVector< const Partition* > availablePVs,
QVector< const Partition* >& selectedPVs,
QWidget* parent )
: VolumeGroupBaseDialog( device->name(), device->physicalVolumes(), parent )
, m_selectedPVs( selectedPVs )
{
setWindowTitle( "Resize Volume Group" );
for ( int i = 0; i < pvList()->count(); i++ )
pvList()->item(i)->setCheckState( Qt::Checked );
for ( const Partition* p : availablePVs )
pvList()->addItem( new ListPhysicalVolumeWidgetItem( p, false ) );
peSize()->setValue( device->peSize() / Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::MiB) );
vgName()->setEnabled( false );
peSize()->setEnabled( false );
vgType()->setEnabled( false );
setUsedSizeValue( device->allocatedPE() * device->peSize() );
setLVQuantity( device->partitionTable()->children().count() );
}
void
ResizeVolumeGroupDialog::accept()
{
m_selectedPVs << checkedItems();
QDialog::accept();
}

View File

@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 RESIZEVOLUMEGROUPDIALOG_H
#define RESIZEVOLUMEGROUPDIALOG_H
#include "gui/VolumeGroupBaseDialog.h"
class LvmDevice;
class ResizeVolumeGroupDialog : public VolumeGroupBaseDialog
{
public:
ResizeVolumeGroupDialog( LvmDevice *device,
QVector< const Partition* > availablePVs,
QVector< const Partition* >& selectedPVs,
QWidget* parent );
void accept() override;
private:
QVector< const Partition* >& m_selectedPVs;
};
#endif // RESIZEVOLUMEGROUPDIALOG_H

View File

@ -0,0 +1,184 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "VolumeGroupBaseDialog.h"
#include "ui_VolumeGroupBaseDialog.h"
#include "gui/ListPhysicalVolumeWidgetItem.h"
#include <kpmcore/util/capacity.h>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
VolumeGroupBaseDialog::VolumeGroupBaseDialog( QString& vgName,
QVector< const Partition* > pvList,
QWidget *parent )
: QDialog(parent)
, ui(new Ui::VolumeGroupBaseDialog)
, m_vgNameValue(vgName)
, m_totalSizeValue(0)
, m_usedSizeValue(0)
{
ui->setupUi(this);
for ( const Partition* p : pvList )
ui->pvList->addItem( new ListPhysicalVolumeWidgetItem( p, false ) );
ui->vgType->addItems( QStringList() << "LVM" << "RAID" );
ui->vgType->setCurrentIndex(0);
QRegularExpression re(R"(^(?!_|\.)[\w\-.+]+)");
ui->vgName->setValidator( new QRegularExpressionValidator( re, this ) );
ui->vgName->setText( m_vgNameValue );
updateOkButton();
updateTotalSize();
connect( ui->pvList, &QListWidget::itemChanged, this,
[&](QListWidgetItem*) {
updateTotalSize();
updateOkButton();
} );
connect( ui->peSize, qOverload<int>(&QSpinBox::valueChanged), this,
[&](int) {
updateTotalSectors();
updateOkButton();
});
connect( ui->vgName, &QLineEdit::textChanged, this,
[&](const QString&) {
updateOkButton();
});
}
VolumeGroupBaseDialog::~VolumeGroupBaseDialog()
{
delete ui;
}
QVector< const Partition* >
VolumeGroupBaseDialog::checkedItems() const
{
QVector< const Partition* > items;
for ( int i = 0; i < ui->pvList->count(); i++) {
ListPhysicalVolumeWidgetItem* item = dynamic_cast< ListPhysicalVolumeWidgetItem* >( ui->pvList->item(i) );
if ( item && item->checkState() == Qt::Checked )
items << item->partition();
}
return items;
}
bool
VolumeGroupBaseDialog::isSizeValid() const
{
return m_totalSizeValue >= m_usedSizeValue;
}
void
VolumeGroupBaseDialog::updateOkButton()
{
okButton()->setEnabled(isSizeValid() &&
!checkedItems().empty() &&
!ui->vgName->text().isEmpty() &&
ui->peSize->value() > 0);
}
void
VolumeGroupBaseDialog::setUsedSizeValue( qint64 usedSize )
{
m_usedSizeValue = usedSize;
ui->usedSize->setText( Capacity::formatByteSize(m_usedSizeValue) );
}
void
VolumeGroupBaseDialog::setLVQuantity( qint32 lvQuantity )
{
ui->lvQuantity->setText( QString::number( lvQuantity ) );
}
void
VolumeGroupBaseDialog::updateTotalSize()
{
m_totalSizeValue = 0;
for ( const Partition *p : checkedItems())
m_totalSizeValue += p->capacity() - p->capacity() % (ui->peSize->value() * Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::MiB));
ui->totalSize->setText(Capacity::formatByteSize(m_totalSizeValue));
updateTotalSectors();
}
void
VolumeGroupBaseDialog::updateTotalSectors()
{
qint32 totalSectors = 0;
qint32 extentSize = ui->peSize->value() * Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::MiB);
if ( extentSize > 0 )
totalSectors = m_totalSizeValue / extentSize;
ui->totalSectors->setText( QString::number( totalSectors ) );
}
QString&
VolumeGroupBaseDialog::vgNameValue() const
{
return m_vgNameValue;
}
QLineEdit*
VolumeGroupBaseDialog::vgName() const
{
return ui->vgName;
}
QComboBox*
VolumeGroupBaseDialog::vgType() const
{
return ui->vgType;
}
QSpinBox*
VolumeGroupBaseDialog::peSize() const
{
return ui->peSize;
}
QListWidget*
VolumeGroupBaseDialog::pvList() const
{
return ui->pvList;
}
QPushButton*
VolumeGroupBaseDialog::okButton() const
{
return ui->buttonBox->button( QDialogButtonBox::StandardButton::Ok );
}

View File

@ -0,0 +1,81 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 VOLUMEGROUPBASEDIALOG_H
#define VOLUMEGROUPBASEDIALOG_H
#include <kpmcore/core/partition.h>
#include <QDialog>
namespace Ui {
class VolumeGroupBaseDialog;
}
class QComboBox;
class QLineEdit;
class QListWidget;
class QSpinBox;
class VolumeGroupBaseDialog : public QDialog
{
Q_OBJECT
public:
explicit VolumeGroupBaseDialog( QString& vgName,
QVector< const Partition* > pvList,
QWidget* parent = nullptr );
~VolumeGroupBaseDialog();
protected:
virtual void updateOkButton();
void setUsedSizeValue( qint64 usedSize );
void setLVQuantity( qint32 lvQuantity );
void updateTotalSize();
void updateTotalSectors();
QVector< const Partition* > checkedItems() const;
bool isSizeValid() const;
QString& vgNameValue() const;
QLineEdit* vgName() const;
QComboBox* vgType() const;
QSpinBox* peSize() const;
QListWidget* pvList() const;
QPushButton* okButton() const;
private:
Ui::VolumeGroupBaseDialog* ui;
QString& m_vgNameValue;
qint64 m_totalSizeValue;
qint64 m_usedSizeValue;
};
#endif // VOLUMEGROUPBASEDIALOG_H

View File

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VolumeGroupBaseDialog</class>
<widget class="QDialog" name="VolumeGroupBaseDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>367</height>
</rect>
</property>
<property name="windowTitle">
<string>VolumeGroupDialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="pvListLabel">
<property name="text">
<string>List of Physical Volumes</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="7">
<widget class="QListWidget" name="pvList"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="vgNameLabel">
<property name="text">
<string>Volume Group Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="vgName"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="vgTypeLabel">
<property name="text">
<string>Volume Group Type:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="vgType"/>
</item>
<item row="3" column="1">
<widget class="QLabel" name="peSizeLabel">
<property name="text">
<string>Physical Extent Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="peSize">
<property name="suffix">
<string> MiB</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="totalSizeLabel">
<property name="text">
<string>Total Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="totalSize">
<property name="text">
<string>---</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="usedSizeLabel">
<property name="text">
<string>Used Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="usedSize">
<property name="text">
<string>---</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="totalSectorsLabel">
<property name="text">
<string>Total Sectors:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="totalSectors">
<property name="text">
<string>---</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="lvQuantityLabel">
<property name="text">
<string>Quantity of LVs:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="lvQuantity">
<property name="text">
<string>---</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>VolumeGroupBaseDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>VolumeGroupBaseDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,84 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "CreateVolumeGroupJob.h"
// KPMcore
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/ops/createvolumegroupoperation.h>
#include <kpmcore/util/report.h>
CreateVolumeGroupJob::CreateVolumeGroupJob( QString& vgName, QVector< const Partition* > pvList, const qint32 peSize )
: m_vgName(vgName)
, m_pvList(pvList)
, m_peSize(peSize)
{
}
QString
CreateVolumeGroupJob::prettyName() const
{
return tr( "Create new volume group named %1." )
.arg( m_vgName );
}
QString
CreateVolumeGroupJob::prettyDescription() const
{
return tr( "Create new volume group named <strong>%1</strong>." )
.arg( m_vgName );
}
QString
CreateVolumeGroupJob::prettyStatusMessage() const
{
return tr( "Creating new volume group named %1." )
.arg( m_vgName );
}
Calamares::JobResult
CreateVolumeGroupJob::exec()
{
Report report( nullptr );
CreateVolumeGroupOperation op( m_vgName, m_pvList, m_peSize );
op.setStatus( Operation::StatusRunning );
QString message = tr( "The installer failed to create a volume group named '%1'.").arg( m_vgName );
if (op.execute(report))
return Calamares::JobResult::ok();
return Calamares::JobResult::error(message, report.toText());
}
void
CreateVolumeGroupJob::updatePreview()
{
LvmDevice::s_DirtyPVs << m_pvList;
}
void
CreateVolumeGroupJob::undoPreview()
{
for ( const auto& pv : m_pvList )
if ( LvmDevice::s_DirtyPVs.contains( pv ))
LvmDevice::s_DirtyPVs.removeAll( pv );
}

View File

@ -0,0 +1,47 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 CREATEVOLUMEGROUPJOB_H
#define CREATEVOLUMEGROUPJOB_H
#include <Job.h>
#include <kpmcore/core/partition.h>
#include <QVector>
class CreateVolumeGroupJob : public Calamares::Job
{
public:
CreateVolumeGroupJob( QString& vgName, QVector< const Partition* > pvList, const qint32 peSize );
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
void updatePreview();
void undoPreview();
private:
QString m_vgName;
QVector< const Partition* > m_pvList;
qint32 m_peSize;
};
#endif // CREATEVOLUMEGROUPJOB_H

View File

@ -0,0 +1,69 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "DeactivateVolumeGroupJob.h"
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
#include <kpmcore/util/report.h>
DeactivateVolumeGroupJob::DeactivateVolumeGroupJob( LvmDevice* device )
: m_device( device )
{
}
QString
DeactivateVolumeGroupJob::prettyName() const
{
return tr( "Deactivate volume group named %1." )
.arg( m_device->name() );
}
QString
DeactivateVolumeGroupJob::prettyDescription() const
{
return tr( "Deactivate volume group named <strong>%1</strong>." )
.arg( m_device->name() );
}
QString
DeactivateVolumeGroupJob::prettyStatusMessage() const
{
return tr( "Deactivate volume group named %1." )
.arg( m_device->name() );
}
Calamares::JobResult
DeactivateVolumeGroupJob::exec()
{
Report report( nullptr );
DeactivateVolumeGroupOperation op( *m_device );
op.setStatus( Operation::OperationStatus::StatusRunning );
QString message = tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() );
if ( op.execute( report ) )
{
op.preview();
return Calamares::JobResult::ok();
}
return Calamares::JobResult::error(message, report.toText());
}

View File

@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 DEACTIVATEVOLUMEGROUPJOB_H
#define DEACTIVATEVOLUMEGROUPJOB_H
#include "Job.h"
class LvmDevice;
class DeactivateVolumeGroupJob : public Calamares::Job
{
public:
DeactivateVolumeGroupJob( LvmDevice* device );
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
private:
LvmDevice* m_device;
};
#endif // DEACTIVATEVOLUMEGROUPJOB_H

View File

@ -0,0 +1,66 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "RemoveVolumeGroupJob.h"
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/ops/removevolumegroupoperation.h>
#include <kpmcore/util/report.h>
RemoveVolumeGroupJob::RemoveVolumeGroupJob( LvmDevice* device )
: m_device( device )
{
}
QString
RemoveVolumeGroupJob::prettyName() const
{
return tr( "Remove Volume Group named %1." )
.arg( m_device->name() );
}
QString
RemoveVolumeGroupJob::prettyDescription() const
{
return tr( "Remove Volume Group named <strong>%1</strong>.")
.arg( m_device->name() );
}
QString
RemoveVolumeGroupJob::prettyStatusMessage() const
{
return tr( "Remove Volume Group named %1." )
.arg( m_device->name() );
}
Calamares::JobResult
RemoveVolumeGroupJob::exec()
{
Report report( nullptr );
RemoveVolumeGroupOperation op( *m_device );
op.setStatus( Operation::OperationStatus::StatusRunning );
QString message = tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() );
if ( op.execute( report ) )
return Calamares::JobResult::ok();
return Calamares::JobResult::error(message, report.toText());
}

View File

@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 REMOVEVOLUMEGROUPJOB_H
#define REMOVEVOLUMEGROUPJOB_H
#include <Job.h>
class LvmDevice;
class RemoveVolumeGroupJob : public Calamares::Job
{
public:
RemoveVolumeGroupJob( LvmDevice* device );
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
private:
LvmDevice* m_device;
};
#endif // REMOVEVOLUMEGROUPJOB_H

View File

@ -0,0 +1,101 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 "ResizeVolumeGroupJob.h"
// KPMcore
#include <kpmcore/core/lvmdevice.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/ops/resizevolumegroupoperation.h>
#include <kpmcore/util/report.h>
ResizeVolumeGroupJob::ResizeVolumeGroupJob( LvmDevice* device, QVector< const Partition* >& partitionList )
: m_device( device )
, m_partitionList( partitionList )
{
}
QString
ResizeVolumeGroupJob::prettyName() const
{
return tr( "Resize volume group named %1 from %2 to %3." )
.arg( m_device->name() )
.arg( currentPartitions() )
.arg( targetPartitions() );
}
QString
ResizeVolumeGroupJob::prettyDescription() const
{
return tr( "Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>." )
.arg( m_device->name() )
.arg( currentPartitions() )
.arg( targetPartitions() );
}
QString
ResizeVolumeGroupJob::prettyStatusMessage() const
{
return tr( "Resize volume group named %1 from %2 to %3." )
.arg( m_device->name() )
.arg( currentPartitions() )
.arg( targetPartitions() );
}
Calamares::JobResult
ResizeVolumeGroupJob::exec()
{
Report report( nullptr );
ResizeVolumeGroupOperation op( *m_device, m_partitionList );
op.setStatus( Operation::OperationStatus::StatusRunning );
QString message = tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() );
if ( op.execute( report ) )
return Calamares::JobResult::ok();
return Calamares::JobResult::error( message, report.toText() );
}
QString
ResizeVolumeGroupJob::currentPartitions() const
{
QString result;
for ( const Partition *p : m_device->physicalVolumes() )
result += p->deviceNode() + ", ";
result.chop(2);
return result;
}
QString
ResizeVolumeGroupJob::targetPartitions() const
{
QString result;
for ( const Partition *p : m_partitionList )
result += p->deviceNode() + ", ";
result.chop(2);
return result;
}

View File

@ -0,0 +1,48 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Caio Jordão Carvalho <caiojcarvalho@gmail.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
* 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 RESIZEVOLUMEGROUPJOB_H
#define RESIZEVOLUMEGROUPJOB_H
#include <Job.h>
#include <QVector>
class LvmDevice;
class Partition;
class ResizeVolumeGroupJob : public Calamares::Job
{
public:
ResizeVolumeGroupJob( LvmDevice* device, QVector< const Partition* >& partitionList );
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
private:
QString currentPartitions() const;
QString targetPartitions() const;
private:
LvmDevice* m_device;
QVector< const Partition* > m_partitionList;
};
#endif // RESIZEVOLUMEGROUPJOB_H

View File

@ -56,7 +56,7 @@ defaultFileSystemType: "ext4"
# Support is offered to system integrators that wish to do so, through the
# Calamares bug tracker, as well as in #calamares on Freenode.
# For more information on setting up GRUB2 for Calamares with LUKS, see
# https://github.com/calamares/calamares/wiki/LUKS-Deployment
# https://github.com/calamares/calamares/wiki/Deploy-LUKS
#
# If nothing is specified, LUKS is enabled in automated modes.
#enableLuksAutomatedPartitioning: true

View File

@ -1,2 +1,6 @@
# Removes a single user (with userdel) from the system.
# This is typically used in OEM setups or if the live user
# spills into the target system.
---
# Username in the target system to be removed.
username: live

View File

@ -0,0 +1,106 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2016, Artoo <artoo@manjaro.org>
# Copyright 2017, Philip Müller <philm@manjaro.org>
# Copyright 2018, Artoo <artoo@artixlinux.org>
# Copyright 2018, 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/>.
import libcalamares
from libcalamares.utils import target_env_call, warning
from os.path import exists, join
class OpenrcController:
"""
This is the openrc service controller.
All of its state comes from global storage and the job
configuration at initialization time.
"""
def __init__(self):
self.root = libcalamares.globalstorage.value('rootMountPoint')
# Translate the entries in the config to the actions passed to rc-config
self.services = dict()
self.services["add"] = libcalamares.job.configuration.get('services', [])
self.services["del"] = libcalamares.job.configuration.get('disable', [])
self.initdDir = libcalamares.job.configuration['initdDir']
self.runlevelsDir = libcalamares.job.configuration['runlevelsDir']
def update(self, state):
"""
Call rc-update for each service listed
in services for the given @p state. rc-update
is called with @p state as the command as well.
"""
for svc in self.services.get(state, []):
if isinstance(svc, str):
name = svc
runlevel = "default"
mandatory = False
else:
name = svc["name"]
runlevel = svc.get("runlevel", "default")
mandatory = svc.get("mandatory", False)
service_path = self.root + self.initdDir + "/" + name
runlevel_path = self.root + self.runlevelsDir + "/" + runlevel
if exists(service_path):
if exists(runlevel_path):
ec = target_env_call(["rc-update", state, name, runlevel])
if ec != 0:
if mandatory:
return ("Cannot {} service {} to {}".format(state, name, runlevel),
"rc-update {} call in chroot returned error code {}".format(state, ec)
)
else:
warning("Could not {} service {} in {}, error {!s}".format(state, name, runlevel, ec))
else:
if mandatory:
return ("Target runlevel {} does not exist for {}.".format(runlevel, name),
"No {} found.".format(runlevel_path))
else:
warning("Target runlevel {} does not exist for {}.".format(runlevel, name))
else:
if mandatory:
return ("Target service {} does not exist.".format(name),
"No {} found.".format(service_path))
else:
warning("Target service {} does not exist in {}.".format(name, self.initdDir))
def run(self):
"""Run the controller
"""
for state in ("add", "del"):
r = self.update(state)
if r is not None:
return r
def run():
"""
Setup services
"""
return OpenrcController().run()

View File

@ -0,0 +1,5 @@
---
type: "job"
name: "services-openrc"
interface: "python"
script: "main.py"

View File

@ -0,0 +1,46 @@
# openrc services module to modify service runlevels via rc-update in the chroot
#
# Services can be added (to any runlevel, or multiple runlevels) or deleted.
# Handle del with care and only use it if absolutely necessary.
#
# if a service is listed in the conf but is not present/detected on the target system,
# or a runlevel does not exist, it will be ignored and skipped; a warning is logged.
#
---
# initdDir: holds the openrc service directory location
initdDir: /etc/init.d
# runlevelsDir: holds the runlevels directory location
runlevelsDir: /etc/runlevels
# services: a list of entries to **enable**
# disable: a list of entries to **disable**
#
# Each entry has three fields:
# - name: the service name
# - (optional) runlevel: can hold any runlevel present on the target
# system; if no runlevel is provided, "default" is assumed.
# - (optional) mandatory: if set to true, a failure to modify
# the service will result in installation failure, rather than just
# a warning. The default is false.
#
# an entry may also be a single string, which is interpreted
# as the name field (runlevel "default" is assumed then, and not-mandatory).
#
# # Example services and disable settings:
# # - add foo1 to default, but it must succeed
# # - add foo2 to nonetwork
# # - remove foo3 from default
# # - remove foo4 from default
# services:
# - name: foo1
# mandatory: true
# - name: foo2
# runlevel: nonetwork
# disable:
# - name: foo3
# runlevel: default
# - foo4
services: []
disable: []

View File

@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2014, Philip Müller <philm@manjaro.org>
# Copyright 2014, Teo Mrnjavac <teo@kde.org>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
# Copyright 2018, 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/>.
import libcalamares
def systemctl(targets, command, suffix):
"""
For each entry in @p targets, run "systemctl <command> <thing>",
where <thing> is the entry's name plus the given @p suffix.
(No dot is added between name and suffix; suffix may be empty)
Returns a failure message, or None if this was successful.
Services that are not mandatory have their failures suppressed
silently.
"""
for svc in targets:
if isinstance(svc, str):
name = svc
mandatory = False
else:
name = svc["name"]
mandatory = svc.get("mandatory", False)
ec = libcalamares.utils.target_env_call(
['systemctl', command, "{}{}".format(name, suffix)]
)
if ec != 0:
if mandatory:
return ("Cannot {} systemd {} {}".format(command, suffix, name),
"systemctl {} call in chroot returned error code {}".format(command, ec)
)
else:
libcalamares.utils.warning(
"Cannot {} systemd {} {}".format(command, suffix, name)
)
libcalamares.utils.warning(
"systemctl {} call in chroot returned error code {}".format(command, ec)
)
return None
def run():
"""
Setup systemd services
"""
cfg = libcalamares.job.configuration
# note that the "systemctl enable" and "systemctl disable" commands used
# here will work in a chroot; in fact, they are the only systemctl commands
# that support that, see:
# http://0pointer.de/blog/projects/changing-roots.html
r = systemctl(cfg.get("services", []), "enable", ".service")
if r is not None:
return r
r = systemctl(cfg.get("targets", []), "enable", ".target")
if r is not None:
return r
r = systemctl(cfg.get("disable", []), "disable", ".service")
if r is not None:
return r
r = systemctl(cfg.get("disable-targets", []), "disable", ".target")
if r is not None:
return r
r = systemctl(cfg.get("mask", []), "mask", "")
if r is not None:
return r
# This could have just been return r
return None

View File

@ -1,6 +1,6 @@
---
type: "job"
name: "services"
name: "services-systemd"
interface: "python"
requires: []
script: "main.py"

View File

@ -0,0 +1,70 @@
# Systemd services manipulation.
#
# This module can enable services and targets for systemd
# (if packaging doesn't already do that). It can calso
# disable services (but not targets).
#
# First, services are enabled; then targets; then services
# are disabled -- this order of operations is fixed.
---
# There are three configuration keys for this module:
# *services*, *targets* and *disable*. The value of each
# key is a list of entries. Each entry has two keys:
# - *name* is the (string) name of the service or target that is being
# changed. Use quotes. Don't include ".target" or ".service"
# in the name.
# - *mandatory* is a boolean option, which states whether the change
# must be done successfully. If systemd reports an error while changing
# a mandatory entry, the installation will fail. When mandatory is false,
# errors for that entry (service or target) are ignored. If mandatory
# is not specified, the default is false.
#
# An entry may also be given as a single string, which is then
# interpreted as the name of the service. In this case, mandatory
# is also set to the default of false.
#
# Use [] to express an empty list.
# # This example enables NetworkManager (and fails if it can't),
# # disables cups (and ignores failure). Then it enables the
# # graphical target (e.g. so that SDDM runs for login), and
# # finally disables pacman-init (an ArchLinux-only service).
# #
# # Enables <name>.service
# services:
# - name: "NetworkManager"
# mandatory: true
# - name: "cups"
# mandatory: false
#
# # Enables <name>.target
# targets:
# - name: "graphical"
# mandatory: true
#
# # Disables <name>.service
# disable:
# - name: "pacman-init"
# mandatory: false
#
# # Disables <name>.target
# # .. this shows how to use just the name
# disable-targets:
# - graphical
#
# # Masks (stronger version of disable). This section
# # is unusual because you **must** include the suffix
# # (e.g. ".service") as part of the name, so, e.g. to mask
# # NetworkManager (rather than just disable it) you must
# # specify "NetworkManager.service" as name.
# mask:
# - name: "NetworkManager.service"
# - mandatory: true
# By default, no changes are made.
services: []
targets: []
disable: []
disable-targets: []
mask: []

View File

@ -1,126 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2014-2016, Philip Müller <philm@manjaro.org>
# Copyright 2014, Teo Mrnjavac <teo@kde.org>
# Copyright 2016, Artoo <artoo@manjaro.org>
# Copyright 2017, Alf Gaida <agaida@siduction.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/>.
import libcalamares
from os.path import join, exists
def run():
"""
Setup systemd services
"""
services = libcalamares.job.configuration['services']
targets = libcalamares.job.configuration['targets']
disable = libcalamares.job.configuration['disable']
rootmnt = libcalamares.globalstorage.value("rootMountPoint")
# note that the "systemctl enable" and "systemctl disable" commands used
# here will work in a chroot; in fact, they are the only systemctl commands
# that support that, see:
# http://0pointer.de/blog/projects/changing-roots.html
# enable services
for svc in services:
ec = libcalamares.utils.target_env_call(
['systemctl', 'enable', '{}.service'.format(svc['name'])]
)
if ec != 0:
if svc['mandatory']:
return ("Cannot enable systemd service {}".format(svc['name']),
"systemctl enable call in chroot returned error code "
"{}".format(ec)
)
else:
libcalamares.utils.debug(
"Cannot enable systemd service {}".format(svc['name'])
)
libcalamares.utils.debug(
"systemctl enable call in chroot returned error code "
"{}".format(ec)
)
# enable targets
for tgt in targets:
ec = libcalamares.utils.target_env_call(
['systemctl', 'enable', '{}.target'.format(tgt['name'])]
)
if ec != 0:
if tgt['mandatory']:
return ("Cannot enable systemd target {}".format(tgt['name']),
"systemctl enable call in chroot returned error code "
"{}".format(ec)
)
else:
libcalamares.utils.debug(
"Cannot enable systemd target {}".format(tgt['name'])
)
libcalamares.utils.debug(
"systemctl enable call in chroot returned error code "
"{}".format(ec)
)
for dbl in disable:
ec = libcalamares.utils.target_env_call(
['systemctl', 'disable', '{}.service'.format(dbl['name'])]
)
if ec != 0:
if dbl['mandatory']:
return ("Cannot disable systemd service"
"{}".format(dbl['name']),
"systemctl disable call in chroot returned error code "
"{}".format(ec))
else:
libcalamares.utils.debug(
"Cannot disable systemd service {}".format(dbl['name'])
)
libcalamares.utils.debug(
"systemctl disable call in chroot returned error code "
"{}".format(ec)
)
if libcalamares.globalstorage.contains("displayManagers"):
for dm in libcalamares.globalstorage.value("displayManagers"):
if not exists(join(
rootmnt, "etc/systemd/system/display-manager.service"
)):
ec = libcalamares.utils.target_env_call(
['systemctl', 'enable', '{}.service'.format(dm)]
)
if ec != 0:
return "Cannot enable systemd service {}".format(dm), \
"systemctl enable call in chroot returned error " \
"code {}".format(ec)
else:
libcalamares.utils.debug(
"Cannot enable systemd service {}".format(dm)
)
libcalamares.utils.debug(
"systemctl enable call in chroot returned error code "
"{}".format(ec)
)
return None

View File

@ -1,20 +0,0 @@
---
#systemd services and targets are enabled in this precise order
services:
- name: "NetworkManager" #name of the service file
mandatory: false #true=> if enabling fails the installer errors out and quits
#false=>if enabling fails print warning to console and continue
- name: "org.cups.cupsd"
mandatory: false
targets:
- name: "graphical"
mandatory: true
disable:
- name: "pacman-init"
mandatory: false
# Example to express an empty list:
# disable: []