Merge branch 'development' into 3.2.x-stable

This commit is contained in:
Philip Müller 2022-02-01 19:17:48 +01:00
commit 62c4d60fe2
166 changed files with 13852 additions and 1853 deletions

View File

@ -28,8 +28,9 @@ PointerAlignment: Left
ReflowComments: "false" ReflowComments: "false"
SortIncludes: "true" SortIncludes: "true"
SpaceAfterCStyleCast: "false" SpaceAfterCStyleCast: "false"
SpaceInEmptyBlock: "false"
SpacesBeforeTrailingComments: "2" SpacesBeforeTrailingComments: "2"
SpacesInAngles: "true" SpacesInAngles: "true"
SpacesInParentheses: "true" SpacesInParentheses: "true"
SpacesInSquareBrackets: "true" SpacesInSquareBrackets: "true"
Standard: Cpp11 Standard: c++17

View File

@ -1,35 +0,0 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
---
BasedOnStyle: WebKit
AlignAfterOpenBracket: Align
AlignEscapedNewlines: DontAlign
AllowAllParametersOfDeclarationOnNextLine: "false"
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: "false"
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: "false"
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: "false"
BinPackParameters: "false"
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: "true"
BreakConstructorInitializers: BeforeComma
ColumnLimit: 120
Cpp11BracedListStyle: "false"
FixNamespaceComments: "true"
IncludeBlocks: Preserve
IndentWidth: "4"
MaxEmptyLinesToKeep: "2"
NamespaceIndentation: None
PointerAlignment: Left
ReflowComments: "false"
SortIncludes: "true"
SpaceAfterCStyleCast: "false"
SpacesBeforeTrailingComments: "2"
SpacesInAngles: "true"
SpacesInParentheses: "true"
SpacesInSquareBrackets: "true"
Standard: Cpp11

View File

@ -7,6 +7,116 @@ 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 changelog -- this log starts with version 3.2.0. The release notes on the
website will have to do for older versions. website will have to do for older versions.
# 3.2.52 (unreleased) #
This release contains contributions from (alphabetically by first name):
- No external contributors yet
## Core ##
- No core changes yet
## Modules ##
- No module changes yet
# 3.2.51 (2022-02-01) #
This release contains contributions from (alphabetically by first name):
- Evan James
**WARNING** The *umount* module has been rewritten in C++. Check your
configuration if you previously used the copy-a-log functionality.
## Core ##
- Evan has made a start on documenting which Global Storage keys there
are and how they tie modules together. This can be found in the
`src/modules/README.md` documentation.
## Modules ##
- *bootloader* can now be configured to try to generate a unique
suffix for the bootloader-id. #1820
- *grubcfg* now has a configurable default for kernel parameters,
which allows distributions to change the value from `quiet`.
The default, if nothing is set, remains `quiet`. Use an explicitly-
empty list to specify no-arguments-at-all.
- *packagechooser* can now export its choices for use by the *netinstall*
module. This makes it possible to use *packagechooser* for large-scale
choices, followed by *netinstall* for fine-grained control. (Thanks Evan)
- When the *partition* module has a conflicting configuration for the
swap choices, it prints a warning and uses the configured choice, rather
than always using "suspend". #1881
- The *umount* module has been re-written in C++. The copy-a-log-file
functionality has been removed. Use the *preservefiles* module for that.
# 3.2.50 (2022-01-18) #
This release contains contributions from (alphabetically by first name):
- Anke Boersma
- Erik Dubois
- Evan James
- Johannes Kamprad
- Taejun Park (new contributor, welcome!)
**Replacement notice:** The *umount* module will be replaced by a C++
implementation in the next release. The "preserve log file" feature
will be removed in that release. Use the *preservefiles* module instead.
## Core ##
- No core changes yet
## Modules ##
- *initcpiocfg* mentioned a special kernel-name "all", which did not work,
and a special kernel-name "$uname" which cannot work. Fixed the former
and removed the "$uname" special key. (Thanks Evan)
- *luksswaphookcfg* has been converted to a C++ module.
- *networkcfg* could fail to update the NetworkManager configuration
if the SSID or username contained non-ASCII characters **and** the
default Python text-file encoding was set to ASCII. The files are
now read and written in UTF-8, explicitly. #1848
- *partition* always sets *bigtime* option on XFS filesystems, if possible.
Requires sufficiently-recent xfsprogs. #1874
- *preservefiles* was missing some necessary features, needed for it
to replace the deprecated log-file-saving functionality in the *umount*
module. (Thanks Erik and Joe for testing) #1851
- *umount* is now marked as an emergency module in the example configuration,
since it should **probably** be run as a cleanup. (Thanks Evan)
- *welcome* and *locale* could be confusing, together, and configure
the target system with a language that does not match the installer
language, even though the user did not make any explicit choice.
(Thanks Taejun) #1864
# 3.2.49.1 (2021-12-11) #
This is a hot-fix release, to fix a regression in the calculation of
swap-size. Reported by EndeavourOS (Joe Kamprad) and Xero Linux.
# 3.2.49 (2021-12-10) #
This release contains contributions from (alphabetically by first name):
- Artem Grinev
- Evan James
Distributions are **specifically** reminded to update the *umount* module
configuration (and to use *preservefiles* if needed).
## Core ##
- Errors (e.g. when an installation fails for whatever reason) are displayed
in a dialog with a scrollable details panel, rather than growing up
to the size of the screen. (Thanks Artem)
## Modules ##
- *bootloader* better supports multiple installations of the same OS.
- *mount* supports btrfs subvolumes on subdirectories of / now.
- *partition* now supports "deep" btrfs subvolume names, e.g. a
separate subvolume for `/usr/local`. (Thanks Evan)
- The *umount* module now warns if the "preserve log file" feature is used.
This has been deprecated for a long time: use the *preservefiles* module
instead. A future release will turn this into an error.
# 3.2.48 (2021-12-03) # # 3.2.48 (2021-12-03) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):

View File

@ -41,11 +41,11 @@
# TODO:3.3: Require CMake 3.12 # TODO:3.3: Require CMake 3.12
cmake_minimum_required( VERSION 3.3 FATAL_ERROR ) cmake_minimum_required( VERSION 3.3 FATAL_ERROR )
project( CALAMARES project( CALAMARES
VERSION 3.2.48 VERSION 3.2.52
LANGUAGES C CXX LANGUAGES C CXX
) )
set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development
if( CALAMARES_VERSION_RC EQUAL 1 AND CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) if( CALAMARES_VERSION_RC EQUAL 1 AND CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
message( FATAL_ERROR "Do not build development versions in the source-directory." ) message( FATAL_ERROR "Do not build development versions in the source-directory." )
endif() endif()
@ -135,15 +135,15 @@ set( CALAMARES_DESCRIPTION_SUMMARY
# NOTE: update these lines by running `txstats.py`, or for full automation # NOTE: update these lines by running `txstats.py`, or for full automation
# `txstats.py -e`. See also # `txstats.py -e`. See also
# #
# Total 81 languages # Total 74 languages
set( _tx_complete az az_AZ ca de fa fi_FI he hr ja ko lt pt_PT si set( _tx_complete az az_AZ ca de fa fi_FI he hi hr ja ko lt pt_BR
sq tr_TR uk zh_TW ) pt_PT si sq sv tr_TR uk zh_TW )
set( _tx_good as be ca@valencia cs_CZ da fr fur hi it_IT ml nl set( _tx_good as be ca@valencia cs_CZ da fr fur it_IT ml nl ru sk
pt_BR ru sk sv tg vi zh_CN ) tg vi zh_CN )
set( _tx_ok ar ast bg bn el en_GB es es_MX et eu gl hu id is mr nb set( _tx_ok ar ast bg bn el en_GB es es_MX et eu gl hu id is mr nb
pl ro sl sr sr@latin th ) pl ro sl sr sr@latin th )
set( _tx_incomplete en_HK en_IN eo es_PE es_PR fr_CH gu hi_IN id_ID set( _tx_incomplete eo es_PR gu ie kk kn lo lv mk ne ne_NP ta_IN te
ie kk kn ko_KR lo lv mk ne ne_NP te te_IN ur zh zh_HK ) ur zh zh_HK )
### Required versions ### Required versions
# #

View File

@ -8,7 +8,7 @@
[![Current issue](https://img.shields.io/badge/issue-in_progress-FE9B48)](https://github.com/calamares/calamares/labels/hacking%3A%20in-progress) [![Current issue](https://img.shields.io/badge/issue-in_progress-FE9B48)](https://github.com/calamares/calamares/labels/hacking%3A%20in-progress)
[![GitHub release](https://img.shields.io/github/release/calamares/calamares.svg)](https://github.com/calamares/calamares/releases) [![GitHub release](https://img.shields.io/github/release/calamares/calamares.svg)](https://github.com/calamares/calamares/releases)
[![GitHub Build Status](https://img.shields.io/github/workflow/status/calamares/calamares/ci?label=GH%20build)](https://github.com/calamares/calamares/actions?query=workflow%3Aci) [![GitHub Build Status](https://img.shields.io/github/workflow/status/calamares/calamares/ci?label=GH%20build)](https://github.com/calamares/calamares/actions?query=workflow%3Aci)
[![GitHub license](https://img.shields.io/github/license/calamares/calamares.svg)](https://github.com/calamares/calamares/blob/calamares/LICENSE) [![GitHub license](https://img.shields.io/github/license/calamares/calamares.svg)](https://github.com/calamares/calamares/blob/calamares/LICENSES/GPL-3.0-or-later.txt)
| [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](CONTRIBUTING.md) | [Matrix: #calamares:kde.org](https://webchat.kde.org/#/room/%23calamares:kde.org) | [IRC: Libera.Chat #calamares](https://kiwiirc.com/client/irc.libera.chat/#calamares) | [Wiki](https://github.com/calamares/calamares/wiki) | | [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](CONTRIBUTING.md) | [Matrix: #calamares:kde.org](https://webchat.kde.org/#/room/%23calamares:kde.org) | [IRC: Libera.Chat #calamares](https://kiwiirc.com/client/irc.libera.chat/#calamares) | [Wiki](https://github.com/calamares/calamares/wiki) |

View File

@ -21,10 +21,18 @@ Name[as]=চিছটেম ইনস্তল কৰক
Icon[as]= Icon[as]=
GenericName[as]=ি GenericName[as]=ি
Comment[as]= ি Comment[as]= ি
Name[ast]=Instalar el sistema
Icon[ast]=calamares
GenericName[ast]=Instalador del sistema
Comment[ast]=Calamares Instalador del sistema
Name[az]=Sistemi Quraşdırmaq Name[az]=Sistemi Quraşdırmaq
Icon[az]=calamares Icon[az]=calamares
GenericName[az]=Sistem Quraşdırıcısı GenericName[az]=Sistem Quraşdırıcısı
Comment[az]=Calamares Sistem Quraşdırıcısı Comment[az]=Calamares Sistem Quraşdırıcısı
Name[az_AZ]=Sistemi quraşdırmaq
Icon[az_AZ]=calamares
GenericName[az_AZ]=Sistem quraşdırcısı
Comment[az_AZ]=Calamares Sistem Quraşdırıcısı
Name[be]=Усталяваць сістэму Name[be]=Усталяваць сістэму
Icon[be]=calamares Icon[be]=calamares
GenericName[be]=Усталёўшчык сістэмы GenericName[be]=Усталёўшчык сістэмы
@ -41,6 +49,10 @@ Name[ca]=Instal·la el sistema
Icon[ca]=calamares Icon[ca]=calamares
GenericName[ca]=Instal·lador de sistema GenericName[ca]=Instal·lador de sistema
Comment[ca]=Calamares Instal·lador de sistema Comment[ca]=Calamares Instal·lador de sistema
Name[cs_CZ]=Nainstalovat systém
Icon[cs_CZ]=calamares
GenericName[cs_CZ]=Instalátor systému
Comment[cs_CZ]=Calamares instalátor operačních systémů
Name[da]=Installér system Name[da]=Installér system
Icon[da]=calamares Icon[da]=calamares
GenericName[da]=Systeminstallationsprogram GenericName[da]=Systeminstallationsprogram
@ -57,10 +69,19 @@ Name[en_GB]=Install System
Icon[en_GB]=calamares Icon[en_GB]=calamares
GenericName[en_GB]=System Installer GenericName[en_GB]=System Installer
Comment[en_GB]=Calamares System Installer Comment[en_GB]=Calamares System Installer
Name[eo]=Instali Sistemo
Icon[eo]=calamares
GenericName[eo]=Sistema Instalilo
Comment[eo]=Calamares Sistema Instalilo
Name[es]=Instalar Sistema Name[es]=Instalar Sistema
Icon[es]=calamares Icon[es]=calamares
GenericName[es]=Instalador del Sistema GenericName[es]=Instalador del Sistema
Comment[es]=Calamares Instalador del Sistema Comment[es]=Calamares Instalador del Sistema
Name[es_MX]=Instalar el Sistema
Icon[es_MX]=calamares
GenericName[es_MX]=Instalador del sistema
Comment[es_MX]=Calamares - Instalador del sistema
Name[es_PR]=Instalar el sistema
Name[et]=Paigalda süsteem Name[et]=Paigalda süsteem
Icon[et]=calamares Icon[et]=calamares
GenericName[et]=Süsteemipaigaldaja GenericName[et]=Süsteemipaigaldaja
@ -73,7 +94,10 @@ Name[fa]=نصب سامانه
Icon[fa]=کالامارس Icon[fa]=کالامارس
GenericName[fa]=نصبکننده سامانه GenericName[fa]=نصبکننده سامانه
Comment[fa]=کالامارس نصبکننده سامانه Comment[fa]=کالامارس نصبکننده سامانه
Name[es_PR]=Instalar el sistema Name[fi_FI]=Asenna järjestelmä
Icon[fi_FI]=calamares
GenericName[fi_FI]=Järjestelmän asennusohjelma
Comment[fi_FI]=Calamares Järjestelmän asentaja
Name[fr]=Installer le système Name[fr]=Installer le système
Icon[fr]=calamares Icon[fr]=calamares
GenericName[fr]=Installateur système GenericName[fr]=Installateur système
@ -98,10 +122,6 @@ Name[hr]=Instaliraj sustav
Icon[hr]=calamares Icon[hr]=calamares
GenericName[hr]=Instalacija sustava GenericName[hr]=Instalacija sustava
Comment[hr]=Calamares Instalacija sustava Comment[hr]=Calamares Instalacija sustava
Name[ie]=Installar li sistema
Icon[ie]=calamares
GenericName[ie]=Installator del sistema
Comment[ie]=Calamares Installator del sistema
Name[hu]=Rendszer telepítése Name[hu]=Rendszer telepítése
Icon[hu]=calamares Icon[hu]=calamares
GenericName[hu]=Rendszertelepítő GenericName[hu]=Rendszertelepítő
@ -110,14 +130,18 @@ Name[id]=Instal Sistem
Icon[id]=calamares Icon[id]=calamares
GenericName[id]=Pemasang GenericName[id]=Pemasang
Comment[id]=Calamares Pemasang Sistem Comment[id]=Calamares Pemasang Sistem
Name[ie]=Installar li sistema
Icon[ie]=calamares
GenericName[ie]=Installator del sistema
Comment[ie]=Calamares Installator del sistema
Name[is]=Setja upp kerfið Name[is]=Setja upp kerfið
Icon[is]=calamares Icon[is]=calamares
GenericName[is]=Kerfis uppsetning GenericName[is]=Kerfis uppsetning
Comment[is]=Calamares Kerfis uppsetning Comment[is]=Calamares Kerfis uppsetning
Name[cs_CZ]=Nainstalovat systém Name[it_IT]=Installa il sistema
Icon[cs_CZ]=calamares Icon[it_IT]=calamares
GenericName[cs_CZ]=Instalátor systému GenericName[it_IT]=Programma d'installazione del sistema
Comment[cs_CZ]=Calamares instalátor operačních systémů Comment[it_IT]=Calamares Programma d'installazione del sistema
Name[ja]= Name[ja]=
Icon[ja]=calamares Icon[ja]=calamares
GenericName[ja]= GenericName[ja]=
@ -130,10 +154,6 @@ Name[lt]=Įdiegti Sistemą
Icon[lt]=calamares Icon[lt]=calamares
GenericName[lt]=Sistemos diegimas į kompiuterį GenericName[lt]=Sistemos diegimas į kompiuterį
Comment[lt]=Calamares Sistemos diegimo programa Comment[lt]=Calamares Sistemos diegimo programa
Name[it_IT]=Installa il sistema
Icon[it_IT]=calamares
GenericName[it_IT]=Programma d'installazione del sistema
Comment[it_IT]=Calamares Programma d'installazione del sistema
Name[mk]=Инсталирај го системот Name[mk]=Инсталирај го системот
Icon[mk]=calamares Icon[mk]=calamares
GenericName[mk]=Системен Инсталер GenericName[mk]=Системен Инсталер
@ -146,14 +166,14 @@ Name[nb]=Installer System
Icon[nb]=calamares Icon[nb]=calamares
GenericName[nb]=Systeminstallatør GenericName[nb]=Systeminstallatør
Comment[nb]=Calamares-systeminstallatør Comment[nb]=Calamares-systeminstallatør
Name[ne_NP]= ि
Icon[ne_NP]=Calamares
GenericName[ne_NP]=ि
Comment[ne_NP]=Calamares - ि
Name[nl]=Installeer systeem Name[nl]=Installeer systeem
Icon[nl]=calamares Icon[nl]=calamares
GenericName[nl]=Installatieprogramma GenericName[nl]=Installatieprogramma
Comment[nl]=Calamares Installatieprogramma Comment[nl]=Calamares Installatieprogramma
Name[az_AZ]=Sistemi quraşdırmaq
Icon[az_AZ]=calamares
GenericName[az_AZ]=Sistem quraşdırcısı
Comment[az_AZ]=Calamares Sistem Quraşdırıcısı
Name[pl]=Zainstaluj system Name[pl]=Zainstaluj system
Icon[pl]=calamares Icon[pl]=calamares
GenericName[pl]=Instalator systemu GenericName[pl]=Instalator systemu
@ -162,6 +182,10 @@ Name[pt_BR]=Sistema de Instalação
Icon[pt_BR]=calamares Icon[pt_BR]=calamares
GenericName[pt_BR]=Instalador de Sistema GenericName[pt_BR]=Instalador de Sistema
Comment[pt_BR]=Calamares Instalador de Sistema Comment[pt_BR]=Calamares Instalador de Sistema
Name[pt_PT]=Instalar Sistema
Icon[pt_PT]=calamares
GenericName[pt_PT]=Instalador de Sistema
Comment[pt_PT]=Instalador de Sistema - Calamares
Name[ro]=Instalează sistemul Name[ro]=Instalează sistemul
Icon[ro]=calamares Icon[ro]=calamares
GenericName[ro]=Instalator de sistem GenericName[ro]=Instalator de sistem
@ -183,15 +207,11 @@ Name[sq]=Instalo Sistemin
Icon[sq]=calamares Icon[sq]=calamares
GenericName[sq]=Instalues Sistemi GenericName[sq]=Instalues Sistemi
Comment[sq]=Calamares Instalues Sistemi Comment[sq]=Calamares Instalues Sistemi
Name[fi_FI]=Asenna järjestelmä
Icon[fi_FI]=calamares
GenericName[fi_FI]=Järjestelmän asennusohjelma
Comment[fi_FI]=Calamares Järjestelmän asentaja
Name[sr@latin]=Instaliraj sistem
Name[sr]=Инсталирај систем Name[sr]=Инсталирај систем
Icon[sr]=calamares Icon[sr]=calamares
GenericName[sr]=Инсталатер система GenericName[sr]=Инсталатер система
Comment[sr]=Каламарес инсталатер система Comment[sr]=Каламарес инсталатер система
Name[sr@latin]=Instaliraj sistem
Name[sv]=Installera system Name[sv]=Installera system
Icon[sv]=calamares Icon[sv]=calamares
GenericName[sv]=Systeminstallerare GenericName[sv]=Systeminstallerare
@ -201,6 +221,10 @@ Icon[tg]=calamares
GenericName[tg]=Насбкунандаи низомӣ GenericName[tg]=Насбкунандаи низомӣ
Comment[tg]=Calamares Насбкунандаи низомӣ Comment[tg]=Calamares Насбкунандаи низомӣ
Name[th]= Name[th]=
Name[tr_TR]=Sistemi Yükle
Icon[tr_TR]=calamares
GenericName[tr_TR]=Sistem Yükleyici
Comment[tr_TR]=Calamares Sistem Yükleyici
Name[uk]=Встановити Систему Name[uk]=Встановити Систему
Icon[uk]=calamares Icon[uk]=calamares
GenericName[uk]=Встановлювач системи GenericName[uk]=Встановлювач системи
@ -217,27 +241,3 @@ Name[zh_TW]=安裝系統
Icon[zh_TW]=calamares Icon[zh_TW]=calamares
GenericName[zh_TW]= GenericName[zh_TW]=
Comment[zh_TW]=Calamares Comment[zh_TW]=Calamares
Name[ast]=Instalar el sistema
Icon[ast]=calamares
GenericName[ast]=Instalador del sistema
Comment[ast]=Calamares Instalador del sistema
Name[eo]=Instali Sistemo
Icon[eo]=calamares
GenericName[eo]=Sistema Instalilo
Comment[eo]=Calamares Sistema Instalilo
Name[ne_NP]= ि
Icon[ne_NP]=Calamares
GenericName[ne_NP]=ि
Comment[ne_NP]=Calamares - ि
Name[es_MX]=Instalar el Sistema
Icon[es_MX]=calamares
GenericName[es_MX]=Instalador del sistema
Comment[es_MX]=Calamares - Instalador del sistema
Name[pt_PT]=Instalar Sistema
Icon[pt_PT]=calamares
GenericName[pt_PT]=Instalador de Sistema
Comment[pt_PT]=Instalador de Sistema - Calamares
Name[tr_TR]=Sistemi Yükle
Icon[tr_TR]=calamares
GenericName[tr_TR]=Sistem Yükleyici
Comment[tr_TR]=Calamares Sistem Yükleyici

View File

@ -75,7 +75,7 @@ fi
# #
# #
BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.) BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.)
KEY_ID="CFDDC96F12B1915C" KEY_ID="328D742D8807A435"
# Try to make gpg cache the signing key, so we can leave the process # Try to make gpg cache the signing key, so we can leave the process
# to run and sign. # to run and sign.

View File

@ -19,12 +19,12 @@ BASEDIR=$(dirname $0)
TOPDIR=$( cd $BASEDIR/.. && pwd -P ) TOPDIR=$( cd $BASEDIR/.. && pwd -P )
test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; } test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; }
test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; } test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; }
test -f "$TOPDIR/.clang-format.base" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; } test -f "$TOPDIR/.clang-format" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; }
AS=$( which astyle ) AS=$( which astyle )
# Allow specifying CF_VERSIONS outside already # Allow specifying CF_VERSIONS outside already
CF_VERSIONS="$CF_VERSIONS clang-format-8 clang-format80 clang-format90 clang-format-9.0.1 clang-format" CF_VERSIONS="$CF_VERSIONS clang-format13 clang-format12 clang-format"
for _cf in $CF_VERSIONS for _cf in $CF_VERSIONS
do do
# Not an error if this particular clang-format isn't found # Not an error if this particular clang-format isn't found
@ -40,31 +40,19 @@ test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; }
### CLANG-FORMAT-WRANGLING ### CLANG-FORMAT-WRANGLING
# #
# Version 7 and earlier doesn't understand all the options we would like # Version 7 and earlier doesn't understand all the options we would like
# Version 8 is ok # Version 12 handles lambdas nicely, so use that.
# Version 9 is ok # Version 13 is also ok.
# Later versions change some defaults so need extra wrangling.
# .. there are extra files that are appended to the settings, per
# .. clang-format version.
format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1` format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1`
case "$format_version" in case "$format_version" in
[0-7] ) 12|13 )
echo "! Clang-format version 8+ required"
exit 1
;;
[89] )
: :
;; ;;
* ) * )
echo "! Clang-format version '$format_version' unsupported." echo "! Clang-format version '$format_version' unsupported, version 12 required."
exit 1 exit 1
;; ;;
esac esac
_fmt="$TOPDIR/.clang-format"
cp "$_fmt.base" "$_fmt"
for f in "$extra_settings" ; do
test -f "$_fmt.$f" && cat "$_fmt.$f" >> "$_fmt"
done
### FILE PROCESSING ### FILE PROCESSING
@ -98,8 +86,3 @@ if test "x$any_dirs" = "xyes" ; then
else else
style_some "$@" style_some "$@"
fi fi
### CLANG-FORMAT-WRANGLING
#
# Restore the original .clang-format
cp "$_fmt.base" "$_fmt"

View File

