Merge branch 'development' into 3.2.x-stable
This commit is contained in:
commit
62c4d60fe2
@ -28,8 +28,9 @@ PointerAlignment: Left
|
||||
ReflowComments: "false"
|
||||
SortIncludes: "true"
|
||||
SpaceAfterCStyleCast: "false"
|
||||
SpaceInEmptyBlock: "false"
|
||||
SpacesBeforeTrailingComments: "2"
|
||||
SpacesInAngles: "true"
|
||||
SpacesInParentheses: "true"
|
||||
SpacesInSquareBrackets: "true"
|
||||
Standard: Cpp11
|
||||
Standard: c++17
|
||||
|
@ -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
|
110
CHANGES-3.2
110
CHANGES-3.2
@ -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
|
||||
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) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
|
@ -41,11 +41,11 @@
|
||||
# TODO:3.3: Require CMake 3.12
|
||||
cmake_minimum_required( VERSION 3.3 FATAL_ERROR )
|
||||
project( CALAMARES
|
||||
VERSION 3.2.48
|
||||
VERSION 3.2.52
|
||||
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 )
|
||||
message( FATAL_ERROR "Do not build development versions in the source-directory." )
|
||||
endif()
|
||||
@ -135,15 +135,15 @@ set( CALAMARES_DESCRIPTION_SUMMARY
|
||||
# NOTE: update these lines by running `txstats.py`, or for full automation
|
||||
# `txstats.py -e`. See also
|
||||
#
|
||||
# Total 81 languages
|
||||
set( _tx_complete az az_AZ ca de fa fi_FI he hr ja ko lt pt_PT si
|
||||
sq tr_TR uk zh_TW )
|
||||
set( _tx_good as be ca@valencia cs_CZ da fr fur hi it_IT ml nl
|
||||
pt_BR ru sk sv tg vi zh_CN )
|
||||
# Total 74 languages
|
||||
set( _tx_complete az az_AZ ca de fa fi_FI he hi hr ja ko lt pt_BR
|
||||
pt_PT si sq sv tr_TR uk zh_TW )
|
||||
set( _tx_good as be ca@valencia cs_CZ da fr fur it_IT ml nl ru sk
|
||||
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
|
||||
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
|
||||
ie kk kn ko_KR lo lv mk ne ne_NP te te_IN ur zh zh_HK )
|
||||
set( _tx_incomplete eo es_PR gu ie kk kn lo lv mk ne ne_NP ta_IN te
|
||||
ur zh zh_HK )
|
||||
|
||||
### Required versions
|
||||
#
|
||||
|
@ -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)
|
||||
[![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 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) |
|
||||
|
@ -21,10 +21,18 @@ Name[as]=চিছটেম ইনস্তল কৰক
|
||||
Icon[as]=কেলামাৰেচ
|
||||
GenericName[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
|
||||
Icon[az]=calamares
|
||||
GenericName[az]=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]=Усталяваць сістэму
|
||||
Icon[be]=calamares
|
||||
GenericName[be]=Усталёўшчык сістэмы
|
||||
@ -41,6 +49,10 @@ Name[ca]=Instal·la el sistema
|
||||
Icon[ca]=calamares
|
||||
GenericName[ca]=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
|
||||
Icon[da]=calamares
|
||||
GenericName[da]=Systeminstallationsprogram
|
||||
@ -57,10 +69,19 @@ Name[en_GB]=Install System
|
||||
Icon[en_GB]=calamares
|
||||
GenericName[en_GB]=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
|
||||
Icon[es]=calamares
|
||||
GenericName[es]=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
|
||||
Icon[et]=calamares
|
||||
GenericName[et]=Süsteemipaigaldaja
|
||||
@ -73,7 +94,10 @@ Name[fa]=نصب سامانه
|
||||
Icon[fa]=کالامارس
|
||||
GenericName[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
|
||||
Icon[fr]=calamares
|
||||
GenericName[fr]=Installateur système
|
||||
@ -98,10 +122,6 @@ Name[hr]=Instaliraj sustav
|
||||
Icon[hr]=calamares
|
||||
GenericName[hr]=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
|
||||
Icon[hu]=calamares
|
||||
GenericName[hu]=Rendszertelepítő
|
||||
@ -110,14 +130,18 @@ Name[id]=Instal Sistem
|
||||
Icon[id]=calamares
|
||||
GenericName[id]=Pemasang
|
||||
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ð
|
||||
Icon[is]=calamares
|
||||
GenericName[is]=Kerfis uppsetning
|
||||
Comment[is]=Calamares — Kerfis uppsetning
|
||||
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[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[ja]=システムをインストール
|
||||
Icon[ja]=calamares
|
||||
GenericName[ja]=システムインストーラー
|
||||
@ -130,10 +154,6 @@ Name[lt]=Įdiegti Sistemą
|
||||
Icon[lt]=calamares
|
||||
GenericName[lt]=Sistemos diegimas į kompiuterį
|
||||
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]=Инсталирај го системот
|
||||
Icon[mk]=calamares
|
||||
GenericName[mk]=Системен Инсталер
|
||||
@ -146,14 +166,14 @@ Name[nb]=Installer System
|
||||
Icon[nb]=calamares
|
||||
GenericName[nb]=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
|
||||
Icon[nl]=calamares
|
||||
GenericName[nl]=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
|
||||
Icon[pl]=calamares
|
||||
GenericName[pl]=Instalator systemu
|
||||
@ -162,6 +182,10 @@ Name[pt_BR]=Sistema de Instalação
|
||||
Icon[pt_BR]=calamares
|
||||
GenericName[pt_BR]=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
|
||||
Icon[ro]=calamares
|
||||
GenericName[ro]=Instalator de sistem
|
||||
@ -183,15 +207,11 @@ Name[sq]=Instalo Sistemin
|
||||
Icon[sq]=calamares
|
||||
GenericName[sq]=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]=Инсталирај систем
|
||||
Icon[sr]=calamares
|
||||
GenericName[sr]=Инсталатер система
|
||||
Comment[sr]=Каламарес — инсталатер система
|
||||
Name[sr@latin]=Instaliraj sistem
|
||||
Name[sv]=Installera system
|
||||
Icon[sv]=calamares
|
||||
GenericName[sv]=Systeminstallerare
|
||||
@ -201,6 +221,10 @@ Icon[tg]=calamares
|
||||
GenericName[tg]=Насбкунандаи низомӣ
|
||||
Comment[tg]=Calamares — Насбкунандаи низомӣ
|
||||
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]=Встановити Систему
|
||||
Icon[uk]=calamares
|
||||
GenericName[uk]=Встановлювач системи
|
||||
@ -217,27 +241,3 @@ Name[zh_TW]=安裝系統
|
||||
Icon[zh_TW]=calamares
|
||||
GenericName[zh_TW]=系統安裝程式
|
||||
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
|
||||
|
@ -75,7 +75,7 @@ fi
|
||||
#
|
||||
#
|
||||
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
|
||||
# to run and sign.
|
||||
|
@ -19,12 +19,12 @@ BASEDIR=$(dirname $0)
|
||||
TOPDIR=$( cd $BASEDIR/.. && pwd -P )
|
||||
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 -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 )
|
||||
|
||||
# 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
|
||||
do
|
||||
# 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
|
||||
#
|
||||
# Version 7 and earlier doesn't understand all the options we would like
|
||||
# Version 8 is ok
|
||||
# Version 9 is ok
|
||||
# Later versions change some defaults so need extra wrangling.
|
||||
# .. there are extra files that are appended to the settings, per
|
||||
# .. clang-format version.
|
||||
# Version 12 handles lambdas nicely, so use that.
|
||||
# Version 13 is also ok.
|
||||
|
||||
format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1`
|
||||
case "$format_version" in
|
||||
[0-7] )
|
||||
echo "! Clang-format version 8+ required"
|
||||
exit 1
|
||||
;;
|
||||
[89] )
|
||||
12|13 )
|
||||
:
|
||||
;;
|
||||
* )
|
||||
echo "! Clang-format version '$format_version' unsupported."
|
||||
echo "! Clang-format version '$format_version' unsupported, version 12 required."
|
||||
exit 1
|
||||
;;
|
||||
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
|
||||
@ -98,8 +86,3 @@ if test "x$any_dirs" = "xyes" ; then
|
||||
else
|
||||
style_some "$@"
|
||||
fi
|
||||
|
||||
### CLANG-FORMAT-WRANGLING
|
||||
#
|
||||
# Restore the original .clang-format
|
||||
cp "$_fmt.base" "$_fmt"
|
||||
|
32
ci/txpull.sh
32
ci/txpull.sh
@ -108,6 +108,21 @@ awk '
|
||||
skip=0; print $0;
|
||||
}}' < calamares.desktop > calamares.desktop.new
|
||||
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 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.
|
||||
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
|
||||
# own complete gettext-based setup.
|
||||
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
|
||||
# Convert PO files to MO files
|
||||
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
|
||||
done
|
||||
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
|
||||
|
||||
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
|
||||
done
|
||||
git add --verbose lang/python*
|
||||
|
@ -693,27 +693,27 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně odpojeno %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vypnut swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vyčištěn swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně zavřeno mapper zařízení %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vypnuta skupina svazků %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1989,7 +1989,7 @@ The installer will quit and all changes will be lost.</translation>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||
<source>Configuration Error</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Configuration Error </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
||||
|
@ -689,27 +689,27 @@ The installer will quit and all changes will be lost.</source>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 को माउंट से हटाना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 स्वैप निष्क्रिय करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 स्वैप रिक्त करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>प्रतिचित्रण उपकरण %1 बंद करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>वॉल्यूम समूह %1 निष्क्रिय करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kelola pengaturan mount otomatis</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -114,12 +114,12 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<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>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
<source>Send Session Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kirim Catatan Sesi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||
@ -165,7 +165,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/JobExample.cpp" line="30"/>
|
||||
<source>Programmed job failure was explicitly requested.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kegagalan pekerjaan diprogram diminta secara eksplisit. </translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -189,7 +189,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||
<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>
|
||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||
@ -245,7 +245,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/>
|
||||
<source>QML Step <i>%1</i>.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>QML Langkah <i>%1</i>.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/>
|
||||
@ -277,7 +277,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/>
|
||||
<source>System-requirements checking is complete.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Pengecekan kebutuhan sistem telah selesai.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -295,7 +295,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
|
||||
<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>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
|
||||
@ -429,7 +429,7 @@ Link copied to clipboard</source>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/>
|
||||
<source>&Done</source>
|
||||
<translation>&Kelar</translation>
|
||||
<translation>&Selesai</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/>
|
||||
@ -1054,12 +1054,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/>
|
||||
<source>Label for the filesystem</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label untuk filesystem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/>
|
||||
<source>FS Label:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label FS:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/>
|
||||
@ -1418,12 +1418,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/>
|
||||
<source>Label for the filesystem</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label untuk filesystem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/>
|
||||
<source>FS Label:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label FS:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/>
|
||||
@ -1582,7 +1582,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/>
|
||||
<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>
|
||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/>
|
||||
@ -1645,12 +1645,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/>
|
||||
<source>is running the installer as an administrator (root)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>menjalankan installer sebagai administrator (root)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/>
|
||||
<source>The setup program is not running with administrator rights.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Installer tidak dijalankan dengan kewenangan administrator.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/>
|
||||
@ -1699,7 +1699,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/oemid/IDJob.cpp" line="53"/>
|
||||
<source>Could not open file <code>%1</code>.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tidak dapat membuka berkas <code>%1</code>.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/oemid/IDJob.cpp" line="60"/>
|
||||
@ -1712,7 +1712,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/>
|
||||
<source>Creating initramfs with mkinitcpio.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Membuat initramfs menggunakan mkinitcpio.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1720,7 +1720,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/>
|
||||
<source>Creating initramfs.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Membuat initramfs.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -2031,12 +2031,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/>
|
||||
<source>Browser software</source>
|
||||
<translation>Peramban perangkat lunak</translation>
|
||||
<translation>Perangkat lunak peramban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/>
|
||||
<source>Browser package</source>
|
||||
<translation>Peramban paket</translation>
|
||||
<translation>Paket peramban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/>
|
||||
@ -2046,12 +2046,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/>
|
||||
<source>Kernel</source>
|
||||
<translation>Inti</translation>
|
||||
<translation>Kernel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/>
|
||||
<source>Services</source>
|
||||
<translation>Jasa</translation>
|
||||
<translation>Servis</translation>
|
||||
</message>
|
||||
<message>
|
||||
<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="550"/>
|
||||
<source>Repeat Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<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>
|
||||
<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>
|
||||
<location filename="../src/modules/users/page_usersetup.ui" line="458"/>
|
||||
@ -4252,7 +4252,7 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="136"/>
|
||||
<source>root is not allowed as username.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>root tidak boleh digunakan sebagai nama pengguna.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="145"/>
|
||||
@ -4287,7 +4287,7 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
||||
<source>Repeat Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="261"/>
|
||||
@ -4297,27 +4297,27 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="406"/>
|
||||
<source>Validate passwords quality</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Validasi kualitas kata sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<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>
|
||||
<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>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="398"/>
|
||||
<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>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="190"/>
|
||||
<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>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="293"/>
|
||||
<source>Reuse user password as root password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gunakan kata sandi pengguna sebagai kata sandi root</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="301"/>
|
||||
@ -4332,12 +4332,12 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="324"/>
|
||||
<source>Root Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kata Sandi Root</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="342"/>
|
||||
<source>Repeat Root Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="368"/>
|
||||
|
4366
lang/calamares_ja-Hira.ts
Normal file
4366
lang/calamares_ja-Hira.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
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>
|
||||
<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
|
||||
para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation>
|
||||
</message>
|
||||
@ -4003,7 +4003,7 @@ Saída de Dados:
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
||||
<source><h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</source>
|
||||
<translation><h1>%1</h1><br/><strong>%2<br/>para %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Obrigado à <a href="https://calamares.io/team/">equipa Calamares</a> e à <a href="https://www.transifex.com/calamares/calamares/">equipa de tradutores do Calamares</a>.<br/><br/>O desenvolvimento do <a href="https://calamares.io/">Calamares</a> é patrocinado pela <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</translation>
|
||||
<translation><h1>%1</h1><br/><strong>%2<br/>para o %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Obrigado à <a href="https://calamares.io/team/">equipa Calamares</a> e à <a href="https://www.transifex.com/calamares/calamares/">equipa de tradutores do Calamares</a>.<br/><br/>O desenvolvimento do <a href="https://calamares.io/">Calamares</a> é patrocinado pela <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -104,17 +104,17 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dă crash lui Calamares, pentru ca doctorul Konqui să se uite la el.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||
<source>Reloads the stylesheet from the branding directory.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Reîncarcă foaia de stil din directorul branding.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<source>Uploads the session log to the configured pastebin.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Încarcă jurnalul sesiunii pe pastebin-ul configurat.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
@ -134,7 +134,7 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||
<source>Widget Tree</source>
|
||||
<translation>Lista widget</translation>
|
||||
<translation>Arborele de widget</translation>
|
||||
</message>
|
||||
<message>
|
||||
<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>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||
<source>Configuration Error</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Eroare de configurare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
||||
|
@ -688,27 +688,27 @@ Alla ändringar kommer att gå förlorade.</translation>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Framgångsrikt avmonterade %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Framgångsrikt inaktiverade swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Framgångsrikt rensade swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Framgångsrikt stängde krypterad enhet %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Framgångsrikt inaktiverade volymgrupp %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
4377
lang/calamares_ta_IN.ts
Normal file
4377
lang/calamares_ta_IN.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Идора кардани танзимоти васлкунии худкор</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Quản lý cài đặt tự động gắn kết(auto-mount)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -104,22 +104,22 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gây crash Calamares, để Dr. Konqui có thể xem nó.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||
<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>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<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>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
<source>Send Session Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gửi log của phiên này</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||
@ -129,7 +129,7 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="128"/>
|
||||
<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>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||
|
@ -688,27 +688,27 @@ The installer will quit and all changes will be lost.</source>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功卸载了 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功禁用了交换空间 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功清理了交换空间 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功关闭了映射设备 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功禁用了卷组 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
322
lang/python.pot
322
lang/python.pot
@ -8,403 +8,397 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\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"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: \n"
|
||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:32
|
||||
msgid "Configuring initramfs."
|
||||
msgstr "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/fstab/main.py:360 src/modules/fstab/main.py:366
|
||||
#: src/modules/fstab/main.py:393 src/modules/networkcfg/main.py:105
|
||||
#: src/modules/initcpiocfg/main.py:235 src/modules/initcpiocfg/main.py:239
|
||||
#: 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/openrcdmcryptcfg/main.py:76
|
||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||
msgid "Configuration Error"
|
||||
msgstr "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/initramfscfg/main.py:86 src/modules/fstab/main.py:361
|
||||
#: 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/luksopenswaphookcfg/main.py:87
|
||||
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/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
||||
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:367
|
||||
#: 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/luksopenswaphookcfg/main.py:91
|
||||
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
|
||||
msgid "Configure GRUB."
|
||||
msgstr "Configure GRUB."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:43
|
||||
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 ""
|
||||
"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
|
||||
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."
|
||||
msgstr "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 "Creating initramfs with dracut."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:49
|
||||
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
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
msgstr "Cannot configure LightDM"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:748
|
||||
#: src/modules/displaymanager/main.py:746
|
||||
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"
|
||||
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"
|
||||
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."
|
||||
msgstr "No display managers selected for the displaymanager module."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:907
|
||||
#: src/modules/displaymanager/main.py:992
|
||||
msgid ""
|
||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||
"displaymanager.conf."
|
||||
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"
|
||||
msgstr "Display manager configuration was incomplete"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:29
|
||||
msgid "Configure OpenRC services"
|
||||
msgstr "Configure OpenRC services"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:57
|
||||
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
|
||||
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
|
||||
msgid ""
|
||||
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
||||
"level {level!s}."
|
||||
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-systemd/main.py:59
|
||||
msgid "Cannot modify service"
|
||||
msgstr "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 ""
|
||||
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
||||
|
||||
#: src/modules/services-openrc/main.py:101
|
||||
msgid "Target runlevel does not exist"
|
||||
msgstr "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 ""
|
||||
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
|
||||
#: src/modules/services-openrc/main.py:110
|
||||
msgid "Target service does not exist"
|
||||
msgstr "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."
|
||||
"The path for service {name!s} is <code>{path!s}</code>, which does not exist."
|
||||
msgstr ""
|
||||
"The path for service {name!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
|
||||
#: src/modules/networkcfg/main.py:29
|
||||
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:69
|
||||
#: src/modules/packages/main.py:54 src/modules/packages/main.py:65
|
||||
#: src/modules/packages/main.py:75
|
||||
msgid "Install packages."
|
||||
msgstr "Install packages."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:57
|
||||
#: src/modules/packages/main.py:63
|
||||
#, python-format
|
||||
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
|
||||
msgid "Installing one package."
|
||||
msgid_plural "Installing %(num)d packages."
|
||||
msgstr[0] "Installing one package."
|
||||
msgstr[1] "Installing %(num)d packages."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: src/modules/packages/main.py:65
|
||||
#: src/modules/packages/main.py:71
|
||||
#, python-format
|
||||
msgid "Removing one package."
|
||||
msgid_plural "Removing %(num)d packages."
|
||||
msgstr[0] "Removing one package."
|
||||
msgstr[1] "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
|
||||
#: src/modules/packages/main.py:725 src/modules/packages/main.py:737
|
||||
#: src/modules/packages/main.py:765
|
||||
msgid "Package Manager error"
|
||||
msgstr "Package Manager error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:639
|
||||
#: src/modules/packages/main.py:726
|
||||
msgid ""
|
||||
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
||||
"returned error code {!s}."
|
||||
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}."
|
||||
|
||||
#: 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 ""
|
||||
"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 ""
|
||||
"The package manager could not make changes to the installed system. The "
|
||||
"command <pre>{!s}</pre> returned error code {!s}."
|
||||
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
|
||||
msgid "Configure Plymouth theme"
|
||||
msgstr "Configure Plymouth theme"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initcpiocfg/main.py:28
|
||||
msgid "Configuring mkinitcpio."
|
||||
msgstr "Configuring mkinitcpio."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/localecfg/main.py:30
|
||||
msgid "Configuring locales."
|
||||
msgstr "Configuring locales."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mount/main.py:30
|
||||
#: src/modules/mount/main.py:42
|
||||
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
|
||||
msgid "Installing data."
|
||||
msgstr "Installing data."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dummypython/main.py:35
|
||||
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:94
|
||||
msgid "Dummy python step {}"
|
||||
msgstr "Dummy python step {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/hwclock/main.py:26
|
||||
msgid "Setting hardware clock."
|
||||
msgstr "Setting hardware clock."
|
||||
|
||||
#: src/modules/umount/main.py:31
|
||||
msgid "Unmount file systems."
|
||||
msgstr "Unmount file systems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/openrcdmcryptcfg/main.py:26
|
||||
msgid "Configuring OpenRC dmcrypt service."
|
||||
msgstr "Configuring OpenRC dmcrypt service."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:26
|
||||
msgid "Configure systemd services"
|
||||
msgstr "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 ""
|
||||
"<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:69
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
msgid ""
|
||||
"Unknown systemd commands <code>{command!s}</code> and "
|
||||
"<code>{suffix!s}</code> for unit {name!s}."
|
||||
"Unknown systemd commands <code>{command!s}</code> and <code>{suffix!s}</"
|
||||
"code> for unit {name!s}."
|
||||
msgstr ""
|
||||
"Unknown systemd commands <code>{command!s}</code> and "
|
||||
"<code>{suffix!s}</code> for unit {name!s}."
|
||||
|
||||
#: src/modules/mkinitfs/main.py:27
|
||||
msgid "Creating initramfs with mkinitfs."
|
||||
msgstr "Creating initramfs with mkinitfs."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mkinitfs/main.py:49
|
||||
msgid "Failed to run mkinitfs on the target"
|
||||
msgstr "Failed to run mkinitfs on the target"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:34
|
||||
msgid "Filling up filesystems."
|
||||
msgstr "Filling up filesystems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:254
|
||||
msgid "rsync failed with error code {}."
|
||||
msgstr "rsync failed with error code {}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:299
|
||||
msgid "Unpacking image {}/{}, file {}/{}"
|
||||
msgstr "Unpacking image {}/{}, file {}/{}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:314
|
||||
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 \"{}\""
|
||||
msgstr "Failed to unpack image \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:430
|
||||
msgid "No mount point for root partition"
|
||||
msgstr "No mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:431
|
||||
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
||||
msgstr "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
||||
msgid "globalstorage does not contain a \"rootMountPoint\" key."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:436
|
||||
#: src/modules/unpackfs/main.py:434
|
||||
msgid "Bad mount point for root partition"
|
||||
msgstr "Bad mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:437
|
||||
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
||||
msgstr "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
||||
#: src/modules/unpackfs/main.py:435
|
||||
msgid "rootMountPoint is \"{}\", which does not exist."
|
||||
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 "Bad unsquash configuration"
|
||||
#: src/modules/unpackfs/main.py:439 src/modules/unpackfs/main.py:455
|
||||
#: src/modules/unpackfs/main.py:459 src/modules/unpackfs/main.py:465
|
||||
#: src/modules/unpackfs/main.py:480
|
||||
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"
|
||||
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"
|
||||
msgstr "The source filesystem \"{}\" does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:464
|
||||
#: src/modules/unpackfs/main.py:466
|
||||
msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
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"
|
||||
msgstr "The destination \"{}\" in the target system is not a directory"
|
||||
|
||||
#: src/modules/luksopenswaphookcfg/main.py:26
|
||||
msgid "Configuring encrypted swap."
|
||||
msgstr "Configuring encrypted swap."
|
||||
msgstr ""
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Translators:
|
||||
# pavelrz, 2017
|
||||
# LiberteCzech <martin.kriz.czech@gmail.com>, 2020
|
||||
# Pavel Borecki <pavel.borecki@gmail.com>, 2021
|
||||
# Pavel Borecki <pavel.borecki@gmail.com>, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@ -15,7 +15,7 @@ msgstr ""
|
||||
"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"
|
||||
"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"
|
||||
"MIME-Version: 1.0\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
|
||||
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
|
||||
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 "
|
||||
"installed."
|
||||
msgstr ""
|
||||
"Nepodařilo se nalézt nástroj unsquashfs – ověřte, že je nainstalovaný "
|
||||
"balíček squashfs-tools."
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
@ -5,6 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Jason Collins <JasonPCollins@protonmail.com>, 2018
|
||||
# Karthik Balan, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@ -13,7 +14,7 @@ msgstr ""
|
||||
"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"
|
||||
"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"
|
||||
"MIME-Version: 1.0\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:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
msgstr "Configuration Error "
|
||||
|
||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||
@ -61,7 +62,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:508
|
||||
msgid "Bootloader installation error"
|
||||
msgstr ""
|
||||
msgstr "Bootloader installation error"
|
||||
|
||||
#: src/modules/bootloader/main.py:509
|
||||
msgid ""
|
||||
@ -91,7 +92,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:526
|
||||
msgid "Cannot write KDM configuration file"
|
||||
msgstr ""
|
||||
msgstr "Cannot write KDM configuration file"
|
||||
|
||||
#: src/modules/displaymanager/main.py:527
|
||||
msgid "KDM config file {!s} does not exist"
|
||||
@ -145,7 +146,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:29
|
||||
msgid "Configure OpenRC services"
|
||||
msgstr ""
|
||||
msgstr "Configure OpenRC services"
|
||||
|
||||
#: src/modules/services-openrc/main.py:57
|
||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||
@ -173,7 +174,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:101
|
||||
msgid "Target runlevel does not exist"
|
||||
msgstr ""
|
||||
msgstr "Target runlevel does not exist"
|
||||
|
||||
#: src/modules/services-openrc/main.py:102
|
||||
msgid ""
|
||||
@ -193,7 +194,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/networkcfg/main.py:29
|
||||
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: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:678
|
||||
msgid "Package Manager error"
|
||||
msgstr ""
|
||||
msgstr "Package Manager error"
|
||||
|
||||
#: src/modules/packages/main.py:639
|
||||
msgid ""
|
||||
|
@ -319,7 +319,7 @@ msgstr "systemd लक्ष्य <code>{name!s}</code>सक्रिय क
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
msgstr "systemd टाइमर <code>{name!s}</code>सक्रिय करना विफल।"
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
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 "
|
||||
"installed."
|
||||
msgstr ""
|
||||
"unsqaushfs खोजने में विफल, सुनिश्चित करें कि squashfs-tools पैकेज इंस्टॉल "
|
||||
"है।"
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
385
lang/python/ja-Hira/LC_MESSAGES/python.po
Normal file
385
lang/python/ja-Hira/LC_MESSAGES/python.po
Normal 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 ""
|
@ -4,7 +4,7 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Marcin Mikołajczak <me@mkljczk.pl>, 2017
|
||||
# marcin mikołajczak <me@mkljczk.pl>, 2017
|
||||
# KagiSame, 2018
|
||||
# Piotr Strębski <strebski@gmail.com>, 2020
|
||||
# Jacob B. <brickminerplyt@gmail.com>, 2021
|
||||
|
@ -6,6 +6,7 @@
|
||||
# Translators:
|
||||
# Jobava Jobava <jobaval10n@gmail.com>, 2018
|
||||
# Sebastian Brici <bricisebastian@gmail.com>, 2018
|
||||
# Chele Ion <krovyoll@gmail.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@ -14,7 +15,7 @@ msgstr ""
|
||||
"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"
|
||||
"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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -24,7 +25,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:32
|
||||
msgid "Configuring initramfs."
|
||||
msgstr ""
|
||||
msgstr "Configurare initramfs"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
||||
#: 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:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
msgstr "Eroare de configurare"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Nu sunt partiţii definite ca 1{!s}1 ."
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Nu este definită o partiţie rădăcină pentru 1{!s}1 ."
|
||||
|
||||
#: src/modules/grubcfg/main.py:28
|
||||
msgid "Configure GRUB."
|
||||
|
387
lang/python/ta_IN/LC_MESSAGES/python.po
Normal file
387
lang/python/ta_IN/LC_MESSAGES/python.po
Normal 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 ""
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# T. Tran <transifex@emiu.net>, 2020
|
||||
# Th1nhhdk, 2021
|
||||
# th1nhhdk <th1nhhdk@tutanota.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@ -14,7 +14,7 @@ msgstr ""
|
||||
"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"
|
||||
"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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@ -9,6 +9,7 @@
|
||||
# Feng Chao <chaofeng111@qq.com>, 2020
|
||||
# Bobby Rong <admin@bobby285271.top>, 2020
|
||||
# 玉堂白鹤 <yjwork@qq.com>, 2021
|
||||
# Giovanni Schiano-Moriello, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@ -17,7 +18,7 @@ msgstr ""
|
||||
"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"
|
||||
"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"
|
||||
"MIME-Version: 1.0\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
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
msgstr "无法启用 systemd 计时器 <code>{name!s}</code>。"
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
@ -384,7 +385,7 @@ msgstr "源文件系统 \"{}\" 不存在"
|
||||
msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
msgstr "寻找 unsquashfs 失败,请确定您已安装 squashfs-tools 软体包。"
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
@ -485,7 +485,7 @@ main( int argc, char* argv[] )
|
||||
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 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 >;
|
||||
|
||||
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() );
|
||||
|
||||
Calamares::JobList jobList = m->jobs();
|
||||
@ -543,6 +543,8 @@ main( int argc, char* argv[] )
|
||||
unsigned int count = 1;
|
||||
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();
|
||||
Calamares::JobResult r = p->exec();
|
||||
if ( !r )
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
|
||||
/** @brief Is this JobResult a success?
|
||||
*
|
||||
* Equivalent to errorCode() == 0, might be named isValid().
|
||||
* Equivalent to errorCode() == 0, see succeeded().
|
||||
*/
|
||||
virtual operator bool() const;
|
||||
|
||||
@ -58,6 +58,11 @@ public:
|
||||
virtual void setDetails( const QString& details );
|
||||
|
||||
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
|
||||
static JobResult ok();
|
||||
|
@ -122,8 +122,9 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
|
||||
<< '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')';
|
||||
cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" )
|
||||
<< jobitem.job->prettyName() << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count()
|
||||
<< ')';
|
||||
o.refresh(); // So next time it shows the function header again
|
||||
emitProgress( 0.0 ); // 0% for *this job*
|
||||
connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );
|
||||
|
@ -26,6 +26,11 @@ namespace CalamaresPython
|
||||
boost::python::object
|
||||
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() )
|
||||
{
|
||||
case QVariant::Map:
|
||||
@ -62,6 +67,9 @@ variantToPyObject( const QVariant& variant )
|
||||
default:
|
||||
return bp::object();
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,6 +23,11 @@ static const char* s_preScript = nullptr;
|
||||
|
||||
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( 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 );
|
||||
@ -42,6 +47,10 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_process_output_overloads,
|
||||
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 )
|
||||
{
|
||||
bp::object package = bp::scope();
|
||||
@ -91,7 +100,7 @@ BOOST_PYTHON_MODULE( libcalamares )
|
||||
bp::args( "s" ),
|
||||
"Writes the given string to the Calamares warning stream." );
|
||||
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
|
||||
|
@ -22,6 +22,11 @@ namespace Partition
|
||||
QString
|
||||
prettyNameForFileSystemType( FileSystem::Type t )
|
||||
{
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||
#endif
|
||||
// 13 enumeration values not handled
|
||||
switch ( t )
|
||||
{
|
||||
case FileSystem::Unknown:
|
||||
@ -60,11 +65,19 @@ prettyNameForFileSystemType( FileSystem::Type t )
|
||||
default:
|
||||
return FileSystem::nameForType( t );
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
QString
|
||||
untranslatedFS( FileSystem::Type t )
|
||||
{
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||
#endif
|
||||
// 34 enumeration values not handled
|
||||
switch ( t )
|
||||
{
|
||||
case FileSystem::Type::ReiserFS:
|
||||
@ -72,6 +85,9 @@ untranslatedFS( FileSystem::Type t )
|
||||
default:
|
||||
return FileSystem::nameForType( t, { QStringLiteral( "C" ) } );
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Partition
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "partition/Sync.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/String.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QTemporaryDir>
|
||||
@ -92,7 +93,7 @@ struct TemporaryMount::Private
|
||||
|
||||
|
||||
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_mountDir.setAutoRemove( false );
|
||||
@ -123,5 +124,32 @@ TemporaryMount::path() const
|
||||
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 CalamaresUtils
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
@ -50,6 +51,13 @@ DLLEXPORT int mount( const QString& devicePath,
|
||||
*/
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -68,6 +76,36 @@ private:
|
||||
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 CalamaresUtils
|
||||
|
||||
|
@ -115,12 +115,14 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
||||
QString completePath = targetPath( path );
|
||||
if ( completePath.isEmpty() )
|
||||
{
|
||||
cWarning() << "No target path for" << path;
|
||||
return CreationResult( CreationResult::Code::Invalid );
|
||||
}
|
||||
|
||||
QFile f( completePath );
|
||||
if ( ( mode == WriteMode::KeepExisting ) && f.exists() )
|
||||
{
|
||||
cWarning() << "Target file" << completePath << "already exists";
|
||||
return CreationResult( CreationResult::Code::AlreadyExists );
|
||||
}
|
||||
|
||||
@ -133,13 +135,16 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
||||
|
||||
if ( !f.open( m ) )
|
||||
{
|
||||
cWarning() << "Could not open target file" << completePath;
|
||||
return CreationResult( CreationResult::Code::Failed );
|
||||
}
|
||||
|
||||
if ( f.write( contents ) != contents.size() )
|
||||
auto written = f.write( contents );
|
||||
if ( written != contents.size() )
|
||||
{
|
||||
f.close();
|
||||
f.remove();
|
||||
cWarning() << "Short write (" << written << "out of" << contents.size() << "bytes) to" << completePath;
|
||||
return CreationResult( CreationResult::Code::Failed );
|
||||
}
|
||||
|
||||
@ -147,6 +152,30 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
||||
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
|
||||
System::removeTargetFile( const QString& path ) const
|
||||
{
|
||||
|
@ -287,6 +287,24 @@ public:
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @param path a full pathname to a desired directory.
|
||||
|
@ -259,21 +259,22 @@ operator<<( QDebug& s, const RedactedCommand& l )
|
||||
* Identical strings with the same context will be hashed 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
|
||||
|
||||
uint val = qHash(context, salt);
|
||||
return qHash(s, val);
|
||||
uint val = qHash( context, salt );
|
||||
return qHash( s, val );
|
||||
}
|
||||
|
||||
RedactedName::RedactedName( const QString& context, const QString& s )
|
||||
: m_id( insertRedactedName(context, s) ),
|
||||
m_context(context)
|
||||
: m_id( insertRedactedName( context, s ) )
|
||||
, m_context( context )
|
||||
{
|
||||
}
|
||||
|
||||
RedactedName::RedactedName(const char *context, const QString& s )
|
||||
RedactedName::RedactedName( const char* context, const QString& s )
|
||||
: RedactedName( QString::fromLatin1( context ), s )
|
||||
{
|
||||
}
|
||||
|
@ -71,8 +71,11 @@ private:
|
||||
inline CDebug&
|
||||
operator<<( CDebug&& s, const FuncSuppressor& f )
|
||||
{
|
||||
s.m_funcinfo = nullptr;
|
||||
s << f.m_s;
|
||||
if ( s.m_funcinfo )
|
||||
{
|
||||
s.m_funcinfo = nullptr;
|
||||
s.m_msg = QString( f.m_s );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -244,7 +247,8 @@ private:
|
||||
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;
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ namespace CalamaresUtils
|
||||
* @param locale the new locale (names as defined by Calamares).
|
||||
* @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
|
||||
*/
|
||||
@ -56,7 +57,8 @@ DLLEXPORT CalamaresUtils::Locale::Translation::Id translatorLocaleName();
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
@ -88,7 +90,7 @@ public:
|
||||
static Retranslator* instance();
|
||||
|
||||
/// @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:
|
||||
void languageChanged();
|
||||
@ -138,8 +140,11 @@ private:
|
||||
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
|
||||
do \
|
||||
{ \
|
||||
connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, this, slotfunc ); \
|
||||
(this->*slotfunc)(); \
|
||||
connect( CalamaresUtils::Retranslator::instance(), \
|
||||
&CalamaresUtils::Retranslator::languageChanged, \
|
||||
this, \
|
||||
slotfunc ); \
|
||||
( this->*slotfunc )(); \
|
||||
} while ( false )
|
||||
|
||||
#endif
|
||||
|
@ -224,5 +224,26 @@ truncateMultiLine( const QString& string, CalamaresUtils::LinesStartEnd lines, C
|
||||
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
|
||||
|
@ -100,6 +100,19 @@ DLLEXPORT QString truncateMultiLine( const QString& string,
|
||||
LinesStartEnd lines = LinesStartEnd { 3, 5 },
|
||||
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
|
||||
|
||||
#endif
|
||||
|
@ -70,12 +70,19 @@ private Q_SLOTS:
|
||||
void testStringTruncation();
|
||||
void testStringTruncationShorter();
|
||||
void testStringTruncationDegenerate();
|
||||
void testStringRemoveLeading_data();
|
||||
void testStringRemoveLeading();
|
||||
void testStringRemoveTrailing_data();
|
||||
void testStringRemoveTrailing();
|
||||
|
||||
/** @section Test Runner directory-manipulation. */
|
||||
void testRunnerDirs();
|
||||
void testCalculateWorkingDirectory();
|
||||
void testRunnerOutput();
|
||||
|
||||
/** @section Test file-functions */
|
||||
void testReadWriteFile();
|
||||
|
||||
private:
|
||||
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
|
||||
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 )
|
||||
|
||||
#include "utils/moc-warnings.h"
|
||||
|
@ -162,14 +162,15 @@ uploadServerFromMap( const QVariantMap& map )
|
||||
|
||||
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
|
||||
return Branding::UploadServerInfo(
|
||||
return Branding::UploadServerInfo {
|
||||
names.find( typestring, bogus ),
|
||||
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
|
||||
|
@ -227,7 +227,14 @@ public:
|
||||
* 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).
|
||||
*/
|
||||
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; }
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,7 @@ set( calamaresui_SOURCES
|
||||
viewpages/ViewStep.cpp
|
||||
|
||||
widgets/ClickableLabel.cpp
|
||||
widgets/ErrorDialog.cpp
|
||||
widgets/FixedAspectRatioLabel.cpp
|
||||
widgets/PrettyRadioButton.cpp
|
||||
widgets/TranslationFix.cpp
|
||||
@ -39,8 +40,6 @@ set( calamaresui_SOURCES
|
||||
|
||||
# Don't warn about third-party sources
|
||||
mark_thirdparty_code(
|
||||
${CMAKE_SOURCE_DIR}/3rdparty/qjsonitem.cpp
|
||||
${CMAKE_SOURCE_DIR}/3rdparty/qjsonmodel.cpp
|
||||
${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp
|
||||
)
|
||||
|
||||
@ -75,6 +74,8 @@ calamares_add_library( calamaresui
|
||||
Qt5::Svg
|
||||
RESOURCES libcalamaresui.qrc
|
||||
EXPORT Calamares
|
||||
UI
|
||||
utils/ErrorDialog/ErrorDialog.ui
|
||||
VERSION ${CALAMARES_VERSION_SHORT}
|
||||
)
|
||||
target_link_libraries( calamaresui PRIVATE yamlcpp::yamlcpp )
|
||||
|
@ -24,11 +24,13 @@
|
||||
#include "viewpages/BlankViewStep.h"
|
||||
#include "viewpages/ExecutionViewStep.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
#include "widgets/ErrorDialog.h"
|
||||
#include "widgets/TranslationFix.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QBoxLayout>
|
||||
#include <QClipboard>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaObject>
|
||||
@ -150,56 +152,32 @@ ViewManager::insertViewStep( int before, ViewStep* step )
|
||||
void
|
||||
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;
|
||||
cDebug() << Logger::SubEntry << "- message:" << message;
|
||||
cDebug() << Logger::SubEntry << "- details:" << Logger::NoQuote << details;
|
||||
|
||||
QString heading
|
||||
= 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();
|
||||
msgBox->setIcon( QMessageBox::Critical );
|
||||
msgBox->setWindowTitle( tr( "Error" ) );
|
||||
msgBox->setText( "<strong>" + heading + "</strong>" );
|
||||
msgBox->setInformativeText( text );
|
||||
if ( shouldOfferWebPaste )
|
||||
{
|
||||
msgBox->setStandardButtons( QMessageBox::Yes | QMessageBox::No );
|
||||
msgBox->setDefaultButton( QMessageBox::No );
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox->setStandardButtons( QMessageBox::Close );
|
||||
msgBox->setDefaultButton( QMessageBox::Close );
|
||||
}
|
||||
Calamares::fixButtonLabels( msgBox );
|
||||
msgBox->show();
|
||||
ErrorDialog* errorDialog = new ErrorDialog();
|
||||
errorDialog->setWindowTitle( tr( "Error" ) );
|
||||
errorDialog->setHeading( "<strong>" + heading + "</strong>" );
|
||||
errorDialog->setInformativeText( message );
|
||||
errorDialog->setShouldOfferWebPaste( Calamares::Branding::instance()->uploadServer() );
|
||||
errorDialog->setDetails( details );
|
||||
errorDialog->show();
|
||||
|
||||
cDebug() << "Calamares will quit when the dialog closes.";
|
||||
connect( msgBox, &QMessageBox::buttonClicked, [msgBox]( QAbstractButton* button ) {
|
||||
if ( msgBox->buttonRole( button ) == QMessageBox::ButtonRole::YesRole )
|
||||
{
|
||||
CalamaresUtils::Paste::doLogUploadUI( msgBox );
|
||||
}
|
||||
QApplication::quit();
|
||||
} );
|
||||
connect( errorDialog,
|
||||
&QDialog::finished,
|
||||
[ errorDialog ]( int result )
|
||||
{
|
||||
if ( result == QDialog::Accepted && errorDialog->shouldOfferWebPaste() )
|
||||
{
|
||||
CalamaresUtils::Paste::doLogUploadUI( errorDialog );
|
||||
}
|
||||
QApplication::quit();
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,7 +69,8 @@ STATICTEST QString
|
||||
ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* 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() )
|
||||
{
|
||||
|
106
src/libcalamaresui/widgets/ErrorDialog.cpp
Normal file
106
src/libcalamaresui/widgets/ErrorDialog.cpp
Normal 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
|
83
src/libcalamaresui/widgets/ErrorDialog.h
Normal file
83
src/libcalamaresui/widgets/ErrorDialog.h
Normal 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
|
133
src/libcalamaresui/widgets/ErrorDialog.ui
Normal file
133
src/libcalamaresui/widgets/ErrorDialog.ui
Normal 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>
|
@ -11,30 +11,34 @@
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QCoreApplication>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
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
|
||||
fixButtonLabels( QMessageBox* box )
|
||||
fixButtonLabels( TButtonBox* box )
|
||||
{
|
||||
if ( !box )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
auto* button = box->button( sb );
|
||||
auto* button = box->button( static_cast< typename TButtonBox::StandardButton >( int( sb ) ) );
|
||||
if ( button )
|
||||
{
|
||||
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
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "DllMacro.h"
|
||||
|
||||
class QMessageBox;
|
||||
class QDialogButtonBox;
|
||||
|
||||
namespace Calamares
|
||||
{
|
||||
@ -26,6 +27,8 @@ namespace Calamares
|
||||
* guess the context.
|
||||
*/
|
||||
void UIDLLEXPORT fixButtonLabels( QMessageBox* );
|
||||
|
||||
void UIDLLEXPORT fixButtonLabels( QDialogButtonBox* );
|
||||
} // namespace Calamares
|
||||
|
||||
#endif
|
||||
|
@ -67,7 +67,7 @@ Note that process modules are not recommended.
|
||||
|
||||
Module descriptors **may** have the following keys:
|
||||
- *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
|
||||
has no configuration file; defaults to false)
|
||||
- *requiredModules* (a list of modules which are required for this module
|
||||
@ -86,24 +86,30 @@ it needs those keys.
|
||||
|
||||
### Emergency Modules
|
||||
|
||||
Only C++ modules and job modules may be emergency modules. If, during an
|
||||
*exec* step in the sequence, a module fails, installation as a whole fails
|
||||
and the install is aborted. If there are emergency modules in the **same**
|
||||
exec block, those will be executed before the installation is aborted.
|
||||
Non-emergency modules are not executed.
|
||||
If, during an *exec* step in the sequence, a module fails, installation as
|
||||
a whole fails and the install is aborted. If there are emergency modules
|
||||
in the **same** exec block, those will be executed before the installation
|
||||
is aborted. Non-emergency modules are not executed.
|
||||
|
||||
If an emergency-module fails while processing emergency-modules for
|
||||
another failed module, that failure is ignored and emergency-module
|
||||
processing continues.
|
||||
|
||||
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
|
||||
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
|
||||
module after all (this is so that you can have modules that have several
|
||||
instances, only some of which are actually needed for emergencies).
|
||||
module after all. This is so that you can have modules that have several
|
||||
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
|
||||
|
||||
@ -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.
|
||||
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
|
||||
read a configuration file, and will not warn that one is missing;
|
||||
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.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
> Type: viewmodule, jobmodule
|
||||
|
@ -46,6 +46,16 @@ efiBootMgr: "efibootmgr"
|
||||
# setting the option here, keep in mind that the name is sanitized
|
||||
# (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"
|
||||
|
||||
# Optionally install a copy of the GRUB EFI bootloader as the EFI
|
||||
|
@ -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
|
||||
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_name = os.path.basename(kernel_path)
|
||||
@ -268,10 +268,166 @@ def create_loader(loader_path, entry):
|
||||
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:
|
||||
efi_bootloader_id = libcalamares.job.configuration[
|
||||
"efiBootloaderId"]
|
||||
efi_bootloader_id = change_efi_suffix( efi_directory, libcalamares.job.configuration["efiBootloaderId"] )
|
||||
else:
|
||||
branding = libcalamares.globalstorage.value("branding")
|
||||
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])
|
||||
|
||||
|
||||
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
|
||||
|
||||
@ -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"])
|
||||
|
||||
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()
|
||||
|
||||
if is_zfs:
|
||||
@ -421,6 +578,7 @@ def run_grub_install(fw_type, partitions, efi_directory=None):
|
||||
"--bootloader-id=" + efi_bootloader_id,
|
||||
"--force"])
|
||||
else:
|
||||
assert efi_directory is None
|
||||
if libcalamares.globalstorage.value("bootLoader") is None:
|
||||
return
|
||||
|
||||
@ -462,7 +620,7 @@ def install_grub(efi_directory, fw_type):
|
||||
if not os.path.isdir(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()
|
||||
|
||||
@ -497,7 +655,7 @@ def install_grub(efi_directory, fw_type):
|
||||
shutil.copy2(efi_file_source, efi_file_target)
|
||||
else:
|
||||
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"])
|
||||
|
||||
@ -506,7 +664,7 @@ def install_secureboot(efi_directory):
|
||||
"""
|
||||
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_efi_directory = install_path + efi_directory
|
||||
|
7
src/modules/bootloader/tests/CMakeTests.txt
Normal file
7
src/modules/bootloader/tests/CMakeTests.txt
Normal 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}
|
||||
)
|
64
src/modules/bootloader/tests/test-bootloader-efiname.py
Normal file
64
src/modules/bootloader/tests/test-bootloader-efiname.py
Normal 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")
|
@ -18,10 +18,16 @@
|
||||
#
|
||||
# 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 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:
|
||||
default: defaults,noatime
|
||||
btrfs: defaults,noatime,autodefrag,compress=zstd
|
||||
btrfs_swap: defaults,noatime
|
||||
# btrfs: defaults,noatime,autodefrag,compress=zstd
|
||||
btrfs: defaults
|
||||
# btrfs_swap: defaults,noatime
|
||||
btrfs_swap: defaults
|
||||
|
||||
# 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,
|
||||
@ -49,7 +55,7 @@ efiMountOptions: umask=0077
|
||||
# The standard configuration applies asynchronous discard support and ssd optimizations to btrfs
|
||||
# and does nothing for other filesystems.
|
||||
ssdExtraMountOptions:
|
||||
btrfs: discard=async,ssd,commit=120
|
||||
btrfs: discard=async
|
||||
|
||||
# Additional options added to each line in /etc/crypttab
|
||||
crypttabOptions: luks
|
||||
|
25
src/modules/fstab/test2.yaml
Normal file
25
src/modules/fstab/test2.yaml
Normal 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"
|
@ -29,8 +29,16 @@ prefer_grub_d: false
|
||||
# kept, not updated to the *bootloaderEntryName* from the branding file.
|
||||
# Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in
|
||||
# some way (e.g. uses shell-command substitution).
|
||||
#
|
||||
# TODO:3.3:snake-case this key
|
||||
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
|
||||
# we are overwriting it.
|
||||
#
|
||||
|
@ -7,8 +7,10 @@ additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
overwrite: { type: boolean, default: false }
|
||||
# TODO:3.3:snake-case this key
|
||||
keepDistributor: { type: boolean, default: false }
|
||||
prefer_grub_d: { type: boolean, default: false }
|
||||
kernel_params: { type: array, items: { type: string } }
|
||||
defaults:
|
||||
type: object
|
||||
additionalProperties: true # Other fields are acceptable
|
||||
|
@ -174,7 +174,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
|
||||
if partition["fs"] == "zfs" and partition["mountPoint"] == "/":
|
||||
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
|
||||
if zfs_root_path:
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
@ -31,15 +32,22 @@ InitcpioJob::prettyName() const
|
||||
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
|
||||
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() );
|
||||
if ( f.exists() )
|
||||
{
|
||||
cDebug() << "initcpio fixing permissions for" << f.fileName();
|
||||
cDebug() << "initcpio setting permissions for" << f.fileName();
|
||||
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;
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "mkinitcpio", "-p", m_kernel }, QString(), QString() /* no timeout , 0 */ );
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand( command, QString(), QString() /* no timeout , 0 */ );
|
||||
return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ );
|
||||
}
|
||||
|
||||
@ -73,28 +91,6 @@ void
|
||||
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
@ -5,21 +5,22 @@
|
||||
---
|
||||
# This key defines the kernel to be loaded.
|
||||
# It can have the following values:
|
||||
# - empty or unset, interpreted as "all"
|
||||
# - the literal string "$uname" (without quotes, with dollar),
|
||||
# which will use the output of `uname -r` to determine the
|
||||
# running kernel, and use that.
|
||||
# - any other string.
|
||||
# - the name of a single mkinitcpio preset
|
||||
# - empty or unset
|
||||
# - the literal string "all"
|
||||
#
|
||||
# Whatever is set, that string is passed as *preset* argument to the
|
||||
# `-p` option of *mkinitcpio*. Take care that both "$uname" operates
|
||||
# in the host system, and might not be correct if the target system is
|
||||
# updated (to a newer kernel) as part of the installation.
|
||||
# If kernel is set to "all" or empty/unset then mkinitpio is called for all
|
||||
# kernels. Otherwise it is called with a single preset with the value
|
||||
# contained in kernel.
|
||||
#
|
||||
# Note that "all" is probably not a good preset to use either.
|
||||
kernel: linux312
|
||||
kernel: linux
|
||||
|
||||
# Set this to true to turn off mitigations for lax file
|
||||
# permissions on initramfs (which, in turn, can compromise
|
||||
# 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
|
||||
|
@ -180,7 +180,8 @@ def find_initcpio_features(partitions, root_mount_point):
|
||||
if partition["fs"] == "btrfs":
|
||||
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
|
||||
|
||||
if "lvm2" in partition["fs"]:
|
||||
|
@ -81,6 +81,7 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kernel = QStringLiteral( "all" );
|
||||
cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation
|
||||
<< r.getExitCode() << r.getOutput();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <KParts/ReadOnlyPart>
|
||||
#include <KParts/kde_terminal_interface.h>
|
||||
#include <KService>
|
||||
#include <kcoreaddons_version.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@ -41,8 +42,10 @@ InteractiveTerminalPage::InteractiveTerminalPage( QWidget* parent )
|
||||
void
|
||||
InteractiveTerminalPage::errorKonsoleNotInstalled()
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Critical,
|
||||
tr( "Konsole not installed" ), tr( "Please install KDE Konsole and try again!" ), QMessageBox::Ok );
|
||||
QMessageBox mb( QMessageBox::Critical,
|
||||
tr( "Konsole not installed" ),
|
||||
tr( "Please install KDE Konsole and try again!" ),
|
||||
QMessageBox::Ok );
|
||||
Calamares::fixButtonLabels( &mb );
|
||||
mb.exec();
|
||||
}
|
||||
@ -54,20 +57,30 @@ InteractiveTerminalPage::onActivate()
|
||||
{
|
||||
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
|
||||
// widget.
|
||||
|
||||
#if KCOREADDONS_VERSION_MAJOR != 5
|
||||
#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" );
|
||||
if ( !service )
|
||||
{
|
||||
// And all of this hoping the Konsole application is installed. If not,
|
||||
// tough cookies.
|
||||
errorKonsoleNotInstalled();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create one instance of konsolepart.
|
||||
KParts::ReadOnlyPart* p = service->createInstance< KParts::ReadOnlyPart >( this, this, {} );
|
||||
#endif
|
||||
if ( !p )
|
||||
{
|
||||
// One more opportunity for the loading operation to fail.
|
||||
@ -91,7 +104,6 @@ InteractiveTerminalPage::onActivate()
|
||||
|
||||
m_termHostWidget = p->widget();
|
||||
m_layout->addWidget( m_termHostWidget );
|
||||
cDebug() << "Part widget ought to be" << m_termHostWidget->metaObject()->className();
|
||||
|
||||
t->showShellInDir( QDir::home().path() );
|
||||
t->sendInput( QString( "%1\n" ).arg( m_command ) );
|
||||
|
@ -221,6 +221,11 @@ Config::setCurrentLocation()
|
||||
{
|
||||
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
|
||||
}
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -252,15 +257,21 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName )
|
||||
void
|
||||
Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location )
|
||||
{
|
||||
if ( location != m_currentLocation )
|
||||
const bool updateLocation = ( location != m_currentLocation );
|
||||
if ( updateLocation )
|
||||
{
|
||||
m_currentLocation = location;
|
||||
// Overwrite those settings that have not been made explicit.
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
}
|
||||
|
||||
// lang should be always be updated
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
|
||||
if ( updateLocation )
|
||||
{
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lc )
|
||||
{
|
||||
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;
|
||||
|
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal file
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal 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
|
||||
)
|
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal file
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal 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
|
181
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal file
181
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal 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 >(); )
|
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal file
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal 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
|
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal file
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal 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"
|
@ -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)
|
@ -1,7 +0,0 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
---
|
||||
type: "job"
|
||||
name: "luksopenswaphookcfg"
|
||||
interface: "python"
|
||||
script: "main.py"
|
@ -193,6 +193,7 @@ def mount_partition(root_mount_point, partition, partitions):
|
||||
for s in btrfs_subvolumes:
|
||||
if not s["subvolume"]:
|
||||
continue
|
||||
os.makedirs(root_mount_point + os.path.dirname(s["subvolume"]), exist_ok=True)
|
||||
subprocess.check_call(["btrfs", "subvolume", "create",
|
||||
root_mount_point + s["subvolume"]])
|
||||
if s["mountPoint"] == "/":
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "PackageModel.h"
|
||||
#include "ui_page_netinst.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "network/Manager.h"
|
||||
@ -62,4 +63,19 @@ void
|
||||
NetInstallPage::onActivate()
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,43 @@
|
||||
#include "utils/Variant.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 )
|
||||
: QAbstractItemModel( parent )
|
||||
{
|
||||
@ -170,6 +207,15 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void
|
||||
PackageModel::setSelections( const QStringList& selectNames )
|
||||
{
|
||||
if ( m_rootItem )
|
||||
{
|
||||
::setSelections( selectNames, m_rootItem );
|
||||
}
|
||||
}
|
||||
|
||||
PackageTreeItem::List
|
||||
PackageModel::getPackages() const
|
||||
{
|
||||
@ -303,9 +349,43 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa
|
||||
void
|
||||
PackageModel::setupModelData( const QVariantList& l )
|
||||
{
|
||||
emit beginResetModel();
|
||||
Q_EMIT beginResetModel();
|
||||
delete m_rootItem;
|
||||
m_rootItem = new PackageTreeItem();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,33 @@ public:
|
||||
int rowCount( 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 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:
|
||||
friend class ItemTests;
|
||||
|
||||
|
@ -70,6 +70,7 @@ PackageTreeItem::PackageTreeItem( const QVariantMap& groupData, GroupTag&& paren
|
||||
, m_description( CalamaresUtils::getString( groupData, "description" ) )
|
||||
, m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) )
|
||||
, m_postScript( CalamaresUtils::getString( groupData, "post-install" ) )
|
||||
, m_source( CalamaresUtils::getString( groupData, "source" ) )
|
||||
, m_isGroup( true )
|
||||
, m_isCritical( parentCriticality( groupData, parent.parent ) )
|
||||
, 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
|
||||
PackageTreeItem::type() const
|
||||
{
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
QString description() const { return m_description; }
|
||||
QString preScript() const { return m_preScript; }
|
||||
QString postScript() const { return m_postScript; }
|
||||
QString source() const { return m_source; }
|
||||
|
||||
/** @brief Is this item a group-item?
|
||||
*
|
||||
@ -124,6 +125,8 @@ public:
|
||||
void setSelected( Qt::CheckState isSelected );
|
||||
void setChildrenSelected( Qt::CheckState isSelected );
|
||||
|
||||
void removeChild( int row );
|
||||
|
||||
/** @brief Update selectedness based on the children's states
|
||||
*
|
||||
* This only makes sense for groups, which might have packages
|
||||
@ -157,6 +160,7 @@ private:
|
||||
QString m_description;
|
||||
QString m_preScript;
|
||||
QString m_postScript;
|
||||
QString m_source;
|
||||
bool m_isGroup = false;
|
||||
bool m_isCritical = false;
|
||||
bool m_isHidden = false;
|
||||
|
@ -410,7 +410,7 @@ ItemTests::testUrlFallback()
|
||||
QEventLoop loop;
|
||||
connect( &c, &Config::statusReady, &loop, &QEventLoop::quit );
|
||||
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();
|
||||
|
||||
// Check it didn't time out
|
||||
|
@ -73,12 +73,12 @@ def replace_username(nm_config_filename, live_user, target_user):
|
||||
if not os.path.exists(nm_config_filename):
|
||||
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()
|
||||
|
||||
live_permissions = 'permissions=user:{}:;'.format(live_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:
|
||||
if live_permissions in line:
|
||||
line = target_permissions
|
||||
|
@ -27,6 +27,29 @@
|
||||
#include "utils/Logger.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 >&
|
||||
packageChooserModeNames()
|
||||
{
|
||||
@ -55,6 +78,8 @@ PackageChooserMethodNames()
|
||||
{ "custom", PackageChooserMethod::Legacy },
|
||||
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||
{ "packages", PackageChooserMethod::Packages },
|
||||
{ "netinstall-add", PackageChooserMethod::NetAdd },
|
||||
{ "netinstall-select", PackageChooserMethod::NetSelect },
|
||||
};
|
||||
return names;
|
||||
}
|
||||
@ -121,6 +146,47 @@ Config::updateGlobalStorage( const QStringList& selected ) const
|
||||
CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
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
|
||||
{
|
||||
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||
|
@ -33,6 +33,8 @@ enum class PackageChooserMethod
|
||||
{
|
||||
Legacy, // use contextualprocess or other custom
|
||||
Packages, // use the packages module
|
||||
NetAdd, // adds packages to the netinstall module
|
||||
NetSelect, // makes selections in the netinstall module
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||
|
@ -15,6 +15,16 @@
|
||||
|
||||
#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
|
||||
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" ) )
|
||||
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
||||
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
||||
, screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) )
|
||||
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
||||
, netinstallData( getSubMap( item_map, "netinstall" ) )
|
||||
{
|
||||
if ( name.isEmpty() && id.isEmpty() )
|
||||
{
|
||||
@ -125,6 +136,25 @@ PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
||||
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
|
||||
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||
{
|
||||
|
@ -26,6 +26,7 @@ struct PackageItem
|
||||
CalamaresUtils::Locale::TranslatedString description;
|
||||
QPixmap screenshot;
|
||||
QStringList packageNames;
|
||||
QVariantMap netinstallData;
|
||||
|
||||
/// @brief Create blank PackageItem
|
||||
PackageItem();
|
||||
@ -111,6 +112,14 @@ public:
|
||||
*/
|
||||
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
|
||||
{
|
||||
NameRole = Qt::DisplayRole,
|
||||
|
@ -33,6 +33,15 @@ mode: required
|
||||
# in the `exec` section. These package settings will then be handed
|
||||
# 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
|
||||
# are no jobs that this module provides. You should put **other**
|
||||
# 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**
|
||||
# directory.
|
||||
#
|
||||
# The following field is **optional** for an item:
|
||||
# The following fields are **optional** for an item:
|
||||
#
|
||||
# - *packages* :
|
||||
# List of package names for the product. If using the *method*
|
||||
# "packages", consider this item mandatory (because otherwise
|
||||
# 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 #
|
||||
#
|
||||
# For data provided by AppData XML: the item has an *appdata*
|
||||
|
@ -382,7 +382,7 @@ class PMPacman(PackageManager):
|
||||
|
||||
def line_cb(line):
|
||||
if line.startswith(":: "):
|
||||
self.in_package_changes = "package changes" in line
|
||||
self.in_package_changes = "package" in line or "hooks" in line
|
||||
else:
|
||||
if self.in_package_changes and line.endswith("...\n"):
|
||||
# Update the message, untranslated; do not change the
|
||||
@ -392,7 +392,7 @@ class PMPacman(PackageManager):
|
||||
global custom_status_message
|
||||
custom_status_message = "pacman: " + line.strip()
|
||||
libcalamares.job.setprogress(self.progress_fraction)
|
||||
libcalamares.utils.debug(line)
|
||||
libcalamares.utils.debug(line)
|
||||
|
||||
self.in_package_changes = False
|
||||
self.line_cb = line_cb
|
||||
@ -444,8 +444,12 @@ class PMPacman(PackageManager):
|
||||
else:
|
||||
command.append("-S")
|
||||
|
||||
# Don't ask for user intervention, take the default action
|
||||
command.append("--noconfirm")
|
||||
|
||||
# Don't report download progress for each file
|
||||
command.append("--noprogressbar")
|
||||
|
||||
if self.pacman_needed_only is True:
|
||||
command.append("--needed")
|
||||
|
||||
|
@ -345,6 +345,11 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
if ( !m_swapChoices.contains( m_initialSwapChoice ) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
setSwapChoice( m_initialSwapChoice );
|
||||
|
@ -146,15 +146,12 @@ modeDescription( Config::InstallChoice choice )
|
||||
case Config::InstallChoice::Alongside:
|
||||
return QCoreApplication::translate( context, "Install %1 <strong>alongside</strong> another operating system." )
|
||||
.arg( branding->shortVersionedName() );
|
||||
break;
|
||||
case Config::InstallChoice::Erase:
|
||||
return QCoreApplication::translate( context, "<strong>Erase</strong> disk and install %1." )
|
||||
.arg( branding->shortVersionedName() );
|
||||
break;
|
||||
case Config::InstallChoice::Replace:
|
||||
return QCoreApplication::translate( context, "<strong>Replace</strong> a partition with %1." )
|
||||
.arg( branding->shortVersionedName() );
|
||||
break;
|
||||
case Config::InstallChoice::NoChoice:
|
||||
case Config::InstallChoice::Manual:
|
||||
return QCoreApplication::translate( context, "<strong>Manual</strong> partitioning." );
|
||||
@ -187,21 +184,18 @@ diskDescription( int listLength, const PartitionCoreModule::SummaryInfo& info, C
|
||||
.arg( branding->shortVersionedName() )
|
||||
.arg( info.deviceNode )
|
||||
.arg( info.deviceName );
|
||||
break;
|
||||
case Config::Erase:
|
||||
return QCoreApplication::translate( context,
|
||||
"<strong>Erase</strong> disk <strong>%2</strong> (%3) and install %1." )
|
||||
.arg( branding->shortVersionedName() )
|
||||
.arg( info.deviceNode )
|
||||
.arg( info.deviceName );
|
||||
break;
|
||||
case Config::Replace:
|
||||
return QCoreApplication::translate(
|
||||
context, "<strong>Replace</strong> a partition on disk <strong>%2</strong> (%3) with %1." )
|
||||
.arg( branding->shortVersionedName() )
|
||||
.arg( info.deviceNode )
|
||||
.arg( info.deviceName );
|
||||
break;
|
||||
case Config::NoChoice:
|
||||
case Config::Manual:
|
||||
return QCoreApplication::translate(
|
||||
@ -558,7 +552,7 @@ PartitionViewStep::onLeave()
|
||||
if ( !okSize )
|
||||
{
|
||||
cDebug() << o << "ESP too small";
|
||||
const auto atLeastBytes = PartUtils::efiFilesystemMinimumSize();
|
||||
const qint64 atLeastBytes = static_cast< qint64 >( PartUtils::efiFilesystemMinimumSize() );
|
||||
const auto atLeastMiB = CalamaresUtils::BytesToMiB( atLeastBytes );
|
||||
description.append( ' ' );
|
||||
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
|
||||
// and remove the spinner.
|
||||
m_future = new QFutureWatcher< void >();
|
||||
connect( m_future, &QFutureWatcher< void >::finished, this, [this] {
|
||||
continueLoading();
|
||||
this->m_future->deleteLater();
|
||||
this->m_future = nullptr;
|
||||
} );
|
||||
connect( m_future,
|
||||
&QFutureWatcher< void >::finished,
|
||||
this,
|
||||
[ this ]
|
||||
{
|
||||
continueLoading();
|
||||
this->m_future->deleteLater();
|
||||
this->m_future = nullptr;
|
||||
} );
|
||||
|
||||
QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
|
||||
m_future->setFuture( future );
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "DeviceList.h"
|
||||
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <kpmcore/backend/corebackend.h>
|
||||
@ -40,16 +41,30 @@ hasRootPartition( Device* device )
|
||||
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
|
||||
blkIdCheckIso9660( const QString& path )
|
||||
{
|
||||
QProcess blkid;
|
||||
blkid.start( "blkid", { path } );
|
||||
blkid.waitForFinished();
|
||||
QString output = QString::fromLocal8Bit( blkid.readAllStandardOutput() );
|
||||
return output.contains( "iso9660" );
|
||||
// If blkid fails, there's no output, but we don't care
|
||||
auto r = CalamaresUtils::System::runCommand( { "blkid", path }, std::chrono::seconds( 30 ) );
|
||||
return r.getOutput().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
|
||||
isIso9660( const Device* device )
|
||||
{
|
||||
@ -65,13 +80,8 @@ isIso9660( const Device* device )
|
||||
|
||||
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
|
||||
{
|
||||
for ( const Partition* partition : device->partitionTable()->children() )
|
||||
{
|
||||
if ( blkIdCheckIso9660( partition->partitionPath() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto& p = device->partitionTable()->children();
|
||||
return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -8,9 +8,10 @@
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
#include "core/DeviceModel.h"
|
||||
#include "DeviceModel.h"
|
||||
|
||||
#include "core/PartitionModel.h"
|
||||
#include "core/SizeUtils.h"
|
||||
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
@ -18,9 +19,6 @@
|
||||
// KPMcore
|
||||
#include <kpmcore/core/device.h>
|
||||
|
||||
// KF5
|
||||
#include <KFormat>
|
||||
|
||||
#include <QIcon>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
@ -30,9 +28,9 @@
|
||||
static void
|
||||
sortDevices( DeviceModel::DeviceList& l )
|
||||
{
|
||||
std::sort( l.begin(), l.end(), []( const Device* dev1, const Device* dev2 ) {
|
||||
return dev1->deviceNode() < dev2->deviceNode();
|
||||
} );
|
||||
std::sort( l.begin(),
|
||||
l.end(),
|
||||
[]( const Device* dev1, const Device* dev2 ) { return dev1->deviceNode() < dev2->deviceNode(); } );
|
||||
}
|
||||
|
||||
DeviceModel::DeviceModel( QObject* parent )
|
||||
@ -83,7 +81,7 @@ DeviceModel::data( const QModelIndex& index, int role ) const
|
||||
//: device[name] - size[number] (device-node[name])
|
||||
return tr( "%1 - %2 (%3)" )
|
||||
.arg( device->name() )
|
||||
.arg( KFormat().formatByteSize( device->capacity() ) )
|
||||
.arg( formatByteSize( device->capacity() ) )
|
||||
.arg( device->deviceNode() );
|
||||
}
|
||||
else
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/String.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/backend/corebackendmanager.h>
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
@ -127,4 +127,23 @@ clonePartition( Device* device, Partition* partition )
|
||||
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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user