@ -108,6 +108,21 @@ awk '
skip=0; print $0; skip=0; print $0;
}}' < calamares.desktop > calamares.desktop.new }}' < calamares.desktop > calamares.desktop.new
mv calamares.desktop.new calamares.desktop mv calamares.desktop.new calamares.desktop
# Now group translated key-names (Name, Icon, Description, ..) by sorted
# language key rather than random-ish language-key order (which shuffles
# entries around).
#
# First, the non-translated lines
grep -v '\[.*\]=' calamares.desktop > calamares.desktop.new
# The translated lines:
# - replace (the first) [] by | so we have a consistent field separator
# - sort based on field 2, then 1 (language code, then reversed key-name)
# - replace the first | by [, the first (remaining) | by ]
# Effectively this puts the fields in this order: Name, Icon, Generic Name,
# Comment -- within each language key. This keeps churn down since the
# language codes and key-names are constant.
grep '\[.*\]=' calamares.desktop | sed -e 's/\[/|/' -e 's/\]/|/' | sort -t '|' -k 2,2 -k 1,1r | sed -e 's/|/\[/' | sed -e 's/|/\]/' >> calamares.desktop.new
mv calamares.desktop.new calamares.desktop
git add --verbose calamares.desktop git add --verbose calamares.desktop
git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true
@ -116,6 +131,19 @@ git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true
# PO-Created line). This applies only to modules which use po-files. # PO-Created line). This applies only to modules which use po-files.
git diff --numstat src/modules | awk '($1==1 && $2==1){print $3}' | xargs git checkout -- git diff --numstat src/modules | awk '($1==1 && $2==1){print $3}' | xargs git checkout --
# sed either wants -i'' (GNU sed) or -i '' (BSD sed) to
# replace in a file, with no backup extension. Define
# a `reinplace` command to deal with the difference.
if test FreeBSD = `uname` ; then
reinplace() {
sed -i '' "$@"
}
else
reinplace() {
sed -i'' "$@"
}
fi
# Go through the Python modules; those with a lang/ subdir have their # Go through the Python modules; those with a lang/ subdir have their
# own complete gettext-based setup. # own complete gettext-based setup.
for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
@ -125,7 +153,7 @@ for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
if [ -d ${MODULE_DIR}/lang ]; then if [ -d ${MODULE_DIR}/lang ]; then
# Convert PO files to MO files # Convert PO files to MO files
for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE reinplace '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
# msgfmt -o ${POFILE%.po}.mo $POFILE # msgfmt -o ${POFILE%.po}.mo $POFILE
done done
git add --verbose ${MODULE_DIR}/lang/* git add --verbose ${MODULE_DIR}/lang/*
@ -135,7 +163,7 @@ for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
done done
for POFILE in $(find lang -name "python.po") ; do for POFILE in $(find lang -name "python.po") ; do
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE reinplace '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
# msgfmt -o ${POFILE%.po}.mo $POFILE # msgfmt -o ${POFILE%.po}.mo $POFILE
done done
git add --verbose lang/python* git add --verbose lang/python*

View File

@ -693,27 +693,27 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
<source>Successfully unmounted %1.</source> <source>Successfully unmounted %1.</source>
<translation type="unfinished"/> <translation>Úspěšně odpojeno %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
<source>Successfully disabled swap %1.</source> <source>Successfully disabled swap %1.</source>
<translation type="unfinished"/> <translation>Úspěšně vypnut swap %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
<source>Successfully cleared swap %1.</source> <source>Successfully cleared swap %1.</source>
<translation type="unfinished"/> <translation>Úspěšně vyčištěn swap %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
<source>Successfully closed mapper device %1.</source> <source>Successfully closed mapper device %1.</source>
<translation type="unfinished"/> <translation>Úspěšně zavřeno mapper zařízení %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
<source>Successfully disabled volume group %1.</source> <source>Successfully disabled volume group %1.</source>
<translation type="unfinished"/> <translation>Úspěšně vypnuta skupina svazků %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>

File diff suppressed because it is too large Load Diff

View File

@ -1989,7 +1989,7 @@ The installer will quit and all changes will be lost.</translation>
<message> <message>
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/> <location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
<source>Configuration Error</source> <source>Configuration Error</source>
<translation type="unfinished"/> <translation>Configuration Error </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/> <location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>

View File

@ -689,27 +689,27 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
<source>Successfully unmounted %1.</source> <source>Successfully unmounted %1.</source>
<translation type="unfinished"/> <translation>%1 </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
<source>Successfully disabled swap %1.</source> <source>Successfully disabled swap %1.</source>
<translation type="unfinished"/> <translation>%1 िि </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
<source>Successfully cleared swap %1.</source> <source>Successfully cleared swap %1.</source>
<translation type="unfinished"/> <translation>%1 ि </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
<source>Successfully closed mapper device %1.</source> <source>Successfully closed mapper device %1.</source>
<translation type="unfinished"/> <translation>िि %1 </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
<source>Successfully disabled volume group %1.</source> <source>Successfully disabled volume group %1.</source>
<translation type="unfinished"/> <translation> %1 िि </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>

View File

@ -6,7 +6,7 @@
<message> <message>
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/> <location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
<source>Manage auto-mount settings</source> <source>Manage auto-mount settings</source>
<translation type="unfinished"/> <translation>Kelola pengaturan mount otomatis</translation>
</message> </message>
</context> </context>
<context> <context>
@ -114,12 +114,12 @@
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="141"/> <location filename="../src/calamares/DebugWindow.ui" line="141"/>
<source>Uploads the session log to the configured pastebin.</source> <source>Uploads the session log to the configured pastebin.</source>
<translation type="unfinished"/> <translation>Unggah catatan sesi ke pastebin yang telah dikonfigurasi.</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="144"/> <location filename="../src/calamares/DebugWindow.ui" line="144"/>
<source>Send Session Log</source> <source>Send Session Log</source>
<translation type="unfinished"/> <translation>Kirim Catatan Sesi</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="118"/> <location filename="../src/calamares/DebugWindow.ui" line="118"/>
@ -165,7 +165,7 @@
<message> <message>
<location filename="../src/libcalamares/JobExample.cpp" line="30"/> <location filename="../src/libcalamares/JobExample.cpp" line="30"/>
<source>Programmed job failure was explicitly requested.</source> <source>Programmed job failure was explicitly requested.</source>
<translation type="unfinished"/> <translation>Kegagalan pekerjaan diprogram diminta secara eksplisit. </translation>
</message> </message>
</context> </context>
<context> <context>
@ -189,7 +189,7 @@
<message> <message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/> <location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
<source>Run command '%1' in target system.</source> <source>Run command '%1' in target system.</source>
<translation>Jalankan perintah '%1' di dalam sistem target.</translation> <translation>Jalankan perintah '%1' pada sistem target.</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/> <location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
@ -245,7 +245,7 @@
<message> <message>
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/> <location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/>
<source>QML Step &lt;i&gt;%1&lt;/i&gt;.</source> <source>QML Step &lt;i&gt;%1&lt;/i&gt;.</source>
<translation type="unfinished"/> <translation>QML Langkah &lt;i&gt;%1&lt;/i&gt;.</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/> <location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/>
@ -277,7 +277,7 @@
<message> <message>
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/> <location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/>
<source>System-requirements checking is complete.</source> <source>System-requirements checking is complete.</source>
<translation type="unfinished"/> <translation>Pengecekan kebutuhan sistem telah selesai.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -295,7 +295,7 @@
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
<source>Would you like to paste the install log to the web?</source> <source>Would you like to paste the install log to the web?</source>
<translation>Maukah anda untuk menempelkan log instalasi ke situs?</translation> <translation>Maukah anda menempelkan log instalasi ke situs?</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
@ -429,7 +429,7 @@ Link copied to clipboard</source>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/>
<source>&amp;Done</source> <source>&amp;Done</source>
<translation>&amp;Kelar</translation> <translation>&amp;Selesai</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/>
@ -1054,12 +1054,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/> <location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/>
<source>Label for the filesystem</source> <source>Label for the filesystem</source>
<translation type="unfinished"/> <translation>Label untuk filesystem</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/> <location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/>
<source>FS Label:</source> <source>FS Label:</source>
<translation type="unfinished"/> <translation>Label FS:</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/> <location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/>
@ -1418,12 +1418,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/> <location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/>
<source>Label for the filesystem</source> <source>Label for the filesystem</source>
<translation type="unfinished"/> <translation>Label untuk filesystem</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/> <location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/>
<source>FS Label:</source> <source>FS Label:</source>
<translation type="unfinished"/> <translation>Label FS:</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/> <location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/>
@ -1582,7 +1582,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/> <location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/>
<source>Format partition %1 (file system: %2, size: %3 MiB) on %4.</source> <source>Format partition %1 (file system: %2, size: %3 MiB) on %4.</source>
<translation type="unfinished"/> <translation>Format partisi %1 (file system: %2, ukuran %3 MiB) pada %4.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/> <location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/>
@ -1645,12 +1645,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/> <location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/>
<source>is running the installer as an administrator (root)</source> <source>is running the installer as an administrator (root)</source>
<translation type="unfinished"/> <translation>menjalankan installer sebagai administrator (root)</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/> <location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/>
<source>The setup program is not running with administrator rights.</source> <source>The setup program is not running with administrator rights.</source>
<translation type="unfinished"/> <translation>Installer tidak dijalankan dengan kewenangan administrator.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/> <location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/>
@ -1699,7 +1699,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/oemid/IDJob.cpp" line="53"/> <location filename="../src/modules/oemid/IDJob.cpp" line="53"/>
<source>Could not open file &lt;code&gt;%1&lt;/code&gt;.</source> <source>Could not open file &lt;code&gt;%1&lt;/code&gt;.</source>
<translation type="unfinished"/> <translation>Tidak dapat membuka berkas &lt;code&gt;%1&lt;/code&gt;.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/oemid/IDJob.cpp" line="60"/> <location filename="../src/modules/oemid/IDJob.cpp" line="60"/>
@ -1712,7 +1712,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/> <location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/>
<source>Creating initramfs with mkinitcpio.</source> <source>Creating initramfs with mkinitcpio.</source>
<translation type="unfinished"/> <translation>Membuat initramfs menggunakan mkinitcpio.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1720,7 +1720,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/> <location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/>
<source>Creating initramfs.</source> <source>Creating initramfs.</source>
<translation type="unfinished"/> <translation>Membuat initramfs.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -2031,12 +2031,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/>
<source>Browser software</source> <source>Browser software</source>
<translation>Peramban perangkat lunak</translation> <translation>Perangkat lunak peramban</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/>
<source>Browser package</source> <source>Browser package</source>
<translation>Peramban paket</translation> <translation>Paket peramban</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/>
@ -2046,12 +2046,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/>
<source>Kernel</source> <source>Kernel</source>
<translation>Inti</translation> <translation>Kernel</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/>
<source>Services</source> <source>Services</source>
<translation>Jasa</translation> <translation>Servis</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="57"/> <location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="57"/>
@ -2587,12 +2587,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
<location filename="../src/modules/users/page_usersetup.ui" line="380"/> <location filename="../src/modules/users/page_usersetup.ui" line="380"/>
<location filename="../src/modules/users/page_usersetup.ui" line="550"/> <location filename="../src/modules/users/page_usersetup.ui" line="550"/>
<source>Repeat Password</source> <source>Repeat Password</source>
<translation type="unfinished"/> <translation>Ulangi Kata Sandi</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/users/page_usersetup.ui" line="455"/> <location filename="../src/modules/users/page_usersetup.ui" line="455"/>
<source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source> <source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source>
<translation type="unfinished"/> <translation>Ketikan kotak ini dicentang, pengecekan kekuatan kata sandi akan dilakukan dan anda tidak akan dapat menggunakan kata sandi yang lemah.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/users/page_usersetup.ui" line="458"/> <location filename="../src/modules/users/page_usersetup.ui" line="458"/>
@ -4252,7 +4252,7 @@ Keluaran:
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="136"/> <location filename="../src/modules/usersq/usersq.qml" line="136"/>
<source>root is not allowed as username.</source> <source>root is not allowed as username.</source>
<translation type="unfinished"/> <translation>root tidak boleh digunakan sebagai nama pengguna.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="145"/> <location filename="../src/modules/usersq/usersq.qml" line="145"/>
@ -4287,7 +4287,7 @@ Keluaran:
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="234"/> <location filename="../src/modules/usersq/usersq.qml" line="234"/>
<source>Repeat Password</source> <source>Repeat Password</source>
<translation type="unfinished"/> <translation>Ulangi Kata Sandi</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="261"/> <location filename="../src/modules/usersq/usersq.qml" line="261"/>
@ -4297,27 +4297,27 @@ Keluaran:
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="406"/> <location filename="../src/modules/usersq/usersq.qml" line="406"/>
<source>Validate passwords quality</source> <source>Validate passwords quality</source>
<translation type="unfinished"/> <translation>Validasi kualitas kata sandi</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="416"/> <location filename="../src/modules/usersq/usersq.qml" line="416"/>
<source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source> <source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source>
<translation type="unfinished"/> <translation>Ketikan kotak ini dicentang, pengecekan kekuatan kata sandi akan dilakukan dan anda tidak akan dapat menggunakan kata sandi yang lemah.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="398"/> <location filename="../src/modules/usersq/usersq.qml" line="398"/>
<source>Log in automatically without asking for the password</source> <source>Log in automatically without asking for the password</source>
<translation type="unfinished"/> <translation>Masuk ke dalam sesi secara otomatis tanpa menanyakan kata sandi</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="190"/> <location filename="../src/modules/usersq/usersq.qml" line="190"/>
<source>Only letters, numbers, underscore and hyphen are allowed, minimal of two characters.</source> <source>Only letters, numbers, underscore and hyphen are allowed, minimal of two characters.</source>
<translation type="unfinished"/> <translation>Hanya huruf, angka, garis bawah, dan tanda hubung yang diperbolehkan, minimal dua karakter.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="293"/> <location filename="../src/modules/usersq/usersq.qml" line="293"/>
<source>Reuse user password as root password</source> <source>Reuse user password as root password</source>
<translation type="unfinished"/> <translation>Gunakan kata sandi pengguna sebagai kata sandi root</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="301"/> <location filename="../src/modules/usersq/usersq.qml" line="301"/>
@ -4332,12 +4332,12 @@ Keluaran:
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="324"/> <location filename="../src/modules/usersq/usersq.qml" line="324"/>
<source>Root Password</source> <source>Root Password</source>
<translation type="unfinished"/> <translation>Kata Sandi Root</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="342"/> <location filename="../src/modules/usersq/usersq.qml" line="342"/>
<source>Repeat Root Password</source> <source>Repeat Root Password</source>
<translation type="unfinished"/> <translation>Ulangi Kata Sandi</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/usersq/usersq.qml" line="368"/> <location filename="../src/modules/usersq/usersq.qml" line="368"/>

4366
lang/calamares_ja-Hira.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2014,7 +2014,7 @@ O instalador será encerrado e todas as alterações serão perdidas.</translati
<source>Please select your preferred location on the map so the installer can suggest the locale <source>Please select your preferred location on the map so the installer can suggest the locale
and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging
to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.</source> to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.</source>
<translation>Por favor selecione o seu local preferido no mapa para que o instalador possa sugerir a localização <translation>Selecione o seu local preferido no mapa para que o instalador possa sugerir a localização
e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando
para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation> para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation>
</message> </message>
@ -4003,7 +4003,7 @@ Saída de Dados:
<message> <message>
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/> <location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
<source>&lt;h1&gt;%1&lt;/h1&gt;&lt;br/&gt;&lt;strong&gt;%2&lt;br/&gt;for %3&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;Copyright 2014-2017 Teo Mrnjavac &amp;lt;teo@kde.org&amp;gt;&lt;br/&gt;Copyright 2017-2020 Adriaan de Groot &amp;lt;groot@kde.org&amp;gt;&lt;br/&gt;Thanks to &lt;a href="https://calamares.io/team/"&gt;the Calamares team&lt;/a&gt; and the &lt;a href="https://www.transifex.com/calamares/calamares/"&gt;Calamares translators team&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;&lt;a href="https://calamares.io/"&gt;Calamares&lt;/a&gt; development is sponsored by &lt;br/&gt;&lt;a href="http://www.blue-systems.com/"&gt;Blue Systems&lt;/a&gt; - Liberating Software.</source> <source>&lt;h1&gt;%1&lt;/h1&gt;&lt;br/&gt;&lt;strong&gt;%2&lt;br/&gt;for %3&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;Copyright 2014-2017 Teo Mrnjavac &amp;lt;teo@kde.org&amp;gt;&lt;br/&gt;Copyright 2017-2020 Adriaan de Groot &amp;lt;groot@kde.org&amp;gt;&lt;br/&gt;Thanks to &lt;a href="https://calamares.io/team/"&gt;the Calamares team&lt;/a&gt; and the &lt;a href="https://www.transifex.com/calamares/calamares/"&gt;Calamares translators team&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;&lt;a href="https://calamares.io/"&gt;Calamares&lt;/a&gt; development is sponsored by &lt;br/&gt;&lt;a href="http://www.blue-systems.com/"&gt;Blue Systems&lt;/a&gt; - Liberating Software.</source>
<translation>&lt;h1&gt;%1&lt;/h1&gt;&lt;br/&gt;&lt;strong&gt;%2&lt;br/&gt;para %3&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;Copyright 2014-2017 Teo Mrnjavac &amp;lt;teo@kde.org&amp;gt;&lt;br/&gt;Copyright 2017-2020 Adriaan de Groot &amp;lt;groot@kde.org&amp;gt;&lt;br/&gt;Obrigado à &lt;a href="https://calamares.io/team/"&gt;equipa Calamares&lt;/a&gt; e à &lt;a href="https://www.transifex.com/calamares/calamares/"&gt;equipa de tradutores do Calamares&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;O desenvolvimento do &lt;a href="https://calamares.io/"&gt;Calamares&lt;/a&gt; é patrocinado pela &lt;br/&gt;&lt;a href="http://www.blue-systems.com/"&gt;Blue Systems&lt;/a&gt; - Liberating Software.</translation> <translation>&lt;h1&gt;%1&lt;/h1&gt;&lt;br/&gt;&lt;strong&gt;%2&lt;br/&gt;para o %3&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;Copyright 2014-2017 Teo Mrnjavac &amp;lt;teo@kde.org&amp;gt;&lt;br/&gt;Copyright 2017-2020 Adriaan de Groot &amp;lt;groot@kde.org&amp;gt;&lt;br/&gt;Obrigado à &lt;a href="https://calamares.io/team/"&gt;equipa Calamares&lt;/a&gt; e à &lt;a href="https://www.transifex.com/calamares/calamares/"&gt;equipa de tradutores do Calamares&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;O desenvolvimento do &lt;a href="https://calamares.io/"&gt;Calamares&lt;/a&gt; é patrocinado pela &lt;br/&gt;&lt;a href="http://www.blue-systems.com/"&gt;Blue Systems&lt;/a&gt; - Liberating Software.</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -104,17 +104,17 @@
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="102"/> <location filename="../src/calamares/DebugWindow.ui" line="102"/>
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source> <source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
<translation type="unfinished"/> <translation> crash lui Calamares, pentru ca doctorul Konqui se uite la el.</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="115"/> <location filename="../src/calamares/DebugWindow.ui" line="115"/>
<source>Reloads the stylesheet from the branding directory.</source> <source>Reloads the stylesheet from the branding directory.</source>
<translation type="unfinished"/> <translation>Reîncarcă foaia de stil din directorul branding.</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="141"/> <location filename="../src/calamares/DebugWindow.ui" line="141"/>
<source>Uploads the session log to the configured pastebin.</source> <source>Uploads the session log to the configured pastebin.</source>
<translation type="unfinished"/> <translation>Încarcă jurnalul sesiunii pe pastebin-ul configurat.</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="144"/> <location filename="../src/calamares/DebugWindow.ui" line="144"/>
@ -134,7 +134,7 @@
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="131"/> <location filename="../src/calamares/DebugWindow.ui" line="131"/>
<source>Widget Tree</source> <source>Widget Tree</source>
<translation>Lista widget</translation> <translation>Arborele de widget</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.cpp" line="221"/> <location filename="../src/calamares/DebugWindow.cpp" line="221"/>
@ -1991,7 +1991,7 @@ Programul de instalare va ieși, iar toate modificările vor fi pierdute.</trans
<message> <message>
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/> <location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
<source>Configuration Error</source> <source>Configuration Error</source>
<translation type="unfinished"/> <translation>Eroare de configurare</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/> <location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>

View File

@ -688,27 +688,27 @@ Alla ändringar kommer att gå förlorade.</translation>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
<source>Successfully unmounted %1.</source> <source>Successfully unmounted %1.</source>
<translation type="unfinished"/> <translation>Framgångsrikt avmonterade %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
<source>Successfully disabled swap %1.</source> <source>Successfully disabled swap %1.</source>
<translation type="unfinished"/> <translation>Framgångsrikt inaktiverade swap %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
<source>Successfully cleared swap %1.</source> <source>Successfully cleared swap %1.</source>
<translation type="unfinished"/> <translation>Framgångsrikt rensade swap %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
<source>Successfully closed mapper device %1.</source> <source>Successfully closed mapper device %1.</source>
<translation type="unfinished"/> <translation>Framgångsrikt stängde krypterad enhet %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
<source>Successfully disabled volume group %1.</source> <source>Successfully disabled volume group %1.</source>
<translation type="unfinished"/> <translation>Framgångsrikt inaktiverade volymgrupp %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>

4377
lang/calamares_ta_IN.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
<message> <message>
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/> <location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
<source>Manage auto-mount settings</source> <source>Manage auto-mount settings</source>
<translation type="unfinished"/> <translation>Идора кардани танзимоти васлкунии худкор</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -6,7 +6,7 @@
<message> <message>
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/> <location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
<source>Manage auto-mount settings</source> <source>Manage auto-mount settings</source>
<translation type="unfinished"/> <translation>Quản cài đt tự đng gắn kết(auto-mount)</translation>
</message> </message>
</context> </context>
<context> <context>
@ -104,22 +104,22 @@
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="102"/> <location filename="../src/calamares/DebugWindow.ui" line="102"/>
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source> <source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
<translation type="unfinished"/> <translation>Gây crash Calamares, đ Dr. Konqui thể xem .</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="115"/> <location filename="../src/calamares/DebugWindow.ui" line="115"/>
<source>Reloads the stylesheet from the branding directory.</source> <source>Reloads the stylesheet from the branding directory.</source>
<translation type="unfinished"/> <translation>Tải lại stylesheet từ thư mục branding</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="141"/> <location filename="../src/calamares/DebugWindow.ui" line="141"/>
<source>Uploads the session log to the configured pastebin.</source> <source>Uploads the session log to the configured pastebin.</source>
<translation type="unfinished"/> <translation>Đăng tải log của phiên này lên pastebin đã đưc cấu hình</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="144"/> <location filename="../src/calamares/DebugWindow.ui" line="144"/>
<source>Send Session Log</source> <source>Send Session Log</source>
<translation type="unfinished"/> <translation>Gửi log của phiên này</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="118"/> <location filename="../src/calamares/DebugWindow.ui" line="118"/>
@ -129,7 +129,7 @@
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="128"/> <location filename="../src/calamares/DebugWindow.ui" line="128"/>
<source>Displays the tree of widget names in the log (for stylesheet debugging).</source> <source>Displays the tree of widget names in the log (for stylesheet debugging).</source>
<translation type="unfinished"/> <translation>Hiễn thị cây của tên widget trong log(đ gỡ lỗi stylesheet)</translation>
</message> </message>
<message> <message>
<location filename="../src/calamares/DebugWindow.ui" line="131"/> <location filename="../src/calamares/DebugWindow.ui" line="131"/>

View File

@ -688,27 +688,27 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
<source>Successfully unmounted %1.</source> <source>Successfully unmounted %1.</source>
<translation type="unfinished"/> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
<source>Successfully disabled swap %1.</source> <source>Successfully disabled swap %1.</source>
<translation type="unfinished"/> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
<source>Successfully cleared swap %1.</source> <source>Successfully cleared swap %1.</source>
<translation type="unfinished"/> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
<source>Successfully closed mapper device %1.</source> <source>Successfully closed mapper device %1.</source>
<translation type="unfinished"/> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
<source>Successfully disabled volume group %1.</source> <source>Successfully disabled volume group %1.</source>
<translation type="unfinished"/> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/> <location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>

View File

@ -2,409 +2,403 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2022-02-01 17:27+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n" "Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: src/modules/initramfscfg/main.py:32 #: src/modules/initramfscfg/main.py:32
msgid "Configuring initramfs." msgid "Configuring initramfs."
msgstr "Configuring initramfs." msgstr ""
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89 #: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361 #: src/modules/fstab/main.py:360 src/modules/fstab/main.py:366
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105 #: src/modules/fstab/main.py:393 src/modules/networkcfg/main.py:105
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231 #: src/modules/initcpiocfg/main.py:235 src/modules/initcpiocfg/main.py:239
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144 #: src/modules/localecfg/main.py:135 src/modules/mount/main.py:229
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72 #: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
#: src/modules/openrcdmcryptcfg/main.py:76 #: src/modules/openrcdmcryptcfg/main.py:76
#: src/modules/luksopenswaphookcfg/main.py:86
#: src/modules/luksopenswaphookcfg/main.py:90
msgid "Configuration Error" msgid "Configuration Error"
msgstr "Configuration Error" msgstr ""
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356 #: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:361
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145 #: src/modules/initcpiocfg/main.py:236 src/modules/mount/main.py:230
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73 #: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
#: src/modules/luksopenswaphookcfg/main.py:87
msgid "No partitions are defined for <pre>{!s}</pre> to use." msgid "No partitions are defined for <pre>{!s}</pre> to use."
msgstr "No partitions are defined for <pre>{!s}</pre> to use." msgstr ""
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362 #: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:367
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232 #: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:240
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77 #: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
#: src/modules/luksopenswaphookcfg/main.py:91
msgid "No root mount point is given for <pre>{!s}</pre> to use." msgid "No root mount point is given for <pre>{!s}</pre> to use."
msgstr "No root mount point is given for <pre>{!s}</pre> to use." msgstr ""
#: src/modules/grubcfg/main.py:28 #: src/modules/grubcfg/main.py:28
msgid "Configure GRUB." msgid "Configure GRUB."
msgstr "Configure GRUB." msgstr ""
#: src/modules/bootloader/main.py:43 #: src/modules/bootloader/main.py:43
msgid "Install bootloader." msgid "Install bootloader."
msgstr "Install bootloader."
#: src/modules/bootloader/main.py:508
msgid "Bootloader installation error"
msgstr "Bootloader installation error"
#: src/modules/bootloader/main.py:509
msgid ""
"The bootloader could not be installed. The installation command "
"<pre>{!s}</pre> returned error code {!s}."
msgstr "" msgstr ""
"The bootloader could not be installed. The installation command "
"<pre>{!s}</pre> returned error code {!s}." #: src/modules/bootloader/main.py:612
msgid "Failed to install grub, no partitions defined in global storage"
msgstr ""
#: src/modules/bootloader/main.py:780
msgid "Bootloader installation error"
msgstr ""
#: src/modules/bootloader/main.py:781
msgid ""
"The bootloader could not be installed. The installation command <pre>{!s}</"
"pre> returned error code {!s}."
msgstr ""
#: src/modules/fstab/main.py:29 #: src/modules/fstab/main.py:29
msgid "Writing fstab." msgid "Writing fstab."
msgstr "Writing fstab." msgstr ""
#: src/modules/fstab/main.py:389 #: src/modules/fstab/main.py:394
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use." msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
msgstr "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use." msgstr ""
#: src/modules/dracut/main.py:27 #: src/modules/dracut/main.py:27
msgid "Creating initramfs with dracut." msgid "Creating initramfs with dracut."
msgstr "Creating initramfs with dracut." msgstr ""
#: src/modules/dracut/main.py:49 #: src/modules/dracut/main.py:49
msgid "Failed to run dracut on the target" msgid "Failed to run dracut on the target"
msgstr "Failed to run dracut on the target" msgstr ""
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50 #: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
msgid "The exit code was {}" msgid "The exit code was {}"
msgstr "The exit code was {}" msgstr ""
#: src/modules/displaymanager/main.py:526 #: src/modules/displaymanager/main.py:524
msgid "Cannot write KDM configuration file" msgid "Cannot write KDM configuration file"
msgstr "Cannot write KDM configuration file" msgstr ""
#: src/modules/displaymanager/main.py:527 #: src/modules/displaymanager/main.py:525
msgid "KDM config file {!s} does not exist" msgid "KDM config file {!s} does not exist"
msgstr "KDM config file {!s} does not exist" msgstr ""
#: src/modules/displaymanager/main.py:588 #: src/modules/displaymanager/main.py:586
msgid "Cannot write LXDM configuration file" msgid "Cannot write LXDM configuration file"
msgstr "Cannot write LXDM configuration file" msgstr ""
#: src/modules/displaymanager/main.py:589 #: src/modules/displaymanager/main.py:587
msgid "LXDM config file {!s} does not exist" msgid "LXDM config file {!s} does not exist"
msgstr "LXDM config file {!s} does not exist" msgstr ""
#: src/modules/displaymanager/main.py:672 #: src/modules/displaymanager/main.py:670
msgid "Cannot write LightDM configuration file" msgid "Cannot write LightDM configuration file"
msgstr "Cannot write LightDM configuration file" msgstr ""
#: src/modules/displaymanager/main.py:673 #: src/modules/displaymanager/main.py:671
msgid "LightDM config file {!s} does not exist" msgid "LightDM config file {!s} does not exist"
msgstr "LightDM config file {!s} does not exist" msgstr ""
#: src/modules/displaymanager/main.py:747 #: src/modules/displaymanager/main.py:745
msgid "Cannot configure LightDM" msgid "Cannot configure LightDM"
msgstr "Cannot configure LightDM" msgstr ""
#: src/modules/displaymanager/main.py:748 #: src/modules/displaymanager/main.py:746
msgid "No LightDM greeter installed." msgid "No LightDM greeter installed."
msgstr "No LightDM greeter installed." msgstr ""
#: src/modules/displaymanager/main.py:779 #: src/modules/displaymanager/main.py:777
msgid "Cannot write SLIM configuration file" msgid "Cannot write SLIM configuration file"
msgstr "Cannot write SLIM configuration file" msgstr ""
#: src/modules/displaymanager/main.py:780 #: src/modules/displaymanager/main.py:778
msgid "SLIM config file {!s} does not exist" msgid "SLIM config file {!s} does not exist"
msgstr "SLIM config file {!s} does not exist" msgstr ""
#: src/modules/displaymanager/main.py:906 #: src/modules/displaymanager/main.py:991
msgid "No display managers selected for the displaymanager module." msgid "No display managers selected for the displaymanager module."
msgstr "No display managers selected for the displaymanager module." msgstr ""
#: src/modules/displaymanager/main.py:907 #: src/modules/displaymanager/main.py:992
msgid "" msgid ""
"The displaymanagers list is empty or undefined in both globalstorage and " "The displaymanagers list is empty or undefined in both globalstorage and "
"displaymanager.conf." "displaymanager.conf."
msgstr "" msgstr ""
"The displaymanagers list is empty or undefined in both globalstorage and "
"displaymanager.conf."
#: src/modules/displaymanager/main.py:989 #: src/modules/displaymanager/main.py:1074
msgid "Display manager configuration was incomplete" msgid "Display manager configuration was incomplete"
msgstr "Display manager configuration was incomplete" msgstr ""
#: src/modules/services-openrc/main.py:29 #: src/modules/services-openrc/main.py:29
msgid "Configure OpenRC services" msgid "Configure OpenRC services"
msgstr "Configure OpenRC services" msgstr ""
#: src/modules/services-openrc/main.py:57 #: src/modules/services-openrc/main.py:57
msgid "Cannot add service {name!s} to run-level {level!s}." msgid "Cannot add service {name!s} to run-level {level!s}."
msgstr "Cannot add service {name!s} to run-level {level!s}." msgstr ""
#: src/modules/services-openrc/main.py:59 #: src/modules/services-openrc/main.py:59
msgid "Cannot remove service {name!s} from run-level {level!s}." msgid "Cannot remove service {name!s} from run-level {level!s}."
msgstr "Cannot remove service {name!s} from run-level {level!s}." msgstr ""
#: src/modules/services-openrc/main.py:61 #: src/modules/services-openrc/main.py:61
msgid "" msgid ""
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-" "Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
"level {level!s}." "level {level!s}."
msgstr "" msgstr ""
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
"level {level!s}."
#: src/modules/services-openrc/main.py:93 #: src/modules/services-openrc/main.py:93
#: src/modules/services-systemd/main.py:59 #: src/modules/services-systemd/main.py:59
msgid "Cannot modify service" msgid "Cannot modify service"
msgstr "Cannot modify service" msgstr ""
#: src/modules/services-openrc/main.py:94 #: src/modules/services-openrc/main.py:94
msgid "" msgid ""
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}." "<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
msgstr "" msgstr ""
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
#: src/modules/services-openrc/main.py:101 #: src/modules/services-openrc/main.py:101
msgid "Target runlevel does not exist" msgid "Target runlevel does not exist"
msgstr "Target runlevel does not exist" msgstr ""
#: src/modules/services-openrc/main.py:102 #: src/modules/services-openrc/main.py:102
msgid "" msgid ""
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not " "The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
"exist." "exist."
msgstr "" msgstr ""
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
"exist."
#: src/modules/services-openrc/main.py:110 #: src/modules/services-openrc/main.py:110
msgid "Target service does not exist" msgid "Target service does not exist"
msgstr "Target service does not exist" msgstr ""
#: src/modules/services-openrc/main.py:111 #: src/modules/services-openrc/main.py:111
msgid "" msgid ""
"The path for service {name!s} is <code>{path!s}</code>, which does not " "The path for service {name!s} is <code>{path!s}</code>, which does not exist."
"exist."
msgstr "" msgstr ""
"The path for service {name!s} is <code>{path!s}</code>, which does not "
"exist."
#: src/modules/networkcfg/main.py:29 #: src/modules/networkcfg/main.py:29
msgid "Saving network configuration." msgid "Saving network configuration."
msgstr "Saving network configuration." msgstr ""
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59 #: src/modules/packages/main.py:54 src/modules/packages/main.py:65
#: src/modules/packages/main.py:69 #: src/modules/packages/main.py:75
msgid "Install packages." msgid "Install packages."
msgstr "Install packages." msgstr ""
#: src/modules/packages/main.py:57 #: src/modules/packages/main.py:63
#, python-format #, python-format
msgid "Processing packages (%(count)d / %(total)d)" msgid "Processing packages (%(count)d / %(total)d)"
msgstr "Processing packages (%(count)d / %(total)d)" msgstr ""
#: src/modules/packages/main.py:62 #: src/modules/packages/main.py:68
#, python-format #, python-format
msgid "Installing one package." msgid "Installing one package."
msgid_plural "Installing %(num)d packages." msgid_plural "Installing %(num)d packages."
msgstr[0] "Installing one package." msgstr[0] ""
msgstr[1] "Installing %(num)d packages." msgstr[1] ""
#: src/modules/packages/main.py:65 #: src/modules/packages/main.py:71
#, python-format #, python-format
msgid "Removing one package." msgid "Removing one package."
msgid_plural "Removing %(num)d packages." msgid_plural "Removing %(num)d packages."
msgstr[0] "Removing one package." msgstr[0] ""
msgstr[1] "Removing %(num)d packages." msgstr[1] ""
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650 #: src/modules/packages/main.py:725 src/modules/packages/main.py:737
#: src/modules/packages/main.py:678 #: src/modules/packages/main.py:765
msgid "Package Manager error" msgid "Package Manager error"
msgstr "Package Manager error" msgstr ""
#: src/modules/packages/main.py:639 #: src/modules/packages/main.py:726
msgid "" msgid ""
"The package manager could not prepare updates. The command <pre>{!s}</pre> " "The package manager could not prepare updates. The command <pre>{!s}</pre> "
"returned error code {!s}." "returned error code {!s}."
msgstr "" msgstr ""
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
#: src/modules/packages/main.py:738
msgid ""
"The package manager could not update the system. The command <pre>{!s}</pre> "
"returned error code {!s}." "returned error code {!s}."
#: src/modules/packages/main.py:651
msgid ""
"The package manager could not update the system. The command <pre>{!s}</pre>"
" returned error code {!s}."
msgstr "" msgstr ""
"The package manager could not update the system. The command <pre>{!s}</pre>"
" returned error code {!s}."
#: src/modules/packages/main.py:679 #: src/modules/packages/main.py:766
msgid "" msgid ""
"The package manager could not make changes to the installed system. The " "The package manager could not make changes to the installed system. The "
"command <pre>{!s}</pre> returned error code {!s}." "command <pre>{!s}</pre> returned error code {!s}."
msgstr "" msgstr ""
"The package manager could not make changes to the installed system. The "
"command <pre>{!s}</pre> returned error code {!s}."
#: src/modules/plymouthcfg/main.py:27 #: src/modules/plymouthcfg/main.py:27
msgid "Configure Plymouth theme" msgid "Configure Plymouth theme"
msgstr "Configure Plymouth theme" msgstr ""
#: src/modules/initcpiocfg/main.py:28 #: src/modules/initcpiocfg/main.py:28
msgid "Configuring mkinitcpio." msgid "Configuring mkinitcpio."
msgstr "Configuring mkinitcpio." msgstr ""
#: src/modules/localecfg/main.py:30 #: src/modules/localecfg/main.py:30
msgid "Configuring locales." msgid "Configuring locales."
msgstr "Configuring locales." msgstr ""
#: src/modules/mount/main.py:30 #: src/modules/mount/main.py:42
msgid "Mounting partitions." msgid "Mounting partitions."
msgstr "Mounting partitions." msgstr ""
#: src/modules/mount/main.py:88 src/modules/mount/main.py:124
msgid "Internal error mounting zfs datasets"
msgstr ""
#: src/modules/mount/main.py:100
msgid "Failed to import zpool"
msgstr ""
#: src/modules/mount/main.py:116
msgid "Failed to unlock zpool"
msgstr ""
#: src/modules/mount/main.py:133 src/modules/mount/main.py:138
msgid "Failed to set zfs mountpoint"
msgstr ""
#: src/modules/mount/main.py:253
msgid "zfs mounting error"
msgstr ""
#: src/modules/rawfs/main.py:26 #: src/modules/rawfs/main.py:26
msgid "Installing data." msgid "Installing data."
msgstr "Installing data." msgstr ""
#: src/modules/dummypython/main.py:35 #: src/modules/dummypython/main.py:35
msgid "Dummy python job." msgid "Dummy python job."
msgstr "Dummy python job." msgstr ""
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93 #: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
#: src/modules/dummypython/main.py:94 #: src/modules/dummypython/main.py:94
msgid "Dummy python step {}" msgid "Dummy python step {}"
msgstr "Dummy python step {}" msgstr ""
#: src/modules/hwclock/main.py:26 #: src/modules/hwclock/main.py:26
msgid "Setting hardware clock." msgid "Setting hardware clock."
msgstr "Setting hardware clock." msgstr ""
#: src/modules/umount/main.py:31
msgid "Unmount file systems."
msgstr "Unmount file systems."
#: src/modules/openrcdmcryptcfg/main.py:26 #: src/modules/openrcdmcryptcfg/main.py:26
msgid "Configuring OpenRC dmcrypt service." msgid "Configuring OpenRC dmcrypt service."
msgstr "Configuring OpenRC dmcrypt service." msgstr ""
#: src/modules/services-systemd/main.py:26 #: src/modules/services-systemd/main.py:26
msgid "Configure systemd services" msgid "Configure systemd services"
msgstr "Configure systemd services" msgstr ""
#: src/modules/services-systemd/main.py:60 #: src/modules/services-systemd/main.py:60
msgid "" msgid ""
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}." "<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
msgstr "" msgstr ""
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
#: src/modules/services-systemd/main.py:63 #: src/modules/services-systemd/main.py:63
#: src/modules/services-systemd/main.py:69 #: src/modules/services-systemd/main.py:69
msgid "Cannot enable systemd service <code>{name!s}</code>." msgid "Cannot enable systemd service <code>{name!s}</code>."
msgstr "Cannot enable systemd service <code>{name!s}</code>." msgstr ""
#: src/modules/services-systemd/main.py:65 #: src/modules/services-systemd/main.py:65
msgid "Cannot enable systemd target <code>{name!s}</code>." msgid "Cannot enable systemd target <code>{name!s}</code>."
msgstr "Cannot enable systemd target <code>{name!s}</code>." msgstr ""
#: src/modules/services-systemd/main.py:67 #: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>." msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr "Cannot enable systemd timer <code>{name!s}</code>." msgstr ""
#: src/modules/services-systemd/main.py:71 #: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>." msgid "Cannot disable systemd target <code>{name!s}</code>."
msgstr "Cannot disable systemd target <code>{name!s}</code>." msgstr ""
#: src/modules/services-systemd/main.py:73 #: src/modules/services-systemd/main.py:73
msgid "Cannot mask systemd unit <code>{name!s}</code>." msgid "Cannot mask systemd unit <code>{name!s}</code>."
msgstr "Cannot mask systemd unit <code>{name!s}</code>." msgstr ""
#: src/modules/services-systemd/main.py:75 #: src/modules/services-systemd/main.py:75
msgid "" msgid ""
"Unknown systemd commands <code>{command!s}</code> and " "Unknown systemd commands <code>{command!s}</code> and <code>{suffix!s}</"
"<code>{suffix!s}</code> for unit {name!s}." "code> for unit {name!s}."
msgstr "" msgstr ""
"Unknown systemd commands <code>{command!s}</code> and "
"<code>{suffix!s}</code> for unit {name!s}."
#: src/modules/mkinitfs/main.py:27 #: src/modules/mkinitfs/main.py:27
msgid "Creating initramfs with mkinitfs." msgid "Creating initramfs with mkinitfs."
msgstr "Creating initramfs with mkinitfs." msgstr ""
#: src/modules/mkinitfs/main.py:49 #: src/modules/mkinitfs/main.py:49
msgid "Failed to run mkinitfs on the target" msgid "Failed to run mkinitfs on the target"
msgstr "Failed to run mkinitfs on the target" msgstr ""
#: src/modules/unpackfs/main.py:34 #: src/modules/unpackfs/main.py:34
msgid "Filling up filesystems." msgid "Filling up filesystems."
msgstr "Filling up filesystems." msgstr ""
#: src/modules/unpackfs/main.py:254 #: src/modules/unpackfs/main.py:254
msgid "rsync failed with error code {}." msgid "rsync failed with error code {}."
msgstr "rsync failed with error code {}." msgstr ""
#: src/modules/unpackfs/main.py:299 #: src/modules/unpackfs/main.py:299
msgid "Unpacking image {}/{}, file {}/{}" msgid "Unpacking image {}/{}, file {}/{}"
msgstr "Unpacking image {}/{}, file {}/{}" msgstr ""
#: src/modules/unpackfs/main.py:314 #: src/modules/unpackfs/main.py:314
msgid "Starting to unpack {}" msgid "Starting to unpack {}"
msgstr "Starting to unpack {}" msgstr ""
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465 #: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:467
msgid "Failed to unpack image \"{}\"" msgid "Failed to unpack image \"{}\""
msgstr "Failed to unpack image \"{}\"" msgstr ""
#: src/modules/unpackfs/main.py:430 #: src/modules/unpackfs/main.py:430
msgid "No mount point for root partition" msgid "No mount point for root partition"
msgstr "No mount point for root partition" msgstr ""
#: src/modules/unpackfs/main.py:431 #: src/modules/unpackfs/main.py:431
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" msgid "globalstorage does not contain a \"rootMountPoint\" key."
msgstr "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" msgstr ""
#: src/modules/unpackfs/main.py:436 #: src/modules/unpackfs/main.py:434
msgid "Bad mount point for root partition" msgid "Bad mount point for root partition"
msgstr "Bad mount point for root partition" msgstr ""
#: src/modules/unpackfs/main.py:437 #: src/modules/unpackfs/main.py:435
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing" msgid "rootMountPoint is \"{}\", which does not exist."
msgstr "rootMountPoint is \"{}\", which does not exist, doing nothing" msgstr ""
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457 #: src/modules/unpackfs/main.py:439 src/modules/unpackfs/main.py:455
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478 #: src/modules/unpackfs/main.py:459 src/modules/unpackfs/main.py:465
msgid "Bad unsquash configuration" #: src/modules/unpackfs/main.py:480
msgstr "Bad unsquash configuration" msgid "Bad unpackfs configuration"
msgstr ""
#: src/modules/unpackfs/main.py:454 #: src/modules/unpackfs/main.py:440
msgid "There is no configuration information."
msgstr ""
#: src/modules/unpackfs/main.py:456
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel" msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
msgstr "The filesystem for \"{}\" ({}) is not supported by your current kernel" msgstr ""
#: src/modules/unpackfs/main.py:458 #: src/modules/unpackfs/main.py:460
msgid "The source filesystem \"{}\" does not exist" msgid "The source filesystem \"{}\" does not exist"
msgstr "The source filesystem \"{}\" does not exist" msgstr ""
#: src/modules/unpackfs/main.py:464 #: src/modules/unpackfs/main.py:466
msgid "" msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package " "Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed." "installed."
msgstr "" msgstr ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed."
#: src/modules/unpackfs/main.py:479 #: src/modules/unpackfs/main.py:481
msgid "The destination \"{}\" in the target system is not a directory" msgid "The destination \"{}\" in the target system is not a directory"
msgstr "The destination \"{}\" in the target system is not a directory" msgstr ""
#: src/modules/luksopenswaphookcfg/main.py:26
msgid "Configuring encrypted swap."
msgstr "Configuring encrypted swap."

View File

@ -6,7 +6,7 @@
# Translators: # Translators:
# pavelrz, 2017 # pavelrz, 2017
# LiberteCzech <martin.kriz.czech@gmail.com>, 2020 # LiberteCzech <martin.kriz.czech@gmail.com>, 2020
# Pavel Borecki <pavel.borecki@gmail.com>, 2021 # Pavel Borecki <pavel.borecki@gmail.com>, 2022
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -15,7 +15,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2021\n" "Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2022\n"
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n" "Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -331,7 +331,7 @@ msgstr "Nedaří se zapnout systemd službu <code>{name!s}</code>."
#: src/modules/services-systemd/main.py:67 #: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>." msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr "" msgstr "Nedaří se zapnout systemd časovač <code>{name!s}</code>."
#: src/modules/services-systemd/main.py:71 #: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>." msgid "Cannot disable systemd target <code>{name!s}</code>."
@ -413,6 +413,8 @@ msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package " "Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed." "installed."
msgstr "" msgstr ""
"Nepodařilo se nalézt nástroj unsquashfs ověřte, že je nainstalovaný "
"balíček squashfs-tools."
#: src/modules/unpackfs/main.py:479 #: src/modules/unpackfs/main.py:479
msgid "The destination \"{}\" in the target system is not a directory" msgid "The destination \"{}\" in the target system is not a directory"

View File

@ -5,6 +5,7 @@
# #
# Translators: # Translators:
# Jason Collins <JasonPCollins@protonmail.com>, 2018 # Jason Collins <JasonPCollins@protonmail.com>, 2018
# Karthik Balan, 2021
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -13,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Last-Translator: Jason Collins <JasonPCollins@protonmail.com>, 2018\n" "Last-Translator: Karthik Balan, 2021\n"
"Language-Team: English (United Kingdom) (https://www.transifex.com/calamares/teams/20061/en_GB/)\n" "Language-Team: English (United Kingdom) (https://www.transifex.com/calamares/teams/20061/en_GB/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -35,7 +36,7 @@ msgstr ""
#: src/modules/luksopenswaphookcfg/main.py:86 #: src/modules/luksopenswaphookcfg/main.py:86
#: src/modules/luksopenswaphookcfg/main.py:90 #: src/modules/luksopenswaphookcfg/main.py:90
msgid "Configuration Error" msgid "Configuration Error"
msgstr "" msgstr "Configuration Error "
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356 #: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145 #: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
@ -61,7 +62,7 @@ msgstr ""
#: src/modules/bootloader/main.py:508 #: src/modules/bootloader/main.py:508
msgid "Bootloader installation error" msgid "Bootloader installation error"
msgstr "" msgstr "Bootloader installation error"
#: src/modules/bootloader/main.py:509 #: src/modules/bootloader/main.py:509
msgid "" msgid ""
@ -91,7 +92,7 @@ msgstr ""
#: src/modules/displaymanager/main.py:526 #: src/modules/displaymanager/main.py:526
msgid "Cannot write KDM configuration file" msgid "Cannot write KDM configuration file"
msgstr "" msgstr "Cannot write KDM configuration file"
#: src/modules/displaymanager/main.py:527 #: src/modules/displaymanager/main.py:527
msgid "KDM config file {!s} does not exist" msgid "KDM config file {!s} does not exist"
@ -145,7 +146,7 @@ msgstr ""
#: src/modules/services-openrc/main.py:29 #: src/modules/services-openrc/main.py:29
msgid "Configure OpenRC services" msgid "Configure OpenRC services"
msgstr "" msgstr "Configure OpenRC services"
#: src/modules/services-openrc/main.py:57 #: src/modules/services-openrc/main.py:57
msgid "Cannot add service {name!s} to run-level {level!s}." msgid "Cannot add service {name!s} to run-level {level!s}."
@ -173,7 +174,7 @@ msgstr ""
#: src/modules/services-openrc/main.py:101 #: src/modules/services-openrc/main.py:101
msgid "Target runlevel does not exist" msgid "Target runlevel does not exist"
msgstr "" msgstr "Target runlevel does not exist"
#: src/modules/services-openrc/main.py:102 #: src/modules/services-openrc/main.py:102
msgid "" msgid ""
@ -193,7 +194,7 @@ msgstr ""
#: src/modules/networkcfg/main.py:29 #: src/modules/networkcfg/main.py:29
msgid "Saving network configuration." msgid "Saving network configuration."
msgstr "" msgstr "Saving network configuration "
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59 #: src/modules/packages/main.py:50 src/modules/packages/main.py:59
#: src/modules/packages/main.py:69 #: src/modules/packages/main.py:69
@ -222,7 +223,7 @@ msgstr[1] "Removing %(num)d packages."
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650 #: src/modules/packages/main.py:638 src/modules/packages/main.py:650
#: src/modules/packages/main.py:678 #: src/modules/packages/main.py:678
msgid "Package Manager error" msgid "Package Manager error"
msgstr "" msgstr "Package Manager error"
#: src/modules/packages/main.py:639 #: src/modules/packages/main.py:639
msgid "" msgid ""

View File

@ -319,7 +319,7 @@ msgstr "systemd लक्ष्य <code>{name!s}</code>सक्रिय क
#: src/modules/services-systemd/main.py:67 #: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>." msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr "" msgstr "systemd टाइमर <code>{name!s}</code>सक्रिय करना विफल।"
#: src/modules/services-systemd/main.py:71 #: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>." msgid "Cannot disable systemd target <code>{name!s}</code>."
@ -399,6 +399,8 @@ msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package " "Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed." "installed."
msgstr "" msgstr ""
"unsqaushfs खोजने में विफल, सुनिश्चित करें कि squashfs-tools पैकेज इंस्टॉल "
"है।"
#: src/modules/unpackfs/main.py:479 #: src/modules/unpackfs/main.py:479
msgid "The destination \"{}\" in the target system is not a directory" msgid "The destination \"{}\" in the target system is not a directory"

View File

@ -0,0 +1,385 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Language-Team: Japanese (Hiragana) (https://www.transifex.com/calamares/teams/20061/ja-Hira/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ja-Hira\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: src/modules/initramfscfg/main.py:32
msgid "Configuring initramfs."
msgstr ""
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
#: src/modules/openrcdmcryptcfg/main.py:76
#: src/modules/luksopenswaphookcfg/main.py:86
#: src/modules/luksopenswaphookcfg/main.py:90
msgid "Configuration Error"
msgstr ""
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
#: src/modules/luksopenswaphookcfg/main.py:87
msgid "No partitions are defined for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
#: src/modules/luksopenswaphookcfg/main.py:91
msgid "No root mount point is given for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/grubcfg/main.py:28
msgid "Configure GRUB."
msgstr ""
#: src/modules/bootloader/main.py:43
msgid "Install bootloader."
msgstr ""
#: src/modules/bootloader/main.py:508
msgid "Bootloader installation error"
msgstr ""
#: src/modules/bootloader/main.py:509
msgid ""
"The bootloader could not be installed. The installation command "
"<pre>{!s}</pre> returned error code {!s}."
msgstr ""
#: src/modules/fstab/main.py:29
msgid "Writing fstab."
msgstr ""
#: src/modules/fstab/main.py:389
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/dracut/main.py:27
msgid "Creating initramfs with dracut."
msgstr ""
#: src/modules/dracut/main.py:49
msgid "Failed to run dracut on the target"
msgstr ""
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
msgid "The exit code was {}"
msgstr ""
#: src/modules/displaymanager/main.py:526
msgid "Cannot write KDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:527
msgid "KDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:588
msgid "Cannot write LXDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:589
msgid "LXDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:672
msgid "Cannot write LightDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:673
msgid "LightDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:747
msgid "Cannot configure LightDM"
msgstr ""
#: src/modules/displaymanager/main.py:748
msgid "No LightDM greeter installed."
msgstr ""
#: src/modules/displaymanager/main.py:779
msgid "Cannot write SLIM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:780
msgid "SLIM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:906
msgid "No display managers selected for the displaymanager module."
msgstr ""
#: src/modules/displaymanager/main.py:907
msgid ""
"The displaymanagers list is empty or undefined in both globalstorage and "
"displaymanager.conf."
msgstr ""
#: src/modules/displaymanager/main.py:989
msgid "Display manager configuration was incomplete"
msgstr ""
#: src/modules/services-openrc/main.py:29
msgid "Configure OpenRC services"
msgstr ""
#: src/modules/services-openrc/main.py:57
msgid "Cannot add service {name!s} to run-level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:59
msgid "Cannot remove service {name!s} from run-level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:61
msgid ""
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
"level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:93
#: src/modules/services-systemd/main.py:59
msgid "Cannot modify service"
msgstr ""
#: src/modules/services-openrc/main.py:94
msgid ""
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
msgstr ""
#: src/modules/services-openrc/main.py:101
msgid "Target runlevel does not exist"
msgstr ""
#: src/modules/services-openrc/main.py:102
msgid ""
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
"exist."
msgstr ""
#: src/modules/services-openrc/main.py:110
msgid "Target service does not exist"
msgstr ""
#: src/modules/services-openrc/main.py:111
msgid ""
"The path for service {name!s} is <code>{path!s}</code>, which does not "
"exist."
msgstr ""
#: src/modules/networkcfg/main.py:29
msgid "Saving network configuration."
msgstr ""
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
#: src/modules/packages/main.py:69
msgid "Install packages."
msgstr ""
#: src/modules/packages/main.py:57
#, python-format
msgid "Processing packages (%(count)d / %(total)d)"
msgstr ""
#: src/modules/packages/main.py:62
#, python-format
msgid "Installing one package."
msgid_plural "Installing %(num)d packages."
msgstr[0] ""
#: src/modules/packages/main.py:65
#, python-format
msgid "Removing one package."
msgid_plural "Removing %(num)d packages."
msgstr[0] ""
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
#: src/modules/packages/main.py:678
msgid "Package Manager error"
msgstr ""
#: src/modules/packages/main.py:639
msgid ""
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
"returned error code {!s}."
msgstr ""
#: src/modules/packages/main.py:651
msgid ""
"The package manager could not update the system. The command <pre>{!s}</pre>"
" returned error code {!s}."
msgstr ""
#: src/modules/packages/main.py:679
msgid ""
"The package manager could not make changes to the installed system. The "
"command <pre>{!s}</pre> returned error code {!s}."
msgstr ""
#: src/modules/plymouthcfg/main.py:27
msgid "Configure Plymouth theme"
msgstr ""
#: src/modules/initcpiocfg/main.py:28
msgid "Configuring mkinitcpio."
msgstr ""
#: src/modules/localecfg/main.py:30
msgid "Configuring locales."
msgstr ""
#: src/modules/mount/main.py:30
msgid "Mounting partitions."
msgstr ""
#: src/modules/rawfs/main.py:26
msgid "Installing data."
msgstr ""
#: src/modules/dummypython/main.py:35
msgid "Dummy python job."
msgstr ""
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
#: src/modules/dummypython/main.py:94
msgid "Dummy python step {}"
msgstr ""
#: src/modules/hwclock/main.py:26
msgid "Setting hardware clock."
msgstr ""
#: src/modules/umount/main.py:31
msgid "Unmount file systems."
msgstr ""
#: src/modules/openrcdmcryptcfg/main.py:26
msgid "Configuring OpenRC dmcrypt service."
msgstr ""
#: src/modules/services-systemd/main.py:26
msgid "Configure systemd services"
msgstr ""
#: src/modules/services-systemd/main.py:60
msgid ""
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
msgstr ""
#: src/modules/services-systemd/main.py:63
#: src/modules/services-systemd/main.py:69
msgid "Cannot enable systemd service <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:65
msgid "Cannot enable systemd target <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:73
msgid "Cannot mask systemd unit <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:75
msgid ""
"Unknown systemd commands <code>{command!s}</code> and "
"<code>{suffix!s}</code> for unit {name!s}."
msgstr ""
#: src/modules/mkinitfs/main.py:27
msgid "Creating initramfs with mkinitfs."
msgstr ""
#: src/modules/mkinitfs/main.py:49
msgid "Failed to run mkinitfs on the target"
msgstr ""
#: src/modules/unpackfs/main.py:34
msgid "Filling up filesystems."
msgstr ""
#: src/modules/unpackfs/main.py:254
msgid "rsync failed with error code {}."
msgstr ""
#: src/modules/unpackfs/main.py:299
msgid "Unpacking image {}/{}, file {}/{}"
msgstr ""
#: src/modules/unpackfs/main.py:314
msgid "Starting to unpack {}"
msgstr ""
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
msgid "Failed to unpack image \"{}\""
msgstr ""
#: src/modules/unpackfs/main.py:430
msgid "No mount point for root partition"
msgstr ""
#: src/modules/unpackfs/main.py:431
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
msgstr ""
#: src/modules/unpackfs/main.py:436
msgid "Bad mount point for root partition"
msgstr ""
#: src/modules/unpackfs/main.py:437
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
msgstr ""
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
msgid "Bad unsquash configuration"
msgstr ""
#: src/modules/unpackfs/main.py:454
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
msgstr ""
#: src/modules/unpackfs/main.py:458
msgid "The source filesystem \"{}\" does not exist"
msgstr ""
#: src/modules/unpackfs/main.py:464
msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed."
msgstr ""
#: src/modules/unpackfs/main.py:479
msgid "The destination \"{}\" in the target system is not a directory"
msgstr ""
#: src/modules/luksopenswaphookcfg/main.py:26
msgid "Configuring encrypted swap."
msgstr ""

View File

@ -4,7 +4,7 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
# Translators: # Translators:
# Marcin Mikołajczak <me@mkljczk.pl>, 2017 # marcin mikołajczak <me@mkljczk.pl>, 2017
# KagiSame, 2018 # KagiSame, 2018
# Piotr Strębski <strebski@gmail.com>, 2020 # Piotr Strębski <strebski@gmail.com>, 2020
# Jacob B. <brickminerplyt@gmail.com>, 2021 # Jacob B. <brickminerplyt@gmail.com>, 2021

View File

@ -6,6 +6,7 @@
# Translators: # Translators:
# Jobava Jobava <jobaval10n@gmail.com>, 2018 # Jobava Jobava <jobaval10n@gmail.com>, 2018
# Sebastian Brici <bricisebastian@gmail.com>, 2018 # Sebastian Brici <bricisebastian@gmail.com>, 2018
# Chele Ion <krovyoll@gmail.com>, 2021
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -14,7 +15,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Last-Translator: Sebastian Brici <bricisebastian@gmail.com>, 2018\n" "Last-Translator: Chele Ion <krovyoll@gmail.com>, 2021\n"
"Language-Team: Romanian (https://www.transifex.com/calamares/teams/20061/ro/)\n" "Language-Team: Romanian (https://www.transifex.com/calamares/teams/20061/ro/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -24,7 +25,7 @@ msgstr ""
#: src/modules/initramfscfg/main.py:32 #: src/modules/initramfscfg/main.py:32
msgid "Configuring initramfs." msgid "Configuring initramfs."
msgstr "" msgstr "Configurare initramfs"
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89 #: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361 #: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
@ -36,21 +37,21 @@ msgstr ""
#: src/modules/luksopenswaphookcfg/main.py:86 #: src/modules/luksopenswaphookcfg/main.py:86
#: src/modules/luksopenswaphookcfg/main.py:90 #: src/modules/luksopenswaphookcfg/main.py:90
msgid "Configuration Error" msgid "Configuration Error"
msgstr "" msgstr "Eroare de configurare"
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356 #: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145 #: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73 #: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
#: src/modules/luksopenswaphookcfg/main.py:87 #: src/modules/luksopenswaphookcfg/main.py:87
msgid "No partitions are defined for <pre>{!s}</pre> to use." msgid "No partitions are defined for <pre>{!s}</pre> to use."
msgstr "" msgstr "Nu sunt partiţii definite ca 1{!s}1 ."
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362 #: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232 #: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77 #: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
#: src/modules/luksopenswaphookcfg/main.py:91 #: src/modules/luksopenswaphookcfg/main.py:91
msgid "No root mount point is given for <pre>{!s}</pre> to use." msgid "No root mount point is given for <pre>{!s}</pre> to use."
msgstr "" msgstr "Nu este definită o partiţie rădăcină pentru 1{!s}1 ."
#: src/modules/grubcfg/main.py:28 #: src/modules/grubcfg/main.py:28
msgid "Configure GRUB." msgid "Configure GRUB."

View File

@ -0,0 +1,387 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Language-Team: Tamil (India) (https://www.transifex.com/calamares/teams/20061/ta_IN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ta_IN\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/modules/initramfscfg/main.py:32
msgid "Configuring initramfs."
msgstr ""
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
#: src/modules/openrcdmcryptcfg/main.py:76
#: src/modules/luksopenswaphookcfg/main.py:86
#: src/modules/luksopenswaphookcfg/main.py:90
msgid "Configuration Error"
msgstr ""
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
#: src/modules/luksopenswaphookcfg/main.py:87
msgid "No partitions are defined for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
#: src/modules/luksopenswaphookcfg/main.py:91
msgid "No root mount point is given for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/grubcfg/main.py:28
msgid "Configure GRUB."
msgstr ""
#: src/modules/bootloader/main.py:43
msgid "Install bootloader."
msgstr ""
#: src/modules/bootloader/main.py:508
msgid "Bootloader installation error"
msgstr ""
#: src/modules/bootloader/main.py:509
msgid ""
"The bootloader could not be installed. The installation command "
"<pre>{!s}</pre> returned error code {!s}."
msgstr ""
#: src/modules/fstab/main.py:29
msgid "Writing fstab."
msgstr ""
#: src/modules/fstab/main.py:389
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
msgstr ""
#: src/modules/dracut/main.py:27
msgid "Creating initramfs with dracut."
msgstr ""
#: src/modules/dracut/main.py:49
msgid "Failed to run dracut on the target"
msgstr ""
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
msgid "The exit code was {}"
msgstr ""
#: src/modules/displaymanager/main.py:526
msgid "Cannot write KDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:527
msgid "KDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:588
msgid "Cannot write LXDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:589
msgid "LXDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:672
msgid "Cannot write LightDM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:673
msgid "LightDM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:747
msgid "Cannot configure LightDM"
msgstr ""
#: src/modules/displaymanager/main.py:748
msgid "No LightDM greeter installed."
msgstr ""
#: src/modules/displaymanager/main.py:779
msgid "Cannot write SLIM configuration file"
msgstr ""
#: src/modules/displaymanager/main.py:780
msgid "SLIM config file {!s} does not exist"
msgstr ""
#: src/modules/displaymanager/main.py:906
msgid "No display managers selected for the displaymanager module."
msgstr ""
#: src/modules/displaymanager/main.py:907
msgid ""
"The displaymanagers list is empty or undefined in both globalstorage and "
"displaymanager.conf."
msgstr ""
#: src/modules/displaymanager/main.py:989
msgid "Display manager configuration was incomplete"
msgstr ""
#: src/modules/services-openrc/main.py:29
msgid "Configure OpenRC services"
msgstr ""
#: src/modules/services-openrc/main.py:57
msgid "Cannot add service {name!s} to run-level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:59
msgid "Cannot remove service {name!s} from run-level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:61
msgid ""
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
"level {level!s}."
msgstr ""
#: src/modules/services-openrc/main.py:93
#: src/modules/services-systemd/main.py:59
msgid "Cannot modify service"
msgstr ""
#: src/modules/services-openrc/main.py:94
msgid ""
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
msgstr ""
#: src/modules/services-openrc/main.py:101
msgid "Target runlevel does not exist"
msgstr ""
#: src/modules/services-openrc/main.py:102
msgid ""
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
"exist."
msgstr ""
#: src/modules/services-openrc/main.py:110
msgid "Target service does not exist"
msgstr ""
#: src/modules/services-openrc/main.py:111
msgid ""
"The path for service {name!s} is <code>{path!s}</code>, which does not "
"exist."
msgstr ""
#: src/modules/networkcfg/main.py:29
msgid "Saving network configuration."
msgstr ""
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
#: src/modules/packages/main.py:69
msgid "Install packages."
msgstr ""
#: src/modules/packages/main.py:57
#, python-format
msgid "Processing packages (%(count)d / %(total)d)"
msgstr ""
#: src/modules/packages/main.py:62
#, python-format
msgid "Installing one package."
msgid_plural "Installing %(num)d packages."
msgstr[0] ""
msgstr[1] ""
#: src/modules/packages/main.py:65
#, python-format
msgid "Removing one package."
msgid_plural "Removing %(num)d packages."
msgstr[0] ""
msgstr[1] ""
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
#: src/modules/packages/main.py:678
msgid "Package Manager error"
msgstr ""
#: src/modules/packages/main.py:639
msgid ""
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
"returned error code {!s}."
msgstr ""
#: src/modules/packages/main.py:651
msgid ""
"The package manager could not update the system. The command <pre>{!s}</pre>"
" returned error code {!s}."
msgstr ""
#: src/modules/packages/main.py:679
msgid ""
"The package manager could not make changes to the installed system. The "
"command <pre>{!s}</pre> returned error code {!s}."
msgstr ""
#: src/modules/plymouthcfg/main.py:27
msgid "Configure Plymouth theme"
msgstr ""
#: src/modules/initcpiocfg/main.py:28
msgid "Configuring mkinitcpio."
msgstr ""
#: src/modules/localecfg/main.py:30
msgid "Configuring locales."
msgstr ""
#: src/modules/mount/main.py:30
msgid "Mounting partitions."
msgstr ""
#: src/modules/rawfs/main.py:26
msgid "Installing data."
msgstr ""
#: src/modules/dummypython/main.py:35
msgid "Dummy python job."
msgstr ""
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
#: src/modules/dummypython/main.py:94
msgid "Dummy python step {}"
msgstr ""
#: src/modules/hwclock/main.py:26
msgid "Setting hardware clock."
msgstr ""
#: src/modules/umount/main.py:31
msgid "Unmount file systems."
msgstr ""
#: src/modules/openrcdmcryptcfg/main.py:26
msgid "Configuring OpenRC dmcrypt service."
msgstr ""
#: src/modules/services-systemd/main.py:26
msgid "Configure systemd services"
msgstr ""
#: src/modules/services-systemd/main.py:60
msgid ""
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
msgstr ""
#: src/modules/services-systemd/main.py:63
#: src/modules/services-systemd/main.py:69
msgid "Cannot enable systemd service <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:65
msgid "Cannot enable systemd target <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:73
msgid "Cannot mask systemd unit <code>{name!s}</code>."
msgstr ""
#: src/modules/services-systemd/main.py:75
msgid ""
"Unknown systemd commands <code>{command!s}</code> and "
"<code>{suffix!s}</code> for unit {name!s}."
msgstr ""
#: src/modules/mkinitfs/main.py:27
msgid "Creating initramfs with mkinitfs."
msgstr ""
#: src/modules/mkinitfs/main.py:49
msgid "Failed to run mkinitfs on the target"
msgstr ""
#: src/modules/unpackfs/main.py:34
msgid "Filling up filesystems."
msgstr ""
#: src/modules/unpackfs/main.py:254
msgid "rsync failed with error code {}."
msgstr ""
#: src/modules/unpackfs/main.py:299
msgid "Unpacking image {}/{}, file {}/{}"
msgstr ""
#: src/modules/unpackfs/main.py:314
msgid "Starting to unpack {}"
msgstr ""
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
msgid "Failed to unpack image \"{}\""
msgstr ""
#: src/modules/unpackfs/main.py:430
msgid "No mount point for root partition"
msgstr ""
#: src/modules/unpackfs/main.py:431
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
msgstr ""
#: src/modules/unpackfs/main.py:436
msgid "Bad mount point for root partition"
msgstr ""
#: src/modules/unpackfs/main.py:437
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
msgstr ""
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
msgid "Bad unsquash configuration"
msgstr ""
#: src/modules/unpackfs/main.py:454
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
msgstr ""
#: src/modules/unpackfs/main.py:458
msgid "The source filesystem \"{}\" does not exist"
msgstr ""
#: src/modules/unpackfs/main.py:464
msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed."
msgstr ""
#: src/modules/unpackfs/main.py:479
msgid "The destination \"{}\" in the target system is not a directory"
msgstr ""
#: src/modules/luksopenswaphookcfg/main.py:26
msgid "Configuring encrypted swap."
msgstr ""

View File

@ -5,7 +5,7 @@
# #
# Translators: # Translators:
# T. Tran <transifex@emiu.net>, 2020 # T. Tran <transifex@emiu.net>, 2020
# Th1nhhdk, 2021 # th1nhhdk <th1nhhdk@tutanota.com>, 2021
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Last-Translator: Th1nhhdk, 2021\n" "Last-Translator: th1nhhdk <th1nhhdk@tutanota.com>, 2021\n"
"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n" "Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"

View File

@ -9,6 +9,7 @@
# Feng Chao <chaofeng111@qq.com>, 2020 # Feng Chao <chaofeng111@qq.com>, 2020
# Bobby Rong <admin@bobby285271.top>, 2020 # Bobby Rong <admin@bobby285271.top>, 2020
# 玉堂白鹤 <yjwork@qq.com>, 2021 # 玉堂白鹤 <yjwork@qq.com>, 2021
# Giovanni Schiano-Moriello, 2022
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -17,7 +18,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n" "POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n"
"Last-Translator: 玉堂白鹤 <yjwork@qq.com>, 2021\n" "Last-Translator: Giovanni Schiano-Moriello, 2022\n"
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n" "Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -305,7 +306,7 @@ msgstr "无法启用 systemd 目标 <code>{name!s}</code>."
#: src/modules/services-systemd/main.py:67 #: src/modules/services-systemd/main.py:67
msgid "Cannot enable systemd timer <code>{name!s}</code>." msgid "Cannot enable systemd timer <code>{name!s}</code>."
msgstr "" msgstr "无法启用 systemd 计时器 <code>{name!s}</code>。"
#: src/modules/services-systemd/main.py:71 #: src/modules/services-systemd/main.py:71
msgid "Cannot disable systemd target <code>{name!s}</code>." msgid "Cannot disable systemd target <code>{name!s}</code>."
@ -384,7 +385,7 @@ msgstr "源文件系统 \"{}\" 不存在"
msgid "" msgid ""
"Failed to find unsquashfs, make sure you have the squashfs-tools package " "Failed to find unsquashfs, make sure you have the squashfs-tools package "
"installed." "installed."
msgstr "" msgstr "寻找 unsquashfs 失败,请确定您已安装 squashfs-tools 软体包。"
#: src/modules/unpackfs/main.py:479 #: src/modules/unpackfs/main.py:479
msgid "The destination \"{}\" in the target system is not a directory" msgid "The destination \"{}\" in the target system is not a directory"

View File

@ -485,7 +485,7 @@ main( int argc, char* argv[] )
return 1; return 1;
} }
cDebug() << Logger::SubEntry << " .. got" << m->name() << m->typeString() << m->interfaceString(); cDebug() << Logger::SubEntry << "got" << m->name() << m->typeString() << m->interfaceString();
if ( m->type() == Calamares::Module::Type::View ) if ( m->type() == Calamares::Module::Type::View )
{ {
// If we forgot the --ui, any ViewModule will core dump as it // If we forgot the --ui, any ViewModule will core dump as it
@ -535,7 +535,7 @@ main( int argc, char* argv[] )
using TR = Logger::DebugRow< const char*, const QString >; using TR = Logger::DebugRow< const char*, const QString >;
cDebug() << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() )
<< TR( "interface", m->interfaceString() ); << TR( "interface", m->interfaceString() );
Calamares::JobList jobList = m->jobs(); Calamares::JobList jobList = m->jobs();
@ -543,6 +543,8 @@ main( int argc, char* argv[] )
unsigned int count = 1; unsigned int count = 1;
for ( const auto& p : jobList ) for ( const auto& p : jobList )
{ {
// This doesn't get a SubEntry because the jobs may log a bunch of
// things; print the function-header to make clear that we're back in main.
cDebug() << "Job #" << count << "name" << p->prettyName(); cDebug() << "Job #" << count << "name" << p->prettyName();
Calamares::JobResult r = p->exec(); Calamares::JobResult r = p->exec();
if ( !r ) if ( !r )

View File

@ -47,7 +47,7 @@ public:
/** @brief Is this JobResult a success? /** @brief Is this JobResult a success?
* *
* Equivalent to errorCode() == 0, might be named isValid(). * Equivalent to errorCode() == 0, see succeeded().
*/ */
virtual operator bool() const; virtual operator bool() const;
@ -58,6 +58,11 @@ public:
virtual void setDetails( const QString& details ); virtual void setDetails( const QString& details );
int errorCode() const { return m_number; } int errorCode() const { return m_number; }
/** @brief Is this JobResult a success?
*
* Equivalent to errorCode() == 0.
*/
bool succeeded() const { return this->operator bool(); }
/// @brief an "ok status" result /// @brief an "ok status" result
static JobResult ok(); static JobResult ok();

View File

@ -122,8 +122,9 @@ public:
} }
else else
{ {
cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName() cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" )
<< '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')'; << jobitem.job->prettyName() << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count()
<< ')';
o.refresh(); // So next time it shows the function header again o.refresh(); // So next time it shows the function header again
emitProgress( 0.0 ); // 0% for *this job* emitProgress( 0.0 ); // 0% for *this job*
connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress ); connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );

View File

@ -26,6 +26,11 @@ namespace CalamaresPython
boost::python::object boost::python::object
variantToPyObject( const QVariant& variant ) variantToPyObject( const QVariant& variant )
{ {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch-enum"
#endif
// 49 enumeration values not handled
switch ( variant.type() ) switch ( variant.type() )
{ {
case QVariant::Map: case QVariant::Map:
@ -62,6 +67,9 @@ variantToPyObject( const QVariant& variant )
default: default:
return bp::object(); return bp::object();
} }
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} }

View File

@ -23,6 +23,11 @@ static const char* s_preScript = nullptr;
namespace bp = boost::python; namespace bp = boost::python;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#endif
BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 );
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_str_overloads, CalamaresPython::target_env_call, 1, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_str_overloads, CalamaresPython::target_env_call, 1, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_list_overloads, CalamaresPython::target_env_call, 1, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_list_overloads, CalamaresPython::target_env_call, 1, 3 );
@ -42,6 +47,10 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_process_output_overloads,
4 ); 4 );
BOOST_PYTHON_FUNCTION_OVERLOADS( host_env_process_output_overloads, CalamaresPython::host_env_process_output, 1, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( host_env_process_output_overloads, CalamaresPython::host_env_process_output, 1, 4 );
#ifdef __clang__
#pragma clang diagnostic pop
#endif
BOOST_PYTHON_MODULE( libcalamares ) BOOST_PYTHON_MODULE( libcalamares )
{ {
bp::object package = bp::scope(); bp::object package = bp::scope();
@ -91,7 +100,7 @@ BOOST_PYTHON_MODULE( libcalamares )
bp::args( "s" ), bp::args( "s" ),
"Writes the given string to the Calamares warning stream." ); "Writes the given string to the Calamares warning stream." );
bp::def( bp::def(
"error", &CalamaresPython::warning, bp::args( "s" ), "Writes the given string to the Calamares error stream." ); "error", &CalamaresPython::error, bp::args( "s" ), "Writes the given string to the Calamares error stream." );
// .. YAML functions // .. YAML functions

View File

@ -22,6 +22,11 @@ namespace Partition
QString QString
prettyNameForFileSystemType( FileSystem::Type t ) prettyNameForFileSystemType( FileSystem::Type t )
{ {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch-enum"
#endif
// 13 enumeration values not handled
switch ( t ) switch ( t )
{ {
case FileSystem::Unknown: case FileSystem::Unknown:
@ -60,11 +65,19 @@ prettyNameForFileSystemType( FileSystem::Type t )
default: default:
return FileSystem::nameForType( t ); return FileSystem::nameForType( t );
} }
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} }
QString QString
untranslatedFS( FileSystem::Type t ) untranslatedFS( FileSystem::Type t )
{ {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch-enum"
#endif
// 34 enumeration values not handled
switch ( t ) switch ( t )
{ {
case FileSystem::Type::ReiserFS: case FileSystem::Type::ReiserFS:
@ -72,6 +85,9 @@ untranslatedFS( FileSystem::Type t )
default: default:
return FileSystem::nameForType( t, { QStringLiteral( "C" ) } ); return FileSystem::nameForType( t, { QStringLiteral( "C" ) } );
} }
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} }
} // namespace Partition } // namespace Partition

View File

@ -14,6 +14,7 @@
#include "partition/Sync.h" #include "partition/Sync.h"
#include "utils/CalamaresUtilsSystem.h" #include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/String.h"
#include <QDir> #include <QDir>
#include <QTemporaryDir> #include <QTemporaryDir>
@ -92,7 +93,7 @@ struct TemporaryMount::Private
TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options ) TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options )
: m_d( std::make_unique<Private>() ) : m_d( std::make_unique< Private >() )
{ {
m_d->m_devicePath = devicePath; m_d->m_devicePath = devicePath;
m_d->m_mountDir.setAutoRemove( false ); m_d->m_mountDir.setAutoRemove( false );
@ -123,5 +124,32 @@ TemporaryMount::path() const
return m_d ? m_d->m_mountDir.path() : QString(); return m_d ? m_d->m_mountDir.path() : QString();
} }
QList< MtabInfo >
MtabInfo::fromMtabFilteredByPrefix( const QString& mountPrefix, const QString& mtabPath )
{
QFile f( mtabPath.isEmpty() ? "/etc/mtab" : mtabPath );
if ( !f.open( QIODevice::ReadOnly ) )
{
return {};
}
QTextStream in( &f );
QList< MtabInfo > l;
while ( !f.atEnd() )
{
QStringList line = in.readLine().split( ' ', SplitSkipEmptyParts );
if ( line.length() == 3 && !line[ 0 ].startsWith( '#' ) )
{
// Lines have format: <device> <mountpoint> <options>, so check
// the mountpoint field. Everything starts with an empty string.
if ( line[ 1 ].startsWith( mountPrefix ) )
{
l.append( { line[ 0 ], line[ 1 ] } );
}
}
}
return l;
}
} // namespace Partition } // namespace Partition
} // namespace CalamaresUtils } // namespace CalamaresUtils

View File

@ -14,6 +14,7 @@
#include "DllMacro.h" #include "DllMacro.h"
#include <QList>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
@ -50,6 +51,13 @@ DLLEXPORT int mount( const QString& devicePath,
*/ */
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() ); DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
/** @brief Mount and automatically unmount a device
*
* The TemporaryMount object mounts a filesystem, and is like calling
* the mount() function, above. When the object is destroyed, unmount()
* is called with suitable options to undo the original mount.
*/
class DLLEXPORT TemporaryMount class DLLEXPORT TemporaryMount
{ {
public: public:
@ -68,6 +76,36 @@ private:
std::unique_ptr< Private > m_d; std::unique_ptr< Private > m_d;
}; };
/** @brief Information about a mount point from /etc/mtab
*
* Entries in /etc/mtab are of the form: <device> <mountpoint> <other>
* This struct only stores device and mountpoint.
*
* The main way of getting these structs is to call fromMtab() to read
* an /etc/mtab-like file and storing all of the entries from it.
*/
struct DLLEXPORT MtabInfo
{
QString device;
QString mountPoint;
/** @brief Reads an mtab-like file and returns the entries from it
*
* When @p mtabPath is given, that file is read. If the given name is
* empty (e.g. the default) then /etc/mtab is read, instead.
*
* If @p mountPrefix is given, then only entries that have a mount point
* that starts with that prefix are returned.
*/
static QList< MtabInfo > fromMtabFilteredByPrefix( const QString& mountPrefix = QString(),
const QString& mtabPath = QString() );
/// @brief Predicate to sort MtabInfo objects by device-name
static bool deviceOrder( const MtabInfo& a, const MtabInfo& b ) { return a.device > b.device; }
/// @brief Predicate to sort MtabInfo objects by mount-point
static bool mountPointOrder( const MtabInfo& a, const MtabInfo& b ) { return a.mountPoint > b.mountPoint; }
};
} // namespace Partition } // namespace Partition
} // namespace CalamaresUtils } // namespace CalamaresUtils

View File

@ -115,12 +115,14 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
QString completePath = targetPath( path ); QString completePath = targetPath( path );
if ( completePath.isEmpty() ) if ( completePath.isEmpty() )
{ {
cWarning() << "No target path for" << path;
return CreationResult( CreationResult::Code::Invalid ); return CreationResult( CreationResult::Code::Invalid );
} }
QFile f( completePath ); QFile f( completePath );
if ( ( mode == WriteMode::KeepExisting ) && f.exists() ) if ( ( mode == WriteMode::KeepExisting ) && f.exists() )
{ {
cWarning() << "Target file" << completePath << "already exists";
return CreationResult( CreationResult::Code::AlreadyExists ); return CreationResult( CreationResult::Code::AlreadyExists );
} }
@ -133,13 +135,16 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
if ( !f.open( m ) ) if ( !f.open( m ) )
{ {
cWarning() << "Could not open target file" << completePath;
return CreationResult( CreationResult::Code::Failed ); return CreationResult( CreationResult::Code::Failed );
} }
if ( f.write( contents ) != contents.size() ) auto written = f.write( contents );
if ( written != contents.size() )
{ {
f.close(); f.close();
f.remove(); f.remove();
cWarning() << "Short write (" << written << "out of" << contents.size() << "bytes) to" << completePath;
return CreationResult( CreationResult::Code::Failed ); return CreationResult( CreationResult::Code::Failed );
} }
@ -147,6 +152,30 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
return CreationResult( QFileInfo( f ).canonicalFilePath() ); return CreationResult( QFileInfo( f ).canonicalFilePath() );
} }
QStringList
System::readTargetFile( const QString& path ) const
{
const QString completePath = targetPath( path );
if ( completePath.isEmpty() )
{
return QStringList();
}
QFile f( completePath );
if ( !f.open( QIODevice::ReadOnly ) )
{
return QStringList();
}
QTextStream in( &f );
QStringList l;
while ( !f.atEnd() )
{
l << in.readLine();
}
return l;
}
void void
System::removeTargetFile( const QString& path ) const System::removeTargetFile( const QString& path ) const
{ {

View File

@ -287,6 +287,24 @@ public:
*/ */
DLLEXPORT void removeTargetFile( const QString& path ) const; DLLEXPORT void removeTargetFile( const QString& path ) const;
/** @brief Reads a file from the target system.
*
* @param path Path to the file; this is interpreted from the root of
* the target system (@see targetPath()).
*
* Does no error checking, and returns an empty list if the file does
* not exist.
*
* NOTE: This function is now basically the same as QFile::readAll(),
* splitting into lines, but Calamares may need to change
* permissions or raise privileges to actually read the file,
* which is why there is an API.
*
* NOTE: Since this buffers the whole file in memory, reading big files
* is not recommended.
*/
DLLEXPORT QStringList readTargetFile( const QString& path ) const;
/** @brief Ensure that the directory @p path exists /** @brief Ensure that the directory @p path exists
* *
* @param path a full pathname to a desired directory. * @param path a full pathname to a desired directory.

View File

@ -259,21 +259,22 @@ operator<<( QDebug& s, const RedactedCommand& l )
* Identical strings with the same context will be hashed the same, * Identical strings with the same context will be hashed the same,
* so that they can be logged and still recognized as the-same. * so that they can be logged and still recognized as the-same.
*/ */
static uint insertRedactedName( const QString& context, const QString& s ) static uint
insertRedactedName( const QString& context, const QString& s )
{ {
static uint salt = QRandomGenerator::global()->generate(); // Just once static uint salt = QRandomGenerator::global()->generate(); // Just once
uint val = qHash(context, salt); uint val = qHash( context, salt );
return qHash(s, val); return qHash( s, val );
} }
RedactedName::RedactedName( const QString& context, const QString& s ) RedactedName::RedactedName( const QString& context, const QString& s )
: m_id( insertRedactedName(context, s) ), : m_id( insertRedactedName( context, s ) )
m_context(context) , m_context( context )
{ {
} }
RedactedName::RedactedName(const char *context, const QString& s ) RedactedName::RedactedName( const char* context, const QString& s )
: RedactedName( QString::fromLatin1( context ), s ) : RedactedName( QString::fromLatin1( context ), s )
{ {
} }

View File

@ -71,8 +71,11 @@ private:
inline CDebug& inline CDebug&
operator<<( CDebug&& s, const FuncSuppressor& f ) operator<<( CDebug&& s, const FuncSuppressor& f )
{ {
s.m_funcinfo = nullptr; if ( s.m_funcinfo )
s << f.m_s; {
s.m_funcinfo = nullptr;
s.m_msg = QString( f.m_s );
}
return s; return s;
} }
@ -244,7 +247,8 @@ private:
const QString m_context; const QString m_context;
}; };
inline QDebug& operator<<( QDebug& s, const RedactedName& n ) inline QDebug&
operator<<( QDebug& s, const RedactedName& n )
{ {
return s << NoQuote << QString( n ) << Quote; return s << NoQuote << QString( n ) << Quote;
} }

View File

@ -29,7 +29,8 @@ namespace CalamaresUtils
* @param locale the new locale (names as defined by Calamares). * @param locale the new locale (names as defined by Calamares).
* @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding. * @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding.
*/ */
DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& brandingTranslationsPrefix ); DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale,
const QString& brandingTranslationsPrefix );
/** @brief Initializes the translations with the current system settings /** @brief Initializes the translations with the current system settings
*/ */
@ -56,7 +57,8 @@ DLLEXPORT CalamaresUtils::Locale::Translation::Id translatorLocaleName();
* *
* @returns @c true on success * @returns @c true on success
*/ */
DLLEXPORT bool loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator ); DLLEXPORT bool
loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator );
/** @brief Set @p allow to true to load translations from current dir. /** @brief Set @p allow to true to load translations from current dir.
* *
@ -88,7 +90,7 @@ public:
static Retranslator* instance(); static Retranslator* instance();
/// @brief Helper function for attaching lambdas /// @brief Helper function for attaching lambdas
static void attach( QObject* o, std::function< void( void ) > f); static void attach( QObject* o, std::function< void( void ) > f );
signals: signals:
void languageChanged(); void languageChanged();
@ -138,8 +140,11 @@ private:
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \ #define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
do \ do \
{ \ { \
connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, this, slotfunc ); \ connect( CalamaresUtils::Retranslator::instance(), \
(this->*slotfunc)(); \ &CalamaresUtils::Retranslator::languageChanged, \
this, \
slotfunc ); \
( this->*slotfunc )(); \
} while ( false ) } while ( false )
#endif #endif

View File

@ -224,5 +224,26 @@ truncateMultiLine( const QString& string, CalamaresUtils::LinesStartEnd lines, C
return front + back.right( chars.total / 2 ); return front + back.right( chars.total / 2 );
} }
void
removeLeading( QString& string, QChar c )
{
int count = 0;
while ( string.length() > count && string[ count ] == c )
{
count++;
}
string.remove( 0, count );
}
void
removeTrailing( QString& string, QChar c )
{
int lastIndex = string.length();
while ( lastIndex > 0 && string[ lastIndex - 1 ] == c )
{
lastIndex--;
}
string.remove( lastIndex, string.length() );
}
} // namespace CalamaresUtils } // namespace CalamaresUtils

View File

@ -100,6 +100,19 @@ DLLEXPORT QString truncateMultiLine( const QString& string,
LinesStartEnd lines = LinesStartEnd { 3, 5 }, LinesStartEnd lines = LinesStartEnd { 3, 5 },
CharCount chars = CharCount { 812 } ); CharCount chars = CharCount { 812 } );
/** @brief Remove all @p c at the beginning of @p string
*
* Modifies the @p string in-place. If @p c is not the first character
* of @p string, the string is left unchanged; otherwise the first character
* is removed and the process repeats.
*/
DLLEXPORT void removeLeading( QString& string, QChar c );
/** @brief Remove all @p c at the end of @p string
*
* Like removeLeading(), but at the end of the string.
*/
DLLEXPORT void removeTrailing( QString& string, QChar c );
} // namespace CalamaresUtils } // namespace CalamaresUtils
#endif #endif

View File

@ -70,12 +70,19 @@ private Q_SLOTS:
void testStringTruncation(); void testStringTruncation();
void testStringTruncationShorter(); void testStringTruncationShorter();
void testStringTruncationDegenerate(); void testStringTruncationDegenerate();
void testStringRemoveLeading_data();
void testStringRemoveLeading();
void testStringRemoveTrailing_data();
void testStringRemoveTrailing();
/** @section Test Runner directory-manipulation. */ /** @section Test Runner directory-manipulation. */
void testRunnerDirs(); void testRunnerDirs();
void testCalculateWorkingDirectory(); void testCalculateWorkingDirectory();
void testRunnerOutput(); void testRunnerOutput();
/** @section Test file-functions */
void testReadWriteFile();
private: private:
void recursiveCompareMap( const QVariantMap& a, const QVariantMap& b, int depth ); void recursiveCompareMap( const QVariantMap& a, const QVariantMap& b, int depth );
}; };
@ -751,6 +758,64 @@ LibCalamaresTests::testStringTruncationDegenerate()
} }
} }
void
LibCalamaresTests::testStringRemoveLeading_data()
{
QTest::addColumn< QString >( "string" );
QTest::addColumn< char >( "c" );
QTest::addColumn< QString >( "result" );
QTest::newRow( "empty" ) << QString() << '/' << QString();
QTest::newRow( "one-slash" ) << QStringLiteral( "/tmp" ) << '/' << QStringLiteral( "tmp" );
QTest::newRow( "two-slash" ) << QStringLiteral( "//tmp" ) << '/' << QStringLiteral( "tmp" );
QTest::newRow( "multi-slash" ) << QStringLiteral( "/tmp/p" ) << '/' << QStringLiteral( "tmp/p" );
QTest::newRow( "later-slash" ) << QStringLiteral( "@/tmp" ) << '/' << QStringLiteral( "@/tmp" );
QTest::newRow( "all-one-slash" ) << QStringLiteral( "/" ) << '/' << QString();
QTest::newRow( "all-many-slash" ) << QStringLiteral( "////////////////////" ) << '/' << QString();
QTest::newRow( "trailing" ) << QStringLiteral( "tmp/" ) << '/' << QStringLiteral( "tmp/" );
}
void
LibCalamaresTests::testStringRemoveLeading()
{
QFETCH( QString, string );
QFETCH( char, c );
QFETCH( QString, result );
const QString initial = string;
CalamaresUtils::removeLeading( string, c );
QCOMPARE( string, result );
}
void
LibCalamaresTests::testStringRemoveTrailing_data()
{
QTest::addColumn< QString >( "string" );
QTest::addColumn< char >( "c" );
QTest::addColumn< QString >( "result" );
QTest::newRow( "empty" ) << QString() << '/' << QString();
QTest::newRow( "one-slash" ) << QStringLiteral( "/tmp" ) << '/' << QStringLiteral( "/tmp" );
QTest::newRow( "two-slash" ) << QStringLiteral( "//tmp" ) << '/' << QStringLiteral( "//tmp" );
QTest::newRow( "multi-slash" ) << QStringLiteral( "/tmp//p/" ) << '/' << QStringLiteral( "/tmp//p" );
QTest::newRow( "later-slash" ) << QStringLiteral( "@/tmp/@" ) << '/' << QStringLiteral( "@/tmp/@" );
QTest::newRow( "later-slash2" ) << QStringLiteral( "@/tmp/@//" ) << '/' << QStringLiteral( "@/tmp/@" );
QTest::newRow( "all-one-slash" ) << QStringLiteral( "/" ) << '/' << QString();
QTest::newRow( "all-many-slash" ) << QStringLiteral( "////////////////////" ) << '/' << QString();
QTest::newRow( "trailing" ) << QStringLiteral( "tmp/" ) << '/' << QStringLiteral( "tmp" );
}
void
LibCalamaresTests::testStringRemoveTrailing()
{
QFETCH( QString, string );
QFETCH( char, c );
QFETCH( QString, result );
const QString initial = string;
CalamaresUtils::removeTrailing( string, c );
QCOMPARE( string, result );
}
static QString static QString
dirname( const QTemporaryDir& d ) dirname( const QTemporaryDir& d )
@ -950,6 +1015,84 @@ LibCalamaresTests::testRunnerOutput()
} }
CalamaresUtils::System*
file_setup( const QTemporaryDir& tempRoot )
{
CalamaresUtils::System* ss = CalamaresUtils::System::instance();
if ( !ss )
{
ss = new CalamaresUtils::System( true );
}
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
if ( !gs )
{
cDebug() << "Creating new JobQueue";
(void)new Calamares::JobQueue();
gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
}
if ( gs )
{
// Working with a rootMountPoint set
gs->insert( "rootMountPoint", tempRoot.path() );
}
return ss;
}
void
LibCalamaresTests::testReadWriteFile()
{
static const QByteArray otherContents( "derp\n" );
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
auto* ss = file_setup( tempRoot );
QVERIFY( ss );
{
auto fullPath = ss->createTargetFile( "test0", QByteArray(), CalamaresUtils::System::WriteMode::Overwrite );
QVERIFY( fullPath );
QVERIFY( !fullPath.path().isEmpty() );
QFileInfo fi( fullPath.path() );
QVERIFY( fi.exists() );
QVERIFY( fi.isFile() );
QCOMPARE( fi.size(), 0 );
}
// It won't overwrite unless you ask for it
{
auto fullPath = ss->createTargetFile( "test0", otherContents );
QVERIFY( !fullPath ); // Failed, because it won't overwrite
QCOMPARE( fullPath.code(), decltype( fullPath )::Code::AlreadyExists );
QVERIFY( fullPath.path().isEmpty() ); // Because it wasn't written
QFileInfo fi( tempRoot.filePath( "test0" ) ); // Compute the name some other way
QVERIFY( fi.exists() );
QVERIFY( fi.isFile() );
QCOMPARE( fi.size(), 0 );
}
// But it will if you say so explicitly
{
auto fullPath = ss->createTargetFile( "test0", otherContents, CalamaresUtils::System::WriteMode::Overwrite );
QVERIFY( fullPath );
QVERIFY( !fullPath.path().isEmpty() );
QFileInfo fi( fullPath.path() );
QVERIFY( fi.exists() );
QVERIFY( fi.isFile() );
QCOMPARE( fi.size(), 5 );
}
// Now it's been written, we can read it, too
{
auto contents = ss->readTargetFile( "test0" );
QVERIFY( !contents.isEmpty() );
QCOMPARE( contents.count(), 1 );
QCOMPARE( contents[ 0 ], QStringLiteral( "derp" ) ); // No trailing \n
}
}
QTEST_GUILESS_MAIN( LibCalamaresTests ) QTEST_GUILESS_MAIN( LibCalamaresTests )
#include "utils/moc-warnings.h" #include "utils/moc-warnings.h"

View File

@ -162,14 +162,15 @@ uploadServerFromMap( const QVariantMap& map )
if ( typestring.isEmpty() || urlstring.isEmpty() ) if ( typestring.isEmpty() || urlstring.isEmpty() )
{ {
return Branding::UploadServerInfo( Branding::UploadServerType::None, QUrl(), 0 ); return Branding::UploadServerInfo { Branding::UploadServerType::None, QUrl(), 0 };
} }
bool bogus = false; // we don't care about type-name lookup success here bool bogus = false; // we don't care about type-name lookup success here
return Branding::UploadServerInfo( return Branding::UploadServerInfo {
names.find( typestring, bogus ), names.find( typestring, bogus ),
QUrl( urlstring, QUrl::ParsingMode::StrictMode ), QUrl( urlstring, QUrl::ParsingMode::StrictMode ),
sizeLimitKiB >= 0 ? CalamaresUtils::KiBtoBytes( static_cast< unsigned long long >( sizeLimitKiB ) ) : -1 ); sizeLimitKiB >= 0 ? CalamaresUtils::KiBtoBytes( static_cast< unsigned long long >( sizeLimitKiB ) ) : -1
};
} }
/** @brief Load the @p map with strings from @p config /** @brief Load the @p map with strings from @p config

View File

@ -227,7 +227,14 @@ public:
* is irrelevant and usually empty), the URL for the upload and the size limit of upload * is irrelevant and usually empty), the URL for the upload and the size limit of upload
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit). * in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
*/ */
using UploadServerInfo = std::tuple< UploadServerType, QUrl, qint64 >; struct UploadServerInfo
{
UploadServerType type;
QUrl url;
qint64 size;
operator bool() const { return type != Calamares::Branding::UploadServerType::None && size != 0; }
};
UploadServerInfo uploadServer() const { return m_uploadServer; } UploadServerInfo uploadServer() const { return m_uploadServer; }
/** /**

View File

@ -27,6 +27,7 @@ set( calamaresui_SOURCES
viewpages/ViewStep.cpp viewpages/ViewStep.cpp
widgets/ClickableLabel.cpp widgets/ClickableLabel.cpp
widgets/ErrorDialog.cpp
widgets/FixedAspectRatioLabel.cpp widgets/FixedAspectRatioLabel.cpp
widgets/PrettyRadioButton.cpp widgets/PrettyRadioButton.cpp
widgets/TranslationFix.cpp widgets/TranslationFix.cpp
@ -39,8 +40,6 @@ set( calamaresui_SOURCES
# Don't warn about third-party sources # Don't warn about third-party sources
mark_thirdparty_code( mark_thirdparty_code(
${CMAKE_SOURCE_DIR}/3rdparty/qjsonitem.cpp
${CMAKE_SOURCE_DIR}/3rdparty/qjsonmodel.cpp
${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp ${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp
) )
@ -75,6 +74,8 @@ calamares_add_library( calamaresui
Qt5::Svg Qt5::Svg
RESOURCES libcalamaresui.qrc RESOURCES libcalamaresui.qrc
EXPORT Calamares EXPORT Calamares
UI
utils/ErrorDialog/ErrorDialog.ui
VERSION ${CALAMARES_VERSION_SHORT} VERSION ${CALAMARES_VERSION_SHORT}
) )
target_link_libraries( calamaresui PRIVATE yamlcpp::yamlcpp ) target_link_libraries( calamaresui PRIVATE yamlcpp::yamlcpp )

View File

@ -24,11 +24,13 @@
#include "viewpages/BlankViewStep.h" #include "viewpages/BlankViewStep.h"
#include "viewpages/ExecutionViewStep.h" #include "viewpages/ExecutionViewStep.h"
#include "viewpages/ViewStep.h" #include "viewpages/ViewStep.h"
#include "widgets/ErrorDialog.h"
#include "widgets/TranslationFix.h" #include "widgets/TranslationFix.h"
#include <QApplication> #include <QApplication>
#include <QBoxLayout> #include <QBoxLayout>
#include <QClipboard> #include <QClipboard>
#include <QDialogButtonBox>
#include <QFile> #include <QFile>
#include <QMessageBox> #include <QMessageBox>
#include <QMetaObject> #include <QMetaObject>
@ -150,56 +152,32 @@ ViewManager::insertViewStep( int before, ViewStep* step )
void void
ViewManager::onInstallationFailed( const QString& message, const QString& details ) ViewManager::onInstallationFailed( const QString& message, const QString& details )
{ {
bool shouldOfferWebPaste = std::get< 0 >( Calamares::Branding::instance()->uploadServer() )
!= Calamares::Branding::UploadServerType::None
and std::get< 2 >( Calamares::Branding::instance()->uploadServer() ) != 0;
cError() << "Installation failed:" << message; cError() << "Installation failed:" << message;
cDebug() << Logger::SubEntry << "- message:" << message; cDebug() << Logger::SubEntry << "- message:" << message;
cDebug() << Logger::SubEntry << "- details:" << Logger::NoQuote << details; cDebug() << Logger::SubEntry << "- details:" << Logger::NoQuote << details;
QString heading QString heading
= Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" ); = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" );
QString pasteMsg = tr( "Would you like to paste the install log to the web?" );
QString text = "<p>" + message + "</p>";
if ( !details.isEmpty() )
{
text += "<p>"
+ CalamaresUtils::truncateMultiLine( details, CalamaresUtils::LinesStartEnd { 6, 2 } )
.replace( '\n', QStringLiteral( "<br/>" ) )
+ "</p>";
}
if ( shouldOfferWebPaste )
{
text += "<p>" + pasteMsg + "</p>";
}
QMessageBox* msgBox = new QMessageBox(); ErrorDialog* errorDialog = new ErrorDialog();
msgBox->setIcon( QMessageBox::Critical ); errorDialog->setWindowTitle( tr( "Error" ) );
msgBox->setWindowTitle( tr( "Error" ) ); errorDialog->setHeading( "<strong>" + heading + "</strong>" );
msgBox->setText( "<strong>" + heading + "</strong>" ); errorDialog->setInformativeText( message );
msgBox->setInformativeText( text ); errorDialog->setShouldOfferWebPaste( Calamares::Branding::instance()->uploadServer() );
if ( shouldOfferWebPaste ) errorDialog->setDetails( details );
{ errorDialog->show();
msgBox->setStandardButtons( QMessageBox::Yes | QMessageBox::No );
msgBox->setDefaultButton( QMessageBox::No );
}
else
{
msgBox->setStandardButtons( QMessageBox::Close );
msgBox->setDefaultButton( QMessageBox::Close );
}
Calamares::fixButtonLabels( msgBox );
msgBox->show();
cDebug() << "Calamares will quit when the dialog closes."; cDebug() << "Calamares will quit when the dialog closes.";
connect( msgBox, &QMessageBox::buttonClicked, [msgBox]( QAbstractButton* button ) { connect( errorDialog,
if ( msgBox->buttonRole( button ) == QMessageBox::ButtonRole::YesRole ) &QDialog::finished,
{ [ errorDialog ]( int result )
CalamaresUtils::Paste::doLogUploadUI( msgBox ); {
} if ( result == QDialog::Accepted && errorDialog->shouldOfferWebPaste() )
QApplication::quit(); {
} ); CalamaresUtils::Paste::doLogUploadUI( errorDialog );
}
QApplication::quit();
} );
} }

View File

@ -69,7 +69,8 @@ STATICTEST QString
ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* parent ) ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* parent )
{ {
QTcpSocket* socket = new QTcpSocket( parent ); QTcpSocket* socket = new QTcpSocket( parent );
socket->connectToHost( serverUrl.host(), serverUrl.port() ); // 16 bits of port-number
socket->connectToHost( serverUrl.host(), quint16( serverUrl.port() ) );
if ( !socket->waitForConnected() ) if ( !socket->waitForConnected() )
{ {

View File

@ -0,0 +1,106 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Artem Grinev <agrinev@manjaro.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#include "ErrorDialog.h"
#include "ui_ErrorDialog.h"
#include "widgets/TranslationFix.h"
#include <QDialogButtonBox>
#include <QIcon>
namespace Calamares
{
ErrorDialog::ErrorDialog( QWidget* parent )
: QDialog( parent )
, ui( new Ui::ErrorDialog )
{
ui->setupUi( this );
ui->iconLabel->setPixmap( QIcon::fromTheme( "dialog-error" ).pixmap( 64 ) );
ui->detailsWidget->hide();
ui->offerWebPasteLabel->hide();
}
ErrorDialog::~ErrorDialog()
{
delete ui;
}
QString
ErrorDialog::heading() const
{
return ui->headingLabel->text();
}
QString
ErrorDialog::informativeText() const
{
return ui->informativeTextLabel->text();
}
QString
ErrorDialog::details() const
{
return ui->detailsBrowser->toPlainText();
}
void
ErrorDialog::setHeading( const QString& newHeading )
{
if ( ui->headingLabel->text() != newHeading )
{
ui->headingLabel->setText( newHeading );
emit headingChanged();
}
}
void
ErrorDialog::setInformativeText( const QString& newInformativeText )
{
if ( ui->informativeTextLabel->text() != newInformativeText )
{
ui->informativeTextLabel->setText( newInformativeText );
emit informativeTextChanged();
}
}
void
ErrorDialog::setDetails( const QString& newDetails )
{
if ( ui->detailsBrowser->toPlainText() != newDetails )
{
ui->detailsBrowser->setPlainText( newDetails );
ui->detailsWidget->setVisible( !ui->detailsBrowser->toPlainText().trimmed().isEmpty() );
emit detailsChanged();
}
}
bool
ErrorDialog::shouldOfferWebPaste() const
{
return m_shouldOfferWebPaste;
}
void
ErrorDialog::setShouldOfferWebPaste( bool newShouldOfferWebPaste )
{
if ( m_shouldOfferWebPaste != newShouldOfferWebPaste )
{
m_shouldOfferWebPaste = newShouldOfferWebPaste;
ui->offerWebPasteLabel->setVisible( m_shouldOfferWebPaste );
ui->buttonBox->setStandardButtons( m_shouldOfferWebPaste ? ( QDialogButtonBox::Yes | QDialogButtonBox::No )
: QDialogButtonBox::Close );
fixButtonLabels( ui->buttonBox );
emit shouldOfferWebPasteChanged();
}
}
} // namespace Calamares

View File

@ -0,0 +1,83 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Artem Grinev <agrinev@manjaro.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_ERRORDIALOG_H
#define LIBCALAMARESUI_ERRORDIALOG_H
#include <QDialog>
namespace Ui
{
class ErrorDialog;
}
namespace Calamares
{
class ErrorDialog : public QDialog
{
Q_OBJECT
Q_PROPERTY( QString heading READ heading WRITE setHeading NOTIFY headingChanged )
Q_PROPERTY( QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged )
Q_PROPERTY( QString details READ details WRITE setDetails NOTIFY detailsChanged )
Q_PROPERTY( bool shouldOfferWebPaste READ shouldOfferWebPaste WRITE setShouldOfferWebPaste NOTIFY
shouldOfferWebPasteChanged )
public:
explicit ErrorDialog( QWidget* parent = nullptr );
~ErrorDialog() override;
/** @brief The heading (title) of the error dialog
*
* This is a short (one-line) title. It is human-readable, so should
* be translated at the time it is set.
*/
QString heading() const;
void setHeading( const QString& newHeading );
/** @brief The description of the problem
*
* Longer, human-readable, description of the problem. This text
* is word-wrapped as necessary.
*/
QString informativeText() const;
void setInformativeText( const QString& newInformativeText );
/** @brief Details of the problem
*
* This is generally command-output; it might not be translated
* when set. It should be considered "background to the informative
* text", or maybe "the reasons". Write the informative text for
* the end-user.
*/
QString details() const;
void setDetails( const QString& newDetails );
/** @brief Enable web-paste button
*
* The web-paste button can be configured at a global level,
* but each individual error dialog can be set separately.
*/
bool shouldOfferWebPaste() const;
void setShouldOfferWebPaste( bool newShouldOfferWebPaste );
signals:
void headingChanged();
void informativeTextChanged();
void detailsChanged();
void shouldOfferWebPasteChanged();
private:
Ui::ErrorDialog* ui;
bool m_shouldOfferWebPaste = false;
};
}; // namespace Calamares
#endif // LIBCALAMARESUI_ERRORDIALOG_H

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ErrorDialog</class>
<widget class="QDialog" name="ErrorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>425</width>
<height>262</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0" colspan="2">
<widget class="QWidget" name="detailsWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="informativeTextLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Details:</string>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="detailsBrowser"/>
</item>
</layout>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="offerWebPasteLabel">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Would you like to paste the install log to the web?</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="iconLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="headingLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ErrorDialog</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>ErrorDialog</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

@ -11,30 +11,34 @@
#include <QAbstractButton> #include <QAbstractButton>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDialogButtonBox>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton>
namespace Calamares namespace Calamares
{ {
//Using QMessageBox's StandardButton enum here but according to headers they should be kept in-sync between multiple classes.
static std::pair< decltype( QMessageBox::Ok ), const char* > maps[] = {
{ QMessageBox::Ok, QT_TRANSLATE_NOOP( "StandardButtons", "&OK" ) },
{ QMessageBox::Yes, QT_TRANSLATE_NOOP( "StandardButtons", "&Yes" ) },
{ QMessageBox::No, QT_TRANSLATE_NOOP( "StandardButtons", "&No" ) },
{ QMessageBox::Cancel, QT_TRANSLATE_NOOP( "StandardButtons", "&Cancel" ) },
{ QMessageBox::Close, QT_TRANSLATE_NOOP( "StandardButtons", "&Close" ) },
};
template < typename TButtonBox >
void void
fixButtonLabels( QMessageBox* box ) fixButtonLabels( TButtonBox* box )
{ {
if ( !box ) if ( !box )
{ {
return; return;
} }
static std::pair< decltype( QMessageBox::Ok ), const char* > maps[] = {
{ QMessageBox::Ok, QT_TRANSLATE_NOOP( "StandardButtons", "&OK" ) },
{ QMessageBox::Yes, QT_TRANSLATE_NOOP( "StandardButtons", "&Yes" ) },
{ QMessageBox::No, QT_TRANSLATE_NOOP( "StandardButtons", "&No" ) },
{ QMessageBox::Cancel, QT_TRANSLATE_NOOP( "StandardButtons", "&Cancel" ) },
{ QMessageBox::Close, QT_TRANSLATE_NOOP( "StandardButtons", "&Close" ) },
};
for ( auto [ sb, label ] : maps ) for ( auto [ sb, label ] : maps )
{ {
auto* button = box->button( sb ); auto* button = box->button( static_cast< typename TButtonBox::StandardButton >( int( sb ) ) );
if ( button ) if ( button )
{ {
button->setText( QCoreApplication::translate( "StandardButtons", label ) ); button->setText( QCoreApplication::translate( "StandardButtons", label ) );
@ -42,4 +46,16 @@ fixButtonLabels( QMessageBox* box )
} }
} }
void
fixButtonLabels( QMessageBox* box )
{
fixButtonLabels< QMessageBox >( box );
}
void
fixButtonLabels( QDialogButtonBox* box )
{
fixButtonLabels< QDialogButtonBox >( box );
}
} // namespace Calamares } // namespace Calamares

View File

@ -13,6 +13,7 @@
#include "DllMacro.h" #include "DllMacro.h"
class QMessageBox; class QMessageBox;
class QDialogButtonBox;
namespace Calamares namespace Calamares
{ {
@ -26,6 +27,8 @@ namespace Calamares
* guess the context. * guess the context.
*/ */
void UIDLLEXPORT fixButtonLabels( QMessageBox* ); void UIDLLEXPORT fixButtonLabels( QMessageBox* );
void UIDLLEXPORT fixButtonLabels( QDialogButtonBox* );
} // namespace Calamares } // namespace Calamares
#endif #endif

View File

@ -67,7 +67,7 @@ Note that process modules are not recommended.
Module descriptors **may** have the following keys: Module descriptors **may** have the following keys:
- *emergency* (a boolean value, set to true to mark the module - *emergency* (a boolean value, set to true to mark the module
as an emergency module) as an emergency module; see the section *Emergency Modules*, below)
- *noconfig* (a boolean value, set to true to state that the module - *noconfig* (a boolean value, set to true to state that the module
has no configuration file; defaults to false) has no configuration file; defaults to false)
- *requiredModules* (a list of modules which are required for this module - *requiredModules* (a list of modules which are required for this module
@ -86,24 +86,30 @@ it needs those keys.
### Emergency Modules ### Emergency Modules
Only C++ modules and job modules may be emergency modules. If, during an If, during an *exec* step in the sequence, a module fails, installation as
*exec* step in the sequence, a module fails, installation as a whole fails a whole fails and the install is aborted. If there are emergency modules
and the install is aborted. If there are emergency modules in the **same** in the **same** exec block, those will be executed before the installation
exec block, those will be executed before the installation is aborted. is aborted. Non-emergency modules are not executed.
Non-emergency modules are not executed.
If an emergency-module fails while processing emergency-modules for If an emergency-module fails while processing emergency-modules for
another failed module, that failure is ignored and emergency-module another failed module, that failure is ignored and emergency-module
processing continues. processing continues.
Use the EMERGENCY keyword in the CMake description of a C++ module Use the EMERGENCY keyword in the CMake description of a C++ module
to generate a suitable `module.desc`. to generate a suitable `module.desc`. For Python modules, manually add
`emergency: true` to `module.desc`.
A module that is marked as an emergency module in its module.desc A module that is marked as an emergency module in its module.desc
must **also** set the *emergency* key to *true* in its configuration file must **also** set the *emergency* key to *true* in its configuration file
(see below). If it does not, the module is not considered to be an emergency (see below). If it does not, the module is not considered to be an emergency
module after all (this is so that you can have modules that have several module after all. This is so that you can have modules that have several
instances, only some of which are actually needed for emergencies). instances, only some of which are actually needed for emergencies.
In summary:
- in `module.desc`, write `emergency: true` to make it **possible** to
run the module in emergency mode,
- in `<modulename>.conf`, write `emergency: true` to make that specific
module run in emergency mode.
### Module-specific configuration ### Module-specific configuration
@ -112,6 +118,10 @@ named `<modulename>.conf`. If such a file is present in the
module's directory, it can be shipped as a *default* configuration file. module's directory, it can be shipped as a *default* configuration file.
This only happens if the CMake-time option `INSTALL_CONFIG` is on. This only happens if the CMake-time option `INSTALL_CONFIG` is on.
The name of the configuration file for a given module can be
influenced by the `settings.conf` of the overall Calamares configuration.
By default, though, the module's own name is used.
Modules that have *noconfig* set to true will not attempt to Modules that have *noconfig* set to true will not attempt to
read a configuration file, and will not warn that one is missing; read a configuration file, and will not warn that one is missing;
conversely if *noconfig* is set to false (or is missing, since conversely if *noconfig* is set to false (or is missing, since
@ -169,6 +179,26 @@ it is possible to take the whole installation-process into account
for determining the relative weights there. for determining the relative weights there.
## Global storage keys
Some modules place values in global storage so that they can be referenced later by other modules or even other parts of the same module. The following table represents a partial list of the values available as well as where they originate from and which module consume them.
Key|Source|Consumers|Description
---|---|---|---
btrfsSubvolumes|mount|fstab|List of maps containing the mountpoint and btrtfs subvolume
btrfsRootSubvolume|mount|bootloader, luksopenswaphook|String containing the subvolume mounted at root
efiSystemPartition|partition|bootloader, fstab|String containing the path to the ESP relative to the installed system
extraMounts|mount|unpackfs|List of maps holding metadata for the temporary mountpoints used by the installer
hostname|users||A string containing the hostname of the new system
netinstallAdd|packagechooser|netinstall|Data to add to netinstall tree. Same format as netinstall.yaml
netinstallSelect|packagechooser|netinstall|List of group names to select in the netinstall tree
partitions|partition, rawfs|numerous modules|List of maps of metadata about each partition
rootMountPoint|mount|numerous modules|A string with the absolute path to the root mountpoint
username|users|networkcfg, plasmainf, preservefiles|A string containing the username of the new user
zfsDatasets|zfs|bootloader, grubcfg, mount|List of maps of zfs datasets including the name and mount information
zfsInfo|partition|mount, zfs|List of encrypted zfs partitions and the encription info
zfsPoolInfo|zfs|mount, umount|List of maps of zfs pool info including the name and mountpoint
## C++ modules ## C++ modules
> Type: viewmodule, jobmodule > Type: viewmodule, jobmodule

View File

@ -46,6 +46,16 @@ efiBootMgr: "efibootmgr"
# setting the option here, keep in mind that the name is sanitized # setting the option here, keep in mind that the name is sanitized
# (problematic characters, see above, are replaced). # (problematic characters, see above, are replaced).
# #
# There are some special words possible at the end of *efiBootloaderId*:
# @@SERIAL@@ can be used to obtain a uniquely-numbered suffix
# that is added to the Id (yielding, e.g., `dirname1` or `dirname72`)
# @@RANDOM@@ can be used to obtain a unique 4-digit hex suffix
# @@PHRASE@@ can be used to obtain a unique 1-to-3-word suffix
# from a dictionary of space-themed words
# Note that these must be at the **end** of the *efiBootloaderId* value.
# There must also be at most one of them. If there is none, no suffix-
# processing is done and the *efiBootloaderId* is used unchanged.
#
# efiBootloaderId: "dirname" # efiBootloaderId: "dirname"
# Optionally install a copy of the GRUB EFI bootloader as the EFI # Optionally install a copy of the GRUB EFI bootloader as the EFI

View File

@ -224,7 +224,7 @@ def create_systemd_boot_conf(install_path, efi_dir, uuid, entry, entry_name, ker
# Copy kernel and initramfs to a subdirectory of /efi partition # Copy kernel and initramfs to a subdirectory of /efi partition
files_dir = os.path.join(install_path + efi_dir, entry_name) files_dir = os.path.join(install_path + efi_dir, entry_name)
os.mkdir(files_dir) os.makedirs(files_dir, exist_ok=True)
kernel_path = install_path + kernel kernel_path = install_path + kernel
kernel_name = os.path.basename(kernel_path) kernel_name = os.path.basename(kernel_path)
@ -268,10 +268,166 @@ def create_loader(loader_path, entry):
loader_file.write(line) loader_file.write(line)
def efi_label(): class suffix_iterator(object):
"""
Wrapper for one of the "generator" classes below to behave like
a proper Python iterator. The iterator is initialized with a
maximum number of attempts to generate a new suffix.
"""
def __init__(self, attempts, generator):
self.generator = generator
self.attempts = attempts
self.counter = 0
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter <= self.attempts:
return self.generator.next()
raise StopIteration
class serialEfi(object):
"""
EFI Id generator that appends a serial number to the given name.
"""
def __init__(self, name):
self.name = name
# So the first call to next() will bump it to 0
self.counter = -1
def next(self):
self.counter += 1
if self.counter > 0:
return "{!s}{!s}".format(self.name, self.counter)
else:
return self.name
def render_in_base(value, base_values, length=-1):
"""
Renders @p value in base-N, where N is the number of
items in @p base_values. When rendering, use the items
of @p base_values (e.g. use "0123456789" to get regular decimal
rendering, or "ABCDEFGHIJ" for letters-as-numbers 'encoding').
If length is positive, pads out to at least that long with
leading "zeroes", whatever base_values[0] is.
"""
if value < 0:
raise ValueError("Cannot render negative values")
if len(base_values) < 2:
raise ValueError("Insufficient items for base-N rendering")
if length < 1:
length = 1
digits = []
base = len(base_values)
while value > 0:
place = value % base
value = value // base
digits.append(base_values[place])
while len(digits) < length:
digits.append(base_values[0])
return "".join(reversed(digits))
class randomEfi(object):
"""
EFI Id generator that appends a random 4-digit hex number to the given name.
"""
def __init__(self, name):
self.name = name
# So the first call to next() will bump it to 0
self.counter = -1
def next(self):
self.counter += 1
if self.counter > 0:
import random
v = random.randint(0, 65535) # 16 bits
return "{!s}{!s}".format(self.name, render_in_base(v, "0123456789ABCDEF", 4))
else:
return self.name
class phraseEfi(object):
"""
EFI Id generator that appends a random phrase to the given name.
"""
words = ("Sun", "Moon", "Mars", "Soyuz", "Falcon", "Kuaizhou", "Gaganyaan")
def __init__(self, name):
self.name = name
# So the first call to next() will bump it to 0
self.counter = -1
def next(self):
self.counter += 1
if self.counter > 0:
import random
desired_length = 1 + self.counter // 5
v = random.randint(0, len(self.words) ** desired_length)
return "{!s}{!s}".format(self.name, render_in_base(v, self.words))
else:
return self.name
def get_efi_suffix_generator(name):
"""
Handle EFI bootloader Ids with @@<something>@@ for suffix-processing.
"""
if "@@" not in name:
raise ValueError("Misplaced call to get_efi_suffix_generator, no @@")
parts = name.split("@@")
if len(parts) != 3:
raise ValueError("EFI Id {!r} is malformed".format(name))
if parts[2]:
# Supposed to be empty because the string ends with "@@"
raise ValueError("EFI Id {!r} is malformed".format(name))
if parts[1] not in ("SERIAL", "RANDOM", "PHRASE"):
raise ValueError("EFI suffix {!r} is unknown".format(parts[1]))
generator = None
if parts[1] == "SERIAL":
generator = serialEfi(parts[0])
elif parts[1] == "RANDOM":
generator = randomEfi(parts[0])
elif parts[1] == "PHRASE":
generator = phraseEfi(parts[0])
if generator is None:
raise ValueError("EFI suffix {!r} is unsupported".format(parts[1]))
return generator
def change_efi_suffix(efi_directory, bootloader_id):
"""
Returns a label based on @p bootloader_id that is usable within
@p efi_directory. If there is a @@<something>@@ suffix marker
in the given id, tries to generate a unique label.
"""
if bootloader_id.endswith("@@"):
# Do 10 attempts with any suffix generator
g = suffix_iterator(10, get_efi_suffix_generator(bootloader_id))
else:
# Just one attempt
g = [bootloader_id]
for candidate_name in g:
if not os.path.exists(os.path.join(efi_directory, candidate_name)):
return candidate_name
return bootloader_id
def efi_label(efi_directory):
"""
Returns a sanitized label, possibly unique, that can be
used within @p efi_directory.
"""
if "efiBootloaderId" in libcalamares.job.configuration: if "efiBootloaderId" in libcalamares.job.configuration:
efi_bootloader_id = libcalamares.job.configuration[ efi_bootloader_id = change_efi_suffix( efi_directory, libcalamares.job.configuration["efiBootloaderId"] )
"efiBootloaderId"]
else: else:
branding = libcalamares.globalstorage.value("branding") branding = libcalamares.globalstorage.value("branding")
efi_bootloader_id = branding["bootloaderEntryName"] efi_bootloader_id = branding["bootloaderEntryName"]
@ -390,7 +546,7 @@ def run_grub_mkconfig(partitions, output_file):
check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file]) check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file])
def run_grub_install(fw_type, partitions, efi_directory=None): def run_grub_install(fw_type, partitions, efi_directory):
""" """
Runs grub-install in the target environment Runs grub-install in the target environment
@ -407,7 +563,8 @@ def run_grub_install(fw_type, partitions, efi_directory=None):
check_target_env_call(["sh", "-c", "echo ZPOOL_VDEV_NAME_PATH=1 >> /etc/environment"]) check_target_env_call(["sh", "-c", "echo ZPOOL_VDEV_NAME_PATH=1 >> /etc/environment"])
if fw_type == "efi": if fw_type == "efi":
efi_bootloader_id = efi_label() assert efi_directory is not None
efi_bootloader_id = efi_label(efi_directory)
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters() efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
if is_zfs: if is_zfs:
@ -421,6 +578,7 @@ def run_grub_install(fw_type, partitions, efi_directory=None):
"--bootloader-id=" + efi_bootloader_id, "--bootloader-id=" + efi_bootloader_id,
"--force"]) "--force"])
else: else:
assert efi_directory is None
if libcalamares.globalstorage.value("bootLoader") is None: if libcalamares.globalstorage.value("bootLoader") is None:
return return
@ -462,7 +620,7 @@ def install_grub(efi_directory, fw_type):
if not os.path.isdir(install_efi_directory): if not os.path.isdir(install_efi_directory):
os.makedirs(install_efi_directory) os.makedirs(install_efi_directory)
efi_bootloader_id = efi_label() efi_bootloader_id = efi_label(efi_directory)
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters() efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
@ -497,7 +655,7 @@ def install_grub(efi_directory, fw_type):
shutil.copy2(efi_file_source, efi_file_target) shutil.copy2(efi_file_source, efi_file_target)
else: else:
libcalamares.utils.debug("Bootloader: grub (bios)") libcalamares.utils.debug("Bootloader: grub (bios)")
run_grub_install(fw_type, partitions) run_grub_install(fw_type, partitions, None)
run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"]) run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"])
@ -506,7 +664,7 @@ def install_secureboot(efi_directory):
""" """
Installs the secureboot shim in the system by calling efibootmgr. Installs the secureboot shim in the system by calling efibootmgr.
""" """
efi_bootloader_id = efi_label() efi_bootloader_id = efi_label(efi_directory)
install_path = libcalamares.globalstorage.value("rootMountPoint") install_path = libcalamares.globalstorage.value("rootMountPoint")
install_efi_directory = install_path + efi_directory install_efi_directory = install_path + efi_directory

View File

@ -0,0 +1,7 @@
# We have tests to exercise some of the module internals.
# Those tests conventionally live in Python files here in the tests/ directory. Add them.
add_test(
NAME test-bootloader-efiname
COMMAND env PYTHONPATH=.: python3 ${CMAKE_CURRENT_LIST_DIR}/test-bootloader-efiname.py
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

View File

@ -0,0 +1,64 @@
# Calamares Boilerplate
import libcalamares
libcalamares.globalstorage = libcalamares.GlobalStorage(None)
libcalamares.globalstorage.insert("testing", True)
# Module prep-work
from src.modules.bootloader import main
# Specific Bootloader test
g = main.get_efi_suffix_generator("derp@@SERIAL@@")
assert g is not None
assert g.next() == "derp" # First time, no suffix
for n in range(9):
print(g.next())
# We called next() 10 times in total, starting from 0
assert g.next() == "derp10"
g = main.get_efi_suffix_generator("derp@@RANDOM@@")
assert g is not None
for n in range(10):
print(g.next())
# it's random, nothing to assert
g = main.get_efi_suffix_generator("derp@@PHRASE@@")
assert g is not None
for n in range(10):
print(g.next())
# it's random, nothing to assert
# Check invalid things
try:
g = main.get_efi_suffix_generator("derp")
raise TypeError("Shouldn't get generator (no indicator)")
except ValueError as e:
pass
try:
g = main.get_efi_suffix_generator("derp@@HEX@@")
raise TypeError("Shouldn't get generator (unknown indicator)")
except ValueError as e:
pass
try:
g = main.get_efi_suffix_generator("derp@@SERIAL@@x")
raise TypeError("Shouldn't get generator (trailing garbage)")
except ValueError as e:
pass
try:
g = main.get_efi_suffix_generator("derp@@SERIAL@@@@RANDOM@@")
raise TypeError("Shouldn't get generator (multiple indicators)")
except ValueError as e:
pass
# Try the generator (assuming no calamares- test files exist in /tmp)
import os
assert "calamares-single" == main.change_efi_suffix("/tmp", "calamares-single")
assert "calamares-serial" == main.change_efi_suffix("/tmp", "calamares-serial@@SERIAL@@")
try:
os.makedirs("/tmp/calamares-serial", exist_ok=True)
assert "calamares-serial1" == main.change_efi_suffix("/tmp", "calamares-serial@@SERIAL@@")
finally:
os.rmdir("/tmp/calamares-serial")

View File

@ -18,10 +18,16 @@
# #
# btrfs_swap options are used when a swapfile is chosen with a btrfs root # btrfs_swap options are used when a swapfile is chosen with a btrfs root
# the options are applied to the subvolume which holds the swap partition # the options are applied to the subvolume which holds the swap partition
#
# The settings shown here apply only the btrfs defaults; these
# are generally the right ones. Commented-out lines show other
# options wich **might** be applicable for specific situations.
mountOptions: mountOptions:
default: defaults,noatime default: defaults,noatime
btrfs: defaults,noatime,autodefrag,compress=zstd # btrfs: defaults,noatime,autodefrag,compress=zstd
btrfs_swap: defaults,noatime btrfs: defaults
# btrfs_swap: defaults,noatime
btrfs_swap: defaults
# Mount options to use for the EFI System Partition. If not defined, the # Mount options to use for the EFI System Partition. If not defined, the
# *mountOptions* for *vfat* are used, or if that is not set either, # *mountOptions* for *vfat* are used, or if that is not set either,
@ -49,7 +55,7 @@ efiMountOptions: umask=0077
# The standard configuration applies asynchronous discard support and ssd optimizations to btrfs # The standard configuration applies asynchronous discard support and ssd optimizations to btrfs
# and does nothing for other filesystems. # and does nothing for other filesystems.
ssdExtraMountOptions: ssdExtraMountOptions:
btrfs: discard=async,ssd,commit=120 btrfs: discard=async
# Additional options added to each line in /etc/crypttab # Additional options added to each line in /etc/crypttab
crypttabOptions: luks crypttabOptions: luks

View File

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
#
# This test shows how btrfs root would work
rootMountPoint: /tmp/mount
partitions:
- device: /dev/sda1
fs: btrfs
mountPoint: /
uuid: 2a00f1d5-1217-49a7-bedd-b55c85764732
- device: /dev/sda2
fs: swap
uuid: 59406569-446f-4730-a874-9f6b4b44fee3
mountPoint:
- device: /dev/sdb1
fs: btrfs
mountPoint: /home
uuid: 59406569-abcd-1234-a874-9f6b4b44fee3
btrfsSubvolumes:
- mountPoint: /
subvolume: "@ROOT"
- mountPoint: /var
subvolume: "@var"
- mountPoint: /usr/local
subvolume: "@local"

View File

@ -29,8 +29,16 @@ prefer_grub_d: false
# kept, not updated to the *bootloaderEntryName* from the branding file. # kept, not updated to the *bootloaderEntryName* from the branding file.
# Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in # Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in
# some way (e.g. uses shell-command substitution). # some way (e.g. uses shell-command substitution).
#
# TODO:3.3:snake-case this key
keepDistributor: false keepDistributor: false
# The default kernel params that should always be applied.
# This is an array of strings. If it is unset, the default is
# `["quiet"]`. To avoid the default, explicitly set this key
# to an empty list, `[]`.
kernel_params: [ "quiet" ]
# Default entries to write to /etc/default/grub if it does not exist yet or if # Default entries to write to /etc/default/grub if it does not exist yet or if
# we are overwriting it. # we are overwriting it.
# #

View File

@ -7,8 +7,10 @@ additionalProperties: false
type: object type: object
properties: properties:
overwrite: { type: boolean, default: false } overwrite: { type: boolean, default: false }
# TODO:3.3:snake-case this key
keepDistributor: { type: boolean, default: false } keepDistributor: { type: boolean, default: false }
prefer_grub_d: { type: boolean, default: false } prefer_grub_d: { type: boolean, default: false }
kernel_params: { type: array, items: { type: string } }
defaults: defaults:
type: object type: object
additionalProperties: true # Other fields are acceptable additionalProperties: true # Other fields are acceptable

View File

@ -174,7 +174,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
if partition["fs"] == "zfs" and partition["mountPoint"] == "/": if partition["fs"] == "zfs" and partition["mountPoint"] == "/":
zfs_root_path = get_zfs_root() zfs_root_path = get_zfs_root()
kernel_params = ["quiet"] kernel_params = libcalamares.job.configuration.get("kernel_params", ["quiet"])
# Currently, grub doesn't detect this properly so it must be set manually # Currently, grub doesn't detect this properly so it must be set manually
if zfs_root_path: if zfs_root_path:

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://calamares.io> === /* === This file is part of Calamares - <https://calamares.io> ===
* *
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> * SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-FileCopyrightText: 2022 Evan James <dalto@fastmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
* *
* Calamares is Free Software: see the License-Identifier above. * Calamares is Free Software: see the License-Identifier above.
@ -31,15 +32,22 @@ InitcpioJob::prettyName() const
return tr( "Creating initramfs with mkinitcpio." ); return tr( "Creating initramfs with mkinitcpio." );
} }
/** @brief Sets secure permissions on each initramfs
*
* Iterates over each initramfs contained directly in the directory @p d.
* For each initramfs found, the permissions are set to owner read/write only.
*
*/
void void
fixPermissions( const QDir& d ) fixPermissions( const QDir& d )
{ {
for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) ) const auto initramList = d.entryInfoList( { "initramfs*" }, QDir::Files );
for ( const auto& fi : initramList )
{ {
QFile f( fi.absoluteFilePath() ); QFile f( fi.absoluteFilePath() );
if ( f.exists() ) if ( f.exists() )
{ {
cDebug() << "initcpio fixing permissions for" << f.fileName(); cDebug() << "initcpio setting permissions for" << f.fileName();
f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner ); f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner );
} }
} }
@ -63,9 +71,19 @@ InitcpioJob::exec()
} }
} }
// If the kernel option isn't set to a specific kernel, run mkinitcpio on all kernels
QStringList command = { "mkinitcpio" };
if ( m_kernel.isEmpty() || m_kernel == "all" )
{
command.append( "-P" );
}
else
{
command.append( { "-p", m_kernel } );
}
cDebug() << "Updating initramfs with kernel" << m_kernel; cDebug() << "Updating initramfs with kernel" << m_kernel;
auto r = CalamaresUtils::System::instance()->targetEnvCommand( auto r = CalamaresUtils::System::instance()->targetEnvCommand( command, QString(), QString() /* no timeout , 0 */ );
{ "mkinitcpio", "-p", m_kernel }, QString(), QString() /* no timeout , 0 */ );
return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ ); return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ );
} }
@ -73,28 +91,6 @@ void
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap ) InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
{ {
m_kernel = CalamaresUtils::getString( configurationMap, "kernel" ); m_kernel = CalamaresUtils::getString( configurationMap, "kernel" );
if ( m_kernel.isEmpty() )
{
m_kernel = QStringLiteral( "all" );
}
else if ( m_kernel == "$uname" )
{
auto r = CalamaresUtils::System::runCommand( CalamaresUtils::System::RunLocation::RunInHost,
{ "/bin/uname", "-r" },
QString(),
QString(),
std::chrono::seconds( 3 ) );
if ( r.getExitCode() == 0 )
{
m_kernel = r.getOutput();
cDebug() << "*initcpio* using running kernel" << m_kernel;
}
else
{
cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation
<< r.getExitCode() << r.getOutput();
}
}
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false ); m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
} }

View File

@ -5,21 +5,22 @@
--- ---
# This key defines the kernel to be loaded. # This key defines the kernel to be loaded.
# It can have the following values: # It can have the following values:
# - empty or unset, interpreted as "all" # - the name of a single mkinitcpio preset
# - the literal string "$uname" (without quotes, with dollar), # - empty or unset
# which will use the output of `uname -r` to determine the # - the literal string "all"
# running kernel, and use that.
# - any other string.
# #
# Whatever is set, that string is passed as *preset* argument to the # If kernel is set to "all" or empty/unset then mkinitpio is called for all
# `-p` option of *mkinitcpio*. Take care that both "$uname" operates # kernels. Otherwise it is called with a single preset with the value
# in the host system, and might not be correct if the target system is # contained in kernel.
# updated (to a newer kernel) as part of the installation.
# #
# Note that "all" is probably not a good preset to use either. kernel: linux
kernel: linux312
# Set this to true to turn off mitigations for lax file # Set this to true to turn off mitigations for lax file
# permissions on initramfs (which, in turn, can compromise # permissions on initramfs (which, in turn, can compromise
# your LUKS encryption keys, CVS-2019-13179). # your LUKS encryption keys, CVS-2019-13179).
#
# If your initramfs are stored in the EFI partition or another non-POSIX
# filesystem, this has no effect as the file permissions cannot be changed.
# In this case, ensure the partition is mounted securely.
#
be_unsafe: false be_unsafe: false

View File

@ -180,7 +180,8 @@ def find_initcpio_features(partitions, root_mount_point):
if partition["fs"] == "btrfs": if partition["fs"] == "btrfs":
uses_btrfs = True uses_btrfs = True
if partition["fs"] == "zfs": # In addition to checking the filesystem, check to ensure that zfs is enabled
if partition["fs"] == "zfs" and libcalamares.globalstorage.contains("zfsPoolInfo"):
uses_zfs = True uses_zfs = True
if "lvm2" in partition["fs"]: if "lvm2" in partition["fs"]:

View File

@ -81,6 +81,7 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
m_kernel = QStringLiteral( "all" );
cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation
<< r.getExitCode() << r.getOutput(); << r.getExitCode() << r.getOutput();
} }

View File

@ -18,6 +18,7 @@
#include <KParts/ReadOnlyPart> #include <KParts/ReadOnlyPart>
#include <KParts/kde_terminal_interface.h> #include <KParts/kde_terminal_interface.h>
#include <KService> #include <KService>
#include <kcoreaddons_version.h>
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
@ -41,8 +42,10 @@ InteractiveTerminalPage::InteractiveTerminalPage( QWidget* parent )
void void
InteractiveTerminalPage::errorKonsoleNotInstalled() InteractiveTerminalPage::errorKonsoleNotInstalled()
{ {
QMessageBox mb(QMessageBox::Critical, QMessageBox mb( QMessageBox::Critical,
tr( "Konsole not installed" ), tr( "Please install KDE Konsole and try again!" ), QMessageBox::Ok ); tr( "Konsole not installed" ),
tr( "Please install KDE Konsole and try again!" ),
QMessageBox::Ok );
Calamares::fixButtonLabels( &mb ); Calamares::fixButtonLabels( &mb );
mb.exec(); mb.exec();
} }
@ -54,20 +57,30 @@ InteractiveTerminalPage::onActivate()
{ {
return; return;
} }
// For whatever reason, instead of simply linking against a library we
// need to do a runtime query to KService just to get a sodding terminal #if KCOREADDONS_VERSION_MAJOR != 5
// widget. #error Incompatible with not-KF5
#endif
#if KCOREADDONS_VERSION_MINOR >= 86
// 5.86 deprecated a bunch of KService and PluginFactory and related methods
auto md = KPluginMetaData::findPluginById( QString(), "konsolepart" );
if ( !md.isValid() )
{
errorKonsoleNotInstalled();
return;
}
auto* p = KPluginFactory::instantiatePlugin< KParts::ReadOnlyPart >( md, this ).plugin;
#else
KService::Ptr service = KService::serviceByDesktopName( "konsolepart" ); KService::Ptr service = KService::serviceByDesktopName( "konsolepart" );
if ( !service ) if ( !service )
{ {
// And all of this hoping the Konsole application is installed. If not,
// tough cookies.
errorKonsoleNotInstalled(); errorKonsoleNotInstalled();
return; return;
} }
// Create one instance of konsolepart. // Create one instance of konsolepart.
KParts::ReadOnlyPart* p = service->createInstance< KParts::ReadOnlyPart >( this, this, {} ); KParts::ReadOnlyPart* p = service->createInstance< KParts::ReadOnlyPart >( this, this, {} );
#endif
if ( !p ) if ( !p )
{ {
// One more opportunity for the loading operation to fail. // One more opportunity for the loading operation to fail.
@ -91,7 +104,6 @@ InteractiveTerminalPage::onActivate()
m_termHostWidget = p->widget(); m_termHostWidget = p->widget();
m_layout->addWidget( m_termHostWidget ); m_layout->addWidget( m_termHostWidget );
cDebug() << "Part widget ought to be" << m_termHostWidget->metaObject()->className();
t->showShellInDir( QDir::home().path() ); t->showShellInDir( QDir::home().path() );
t->sendInput( QString( "%1\n" ).arg( m_command ) ); t->sendInput( QString( "%1\n" ).arg( m_command ) );

View File

@ -221,6 +221,11 @@ Config::setCurrentLocation()
{ {
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second ); setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
} }
if ( !m_selectedLocaleConfiguration.explicit_lang )
{
auto newLocale = automaticLocaleConfiguration();
setLanguage( newLocale.language() );
}
} }
void void
@ -252,15 +257,21 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName )
void void
Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location ) Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location )
{ {
if ( location != m_currentLocation ) const bool updateLocation = ( location != m_currentLocation );
if ( updateLocation )
{ {
m_currentLocation = location; m_currentLocation = location;
// Overwrite those settings that have not been made explicit. }
auto newLocale = automaticLocaleConfiguration();
if ( !m_selectedLocaleConfiguration.explicit_lang ) // lang should be always be updated
{ auto newLocale = automaticLocaleConfiguration();
setLanguage( newLocale.language() ); if ( !m_selectedLocaleConfiguration.explicit_lang )
} {
setLanguage( newLocale.language() );
}
if ( updateLocation )
{
if ( !m_selectedLocaleConfiguration.explicit_lc ) if ( !m_selectedLocaleConfiguration.explicit_lc )
{ {
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric; m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;

View File

@ -0,0 +1,22 @@
# === This file is part of Calamares - <https://calamares.io> ===
#
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
# SPDX-License-Identifier: BSD-2-Clause
#
# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
# use LOSH all over the place as a shorthand.
calamares_add_plugin( luksopenswaphookcfg
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
LOSHJob.cpp
SHARED_LIB
)
calamares_add_test(
luksopenswaphooktest
SOURCES
LOSHJob.cpp
Tests.cpp
)

View File

@ -0,0 +1,66 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef LUKSOPENSWAPHOOKCFG_LOSHINFO_H
#define LUKSOPENSWAPHOOKCFG_LOSHINFO_H
#include <QString>
/** @brief Information needed to create a suitable config file
*
* The LUKS swap configuration has a handful of keys that need to
* be written to the config file. This struct holds those keys
* and can find the key values from Global Storage (where the
* *partition* module sets them).
*/
struct LOSHInfo
{
// Member names copied from Python code
QString swap_outer_uuid;
QString swap_mapper_name;
QString mountable_keyfile_device;
QString swap_device_path;
QString keyfile_device_mount_options;
bool isValid() const { return !swap_device_path.isEmpty(); }
/** @brief Helper method for doing key-value replacements
*
* Given a named @p key (e.g. "duck", or "swap_device"), returns the
* value set for that key. Invalid keys (e.g. "duck") return an empty string.
*/
QString replacementFor( const QString& key ) const
{
if ( key == QStringLiteral( "swap_device" ) )
{
return swap_device_path;
}
if ( key == QStringLiteral( "crypt_swap_name" ) )
{
return swap_mapper_name;
}
if ( key == QStringLiteral( "keyfile_device" ) )
{
return mountable_keyfile_device;
}
if ( key == QStringLiteral( "keyfile_filename" ) )
{
return QStringLiteral( "crypto_keyfile.bin" );
}
if ( key == QStringLiteral( "keyfile_device_mount_options" ) )
{
return keyfile_device_mount_options;
}
return QString();
}
/** @brief Creates a struct from information already set in GS
*
*/
static LOSHInfo fromGlobalStorage();
};
#endif

View File

@ -0,0 +1,181 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "LOSHJob.h"
#include "LOSHInfo.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include "utils/Permissions.h"
#include "utils/PluginFactory.h"
#include "utils/String.h"
#include "utils/Variant.h"
#include <QList>
#include <QObject>
#include <QRegularExpression>
#include <QVariantMap>
LOSHJob::LOSHJob( QObject* parent )
: Calamares::CppJob( parent )
{
}
LOSHJob::~LOSHJob() {}
QString
LOSHJob::prettyName() const
{
return tr( "Configuring encrypted swap." );
}
STATICTEST QString
get_assignment_part( const QString& line )
{
static QRegularExpression re( "^[# \\t]*([A-Za-z_]+)[ \\t]*=" );
auto m = re.match( line );
if ( m.hasMatch() )
{
return m.captured( 1 );
}
return QString();
}
/** Writes the config file at @p path
*
* NOTE: @p path is relative to the target system, not an absolute path.
*/
STATICTEST void
write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info )
{
if ( info.isValid() )
{
for ( auto& line : contents )
{
const QString key = get_assignment_part( line );
QString replacement = info.replacementFor( key );
if ( !replacement.isEmpty() )
{
line.clear();
line.append( QStringLiteral( "%1=%2" ).arg( key, replacement ) );
}
}
cDebug() << "Writing" << contents.length() << "line configuration to" << path;
// \n between each two lines, and a \n at the end
CalamaresUtils::System::instance()->createTargetFile(
path, contents.join( '\n' ).append( '\n' ).toUtf8(), CalamaresUtils::System::WriteMode::Overwrite );
}
else
{
cDebug() << "Will not write an invalid configuration to" << path;
}
}
Calamares::JobResult
LOSHJob::exec()
{
const auto* sys = CalamaresUtils::System::instance();
if ( !sys )
{
return Calamares::JobResult::internalError(
"LuksOpenSwapHook", tr( "No target system available." ), Calamares::JobResult::InvalidConfiguration );
}
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
if ( !gs || gs->value( "rootMountPoint" ).toString().isEmpty() )
{
return Calamares::JobResult::internalError(
"LuksOpenSwapHook", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
}
if ( m_configFilePath.isEmpty() )
{
return Calamares::JobResult::internalError(
"LuksOpenSwapHook", tr( "No configFilePath is set." ), Calamares::JobResult::InvalidConfiguration );
}
QStringList contents = sys->readTargetFile( m_configFilePath );
if ( contents.isEmpty() )
{
contents << QStringLiteral( "# swap_device=" ) << QStringLiteral( "# crypt_swap_name=" )
<< QStringLiteral( "# keyfile_device=" ) << QStringLiteral( "# keyfile_filename=" )
<< QStringLiteral( "# keyfile_device_mount_options" );
}
write_openswap_conf( m_configFilePath, contents, LOSHInfo::fromGlobalStorage() );
return Calamares::JobResult::ok();
}
void
LOSHJob::setConfigurationMap( const QVariantMap& configurationMap )
{
m_configFilePath = CalamaresUtils::getString(
configurationMap, QStringLiteral( "configFilePath" ), QStringLiteral( "/etc/openswap.conf" ) );
}
STATICTEST void
globalStoragePartitionInfo( Calamares::GlobalStorage* gs, LOSHInfo& info )
{
if ( !gs )
{
return;
}
QVariantList l = gs->value( "partitions" ).toList();
if ( l.isEmpty() )
{
return;
}
for ( const auto& pv : l )
{
const QVariantMap partition = pv.toMap();
if ( !partition.isEmpty() )
{
QString mountPoint = partition.value( "mountPoint" ).toString();
QString fileSystem = partition.value( "fs" ).toString();
QString luksMapperName = partition.value( "luksMapperName" ).toString();
// if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
if ( fileSystem == QStringLiteral( "linuxswap" ) && !luksMapperName.isEmpty() )
{
info.swap_outer_uuid = partition.value( "luksUuid" ).toString();
info.swap_mapper_name = luksMapperName;
}
else if ( mountPoint == QStringLiteral( "/" ) && !luksMapperName.isEmpty() )
{
info.mountable_keyfile_device = QStringLiteral( "/dev/mapper/" ) + luksMapperName;
}
}
}
if ( !info.mountable_keyfile_device.isEmpty() && !info.swap_outer_uuid.isEmpty() )
{
info.swap_device_path = QStringLiteral( "/dev/disk/by-uuid/" ) + info.swap_outer_uuid;
}
QString btrfsRootSubvolume = gs->value( "btrfsRootSubvolume" ).toString();
if ( !btrfsRootSubvolume.isEmpty() )
{
CalamaresUtils::removeLeading( btrfsRootSubvolume, '/' );
info.keyfile_device_mount_options
= QStringLiteral( "keyfile_device_mount_options=--options=subvol=" ) + btrfsRootSubvolume;
}
}
LOSHInfo
LOSHInfo::fromGlobalStorage()
{
LOSHInfo i {};
globalStoragePartitionInfo(
Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr, i );
return i;
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( LOSHJobFactory, registerPlugin< LOSHJob >(); )

View File

@ -0,0 +1,37 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef LUKSOPENSWAPHOOKCFG_LOSHJOB_H
#define LUKSOPENSWAPHOOKCFG_LOSHJOB_H
#include "CppJob.h"
#include "DllMacro.h"
#include "utils/PluginFactory.h"
#include <QString>
#include <QVariantMap>
class PLUGINDLLEXPORT LOSHJob : public Calamares::CppJob
{
Q_OBJECT
public:
explicit LOSHJob( QObject* parent = nullptr );
~LOSHJob() override;
QString prettyName() const override;
Calamares::JobResult exec() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
private:
QString m_configFilePath;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( LOSHJobFactory )
#endif

View File

@ -0,0 +1,253 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "LOSHInfo.h"
#include "LOSHJob.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include <QtTest/QtTest>
// LOSH = LUKS Open Swap Hook (Job)
// Implementation details
extern QString get_assignment_part( const QString& line );
extern void write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info );
class LOSHTests : public QObject
{
Q_OBJECT
public:
LOSHTests();
~LOSHTests() override {}
private Q_SLOTS:
void initTestCase();
void testAssignmentExtraction_data();
void testAssignmentExtraction();
void testLOSHInfo();
void testConfigWriting();
void testJob();
};
LOSHTests::LOSHTests() {}
void
LOSHTests::initTestCase()
{
Logger::setupLogLevel( Logger::LOGDEBUG );
cDebug() << "LOSH test started.";
}
void
LOSHTests::testAssignmentExtraction_data()
{
QTest::addColumn< QString >( "line" );
QTest::addColumn< QString >( "match" );
QTest::newRow( "empty" ) << QString() << QString();
QTest::newRow( "comment-only1" ) << QStringLiteral( "# " ) << QString();
QTest::newRow( "comment-only2" ) << QStringLiteral( "###" ) << QString();
QTest::newRow( "comment-only3" ) << QStringLiteral( "# # #" ) << QString();
QTest::newRow( "comment-text" ) << QStringLiteral( "# NOTE:" ) << QString();
QTest::newRow( "comment-story" ) << QStringLiteral( "# This is a shell comment" ) << QString();
// We look for assignments, but only for single-words
QTest::newRow( "comment-space-eq" ) << QStringLiteral( "# Check that a = b" ) << QString();
QTest::newRow( "assignment1" ) << QStringLiteral( "a=1" ) << QStringLiteral( "a" );
QTest::newRow( "assignment2" ) << QStringLiteral( "a = 1" ) << QStringLiteral( "a" );
QTest::newRow( "assignment3" ) << QStringLiteral( "# a=1" ) << QStringLiteral( "a" );
QTest::newRow( "assignment4" ) << QStringLiteral( "cows = 12" ) << QStringLiteral( "cows" );
QTest::newRow( "assignment5" ) << QStringLiteral( "# # cows=1" ) << QStringLiteral( "cows" );
QTest::newRow( "assignment6" ) << QStringLiteral( "# moose='cool' # not cows" ) << QStringLiteral( "moose" );
QTest::newRow( "assignment7" ) << QStringLiteral( " moose=cows=42" ) << QStringLiteral( "moose" );
QTest::newRow( "assignment8" ) << QStringLiteral( "#swap_device=/dev/something" )
<< QStringLiteral( "swap_device" );
QTest::newRow( "assignment9" ) << QStringLiteral( "# swap_device=/dev/something" )
<< QStringLiteral( "swap_device" );
QTest::newRow( "assignment10" ) << QStringLiteral( "swap_device=/dev/something" )
<< QStringLiteral( "swap_device" );
}
void
LOSHTests::testAssignmentExtraction()
{
QFETCH( QString, line );
QFETCH( QString, match );
QCOMPARE( get_assignment_part( line ), match );
}
static CalamaresUtils::System*
file_setup( const QTemporaryDir& tempRoot )
{
CalamaresUtils::System* ss = CalamaresUtils::System::instance();
if ( !ss )
{
ss = new CalamaresUtils::System( true );
}
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
if ( !gs )
{
cDebug() << "Creating new JobQueue";
(void)new Calamares::JobQueue();
gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
}
if ( gs )
{
// Working with a rootMountPoint set
gs->insert( "rootMountPoint", tempRoot.path() );
}
return ss;
}
static void
make_valid_loshinfo( LOSHInfo& i )
{
i.swap_outer_uuid = QStringLiteral( "UUID-0000" );
i.swap_mapper_name = QStringLiteral( "/dev/mapper/0000" );
i.swap_device_path = QStringLiteral( "/dev/sda0" );
i.mountable_keyfile_device = QStringLiteral( "/dev/ada0p0s0" );
}
void
LOSHTests::testLOSHInfo()
{
LOSHInfo i {};
QVERIFY( !i.isValid() );
make_valid_loshinfo( i );
QVERIFY( i.isValid() );
QCOMPARE( i.replacementFor( QStringLiteral( "swap_device" ) ), QStringLiteral( "/dev/sda0" ) );
QCOMPARE( i.replacementFor( QStringLiteral( "duck" ) ), QString() );
}
void
LOSHTests::testConfigWriting()
{
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
QVERIFY( tempRoot.isValid() );
auto* ss = file_setup( tempRoot );
QVERIFY( ss );
QVERIFY( Calamares::JobQueue::instance()->globalStorage() );
QVERIFY( QFile::exists( tempRoot.path() ) );
QVERIFY( QFileInfo( tempRoot.path() ).isDir() );
const QString targetFilePath = QStringLiteral( "losh.conf" );
const QString filePath = tempRoot.filePath( targetFilePath );
QStringList contents { QStringLiteral( "# Calamares demo" ),
QStringLiteral( "# swap_device=a thing" ),
QStringLiteral( "# duck duck swap_device=another" ) };
// When the information is invalid, file contents are unchanged,
// and no file is written either.
LOSHInfo i {};
QVERIFY( !i.isValid() );
QVERIFY( !QFile::exists( filePath ) );
write_openswap_conf( targetFilePath, contents, i ); // Invalid i
QVERIFY( !QFile::exists( filePath ) );
QCOMPARE( contents.length(), 3 );
QCOMPARE( contents.at( 1 ).left( 4 ), QStringLiteral( "# s" ) );
// Can we write there at all?
QFile derp( filePath );
QVERIFY( derp.open( QIODevice::WriteOnly ) );
QVERIFY( derp.write( "xx", 2 ) );
derp.close();
QVERIFY( QFile::exists( filePath ) );
QVERIFY( QFile::remove( filePath ) );
// Once the information is valid, though, the file is written
make_valid_loshinfo( i );
QVERIFY( i.isValid() );
QVERIFY( !QFile::exists( filePath ) );
write_openswap_conf( targetFilePath, contents, i ); // Now it is valid
QVERIFY( QFile::exists( filePath ) );
QCOMPARE( contents.length(), 3 );
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/sda0" ) ); // expected key value
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/sda0" ) ); // expected line
// readLine() returns with newlines-added
QFile f( filePath );
QVERIFY( f.open( QIODevice::ReadOnly ) );
QCOMPARE( f.readLine(), QStringLiteral( "# Calamares demo\n" ) );
QCOMPARE( f.readLine(), QStringLiteral( "swap_device=/dev/sda0\n" ) );
QCOMPARE( f.readLine(), QStringLiteral( "# duck duck swap_device=another\n" ) );
QCOMPARE( f.readLine(), QString() );
QVERIFY( f.atEnd() );
// Note how the contents is updated on every write_openswap_conf()
i.swap_device_path = QStringLiteral( "/dev/zram/0.zram" );
write_openswap_conf( targetFilePath, contents, i ); // Still valid
QCOMPARE( contents.length(), 3 );
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/zram/0.zram" ) ); // expected key value
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/zram/0.zram" ) ); // expected line
}
void
LOSHTests::testJob()
{
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
QVERIFY( tempRoot.isValid() );
auto* ss = file_setup( tempRoot );
QVERIFY( ss );
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
QVERIFY( gs );
{
QDir d( tempRoot.path() );
d.mkdir( "etc" );
}
QVERIFY( !LOSHInfo::fromGlobalStorage().isValid() );
QVariantList outerPartition;
QVariantMap innerPartition;
innerPartition.insert( "mountPoint", "/" );
innerPartition.insert( "fs", "ext4" );
innerPartition.insert( "luksMapperName", "root" );
innerPartition.insert( "luksUUID", "0000" );
outerPartition.append( innerPartition );
innerPartition.remove( "mountPoint" );
innerPartition.insert( "fs", "linuxswap" );
innerPartition.insert( "luksMapperName", "swap" );
innerPartition.insert( "luksUuid", "0001" );
outerPartition.append( innerPartition );
gs->insert( "partitions", outerPartition );
QVERIFY( LOSHInfo::fromGlobalStorage().isValid() );
LOSHJob j;
j.setConfigurationMap( QVariantMap() );
auto jobresult = j.exec();
QVERIFY( jobresult );
{
QFile f( tempRoot.filePath( "etc/openswap.conf" ) );
QVERIFY( f.exists() );
QVERIFY( f.open( QIODevice::ReadOnly ) );
cDebug() << f.readAll();
}
}
QTEST_GUILESS_MAIN( LOSHTests )
#include "utils/moc-warnings.h"
#include "Tests.moc"

View File

@ -1,95 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://calamares.io> ===
#
# SPDX-FileCopyrightText: 2016 Teo Mrnjavac <teo@kde.org>
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Calamares is Free Software: see the License-Identifier above.
#
import libcalamares
import os.path
import gettext
_ = gettext.translation("calamares-python",
localedir=libcalamares.utils.gettext_path(),
languages=libcalamares.utils.gettext_languages(),
fallback=True).gettext
def pretty_name():
return _("Configuring encrypted swap.")
def write_openswap_conf(partitions, root_mount_point, openswap_conf_path):
swap_outer_uuid = ""
swap_mapper_name = ""
mountable_keyfile_device = ""
for partition in partitions:
if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
swap_outer_uuid = partition["luksUuid"]
swap_mapper_name = partition["luksMapperName"]
elif partition["mountPoint"] == "/" and "luksMapperName" in partition:
mountable_keyfile_device = (
"/dev/mapper/{!s}".format(partition["luksMapperName"])
)
if not mountable_keyfile_device or not swap_outer_uuid:
return None
swap_device_path = "/dev/disk/by-uuid/{!s}".format(swap_outer_uuid)
lines = []
with open(os.path.join(root_mount_point,
openswap_conf_path), 'r') as openswap_file:
lines = [x.strip() for x in openswap_file.readlines()]
for i in range(len(lines)):
if lines[i].startswith("swap_device"):
lines[i] = "swap_device={!s}".format(swap_device_path)
elif lines[i].startswith("crypt_swap_name"):
lines[i] = "crypt_swap_name={!s}".format(swap_mapper_name)
elif lines[i].startswith("keyfile_device"):
lines[i] = "keyfile_device={!s}".format(mountable_keyfile_device)
elif lines[i].startswith("keyfile_filename"):
lines[i] = "keyfile_filename=crypto_keyfile.bin"
with open(os.path.join(root_mount_point,
openswap_conf_path), 'w') as openswap_file:
openswap_file.write("\n".join(lines) + "\n")
return None
def run():
"""
This module sets up the openswap hook for a resumable encrypted swap.
:return:
"""
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
openswap_conf_path = libcalamares.job.configuration["configFilePath"]
partitions = libcalamares.globalstorage.value("partitions")
if not partitions:
libcalamares.utils.warning("partitions is empty, {!s}".format(partitions))
return (_("Configuration Error"),
_("No partitions are defined for <pre>{!s}</pre> to use." ).format("luksopenswaphookcfg"))
if not root_mount_point:
libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
return (_("Configuration Error"),
_("No root mount point is given for <pre>{!s}</pre> to use." ).format("luksopenswaphookcfg"))
openswap_conf_path = openswap_conf_path.lstrip('/')
return write_openswap_conf(partitions, root_mount_point, openswap_conf_path)

View File

@ -1,7 +0,0 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
---
type: "job"
name: "luksopenswaphookcfg"
interface: "python"
script: "main.py"

View File

@ -193,6 +193,7 @@ def mount_partition(root_mount_point, partition, partitions):
for s in btrfs_subvolumes: for s in btrfs_subvolumes:
if not s["subvolume"]: if not s["subvolume"]:
continue continue
os.makedirs(root_mount_point + os.path.dirname(s["subvolume"]), exist_ok=True)
subprocess.check_call(["btrfs", "subvolume", "create", subprocess.check_call(["btrfs", "subvolume", "create",
root_mount_point + s["subvolume"]]) root_mount_point + s["subvolume"]])
if s["mountPoint"] == "/": if s["mountPoint"] == "/":

View File

@ -15,6 +15,7 @@
#include "PackageModel.h" #include "PackageModel.h"
#include "ui_page_netinst.h" #include "ui_page_netinst.h"
#include "GlobalStorage.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "network/Manager.h" #include "network/Manager.h"
@ -62,4 +63,19 @@ void
NetInstallPage::onActivate() NetInstallPage::onActivate()
{ {
ui->groupswidget->setFocus(); ui->groupswidget->setFocus();
// The netinstallSelect global storage value can be used to make additional items selected by default
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
const QStringList selectNames = gs->value( "netinstallSelect" ).toStringList();
if ( !selectNames.isEmpty() )
{
m_config->model()->setSelections( selectNames );
}
// If NetInstallAdd is found in global storage, add those items to the tree
const QVariantList groups = gs->value( "netinstallAdd" ).toList();
if ( !groups.isEmpty() )
{
m_config->model()->appendModelData( groups );
}
} }

View File

@ -14,6 +14,43 @@
#include "utils/Variant.h" #include "utils/Variant.h"
#include "utils/Yaml.h" #include "utils/Yaml.h"
/// Recursive helper for setSelections()
static void
setSelections( const QStringList& selectNames, PackageTreeItem* item )
{
for ( int i = 0; i < item->childCount(); i++ )
{
auto* child = item->child( i );
setSelections( selectNames, child );
}
if ( item->isGroup() && selectNames.contains( item->name() ) )
{
item->setSelected( Qt::CheckState::Checked );
}
}
/** @brief Collects all the "source" values from @p groupList
*
* Iterates over @p groupList and returns all nonempty "source"
* values from the maps.
*
*/
static QStringList
collectSources( const QVariantList& groupList )
{
QStringList sources;
for ( const QVariant& group : groupList )
{
QVariantMap groupMap = group.toMap();
if ( !groupMap[ "source" ].toString().isEmpty() )
{
sources.append( groupMap[ "source" ].toString() );
}
}
return sources;
}
PackageModel::PackageModel( QObject* parent ) PackageModel::PackageModel( QObject* parent )
: QAbstractItemModel( parent ) : QAbstractItemModel( parent )
{ {
@ -170,6 +207,15 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c
return QVariant(); return QVariant();
} }
void
PackageModel::setSelections( const QStringList& selectNames )
{
if ( m_rootItem )
{
::setSelections( selectNames, m_rootItem );
}
}
PackageTreeItem::List PackageTreeItem::List
PackageModel::getPackages() const PackageModel::getPackages() const
{ {
@ -303,9 +349,43 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa
void void
PackageModel::setupModelData( const QVariantList& l ) PackageModel::setupModelData( const QVariantList& l )
{ {
emit beginResetModel(); Q_EMIT beginResetModel();
delete m_rootItem; delete m_rootItem;
m_rootItem = new PackageTreeItem(); m_rootItem = new PackageTreeItem();
setupModelData( l, m_rootItem ); setupModelData( l, m_rootItem );
emit endResetModel(); Q_EMIT endResetModel();
}
void
PackageModel::appendModelData( const QVariantList& groupList )
{
if ( m_rootItem )
{
Q_EMIT beginResetModel();
const QStringList sources = collectSources( groupList );
if ( !sources.isEmpty() )
{
// Prune any existing data from the same source
QList< int > removeList;
for ( int i = 0; i < m_rootItem->childCount(); i++ )
{
PackageTreeItem* child = m_rootItem->child( i );
if ( sources.contains( child->source() ) )
{
removeList.insert( 0, i );
}
}
for ( const int& item : qAsConst( removeList ) )
{
m_rootItem->removeChild( item );
}
}
// Add the new data to the model
setupModelData( groupList, m_rootItem );
Q_EMIT endResetModel();
}
} }

View File

@ -54,9 +54,33 @@ public:
int rowCount( const QModelIndex& parent = QModelIndex() ) const override; int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
int columnCount( const QModelIndex& parent = QModelIndex() ) const override; int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
/** @brief Sets the checked flag on matching groups in the tree
*
* Recursively traverses the tree pointed to by m_rootItem and
* checks if a group name matches any of the items in @p selectNames.
* If a match is found, set check the box for that group and it's children.
*
* Individual packages will not be matched.
*
*/
void setSelections( const QStringList& selectNames );
PackageTreeItem::List getPackages() const; PackageTreeItem::List getPackages() const;
PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const; PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const;
/** @brief Appends groups to the tree
*
* Uses the data from @p groupList to add elements to the
* existing tree that m_rootItem points to. If m_rootItem
* is not valid, it does nothing
*
* Before adding anything to the model, it ensures that there
* is no existing data from the same source. If there is, that
* data is pruned first
*
*/
void appendModelData( const QVariantList& groupList );
private: private:
friend class ItemTests; friend class ItemTests;

View File

@ -70,6 +70,7 @@ PackageTreeItem::PackageTreeItem( const QVariantMap& groupData, GroupTag&& paren
, m_description( CalamaresUtils::getString( groupData, "description" ) ) , m_description( CalamaresUtils::getString( groupData, "description" ) )
, m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) ) , m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) )
, m_postScript( CalamaresUtils::getString( groupData, "post-install" ) ) , m_postScript( CalamaresUtils::getString( groupData, "post-install" ) )
, m_source( CalamaresUtils::getString( groupData, "source" ) )
, m_isGroup( true ) , m_isGroup( true )
, m_isCritical( parentCriticality( groupData, parent.parent ) ) , m_isCritical( parentCriticality( groupData, parent.parent ) )
, m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) ) , m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) )
@ -248,6 +249,19 @@ PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected )
} }
} }
void
PackageTreeItem::removeChild( int row )
{
if ( 0 <= row && row < m_childItems.count() )
{
m_childItems.removeAt( row );
}
else
{
cWarning() << "Attempt to remove invalid child in removeChild() at row " << row;
}
}
int int
PackageTreeItem::type() const PackageTreeItem::type() const
{ {

View File

@ -56,6 +56,7 @@ public:
QString description() const { return m_description; } QString description() const { return m_description; }
QString preScript() const { return m_preScript; } QString preScript() const { return m_preScript; }
QString postScript() const { return m_postScript; } QString postScript() const { return m_postScript; }
QString source() const { return m_source; }
/** @brief Is this item a group-item? /** @brief Is this item a group-item?
* *
@ -124,6 +125,8 @@ public:
void setSelected( Qt::CheckState isSelected ); void setSelected( Qt::CheckState isSelected );
void setChildrenSelected( Qt::CheckState isSelected ); void setChildrenSelected( Qt::CheckState isSelected );
void removeChild( int row );
/** @brief Update selectedness based on the children's states /** @brief Update selectedness based on the children's states
* *
* This only makes sense for groups, which might have packages * This only makes sense for groups, which might have packages
@ -157,6 +160,7 @@ private:
QString m_description; QString m_description;
QString m_preScript; QString m_preScript;
QString m_postScript; QString m_postScript;
QString m_source;
bool m_isGroup = false; bool m_isGroup = false;
bool m_isCritical = false; bool m_isCritical = false;
bool m_isHidden = false; bool m_isHidden = false;

View File

@ -410,7 +410,7 @@ ItemTests::testUrlFallback()
QEventLoop loop; QEventLoop loop;
connect( &c, &Config::statusReady, &loop, &QEventLoop::quit ); connect( &c, &Config::statusReady, &loop, &QEventLoop::quit );
QSignalSpy spy( &c, &Config::statusReady ); QSignalSpy spy( &c, &Config::statusReady );
QTimer::singleShot( std::chrono::seconds(1), &loop, &QEventLoop::quit ); QTimer::singleShot( std::chrono::seconds( 1 ), &loop, &QEventLoop::quit );
loop.exec(); loop.exec();
// Check it didn't time out // Check it didn't time out

View File

@ -73,12 +73,12 @@ def replace_username(nm_config_filename, live_user, target_user):
if not os.path.exists(nm_config_filename): if not os.path.exists(nm_config_filename):
return return
with open(nm_config_filename, "r") as network_conf: with open(nm_config_filename, "r", encoding="UTF-8") as network_conf:
text = network_conf.readlines() text = network_conf.readlines()
live_permissions = 'permissions=user:{}:;'.format(live_user) live_permissions = 'permissions=user:{}:;'.format(live_user)
target_permissions = 'permissions=user:{}:;\n'.format(target_user) target_permissions = 'permissions=user:{}:;\n'.format(target_user)
with open(nm_config_filename, "w") as network_conf: with open(nm_config_filename, "w", encoding="UTF-8") as network_conf:
for line in text: for line in text:
if live_permissions in line: if live_permissions in line:
line = target_permissions line = target_permissions

View File

@ -27,6 +27,29 @@
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Variant.h" #include "utils/Variant.h"
/** @brief This removes any values from @p groups that match @p source
*
* This is used to remove duplicates from the netinstallAdd structure
* It iterates over @p groups and for each map in the list, if the
* "source" element matches @p source, it is removed from the returned
* list.
*/
static QVariantList
pruneNetinstallAdd( const QString& source, const QVariant& groups )
{
QVariantList newGroupList;
const QVariantList groupList = groups.toList();
for ( const QVariant& group : groupList )
{
QVariantMap groupMap = group.toMap();
if ( groupMap.value( "source", "" ).toString() != source )
{
newGroupList.append( groupMap );
}
}
return newGroupList;
}
const NamedEnumTable< PackageChooserMode >& const NamedEnumTable< PackageChooserMode >&
packageChooserModeNames() packageChooserModeNames()
{ {
@ -55,6 +78,8 @@ PackageChooserMethodNames()
{ "custom", PackageChooserMethod::Legacy }, { "custom", PackageChooserMethod::Legacy },
{ "contextualprocess", PackageChooserMethod::Legacy }, { "contextualprocess", PackageChooserMethod::Legacy },
{ "packages", PackageChooserMethod::Packages }, { "packages", PackageChooserMethod::Packages },
{ "netinstall-add", PackageChooserMethod::NetAdd },
{ "netinstall-select", PackageChooserMethod::NetSelect },
}; };
return names; return names;
} }
@ -121,6 +146,47 @@ Config::updateGlobalStorage( const QStringList& selected ) const
CalamaresUtils::Packages::setGSPackageAdditions( CalamaresUtils::Packages::setGSPackageAdditions(
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames ); Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
} }
else if ( m_method == PackageChooserMethod::NetAdd )
{
QVariantList netinstallDataList = m_model->getNetinstallDataForNames( selected );
if ( netinstallDataList.isEmpty() )
{
cWarning() << "No netinstall information found for " << selected;
}
else
{
// If an earlier packagechooser instance added this data to global storage, combine them
auto* gs = Calamares::JobQueue::instance()->globalStorage();
if ( gs->contains( "netinstallAdd" ) )
{
netinstallDataList
+= pruneNetinstallAdd( QStringLiteral( "packageChooser" ), gs->value( "netinstallAdd" ) );
}
gs->insert( "netinstallAdd", netinstallDataList );
}
}
else if ( m_method == PackageChooserMethod::NetSelect )
{
cDebug() << m_defaultId << "groups to select in netinstall" << selected;
QStringList newSelected = selected;
auto* gs = Calamares::JobQueue::instance()->globalStorage();
// If an earlier packagechooser instance added this data to global storage, combine them
if ( gs->contains( "netinstallSelect" ) )
{
auto selectedOrig = gs->value( "netinstallSelect" );
if ( selectedOrig.canConvert( QVariant::StringList ) )
{
newSelected += selectedOrig.toStringList();
}
else
{
cWarning() << "Invalid NetinstallSelect data in global storage. Earlier selections purged";
}
gs->remove( "netinstallSelect" );
}
gs->insert( "netinstallSelect", newSelected );
}
else else
{ {
cWarning() << "Unknown packagechooser method" << smash( m_method ); cWarning() << "Unknown packagechooser method" << smash( m_method );

View File

@ -33,6 +33,8 @@ enum class PackageChooserMethod
{ {
Legacy, // use contextualprocess or other custom Legacy, // use contextualprocess or other custom
Packages, // use the packages module Packages, // use the packages module
NetAdd, // adds packages to the netinstall module
NetSelect, // makes selections in the netinstall module
}; };
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames(); const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();

View File

@ -15,6 +15,16 @@
#include <QFileInfo> #include <QFileInfo>
/** @brief A wrapper for CalamaresUtils::getSubMap that excludes the success param
*/
static QVariantMap
getSubMap( const QVariantMap& map, const QString& key )
{
bool success;
return CalamaresUtils::getSubMap( map, key, success );
}
static QPixmap static QPixmap
loadScreenshot( const QString& path ) loadScreenshot( const QString& path )
{ {
@ -51,12 +61,13 @@ PackageItem::PackageItem( const QString& a_id,
{ {
} }
PackageItem::PackageItem::PackageItem( const QVariantMap& item_map ) PackageItem::PackageItem( const QVariantMap& item_map )
: id( CalamaresUtils::getString( item_map, "id" ) ) : id( CalamaresUtils::getString( item_map, "id" ) )
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) ) , name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) ) , description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
, screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) ) , screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) )
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) ) , packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
, netinstallData( getSubMap( item_map, "netinstall" ) )
{ {
if ( name.isEmpty() && id.isEmpty() ) if ( name.isEmpty() && id.isEmpty() )
{ {
@ -125,6 +136,25 @@ PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
return l; return l;
} }
QVariantList
PackageListModel::getNetinstallDataForNames( const QStringList& ids ) const
{
QVariantList l;
for ( auto& p : m_packages )
{
if ( ids.contains( p.id ) )
{
if ( !p.netinstallData.isEmpty() )
{
QVariantMap newData = p.netinstallData;
newData[ "source" ] = QStringLiteral( "packageChooser" );
l.append( newData );
}
}
}
return l;
}
int int
PackageListModel::rowCount( const QModelIndex& index ) const PackageListModel::rowCount( const QModelIndex& index ) const
{ {

View File

@ -26,6 +26,7 @@ struct PackageItem
CalamaresUtils::Locale::TranslatedString description; CalamaresUtils::Locale::TranslatedString description;
QPixmap screenshot; QPixmap screenshot;
QStringList packageNames; QStringList packageNames;
QVariantMap netinstallData;
/// @brief Create blank PackageItem /// @brief Create blank PackageItem
PackageItem(); PackageItem();
@ -111,6 +112,14 @@ public:
*/ */
QStringList getInstallPackagesForNames( const QStringList& ids ) const; QStringList getInstallPackagesForNames( const QStringList& ids ) const;
/** @brief Does a name lookup (based on id) and returns the netinstall data
*
* If there is a package with an id in @p ids, returns their netinstall data
*
* returns a list of netinstall data or an emply list if none is found
*/
QVariantList getNetinstallDataForNames( const QStringList& ids ) const;
enum Roles : int enum Roles : int
{ {
NameRole = Qt::DisplayRole, NameRole = Qt::DisplayRole,

View File

@ -33,6 +33,15 @@ mode: required
# in the `exec` section. These package settings will then be handed # in the `exec` section. These package settings will then be handed
# off to whatever package manager is configured there. # off to whatever package manager is configured there.
# #
# - "netinstall-select"
# When this is set, the id(s) selected are passed to the netinstall module.
# Any id that matches a group name in that module is set to checked
#
# - "netinstall-add"
# With this method, the packagechooser module is used to add groups to the
# netinstall module. For this to hav=e any effect. You must set netinstall,
# which is described below.
#
# There is no need to put this module in the `exec` section. There # There is no need to put this module in the `exec` section. There
# are no jobs that this module provides. You should put **other** # are no jobs that this module provides. You should put **other**
# modules, either *contextualprocess* or *packages* or some custom # modules, either *contextualprocess* or *packages* or some custom
@ -101,13 +110,19 @@ labels:
# an additional attempt is made to load the image from the **branding** # an additional attempt is made to load the image from the **branding**
# directory. # directory.
# #
# The following field is **optional** for an item: # The following fields are **optional** for an item:
# #
# - *packages* : # - *packages* :
# List of package names for the product. If using the *method* # List of package names for the product. If using the *method*
# "packages", consider this item mandatory (because otherwise # "packages", consider this item mandatory (because otherwise
# selecting the item would install no packages). # selecting the item would install no packages).
# #
# - *netinstall* :
# The data in this field should follow the format of a group
# from the netinstall module documented in
# src/modules/netinstall/netinstall.conf. This is only used
# when method is set to "netinstall-add"
#
# # AppData Items # # # AppData Items #
# #
# For data provided by AppData XML: the item has an *appdata* # For data provided by AppData XML: the item has an *appdata*

View File

@ -382,7 +382,7 @@ class PMPacman(PackageManager):
def line_cb(line): def line_cb(line):
if line.startswith(":: "): if line.startswith(":: "):
self.in_package_changes = "package changes" in line self.in_package_changes = "package" in line or "hooks" in line
else: else:
if self.in_package_changes and line.endswith("...\n"): if self.in_package_changes and line.endswith("...\n"):
# Update the message, untranslated; do not change the # Update the message, untranslated; do not change the
@ -392,7 +392,7 @@ class PMPacman(PackageManager):
global custom_status_message global custom_status_message
custom_status_message = "pacman: " + line.strip() custom_status_message = "pacman: " + line.strip()
libcalamares.job.setprogress(self.progress_fraction) libcalamares.job.setprogress(self.progress_fraction)
libcalamares.utils.debug(line) libcalamares.utils.debug(line)
self.in_package_changes = False self.in_package_changes = False
self.line_cb = line_cb self.line_cb = line_cb
@ -444,8 +444,12 @@ class PMPacman(PackageManager):
else: else:
command.append("-S") command.append("-S")
# Don't ask for user intervention, take the default action
command.append("--noconfirm") command.append("--noconfirm")
# Don't report download progress for each file
command.append("--noprogressbar")
if self.pacman_needed_only is True: if self.pacman_needed_only is True:
command.append("--needed") command.append("--needed")

View File

@ -345,6 +345,11 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
if ( !m_swapChoices.contains( m_initialSwapChoice ) ) if ( !m_swapChoices.contains( m_initialSwapChoice ) )
{ {
cWarning() << "Configuration for *initialSwapChoice* is not one of the *userSwapChoices*"; cWarning() << "Configuration for *initialSwapChoice* is not one of the *userSwapChoices*";
if ( nameFound )
{
cWarning() << Logger::SubEntry << "Choice" << swapChoiceNames().find( m_initialSwapChoice ) << "added.";
m_swapChoices.insert( m_initialSwapChoice );
}
m_initialSwapChoice = pickOne( m_swapChoices ); m_initialSwapChoice = pickOne( m_swapChoices );
} }
setSwapChoice( m_initialSwapChoice ); setSwapChoice( m_initialSwapChoice );

View File

@ -146,15 +146,12 @@ modeDescription( Config::InstallChoice choice )
case Config::InstallChoice::Alongside: case Config::InstallChoice::Alongside:
return QCoreApplication::translate( context, "Install %1 <strong>alongside</strong> another operating system." ) return QCoreApplication::translate( context, "Install %1 <strong>alongside</strong> another operating system." )
.arg( branding->shortVersionedName() ); .arg( branding->shortVersionedName() );
break;
case Config::InstallChoice::Erase: case Config::InstallChoice::Erase:
return QCoreApplication::translate( context, "<strong>Erase</strong> disk and install %1." ) return QCoreApplication::translate( context, "<strong>Erase</strong> disk and install %1." )
.arg( branding->shortVersionedName() ); .arg( branding->shortVersionedName() );
break;
case Config::InstallChoice::Replace: case Config::InstallChoice::Replace:
return QCoreApplication::translate( context, "<strong>Replace</strong> a partition with %1." ) return QCoreApplication::translate( context, "<strong>Replace</strong> a partition with %1." )
.arg( branding->shortVersionedName() ); .arg( branding->shortVersionedName() );
break;
case Config::InstallChoice::NoChoice: case Config::InstallChoice::NoChoice:
case Config::InstallChoice::Manual: case Config::InstallChoice::Manual:
return QCoreApplication::translate( context, "<strong>Manual</strong> partitioning." ); return QCoreApplication::translate( context, "<strong>Manual</strong> partitioning." );
@ -187,21 +184,18 @@ diskDescription( int listLength, const PartitionCoreModule::SummaryInfo& info, C
.arg( branding->shortVersionedName() ) .arg( branding->shortVersionedName() )
.arg( info.deviceNode ) .arg( info.deviceNode )
.arg( info.deviceName ); .arg( info.deviceName );
break;
case Config::Erase: case Config::Erase:
return QCoreApplication::translate( context, return QCoreApplication::translate( context,
"<strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1." ) "<strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1." )
.arg( branding->shortVersionedName() ) .arg( branding->shortVersionedName() )
.arg( info.deviceNode ) .arg( info.deviceNode )
.arg( info.deviceName ); .arg( info.deviceName );
break;
case Config::Replace: case Config::Replace:
return QCoreApplication::translate( return QCoreApplication::translate(
context, "<strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1." ) context, "<strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1." )
.arg( branding->shortVersionedName() ) .arg( branding->shortVersionedName() )
.arg( info.deviceNode ) .arg( info.deviceNode )
.arg( info.deviceName ); .arg( info.deviceName );
break;
case Config::NoChoice: case Config::NoChoice:
case Config::Manual: case Config::Manual:
return QCoreApplication::translate( return QCoreApplication::translate(
@ -558,7 +552,7 @@ PartitionViewStep::onLeave()
if ( !okSize ) if ( !okSize )
{ {
cDebug() << o << "ESP too small"; cDebug() << o << "ESP too small";
const auto atLeastBytes = PartUtils::efiFilesystemMinimumSize(); const qint64 atLeastBytes = static_cast< qint64 >( PartUtils::efiFilesystemMinimumSize() );
const auto atLeastMiB = CalamaresUtils::BytesToMiB( atLeastBytes ); const auto atLeastMiB = CalamaresUtils::BytesToMiB( atLeastBytes );
description.append( ' ' ); description.append( ' ' );
description.append( tr( "The filesystem must be at least %1 MiB in size." ).arg( atLeastMiB ) ); description.append( tr( "The filesystem must be at least %1 MiB in size." ).arg( atLeastMiB ) );
@ -681,11 +675,15 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// because it could take a while. Then when it's done, we can set up the widgets // because it could take a while. Then when it's done, we can set up the widgets
// and remove the spinner. // and remove the spinner.
m_future = new QFutureWatcher< void >(); m_future = new QFutureWatcher< void >();
connect( m_future, &QFutureWatcher< void >::finished, this, [this] { connect( m_future,
continueLoading(); &QFutureWatcher< void >::finished,
this->m_future->deleteLater(); this,
this->m_future = nullptr; [ this ]
} ); {
continueLoading();
this->m_future->deleteLater();
this->m_future = nullptr;
} );
QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
m_future->setFuture( future ); m_future->setFuture( future );

View File

@ -11,6 +11,7 @@
#include "DeviceList.h" #include "DeviceList.h"
#include "partition/PartitionIterator.h" #include "partition/PartitionIterator.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <kpmcore/backend/corebackend.h> #include <kpmcore/backend/corebackend.h>
@ -40,16 +41,30 @@ hasRootPartition( Device* device )
return false; return false;
} }
/** @brief Check if @p path holds an iso9660 filesystem
*
* The @p path should point to a device; blkid is used to check the FS type.
*/
static bool static bool
blkIdCheckIso9660( const QString& path ) blkIdCheckIso9660( const QString& path )
{ {
QProcess blkid; // If blkid fails, there's no output, but we don't care
blkid.start( "blkid", { path } ); auto r = CalamaresUtils::System::runCommand( { "blkid", path }, std::chrono::seconds( 30 ) );
blkid.waitForFinished(); return r.getOutput().contains( "iso9660" );
QString output = QString::fromLocal8Bit( blkid.readAllStandardOutput() );
return output.contains( "iso9660" );
} }
/// @brief Convenience to check if @p partition holds an iso9660 filesystem
static bool
blkIdCheckIso9660P( const Partition* partition )
{
return blkIdCheckIso9660( partition->partitionPath() );
}
/** @brief Check if the @p device is an iso9660 device
*
* An iso9660 device is **probably** a CD-ROM. If the device holds an
* iso9660 FS, or any of its partitions do, then we call it an iso9660 device.
*/
static bool static bool
isIso9660( const Device* device ) isIso9660( const Device* device )
{ {
@ -65,13 +80,8 @@ isIso9660( const Device* device )
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() ) if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
{ {
for ( const Partition* partition : device->partitionTable()->children() ) const auto& p = device->partitionTable()->children();
{ return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P );
if ( blkIdCheckIso9660( partition->partitionPath() ) )
{
return true;
}
}
} }
return false; return false;
} }

View File

@ -8,9 +8,10 @@
* Calamares is Free Software: see the License-Identifier above. * Calamares is Free Software: see the License-Identifier above.
* *
*/ */
#include "core/DeviceModel.h" #include "DeviceModel.h"
#include "core/PartitionModel.h" #include "core/PartitionModel.h"
#include "core/SizeUtils.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
@ -18,9 +19,6 @@
// KPMcore // KPMcore
#include <kpmcore/core/device.h> #include <kpmcore/core/device.h>
// KF5
#include <KFormat>
#include <QIcon> #include <QIcon>
#include <QStandardItemModel> #include <QStandardItemModel>
@ -30,9 +28,9 @@
static void static void
sortDevices( DeviceModel::DeviceList& l ) sortDevices( DeviceModel::DeviceList& l )
{ {
std::sort( l.begin(), l.end(), []( const Device* dev1, const Device* dev2 ) { std::sort( l.begin(),
return dev1->deviceNode() < dev2->deviceNode(); l.end(),
} ); []( const Device* dev1, const Device* dev2 ) { return dev1->deviceNode() < dev2->deviceNode(); } );
} }
DeviceModel::DeviceModel( QObject* parent ) DeviceModel::DeviceModel( QObject* parent )
@ -83,7 +81,7 @@ DeviceModel::data( const QModelIndex& index, int role ) const
//: device[name] - size[number] (device-node[name]) //: device[name] - size[number] (device-node[name])
return tr( "%1 - %2 (%3)" ) return tr( "%1 - %2 (%3)" )
.arg( device->name() ) .arg( device->name() )
.arg( KFormat().formatByteSize( device->capacity() ) ) .arg( formatByteSize( device->capacity() ) )
.arg( device->deviceNode() ); .arg( device->deviceNode() );
} }
else else

View File

@ -15,8 +15,8 @@
#include "partition/PartitionIterator.h" #include "partition/PartitionIterator.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/String.h"
// KPMcore
#include <kpmcore/backend/corebackendmanager.h> #include <kpmcore/backend/corebackendmanager.h>
#include <kpmcore/core/device.h> #include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h> #include <kpmcore/core/partition.h>
@ -127,4 +127,23 @@ clonePartition( Device* device, Partition* partition )
partition->activeFlags() ); partition->activeFlags() );
} }
Calamares::JobResult
execute( Operation& operation, const QString& failureMessage )
{
operation.setStatus( Operation::StatusRunning );
Report report( nullptr );
if ( operation.execute( report ) )
{
return Calamares::JobResult::ok();
}
// Remove the === lines from the report by trimming them to empty
QStringList l = report.toText().split( '\n' );
std::for_each( l.begin(), l.end(), []( QString& s ) { CalamaresUtils::removeLeading( s, '=' ); } );
return Calamares::JobResult::error( failureMessage, l.join( '\n' ) );
}
} // namespace KPMHelpers } // namespace KPMHelpers

Some files were not shown because too many files have changed in this diff Show More