Merge branch 'calamares' into work-3.3
This commit is contained in:
commit
d1e4740e70
@ -28,8 +28,9 @@ PointerAlignment: Left
|
|||||||
ReflowComments: "false"
|
ReflowComments: "false"
|
||||||
SortIncludes: "true"
|
SortIncludes: "true"
|
||||||
SpaceAfterCStyleCast: "false"
|
SpaceAfterCStyleCast: "false"
|
||||||
|
SpaceInEmptyBlock: "false"
|
||||||
SpacesBeforeTrailingComments: "2"
|
SpacesBeforeTrailingComments: "2"
|
||||||
SpacesInAngles: "true"
|
SpacesInAngles: "true"
|
||||||
SpacesInParentheses: "true"
|
SpacesInParentheses: "true"
|
||||||
SpacesInSquareBrackets: "true"
|
SpacesInSquareBrackets: "true"
|
||||||
Standard: Cpp11
|
Standard: c++17
|
||||||
|
@ -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
|
|
66
CHANGES-3.2
66
CHANGES-3.2
@ -7,22 +7,84 @@ contributors are listed. Note that Calamares does not have a historical
|
|||||||
changelog -- this log starts with version 3.2.0. The release notes on the
|
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||||
website will have to do for older versions.
|
website will have to do for older versions.
|
||||||
|
|
||||||
# 3.2.50 (unreleased) #
|
# 3.2.52 (unreleased) #
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
This release contains contributions from (alphabetically by first name):
|
||||||
- Erik Dubois
|
- No external contributors yet
|
||||||
|
|
||||||
## Core ##
|
## Core ##
|
||||||
- No core changes yet
|
- No core changes yet
|
||||||
|
|
||||||
## Modules ##
|
## 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
|
- *networkcfg* could fail to update the NetworkManager configuration
|
||||||
if the SSID or username contained non-ASCII characters **and** the
|
if the SSID or username contained non-ASCII characters **and** the
|
||||||
default Python text-file encoding was set to ASCII. The files are
|
default Python text-file encoding was set to ASCII. The files are
|
||||||
now read and written in UTF-8, explicitly. #1848
|
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
|
- *preservefiles* was missing some necessary features, needed for it
|
||||||
to replace the deprecated log-file-saving functionality in the *umount*
|
to replace the deprecated log-file-saving functionality in the *umount*
|
||||||
module. (Thanks Erik and Joe for testing) #1851
|
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) #
|
# 3.2.49.1 (2021-12-11) #
|
||||||
|
@ -75,7 +75,7 @@ fi
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.)
|
BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.)
|
||||||
KEY_ID="CFDDC96F12B1915C"
|
KEY_ID="328D742D8807A435"
|
||||||
|
|
||||||
# Try to make gpg cache the signing key, so we can leave the process
|
# Try to make gpg cache the signing key, so we can leave the process
|
||||||
# to run and sign.
|
# to run and sign.
|
||||||
|
@ -19,12 +19,12 @@ BASEDIR=$(dirname $0)
|
|||||||
TOPDIR=$( cd $BASEDIR/.. && pwd -P )
|
TOPDIR=$( cd $BASEDIR/.. && pwd -P )
|
||||||
test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; }
|
test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; }
|
||||||
test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; }
|
test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; }
|
||||||
test -f "$TOPDIR/.clang-format.base" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; }
|
test -f "$TOPDIR/.clang-format" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; }
|
||||||
|
|
||||||
AS=$( which astyle )
|
AS=$( which astyle )
|
||||||
|
|
||||||
# Allow specifying CF_VERSIONS outside already
|
# Allow specifying CF_VERSIONS outside already
|
||||||
CF_VERSIONS="$CF_VERSIONS clang-format-8 clang-format80 clang-format90 clang-format-9.0.1 clang-format"
|
CF_VERSIONS="$CF_VERSIONS clang-format13 clang-format12 clang-format"
|
||||||
for _cf in $CF_VERSIONS
|
for _cf in $CF_VERSIONS
|
||||||
do
|
do
|
||||||
# Not an error if this particular clang-format isn't found
|
# Not an error if this particular clang-format isn't found
|
||||||
@ -40,31 +40,19 @@ test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; }
|
|||||||
### CLANG-FORMAT-WRANGLING
|
### CLANG-FORMAT-WRANGLING
|
||||||
#
|
#
|
||||||
# Version 7 and earlier doesn't understand all the options we would like
|
# Version 7 and earlier doesn't understand all the options we would like
|
||||||
# Version 8 is ok
|
# Version 12 handles lambdas nicely, so use that.
|
||||||
# Version 9 is ok
|
# Version 13 is also ok.
|
||||||
# Later versions change some defaults so need extra wrangling.
|
|
||||||
# .. there are extra files that are appended to the settings, per
|
|
||||||
# .. clang-format version.
|
|
||||||
|
|
||||||
format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1`
|
format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1`
|
||||||
case "$format_version" in
|
case "$format_version" in
|
||||||
[0-7] )
|
12|13 )
|
||||||
echo "! Clang-format version 8+ required"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
[89] )
|
|
||||||
:
|
:
|
||||||
;;
|
;;
|
||||||
* )
|
* )
|
||||||
echo "! Clang-format version '$format_version' unsupported."
|
echo "! Clang-format version '$format_version' unsupported, version 12 required."
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
_fmt="$TOPDIR/.clang-format"
|
|
||||||
cp "$_fmt.base" "$_fmt"
|
|
||||||
for f in "$extra_settings" ; do
|
|
||||||
test -f "$_fmt.$f" && cat "$_fmt.$f" >> "$_fmt"
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
### FILE PROCESSING
|
### FILE PROCESSING
|
||||||
@ -98,8 +86,3 @@ if test "x$any_dirs" = "xyes" ; then
|
|||||||
else
|
else
|
||||||
style_some "$@"
|
style_some "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
### CLANG-FORMAT-WRANGLING
|
|
||||||
#
|
|
||||||
# Restore the original .clang-format
|
|
||||||
cp "$_fmt.base" "$_fmt"
|
|
||||||
|
@ -693,27 +693,27 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||||
<source>Successfully unmounted %1.</source>
|
<source>Successfully unmounted %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Úspěšně odpojeno %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||||
<source>Successfully disabled swap %1.</source>
|
<source>Successfully disabled swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Úspěšně vypnut swap %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||||
<source>Successfully cleared swap %1.</source>
|
<source>Successfully cleared swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Úspěšně vyčištěn swap %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||||
<source>Successfully closed mapper device %1.</source>
|
<source>Successfully closed mapper device %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Úspěšně zavřeno mapper zařízení %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||||
<source>Successfully disabled volume group %1.</source>
|
<source>Successfully disabled volume group %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Úspěšně vypnuta skupina svazků %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||||
|
File diff suppressed because it is too large
Load Diff
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
|
<source>Please select your preferred location on the map so the installer can suggest the locale
|
||||||
and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging
|
and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging
|
||||||
to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.</source>
|
to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.</source>
|
||||||
<translation>Por favor selecione o seu local preferido no mapa para que o instalador possa sugerir a localização
|
<translation>Selecione o seu local preferido no mapa para que o instalador possa sugerir a localização
|
||||||
e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando
|
e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando
|
||||||
para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation>
|
para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -4003,7 +4003,7 @@ Saída de Dados:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
||||||
<source><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>
|
<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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -104,17 +104,17 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Dă crash lui Calamares, pentru ca doctorul Konqui să se uite la el.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||||
<source>Reloads the stylesheet from the branding directory.</source>
|
<source>Reloads the stylesheet from the branding directory.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Reîncarcă foaia de stil din directorul branding.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||||
<source>Uploads the session log to the configured pastebin.</source>
|
<source>Uploads the session log to the configured pastebin.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Încarcă jurnalul sesiunii pe pastebin-ul configurat.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||||
@ -134,7 +134,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||||
<source>Widget Tree</source>
|
<source>Widget Tree</source>
|
||||||
<translation>Lista widget</translation>
|
<translation>Arborele de widget</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.cpp" line="221"/>
|
<location filename="../src/calamares/DebugWindow.cpp" line="221"/>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||||
<source>Manage auto-mount settings</source>
|
<source>Manage auto-mount settings</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Идора кардани танзимоти васлкунии худкор</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -688,27 +688,27 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||||
<source>Successfully unmounted %1.</source>
|
<source>Successfully unmounted %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>成功卸载了 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||||
<source>Successfully disabled swap %1.</source>
|
<source>Successfully disabled swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>成功禁用了交换空间 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||||
<source>Successfully cleared swap %1.</source>
|
<source>Successfully cleared swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>成功清理了交换空间 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||||
<source>Successfully closed mapper device %1.</source>
|
<source>Successfully closed mapper device %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>成功关闭了映射设备 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||||
<source>Successfully disabled volume group %1.</source>
|
<source>Successfully disabled volume group %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>成功禁用了卷组 %1。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||||
|
316
lang/python.pot
316
lang/python.pot
@ -8,403 +8,397 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2022-02-01 17:27+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Language: \n"
|
|
||||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:32
|
#: src/modules/initramfscfg/main.py:32
|
||||||
msgid "Configuring initramfs."
|
msgid "Configuring initramfs."
|
||||||
msgstr "Configuring initramfs."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
||||||
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
|
#: src/modules/fstab/main.py:360 src/modules/fstab/main.py:366
|
||||||
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
|
#: src/modules/fstab/main.py:393 src/modules/networkcfg/main.py:105
|
||||||
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
|
#: src/modules/initcpiocfg/main.py:235 src/modules/initcpiocfg/main.py:239
|
||||||
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
|
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:229
|
||||||
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
|
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
|
||||||
#: src/modules/openrcdmcryptcfg/main.py:76
|
#: src/modules/openrcdmcryptcfg/main.py:76
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
|
||||||
msgid "Configuration Error"
|
msgid "Configuration Error"
|
||||||
msgstr "Configuration Error"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:361
|
||||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
#: src/modules/initcpiocfg/main.py:236 src/modules/mount/main.py:230
|
||||||
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:87
|
|
||||||
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
||||||
msgstr "No partitions are defined for <pre>{!s}</pre> to use."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
|
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:367
|
||||||
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:240
|
||||||
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:91
|
|
||||||
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
||||||
msgstr "No root mount point is given for <pre>{!s}</pre> to use."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/grubcfg/main.py:28
|
#: src/modules/grubcfg/main.py:28
|
||||||
msgid "Configure GRUB."
|
msgid "Configure GRUB."
|
||||||
msgstr "Configure GRUB."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/bootloader/main.py:43
|
#: src/modules/bootloader/main.py:43
|
||||||
msgid "Install bootloader."
|
msgid "Install bootloader."
|
||||||
msgstr "Install bootloader."
|
|
||||||
|
|
||||||
#: src/modules/bootloader/main.py:508
|
|
||||||
msgid "Bootloader installation error"
|
|
||||||
msgstr "Bootloader installation error"
|
|
||||||
|
|
||||||
#: src/modules/bootloader/main.py:509
|
|
||||||
msgid ""
|
|
||||||
"The bootloader could not be installed. The installation command "
|
|
||||||
"<pre>{!s}</pre> returned error code {!s}."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The bootloader could not be installed. The installation command "
|
|
||||||
"<pre>{!s}</pre> returned error code {!s}."
|
#: src/modules/bootloader/main.py:612
|
||||||
|
msgid "Failed to install grub, no partitions defined in global storage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/bootloader/main.py:780
|
||||||
|
msgid "Bootloader installation error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/bootloader/main.py:781
|
||||||
|
msgid ""
|
||||||
|
"The bootloader could not be installed. The installation command <pre>{!s}</"
|
||||||
|
"pre> returned error code {!s}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/fstab/main.py:29
|
#: src/modules/fstab/main.py:29
|
||||||
msgid "Writing fstab."
|
msgid "Writing fstab."
|
||||||
msgstr "Writing fstab."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/fstab/main.py:389
|
#: src/modules/fstab/main.py:394
|
||||||
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
|
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
|
||||||
msgstr "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/dracut/main.py:27
|
#: src/modules/dracut/main.py:27
|
||||||
msgid "Creating initramfs with dracut."
|
msgid "Creating initramfs with dracut."
|
||||||
msgstr "Creating initramfs with dracut."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/dracut/main.py:49
|
#: src/modules/dracut/main.py:49
|
||||||
msgid "Failed to run dracut on the target"
|
msgid "Failed to run dracut on the target"
|
||||||
msgstr "Failed to run dracut on the target"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
|
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
|
||||||
msgid "The exit code was {}"
|
msgid "The exit code was {}"
|
||||||
msgstr "The exit code was {}"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:526
|
#: src/modules/displaymanager/main.py:524
|
||||||
msgid "Cannot write KDM configuration file"
|
msgid "Cannot write KDM configuration file"
|
||||||
msgstr "Cannot write KDM configuration file"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:527
|
#: src/modules/displaymanager/main.py:525
|
||||||
msgid "KDM config file {!s} does not exist"
|
msgid "KDM config file {!s} does not exist"
|
||||||
msgstr "KDM config file {!s} does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:588
|
#: src/modules/displaymanager/main.py:586
|
||||||
msgid "Cannot write LXDM configuration file"
|
msgid "Cannot write LXDM configuration file"
|
||||||
msgstr "Cannot write LXDM configuration file"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:589
|
#: src/modules/displaymanager/main.py:587
|
||||||
msgid "LXDM config file {!s} does not exist"
|
msgid "LXDM config file {!s} does not exist"
|
||||||
msgstr "LXDM config file {!s} does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:672
|
#: src/modules/displaymanager/main.py:670
|
||||||
msgid "Cannot write LightDM configuration file"
|
msgid "Cannot write LightDM configuration file"
|
||||||
msgstr "Cannot write LightDM configuration file"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:673
|
#: src/modules/displaymanager/main.py:671
|
||||||
msgid "LightDM config file {!s} does not exist"
|
msgid "LightDM config file {!s} does not exist"
|
||||||
msgstr "LightDM config file {!s} does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:747
|
#: src/modules/displaymanager/main.py:745
|
||||||
msgid "Cannot configure LightDM"
|
msgid "Cannot configure LightDM"
|
||||||
msgstr "Cannot configure LightDM"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:748
|
#: src/modules/displaymanager/main.py:746
|
||||||
msgid "No LightDM greeter installed."
|
msgid "No LightDM greeter installed."
|
||||||
msgstr "No LightDM greeter installed."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:779
|
#: src/modules/displaymanager/main.py:777
|
||||||
msgid "Cannot write SLIM configuration file"
|
msgid "Cannot write SLIM configuration file"
|
||||||
msgstr "Cannot write SLIM configuration file"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:780
|
#: src/modules/displaymanager/main.py:778
|
||||||
msgid "SLIM config file {!s} does not exist"
|
msgid "SLIM config file {!s} does not exist"
|
||||||
msgstr "SLIM config file {!s} does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:906
|
#: src/modules/displaymanager/main.py:991
|
||||||
msgid "No display managers selected for the displaymanager module."
|
msgid "No display managers selected for the displaymanager module."
|
||||||
msgstr "No display managers selected for the displaymanager module."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:907
|
#: src/modules/displaymanager/main.py:992
|
||||||
msgid ""
|
msgid ""
|
||||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||||
"displaymanager.conf."
|
"displaymanager.conf."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
|
||||||
"displaymanager.conf."
|
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:989
|
#: src/modules/displaymanager/main.py:1074
|
||||||
msgid "Display manager configuration was incomplete"
|
msgid "Display manager configuration was incomplete"
|
||||||
msgstr "Display manager configuration was incomplete"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:29
|
#: src/modules/services-openrc/main.py:29
|
||||||
msgid "Configure OpenRC services"
|
msgid "Configure OpenRC services"
|
||||||
msgstr "Configure OpenRC services"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:57
|
#: src/modules/services-openrc/main.py:57
|
||||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||||
msgstr "Cannot add service {name!s} to run-level {level!s}."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:59
|
#: src/modules/services-openrc/main.py:59
|
||||||
msgid "Cannot remove service {name!s} from run-level {level!s}."
|
msgid "Cannot remove service {name!s} from run-level {level!s}."
|
||||||
msgstr "Cannot remove service {name!s} from run-level {level!s}."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:61
|
#: src/modules/services-openrc/main.py:61
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
||||||
"level {level!s}."
|
"level {level!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
|
||||||
"level {level!s}."
|
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:93
|
#: src/modules/services-openrc/main.py:93
|
||||||
#: src/modules/services-systemd/main.py:59
|
#: src/modules/services-systemd/main.py:59
|
||||||
msgid "Cannot modify service"
|
msgid "Cannot modify service"
|
||||||
msgstr "Cannot modify service"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:94
|
#: src/modules/services-openrc/main.py:94
|
||||||
msgid ""
|
msgid ""
|
||||||
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:101
|
#: src/modules/services-openrc/main.py:101
|
||||||
msgid "Target runlevel does not exist"
|
msgid "Target runlevel does not exist"
|
||||||
msgstr "Target runlevel does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:102
|
#: src/modules/services-openrc/main.py:102
|
||||||
msgid ""
|
msgid ""
|
||||||
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
||||||
"exist."
|
"exist."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
|
||||||
"exist."
|
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:110
|
#: src/modules/services-openrc/main.py:110
|
||||||
msgid "Target service does not exist"
|
msgid "Target service does not exist"
|
||||||
msgstr "Target service does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:111
|
#: src/modules/services-openrc/main.py:111
|
||||||
msgid ""
|
msgid ""
|
||||||
"The path for service {name!s} is <code>{path!s}</code>, which does not "
|
"The path for service {name!s} is <code>{path!s}</code>, which does not exist."
|
||||||
"exist."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The path for service {name!s} is <code>{path!s}</code>, which does not "
|
|
||||||
"exist."
|
|
||||||
|
|
||||||
#: src/modules/networkcfg/main.py:29
|
#: src/modules/networkcfg/main.py:29
|
||||||
msgid "Saving network configuration."
|
msgid "Saving network configuration."
|
||||||
msgstr "Saving network configuration."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
|
#: src/modules/packages/main.py:54 src/modules/packages/main.py:65
|
||||||
#: src/modules/packages/main.py:69
|
#: src/modules/packages/main.py:75
|
||||||
msgid "Install packages."
|
msgid "Install packages."
|
||||||
msgstr "Install packages."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:57
|
#: src/modules/packages/main.py:63
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Processing packages (%(count)d / %(total)d)"
|
msgid "Processing packages (%(count)d / %(total)d)"
|
||||||
msgstr "Processing packages (%(count)d / %(total)d)"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:62
|
#: src/modules/packages/main.py:68
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Installing one package."
|
msgid "Installing one package."
|
||||||
msgid_plural "Installing %(num)d packages."
|
msgid_plural "Installing %(num)d packages."
|
||||||
msgstr[0] "Installing one package."
|
msgstr[0] ""
|
||||||
msgstr[1] "Installing %(num)d packages."
|
msgstr[1] ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:65
|
#: src/modules/packages/main.py:71
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Removing one package."
|
msgid "Removing one package."
|
||||||
msgid_plural "Removing %(num)d packages."
|
msgid_plural "Removing %(num)d packages."
|
||||||
msgstr[0] "Removing one package."
|
msgstr[0] ""
|
||||||
msgstr[1] "Removing %(num)d packages."
|
msgstr[1] ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
|
#: src/modules/packages/main.py:725 src/modules/packages/main.py:737
|
||||||
#: src/modules/packages/main.py:678
|
#: src/modules/packages/main.py:765
|
||||||
msgid "Package Manager error"
|
msgid "Package Manager error"
|
||||||
msgstr "Package Manager error"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/packages/main.py:639
|
#: src/modules/packages/main.py:726
|
||||||
msgid ""
|
msgid ""
|
||||||
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
||||||
"returned error code {!s}."
|
"returned error code {!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
|
||||||
"returned error code {!s}."
|
|
||||||
|
|
||||||
#: src/modules/packages/main.py:651
|
#: src/modules/packages/main.py:738
|
||||||
msgid ""
|
msgid ""
|
||||||
"The package manager could not update the system. The command <pre>{!s}</pre> "
|
"The package manager could not update the system. The command <pre>{!s}</pre> "
|
||||||
"returned error code {!s}."
|
"returned error code {!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The package manager could not update the system. The command <pre>{!s}</pre>"
|
|
||||||
" returned error code {!s}."
|
|
||||||
|
|
||||||
#: src/modules/packages/main.py:679
|
#: src/modules/packages/main.py:766
|
||||||
msgid ""
|
msgid ""
|
||||||
"The package manager could not make changes to the installed system. The "
|
"The package manager could not make changes to the installed system. The "
|
||||||
"command <pre>{!s}</pre> returned error code {!s}."
|
"command <pre>{!s}</pre> returned error code {!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"The package manager could not make changes to the installed system. The "
|
|
||||||
"command <pre>{!s}</pre> returned error code {!s}."
|
|
||||||
|
|
||||||
#: src/modules/plymouthcfg/main.py:27
|
#: src/modules/plymouthcfg/main.py:27
|
||||||
msgid "Configure Plymouth theme"
|
msgid "Configure Plymouth theme"
|
||||||
msgstr "Configure Plymouth theme"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/initcpiocfg/main.py:28
|
#: src/modules/initcpiocfg/main.py:28
|
||||||
msgid "Configuring mkinitcpio."
|
msgid "Configuring mkinitcpio."
|
||||||
msgstr "Configuring mkinitcpio."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/localecfg/main.py:30
|
#: src/modules/localecfg/main.py:30
|
||||||
msgid "Configuring locales."
|
msgid "Configuring locales."
|
||||||
msgstr "Configuring locales."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/mount/main.py:30
|
#: src/modules/mount/main.py:42
|
||||||
msgid "Mounting partitions."
|
msgid "Mounting partitions."
|
||||||
msgstr "Mounting partitions."
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/mount/main.py:88 src/modules/mount/main.py:124
|
||||||
|
msgid "Internal error mounting zfs datasets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/mount/main.py:100
|
||||||
|
msgid "Failed to import zpool"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/mount/main.py:116
|
||||||
|
msgid "Failed to unlock zpool"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/mount/main.py:133 src/modules/mount/main.py:138
|
||||||
|
msgid "Failed to set zfs mountpoint"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/mount/main.py:253
|
||||||
|
msgid "zfs mounting error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/rawfs/main.py:26
|
#: src/modules/rawfs/main.py:26
|
||||||
msgid "Installing data."
|
msgid "Installing data."
|
||||||
msgstr "Installing data."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/dummypython/main.py:35
|
#: src/modules/dummypython/main.py:35
|
||||||
msgid "Dummy python job."
|
msgid "Dummy python job."
|
||||||
msgstr "Dummy python job."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
|
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
|
||||||
#: src/modules/dummypython/main.py:94
|
#: src/modules/dummypython/main.py:94
|
||||||
msgid "Dummy python step {}"
|
msgid "Dummy python step {}"
|
||||||
msgstr "Dummy python step {}"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/hwclock/main.py:26
|
#: src/modules/hwclock/main.py:26
|
||||||
msgid "Setting hardware clock."
|
msgid "Setting hardware clock."
|
||||||
msgstr "Setting hardware clock."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/umount/main.py:31
|
|
||||||
msgid "Unmount file systems."
|
|
||||||
msgstr "Unmount file systems."
|
|
||||||
|
|
||||||
#: src/modules/openrcdmcryptcfg/main.py:26
|
#: src/modules/openrcdmcryptcfg/main.py:26
|
||||||
msgid "Configuring OpenRC dmcrypt service."
|
msgid "Configuring OpenRC dmcrypt service."
|
||||||
msgstr "Configuring OpenRC dmcrypt service."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:26
|
#: src/modules/services-systemd/main.py:26
|
||||||
msgid "Configure systemd services"
|
msgid "Configure systemd services"
|
||||||
msgstr "Configure systemd services"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:60
|
#: src/modules/services-systemd/main.py:60
|
||||||
msgid ""
|
msgid ""
|
||||||
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
|
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
|
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:63
|
#: src/modules/services-systemd/main.py:63
|
||||||
#: src/modules/services-systemd/main.py:69
|
#: src/modules/services-systemd/main.py:69
|
||||||
msgid "Cannot enable systemd service <code>{name!s}</code>."
|
msgid "Cannot enable systemd service <code>{name!s}</code>."
|
||||||
msgstr "Cannot enable systemd service <code>{name!s}</code>."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:65
|
#: src/modules/services-systemd/main.py:65
|
||||||
msgid "Cannot enable systemd target <code>{name!s}</code>."
|
msgid "Cannot enable systemd target <code>{name!s}</code>."
|
||||||
msgstr "Cannot enable systemd target <code>{name!s}</code>."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:67
|
#: src/modules/services-systemd/main.py:67
|
||||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||||
msgstr "Cannot enable systemd timer <code>{name!s}</code>."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:71
|
#: src/modules/services-systemd/main.py:71
|
||||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||||
msgstr "Cannot disable systemd target <code>{name!s}</code>."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:73
|
#: src/modules/services-systemd/main.py:73
|
||||||
msgid "Cannot mask systemd unit <code>{name!s}</code>."
|
msgid "Cannot mask systemd unit <code>{name!s}</code>."
|
||||||
msgstr "Cannot mask systemd unit <code>{name!s}</code>."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:75
|
#: src/modules/services-systemd/main.py:75
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unknown systemd commands <code>{command!s}</code> and "
|
"Unknown systemd commands <code>{command!s}</code> and <code>{suffix!s}</"
|
||||||
"<code>{suffix!s}</code> for unit {name!s}."
|
"code> for unit {name!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Unknown systemd commands <code>{command!s}</code> and "
|
|
||||||
"<code>{suffix!s}</code> for unit {name!s}."
|
|
||||||
|
|
||||||
#: src/modules/mkinitfs/main.py:27
|
#: src/modules/mkinitfs/main.py:27
|
||||||
msgid "Creating initramfs with mkinitfs."
|
msgid "Creating initramfs with mkinitfs."
|
||||||
msgstr "Creating initramfs with mkinitfs."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/mkinitfs/main.py:49
|
#: src/modules/mkinitfs/main.py:49
|
||||||
msgid "Failed to run mkinitfs on the target"
|
msgid "Failed to run mkinitfs on the target"
|
||||||
msgstr "Failed to run mkinitfs on the target"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:34
|
#: src/modules/unpackfs/main.py:34
|
||||||
msgid "Filling up filesystems."
|
msgid "Filling up filesystems."
|
||||||
msgstr "Filling up filesystems."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:254
|
#: src/modules/unpackfs/main.py:254
|
||||||
msgid "rsync failed with error code {}."
|
msgid "rsync failed with error code {}."
|
||||||
msgstr "rsync failed with error code {}."
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:299
|
#: src/modules/unpackfs/main.py:299
|
||||||
msgid "Unpacking image {}/{}, file {}/{}"
|
msgid "Unpacking image {}/{}, file {}/{}"
|
||||||
msgstr "Unpacking image {}/{}, file {}/{}"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:314
|
#: src/modules/unpackfs/main.py:314
|
||||||
msgid "Starting to unpack {}"
|
msgid "Starting to unpack {}"
|
||||||
msgstr "Starting to unpack {}"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
|
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:467
|
||||||
msgid "Failed to unpack image \"{}\""
|
msgid "Failed to unpack image \"{}\""
|
||||||
msgstr "Failed to unpack image \"{}\""
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:430
|
#: src/modules/unpackfs/main.py:430
|
||||||
msgid "No mount point for root partition"
|
msgid "No mount point for root partition"
|
||||||
msgstr "No mount point for root partition"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:431
|
#: src/modules/unpackfs/main.py:431
|
||||||
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
msgid "globalstorage does not contain a \"rootMountPoint\" key."
|
||||||
msgstr "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:436
|
#: src/modules/unpackfs/main.py:434
|
||||||
msgid "Bad mount point for root partition"
|
msgid "Bad mount point for root partition"
|
||||||
msgstr "Bad mount point for root partition"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:437
|
#: src/modules/unpackfs/main.py:435
|
||||||
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
msgid "rootMountPoint is \"{}\", which does not exist."
|
||||||
msgstr "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
|
#: src/modules/unpackfs/main.py:439 src/modules/unpackfs/main.py:455
|
||||||
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
|
#: src/modules/unpackfs/main.py:459 src/modules/unpackfs/main.py:465
|
||||||
msgid "Bad unsquash configuration"
|
#: src/modules/unpackfs/main.py:480
|
||||||
msgstr "Bad unsquash configuration"
|
msgid "Bad unpackfs configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:454
|
#: src/modules/unpackfs/main.py:440
|
||||||
|
msgid "There is no configuration information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/unpackfs/main.py:456
|
||||||
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
|
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
|
||||||
msgstr "The filesystem for \"{}\" ({}) is not supported by your current kernel"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:458
|
#: src/modules/unpackfs/main.py:460
|
||||||
msgid "The source filesystem \"{}\" does not exist"
|
msgid "The source filesystem \"{}\" does not exist"
|
||||||
msgstr "The source filesystem \"{}\" does not exist"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:464
|
#: src/modules/unpackfs/main.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||||
"installed."
|
"installed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
|
||||||
"installed."
|
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:479
|
#: src/modules/unpackfs/main.py:481
|
||||||
msgid "The destination \"{}\" in the target system is not a directory"
|
msgid "The destination \"{}\" in the target system is not a directory"
|
||||||
msgstr "The destination \"{}\" in the target system is not a directory"
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:26
|
|
||||||
msgid "Configuring encrypted swap."
|
|
||||||
msgstr "Configuring encrypted swap."
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# Translators:
|
# Translators:
|
||||||
# pavelrz, 2017
|
# pavelrz, 2017
|
||||||
# LiberteCzech <martin.kriz.czech@gmail.com>, 2020
|
# LiberteCzech <martin.kriz.czech@gmail.com>, 2020
|
||||||
# Pavel Borecki <pavel.borecki@gmail.com>, 2021
|
# Pavel Borecki <pavel.borecki@gmail.com>, 2022
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -15,7 +15,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||||
"Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2021\n"
|
"Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2022\n"
|
||||||
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n"
|
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -331,7 +331,7 @@ msgstr "Nedaří se zapnout systemd službu <code>{name!s}</code>."
|
|||||||
|
|
||||||
#: src/modules/services-systemd/main.py:67
|
#: src/modules/services-systemd/main.py:67
|
||||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||||
msgstr ""
|
msgstr "Nedaří se zapnout systemd časovač <code>{name!s}</code>."
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:71
|
#: src/modules/services-systemd/main.py:71
|
||||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||||
@ -413,6 +413,8 @@ msgid ""
|
|||||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||||
"installed."
|
"installed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Nepodařilo se nalézt nástroj unsquashfs – ověřte, že je nainstalovaný "
|
||||||
|
"balíček squashfs-tools."
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:479
|
#: src/modules/unpackfs/main.py:479
|
||||||
msgid "The destination \"{}\" in the target system is not a directory"
|
msgid "The destination \"{}\" in the target system is not a directory"
|
||||||
|
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 ""
|
@ -9,6 +9,7 @@
|
|||||||
# Feng Chao <chaofeng111@qq.com>, 2020
|
# Feng Chao <chaofeng111@qq.com>, 2020
|
||||||
# Bobby Rong <admin@bobby285271.top>, 2020
|
# Bobby Rong <admin@bobby285271.top>, 2020
|
||||||
# 玉堂白鹤 <yjwork@qq.com>, 2021
|
# 玉堂白鹤 <yjwork@qq.com>, 2021
|
||||||
|
# Giovanni Schiano-Moriello, 2022
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -17,7 +18,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||||
"Last-Translator: 玉堂白鹤 <yjwork@qq.com>, 2021\n"
|
"Last-Translator: Giovanni Schiano-Moriello, 2022\n"
|
||||||
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
|
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -305,7 +306,7 @@ msgstr "无法启用 systemd 目标 <code>{name!s}</code>."
|
|||||||
|
|
||||||
#: src/modules/services-systemd/main.py:67
|
#: src/modules/services-systemd/main.py:67
|
||||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||||
msgstr ""
|
msgstr "无法启用 systemd 计时器 <code>{name!s}</code>。"
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:71
|
#: src/modules/services-systemd/main.py:71
|
||||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||||
@ -384,7 +385,7 @@ msgstr "源文件系统 \"{}\" 不存在"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||||
"installed."
|
"installed."
|
||||||
msgstr ""
|
msgstr "寻找 unsquashfs 失败,请确定您已安装 squashfs-tools 软体包。"
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:479
|
#: src/modules/unpackfs/main.py:479
|
||||||
msgid "The destination \"{}\" in the target system is not a directory"
|
msgid "The destination \"{}\" in the target system is not a directory"
|
||||||
|
@ -485,7 +485,7 @@ main( int argc, char* argv[] )
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cDebug() << Logger::SubEntry << " .. got" << m->name() << m->typeString() << m->interfaceString();
|
cDebug() << Logger::SubEntry << "got" << m->name() << m->typeString() << m->interfaceString();
|
||||||
if ( m->type() == Calamares::Module::Type::View )
|
if ( m->type() == Calamares::Module::Type::View )
|
||||||
{
|
{
|
||||||
// If we forgot the --ui, any ViewModule will core dump as it
|
// If we forgot the --ui, any ViewModule will core dump as it
|
||||||
@ -535,7 +535,7 @@ main( int argc, char* argv[] )
|
|||||||
|
|
||||||
using TR = Logger::DebugRow< const char*, const QString >;
|
using TR = Logger::DebugRow< const char*, const QString >;
|
||||||
|
|
||||||
cDebug() << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() )
|
cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() )
|
||||||
<< TR( "interface", m->interfaceString() );
|
<< TR( "interface", m->interfaceString() );
|
||||||
|
|
||||||
Calamares::JobList jobList = m->jobs();
|
Calamares::JobList jobList = m->jobs();
|
||||||
@ -543,6 +543,8 @@ main( int argc, char* argv[] )
|
|||||||
unsigned int count = 1;
|
unsigned int count = 1;
|
||||||
for ( const auto& p : jobList )
|
for ( const auto& p : jobList )
|
||||||
{
|
{
|
||||||
|
// This doesn't get a SubEntry because the jobs may log a bunch of
|
||||||
|
// things; print the function-header to make clear that we're back in main.
|
||||||
cDebug() << "Job #" << count << "name" << p->prettyName();
|
cDebug() << "Job #" << count << "name" << p->prettyName();
|
||||||
Calamares::JobResult r = p->exec();
|
Calamares::JobResult r = p->exec();
|
||||||
if ( !r )
|
if ( !r )
|
||||||
|
@ -47,7 +47,7 @@ public:
|
|||||||
|
|
||||||
/** @brief Is this JobResult a success?
|
/** @brief Is this JobResult a success?
|
||||||
*
|
*
|
||||||
* Equivalent to errorCode() == 0, might be named isValid().
|
* Equivalent to errorCode() == 0, see succeeded().
|
||||||
*/
|
*/
|
||||||
virtual operator bool() const;
|
virtual operator bool() const;
|
||||||
|
|
||||||
@ -58,6 +58,11 @@ public:
|
|||||||
virtual void setDetails( const QString& details );
|
virtual void setDetails( const QString& details );
|
||||||
|
|
||||||
int errorCode() const { return m_number; }
|
int errorCode() const { return m_number; }
|
||||||
|
/** @brief Is this JobResult a success?
|
||||||
|
*
|
||||||
|
* Equivalent to errorCode() == 0.
|
||||||
|
*/
|
||||||
|
bool succeeded() const { return this->operator bool(); }
|
||||||
|
|
||||||
/// @brief an "ok status" result
|
/// @brief an "ok status" result
|
||||||
static JobResult ok();
|
static JobResult ok();
|
||||||
|
@ -122,8 +122,9 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
|
cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" )
|
||||||
<< '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')';
|
<< jobitem.job->prettyName() << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count()
|
||||||
|
<< ')';
|
||||||
o.refresh(); // So next time it shows the function header again
|
o.refresh(); // So next time it shows the function header again
|
||||||
emitProgress( 0.0 ); // 0% for *this job*
|
emitProgress( 0.0 ); // 0% for *this job*
|
||||||
connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );
|
connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );
|
||||||
|
@ -100,7 +100,7 @@ BOOST_PYTHON_MODULE( libcalamares )
|
|||||||
bp::args( "s" ),
|
bp::args( "s" ),
|
||||||
"Writes the given string to the Calamares warning stream." );
|
"Writes the given string to the Calamares warning stream." );
|
||||||
bp::def(
|
bp::def(
|
||||||
"error", &CalamaresPython::warning, bp::args( "s" ), "Writes the given string to the Calamares error stream." );
|
"error", &CalamaresPython::error, bp::args( "s" ), "Writes the given string to the Calamares error stream." );
|
||||||
|
|
||||||
|
|
||||||
// .. YAML functions
|
// .. YAML functions
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "partition/Sync.h"
|
#include "partition/Sync.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/String.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
@ -123,5 +124,32 @@ TemporaryMount::path() const
|
|||||||
return m_d ? m_d->m_mountDir.path() : QString();
|
return m_d ? m_d->m_mountDir.path() : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList< MtabInfo >
|
||||||
|
MtabInfo::fromMtabFilteredByPrefix( const QString& mountPrefix, const QString& mtabPath )
|
||||||
|
{
|
||||||
|
QFile f( mtabPath.isEmpty() ? "/etc/mtab" : mtabPath );
|
||||||
|
if ( !f.open( QIODevice::ReadOnly ) )
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in( &f );
|
||||||
|
QList< MtabInfo > l;
|
||||||
|
while ( !f.atEnd() )
|
||||||
|
{
|
||||||
|
QStringList line = in.readLine().split( ' ', SplitSkipEmptyParts );
|
||||||
|
if ( line.length() == 3 && !line[ 0 ].startsWith( '#' ) )
|
||||||
|
{
|
||||||
|
// Lines have format: <device> <mountpoint> <options>, so check
|
||||||
|
// the mountpoint field. Everything starts with an empty string.
|
||||||
|
if ( line[ 1 ].startsWith( mountPrefix ) )
|
||||||
|
{
|
||||||
|
l.append( { line[ 0 ], line[ 1 ] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Partition
|
} // namespace Partition
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@ -50,6 +51,13 @@ DLLEXPORT int mount( const QString& devicePath,
|
|||||||
*/
|
*/
|
||||||
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
|
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Mount and automatically unmount a device
|
||||||
|
*
|
||||||
|
* The TemporaryMount object mounts a filesystem, and is like calling
|
||||||
|
* the mount() function, above. When the object is destroyed, unmount()
|
||||||
|
* is called with suitable options to undo the original mount.
|
||||||
|
*/
|
||||||
class DLLEXPORT TemporaryMount
|
class DLLEXPORT TemporaryMount
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -68,6 +76,36 @@ private:
|
|||||||
std::unique_ptr< Private > m_d;
|
std::unique_ptr< Private > m_d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Information about a mount point from /etc/mtab
|
||||||
|
*
|
||||||
|
* Entries in /etc/mtab are of the form: <device> <mountpoint> <other>
|
||||||
|
* This struct only stores device and mountpoint.
|
||||||
|
*
|
||||||
|
* The main way of getting these structs is to call fromMtab() to read
|
||||||
|
* an /etc/mtab-like file and storing all of the entries from it.
|
||||||
|
*/
|
||||||
|
struct DLLEXPORT MtabInfo
|
||||||
|
{
|
||||||
|
QString device;
|
||||||
|
QString mountPoint;
|
||||||
|
|
||||||
|
/** @brief Reads an mtab-like file and returns the entries from it
|
||||||
|
*
|
||||||
|
* When @p mtabPath is given, that file is read. If the given name is
|
||||||
|
* empty (e.g. the default) then /etc/mtab is read, instead.
|
||||||
|
*
|
||||||
|
* If @p mountPrefix is given, then only entries that have a mount point
|
||||||
|
* that starts with that prefix are returned.
|
||||||
|
*/
|
||||||
|
static QList< MtabInfo > fromMtabFilteredByPrefix( const QString& mountPrefix = QString(),
|
||||||
|
const QString& mtabPath = QString() );
|
||||||
|
/// @brief Predicate to sort MtabInfo objects by device-name
|
||||||
|
static bool deviceOrder( const MtabInfo& a, const MtabInfo& b ) { return a.device > b.device; }
|
||||||
|
/// @brief Predicate to sort MtabInfo objects by mount-point
|
||||||
|
static bool mountPointOrder( const MtabInfo& a, const MtabInfo& b ) { return a.mountPoint > b.mountPoint; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Partition
|
} // namespace Partition
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
|
||||||
|
@ -259,7 +259,8 @@ operator<<( QDebug& s, const RedactedCommand& l )
|
|||||||
* Identical strings with the same context will be hashed the same,
|
* Identical strings with the same context will be hashed the same,
|
||||||
* so that they can be logged and still recognized as the-same.
|
* so that they can be logged and still recognized as the-same.
|
||||||
*/
|
*/
|
||||||
static uint insertRedactedName( const QString& context, const QString& s )
|
static uint
|
||||||
|
insertRedactedName( const QString& context, const QString& s )
|
||||||
{
|
{
|
||||||
static uint salt = QRandomGenerator::global()->generate(); // Just once
|
static uint salt = QRandomGenerator::global()->generate(); // Just once
|
||||||
|
|
||||||
@ -268,8 +269,8 @@ static uint insertRedactedName( const QString& context, const QString& s )
|
|||||||
}
|
}
|
||||||
|
|
||||||
RedactedName::RedactedName( const QString& context, const QString& s )
|
RedactedName::RedactedName( const QString& context, const QString& s )
|
||||||
: m_id( insertRedactedName(context, s) ),
|
: m_id( insertRedactedName( context, s ) )
|
||||||
m_context(context)
|
, m_context( context )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +70,12 @@ private:
|
|||||||
|
|
||||||
inline CDebug&
|
inline CDebug&
|
||||||
operator<<( CDebug&& s, const FuncSuppressor& f )
|
operator<<( CDebug&& s, const FuncSuppressor& f )
|
||||||
|
{
|
||||||
|
if ( s.m_funcinfo )
|
||||||
{
|
{
|
||||||
s.m_funcinfo = nullptr;
|
s.m_funcinfo = nullptr;
|
||||||
s << f.m_s;
|
s.m_msg = QString( f.m_s );
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +247,8 @@ private:
|
|||||||
const QString m_context;
|
const QString m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QDebug& operator<<( QDebug& s, const RedactedName& n )
|
inline QDebug&
|
||||||
|
operator<<( QDebug& s, const RedactedName& n )
|
||||||
{
|
{
|
||||||
return s << NoQuote << QString( n ) << Quote;
|
return s << NoQuote << QString( n ) << Quote;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ namespace CalamaresUtils
|
|||||||
* @param locale the new locale (names as defined by Calamares).
|
* @param locale the new locale (names as defined by Calamares).
|
||||||
* @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding.
|
* @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding.
|
||||||
*/
|
*/
|
||||||
DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& brandingTranslationsPrefix );
|
DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale,
|
||||||
|
const QString& brandingTranslationsPrefix );
|
||||||
|
|
||||||
/** @brief Initializes the translations with the current system settings
|
/** @brief Initializes the translations with the current system settings
|
||||||
*/
|
*/
|
||||||
@ -56,7 +57,8 @@ DLLEXPORT CalamaresUtils::Locale::Translation::Id translatorLocaleName();
|
|||||||
*
|
*
|
||||||
* @returns @c true on success
|
* @returns @c true on success
|
||||||
*/
|
*/
|
||||||
DLLEXPORT bool loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator );
|
DLLEXPORT bool
|
||||||
|
loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator );
|
||||||
|
|
||||||
/** @brief Set @p allow to true to load translations from current dir.
|
/** @brief Set @p allow to true to load translations from current dir.
|
||||||
*
|
*
|
||||||
@ -138,7 +140,10 @@ private:
|
|||||||
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
|
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, this, slotfunc ); \
|
connect( CalamaresUtils::Retranslator::instance(), \
|
||||||
|
&CalamaresUtils::Retranslator::languageChanged, \
|
||||||
|
this, \
|
||||||
|
slotfunc ); \
|
||||||
( this->*slotfunc )(); \
|
( this->*slotfunc )(); \
|
||||||
} while ( false )
|
} while ( false )
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ Note that process modules are not recommended.
|
|||||||
|
|
||||||
Module descriptors **may** have the following keys:
|
Module descriptors **may** have the following keys:
|
||||||
- *emergency* (a boolean value, set to true to mark the module
|
- *emergency* (a boolean value, set to true to mark the module
|
||||||
as an emergency module)
|
as an emergency module; see the section *Emergency Modules*, below)
|
||||||
- *noconfig* (a boolean value, set to true to state that the module
|
- *noconfig* (a boolean value, set to true to state that the module
|
||||||
has no configuration file; defaults to false)
|
has no configuration file; defaults to false)
|
||||||
- *requiredModules* (a list of modules which are required for this module
|
- *requiredModules* (a list of modules which are required for this module
|
||||||
@ -102,8 +102,14 @@ to generate a suitable `module.desc`. For Python modules, manually add
|
|||||||
A module that is marked as an emergency module in its module.desc
|
A module that is marked as an emergency module in its module.desc
|
||||||
must **also** set the *emergency* key to *true* in its configuration file
|
must **also** set the *emergency* key to *true* in its configuration file
|
||||||
(see below). If it does not, the module is not considered to be an emergency
|
(see below). If it does not, the module is not considered to be an emergency
|
||||||
module after all (this is so that you can have modules that have several
|
module after all. This is so that you can have modules that have several
|
||||||
instances, only some of which are actually needed for emergencies).
|
instances, only some of which are actually needed for emergencies.
|
||||||
|
|
||||||
|
In summary:
|
||||||
|
- in `module.desc`, write `emergency: true` to make it **possible** to
|
||||||
|
run the module in emergency mode,
|
||||||
|
- in `<modulename>.conf`, write `emergency: true` to make that specific
|
||||||
|
module run in emergency mode.
|
||||||
|
|
||||||
### Module-specific configuration
|
### Module-specific configuration
|
||||||
|
|
||||||
@ -112,6 +118,10 @@ named `<modulename>.conf`. If such a file is present in the
|
|||||||
module's directory, it can be shipped as a *default* configuration file.
|
module's directory, it can be shipped as a *default* configuration file.
|
||||||
This only happens if the CMake-time option `INSTALL_CONFIG` is on.
|
This only happens if the CMake-time option `INSTALL_CONFIG` is on.
|
||||||
|
|
||||||
|
The name of the configuration file for a given module can be
|
||||||
|
influenced by the `settings.conf` of the overall Calamares configuration.
|
||||||
|
By default, though, the module's own name is used.
|
||||||
|
|
||||||
Modules that have *noconfig* set to true will not attempt to
|
Modules that have *noconfig* set to true will not attempt to
|
||||||
read a configuration file, and will not warn that one is missing;
|
read a configuration file, and will not warn that one is missing;
|
||||||
conversely if *noconfig* is set to false (or is missing, since
|
conversely if *noconfig* is set to false (or is missing, since
|
||||||
@ -169,6 +179,26 @@ it is possible to take the whole installation-process into account
|
|||||||
for determining the relative weights there.
|
for determining the relative weights there.
|
||||||
|
|
||||||
|
|
||||||
|
## Global storage keys
|
||||||
|
Some modules place values in global storage so that they can be referenced later by other modules or even other parts of the same module. The following table represents a partial list of the values available as well as where they originate from and which module consume them.
|
||||||
|
|
||||||
|
Key|Source|Consumers|Description
|
||||||
|
---|---|---|---
|
||||||
|
btrfsSubvolumes|mount|fstab|List of maps containing the mountpoint and btrtfs subvolume
|
||||||
|
btrfsRootSubvolume|mount|bootloader, luksopenswaphook|String containing the subvolume mounted at root
|
||||||
|
efiSystemPartition|partition|bootloader, fstab|String containing the path to the ESP relative to the installed system
|
||||||
|
extraMounts|mount|unpackfs|List of maps holding metadata for the temporary mountpoints used by the installer
|
||||||
|
hostname|users||A string containing the hostname of the new system
|
||||||
|
netinstallAdd|packagechooser|netinstall|Data to add to netinstall tree. Same format as netinstall.yaml
|
||||||
|
netinstallSelect|packagechooser|netinstall|List of group names to select in the netinstall tree
|
||||||
|
partitions|partition, rawfs|numerous modules|List of maps of metadata about each partition
|
||||||
|
rootMountPoint|mount|numerous modules|A string with the absolute path to the root mountpoint
|
||||||
|
username|users|networkcfg, plasmainf, preservefiles|A string containing the username of the new user
|
||||||
|
zfsDatasets|zfs|bootloader, grubcfg, mount|List of maps of zfs datasets including the name and mount information
|
||||||
|
zfsInfo|partition|mount, zfs|List of encrypted zfs partitions and the encription info
|
||||||
|
zfsPoolInfo|zfs|mount, umount|List of maps of zfs pool info including the name and mountpoint
|
||||||
|
|
||||||
|
|
||||||
## C++ modules
|
## C++ modules
|
||||||
|
|
||||||
> Type: viewmodule, jobmodule
|
> Type: viewmodule, jobmodule
|
||||||
|
@ -48,6 +48,16 @@ efiBootMgr: "efibootmgr"
|
|||||||
# setting the option here, keep in mind that the name is sanitized
|
# setting the option here, keep in mind that the name is sanitized
|
||||||
# (problematic characters, see above, are replaced).
|
# (problematic characters, see above, are replaced).
|
||||||
#
|
#
|
||||||
|
# There are some special words possible at the end of *efiBootloaderId*:
|
||||||
|
# @@SERIAL@@ can be used to obtain a uniquely-numbered suffix
|
||||||
|
# that is added to the Id (yielding, e.g., `dirname1` or `dirname72`)
|
||||||
|
# @@RANDOM@@ can be used to obtain a unique 4-digit hex suffix
|
||||||
|
# @@PHRASE@@ can be used to obtain a unique 1-to-3-word suffix
|
||||||
|
# from a dictionary of space-themed words
|
||||||
|
# Note that these must be at the **end** of the *efiBootloaderId* value.
|
||||||
|
# There must also be at most one of them. If there is none, no suffix-
|
||||||
|
# processing is done and the *efiBootloaderId* is used unchanged.
|
||||||
|
#
|
||||||
# efiBootloaderId: "dirname"
|
# efiBootloaderId: "dirname"
|
||||||
|
|
||||||
# Optionally install a copy of the GRUB EFI bootloader as the EFI
|
# Optionally install a copy of the GRUB EFI bootloader as the EFI
|
||||||
|
@ -285,10 +285,166 @@ def create_loader(loader_path, entry):
|
|||||||
loader_file.write(line)
|
loader_file.write(line)
|
||||||
|
|
||||||
|
|
||||||
def efi_label():
|
class suffix_iterator(object):
|
||||||
|
"""
|
||||||
|
Wrapper for one of the "generator" classes below to behave like
|
||||||
|
a proper Python iterator. The iterator is initialized with a
|
||||||
|
maximum number of attempts to generate a new suffix.
|
||||||
|
"""
|
||||||
|
def __init__(self, attempts, generator):
|
||||||
|
self.generator = generator
|
||||||
|
self.attempts = attempts
|
||||||
|
self.counter = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
self.counter += 1
|
||||||
|
if self.counter <= self.attempts:
|
||||||
|
return self.generator.next()
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
|
||||||
|
class serialEfi(object):
|
||||||
|
"""
|
||||||
|
EFI Id generator that appends a serial number to the given name.
|
||||||
|
"""
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
# So the first call to next() will bump it to 0
|
||||||
|
self.counter = -1
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
self.counter += 1
|
||||||
|
if self.counter > 0:
|
||||||
|
return "{!s}{!s}".format(self.name, self.counter)
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
def render_in_base(value, base_values, length=-1):
|
||||||
|
"""
|
||||||
|
Renders @p value in base-N, where N is the number of
|
||||||
|
items in @p base_values. When rendering, use the items
|
||||||
|
of @p base_values (e.g. use "0123456789" to get regular decimal
|
||||||
|
rendering, or "ABCDEFGHIJ" for letters-as-numbers 'encoding').
|
||||||
|
|
||||||
|
If length is positive, pads out to at least that long with
|
||||||
|
leading "zeroes", whatever base_values[0] is.
|
||||||
|
"""
|
||||||
|
if value < 0:
|
||||||
|
raise ValueError("Cannot render negative values")
|
||||||
|
if len(base_values) < 2:
|
||||||
|
raise ValueError("Insufficient items for base-N rendering")
|
||||||
|
if length < 1:
|
||||||
|
length = 1
|
||||||
|
digits = []
|
||||||
|
base = len(base_values)
|
||||||
|
while value > 0:
|
||||||
|
place = value % base
|
||||||
|
value = value // base
|
||||||
|
digits.append(base_values[place])
|
||||||
|
while len(digits) < length:
|
||||||
|
digits.append(base_values[0])
|
||||||
|
return "".join(reversed(digits))
|
||||||
|
|
||||||
|
|
||||||
|
class randomEfi(object):
|
||||||
|
"""
|
||||||
|
EFI Id generator that appends a random 4-digit hex number to the given name.
|
||||||
|
"""
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
# So the first call to next() will bump it to 0
|
||||||
|
self.counter = -1
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
self.counter += 1
|
||||||
|
if self.counter > 0:
|
||||||
|
import random
|
||||||
|
v = random.randint(0, 65535) # 16 bits
|
||||||
|
return "{!s}{!s}".format(self.name, render_in_base(v, "0123456789ABCDEF", 4))
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class phraseEfi(object):
|
||||||
|
"""
|
||||||
|
EFI Id generator that appends a random phrase to the given name.
|
||||||
|
"""
|
||||||
|
words = ("Sun", "Moon", "Mars", "Soyuz", "Falcon", "Kuaizhou", "Gaganyaan")
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
# So the first call to next() will bump it to 0
|
||||||
|
self.counter = -1
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
self.counter += 1
|
||||||
|
if self.counter > 0:
|
||||||
|
import random
|
||||||
|
desired_length = 1 + self.counter // 5
|
||||||
|
v = random.randint(0, len(self.words) ** desired_length)
|
||||||
|
return "{!s}{!s}".format(self.name, render_in_base(v, self.words))
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
def get_efi_suffix_generator(name):
|
||||||
|
"""
|
||||||
|
Handle EFI bootloader Ids with @@<something>@@ for suffix-processing.
|
||||||
|
"""
|
||||||
|
if "@@" not in name:
|
||||||
|
raise ValueError("Misplaced call to get_efi_suffix_generator, no @@")
|
||||||
|
parts = name.split("@@")
|
||||||
|
if len(parts) != 3:
|
||||||
|
raise ValueError("EFI Id {!r} is malformed".format(name))
|
||||||
|
if parts[2]:
|
||||||
|
# Supposed to be empty because the string ends with "@@"
|
||||||
|
raise ValueError("EFI Id {!r} is malformed".format(name))
|
||||||
|
if parts[1] not in ("SERIAL", "RANDOM", "PHRASE"):
|
||||||
|
raise ValueError("EFI suffix {!r} is unknown".format(parts[1]))
|
||||||
|
|
||||||
|
generator = None
|
||||||
|
if parts[1] == "SERIAL":
|
||||||
|
generator = serialEfi(parts[0])
|
||||||
|
elif parts[1] == "RANDOM":
|
||||||
|
generator = randomEfi(parts[0])
|
||||||
|
elif parts[1] == "PHRASE":
|
||||||
|
generator = phraseEfi(parts[0])
|
||||||
|
if generator is None:
|
||||||
|
raise ValueError("EFI suffix {!r} is unsupported".format(parts[1]))
|
||||||
|
|
||||||
|
return generator
|
||||||
|
|
||||||
|
|
||||||
|
def change_efi_suffix(efi_directory, bootloader_id):
|
||||||
|
"""
|
||||||
|
Returns a label based on @p bootloader_id that is usable within
|
||||||
|
@p efi_directory. If there is a @@<something>@@ suffix marker
|
||||||
|
in the given id, tries to generate a unique label.
|
||||||
|
"""
|
||||||
|
if bootloader_id.endswith("@@"):
|
||||||
|
# Do 10 attempts with any suffix generator
|
||||||
|
g = suffix_iterator(10, get_efi_suffix_generator(bootloader_id))
|
||||||
|
else:
|
||||||
|
# Just one attempt
|
||||||
|
g = [bootloader_id]
|
||||||
|
|
||||||
|
for candidate_name in g:
|
||||||
|
if not os.path.exists(os.path.join(efi_directory, candidate_name)):
|
||||||
|
return candidate_name
|
||||||
|
return bootloader_id
|
||||||
|
|
||||||
|
|
||||||
|
def efi_label(efi_directory):
|
||||||
|
"""
|
||||||
|
Returns a sanitized label, possibly unique, that can be
|
||||||
|
used within @p efi_directory.
|
||||||
|
"""
|
||||||
if "efiBootloaderId" in libcalamares.job.configuration:
|
if "efiBootloaderId" in libcalamares.job.configuration:
|
||||||
efi_bootloader_id = libcalamares.job.configuration[
|
efi_bootloader_id = change_efi_suffix( efi_directory, libcalamares.job.configuration["efiBootloaderId"] )
|
||||||
"efiBootloaderId"]
|
|
||||||
else:
|
else:
|
||||||
branding = libcalamares.globalstorage.value("branding")
|
branding = libcalamares.globalstorage.value("branding")
|
||||||
efi_bootloader_id = branding["bootloaderEntryName"]
|
efi_bootloader_id = branding["bootloaderEntryName"]
|
||||||
@ -427,7 +583,7 @@ def run_grub_mkconfig(partitions, output_file):
|
|||||||
check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file])
|
check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file])
|
||||||
|
|
||||||
|
|
||||||
def run_grub_install(fw_type, partitions, efi_directory=None):
|
def run_grub_install(fw_type, partitions, efi_directory):
|
||||||
"""
|
"""
|
||||||
Runs grub-install in the target environment
|
Runs grub-install in the target environment
|
||||||
|
|
||||||
@ -444,7 +600,8 @@ def run_grub_install(fw_type, partitions, efi_directory=None):
|
|||||||
check_target_env_call(["sh", "-c", "echo ZPOOL_VDEV_NAME_PATH=1 >> /etc/environment"])
|
check_target_env_call(["sh", "-c", "echo ZPOOL_VDEV_NAME_PATH=1 >> /etc/environment"])
|
||||||
|
|
||||||
if fw_type == "efi":
|
if fw_type == "efi":
|
||||||
efi_bootloader_id = efi_label()
|
assert efi_directory is not None
|
||||||
|
efi_bootloader_id = efi_label(efi_directory)
|
||||||
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
|
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
|
||||||
|
|
||||||
if is_zfs:
|
if is_zfs:
|
||||||
@ -458,6 +615,7 @@ def run_grub_install(fw_type, partitions, efi_directory=None):
|
|||||||
"--bootloader-id=" + efi_bootloader_id,
|
"--bootloader-id=" + efi_bootloader_id,
|
||||||
"--force"])
|
"--force"])
|
||||||
else:
|
else:
|
||||||
|
assert efi_directory is None
|
||||||
if libcalamares.globalstorage.value("bootLoader") is None:
|
if libcalamares.globalstorage.value("bootLoader") is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -499,7 +657,7 @@ def install_grub(efi_directory, fw_type):
|
|||||||
if not os.path.isdir(install_efi_directory):
|
if not os.path.isdir(install_efi_directory):
|
||||||
os.makedirs(install_efi_directory)
|
os.makedirs(install_efi_directory)
|
||||||
|
|
||||||
efi_bootloader_id = efi_label()
|
efi_bootloader_id = efi_label(efi_directory)
|
||||||
|
|
||||||
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
|
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
|
||||||
|
|
||||||
@ -534,7 +692,7 @@ def install_grub(efi_directory, fw_type):
|
|||||||
shutil.copy2(efi_file_source, efi_file_target)
|
shutil.copy2(efi_file_source, efi_file_target)
|
||||||
else:
|
else:
|
||||||
libcalamares.utils.debug("Bootloader: grub (bios)")
|
libcalamares.utils.debug("Bootloader: grub (bios)")
|
||||||
run_grub_install(fw_type, partitions)
|
run_grub_install(fw_type, partitions, None)
|
||||||
|
|
||||||
run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"])
|
run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"])
|
||||||
|
|
||||||
@ -543,7 +701,7 @@ def install_secureboot(efi_directory):
|
|||||||
"""
|
"""
|
||||||
Installs the secureboot shim in the system by calling efibootmgr.
|
Installs the secureboot shim in the system by calling efibootmgr.
|
||||||
"""
|
"""
|
||||||
efi_bootloader_id = efi_label()
|
efi_bootloader_id = efi_label(efi_directory)
|
||||||
|
|
||||||
installation_root_path = libcalamares.globalstorage.value("rootMountPoint")
|
installation_root_path = libcalamares.globalstorage.value("rootMountPoint")
|
||||||
install_efi_directory = installation_root_path + efi_directory
|
install_efi_directory = installation_root_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")
|
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.
|
# kept, not updated to the *bootloaderEntryName* from the branding file.
|
||||||
# Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in
|
# Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in
|
||||||
# some way (e.g. uses shell-command substitution).
|
# some way (e.g. uses shell-command substitution).
|
||||||
|
#
|
||||||
|
# TODO:3.3:snake-case this key
|
||||||
keepDistributor: false
|
keepDistributor: false
|
||||||
|
|
||||||
|
# The default kernel params that should always be applied.
|
||||||
|
# This is an array of strings. If it is unset, the default is
|
||||||
|
# `["quiet"]`. To avoid the default, explicitly set this key
|
||||||
|
# to an empty list, `[]`.
|
||||||
|
kernel_params: [ "quiet" ]
|
||||||
|
|
||||||
# Default entries to write to /etc/default/grub if it does not exist yet or if
|
# Default entries to write to /etc/default/grub if it does not exist yet or if
|
||||||
# we are overwriting it.
|
# we are overwriting it.
|
||||||
#
|
#
|
||||||
|
@ -7,8 +7,10 @@ additionalProperties: false
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
overwrite: { type: boolean, default: false }
|
overwrite: { type: boolean, default: false }
|
||||||
|
# TODO:3.3:snake-case this key
|
||||||
keepDistributor: { type: boolean, default: false }
|
keepDistributor: { type: boolean, default: false }
|
||||||
prefer_grub_d: { type: boolean, default: false }
|
prefer_grub_d: { type: boolean, default: false }
|
||||||
|
kernel_params: { type: array, items: { type: string } }
|
||||||
defaults:
|
defaults:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: true # Other fields are acceptable
|
additionalProperties: true # Other fields are acceptable
|
||||||
|
@ -170,7 +170,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
|
|||||||
if partition["fs"] == "zfs" and partition["mountPoint"] == "/":
|
if partition["fs"] == "zfs" and partition["mountPoint"] == "/":
|
||||||
zfs_root_path = get_zfs_root()
|
zfs_root_path = get_zfs_root()
|
||||||
|
|
||||||
kernel_params = ["quiet"]
|
kernel_params = libcalamares.job.configuration.get("kernel_params", ["quiet"])
|
||||||
|
|
||||||
# Currently, grub doesn't detect this properly so it must be set manually
|
# Currently, grub doesn't detect this properly so it must be set manually
|
||||||
if zfs_root_path:
|
if zfs_root_path:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2022 Evan James <dalto@fastmail.com>
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*
|
*
|
||||||
* Calamares is Free Software: see the License-Identifier above.
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
@ -31,15 +32,22 @@ InitcpioJob::prettyName() const
|
|||||||
return tr( "Creating initramfs with mkinitcpio." );
|
return tr( "Creating initramfs with mkinitcpio." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Sets secure permissions on each initramfs
|
||||||
|
*
|
||||||
|
* Iterates over each initramfs contained directly in the directory @p d.
|
||||||
|
* For each initramfs found, the permissions are set to owner read/write only.
|
||||||
|
*
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
fixPermissions( const QDir& d )
|
fixPermissions( const QDir& d )
|
||||||
{
|
{
|
||||||
for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) )
|
const auto initramList = d.entryInfoList( { "initramfs*" }, QDir::Files );
|
||||||
|
for ( const auto& fi : initramList )
|
||||||
{
|
{
|
||||||
QFile f( fi.absoluteFilePath() );
|
QFile f( fi.absoluteFilePath() );
|
||||||
if ( f.exists() )
|
if ( f.exists() )
|
||||||
{
|
{
|
||||||
cDebug() << "initcpio fixing permissions for" << f.fileName();
|
cDebug() << "initcpio setting permissions for" << f.fileName();
|
||||||
f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner );
|
f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,9 +71,19 @@ InitcpioJob::exec()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the kernel option isn't set to a specific kernel, run mkinitcpio on all kernels
|
||||||
|
QStringList command = { "mkinitcpio" };
|
||||||
|
if ( m_kernel.isEmpty() || m_kernel == "all" )
|
||||||
|
{
|
||||||
|
command.append( "-P" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command.append( { "-p", m_kernel } );
|
||||||
|
}
|
||||||
|
|
||||||
cDebug() << "Updating initramfs with kernel" << m_kernel;
|
cDebug() << "Updating initramfs with kernel" << m_kernel;
|
||||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
|
auto r = CalamaresUtils::System::instance()->targetEnvCommand( command, QString(), QString() /* no timeout , 0 */ );
|
||||||
{ "mkinitcpio", "-p", m_kernel }, QString(), QString() /* no timeout , 0 */ );
|
|
||||||
return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ );
|
return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,28 +91,6 @@ void
|
|||||||
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
|
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
{
|
{
|
||||||
m_kernel = CalamaresUtils::getString( configurationMap, "kernel" );
|
m_kernel = CalamaresUtils::getString( configurationMap, "kernel" );
|
||||||
if ( m_kernel.isEmpty() )
|
|
||||||
{
|
|
||||||
m_kernel = QStringLiteral( "all" );
|
|
||||||
}
|
|
||||||
else if ( m_kernel == "$uname" )
|
|
||||||
{
|
|
||||||
auto r = CalamaresUtils::System::runCommand( CalamaresUtils::System::RunLocation::RunInHost,
|
|
||||||
{ "/bin/uname", "-r" },
|
|
||||||
QString(),
|
|
||||||
QString(),
|
|
||||||
std::chrono::seconds( 3 ) );
|
|
||||||
if ( r.getExitCode() == 0 )
|
|
||||||
{
|
|
||||||
m_kernel = r.getOutput();
|
|
||||||
cDebug() << "*initcpio* using running kernel" << m_kernel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation
|
|
||||||
<< r.getExitCode() << r.getOutput();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
|
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
|
||||||
}
|
}
|
||||||
|
@ -5,21 +5,22 @@
|
|||||||
---
|
---
|
||||||
# This key defines the kernel to be loaded.
|
# This key defines the kernel to be loaded.
|
||||||
# It can have the following values:
|
# It can have the following values:
|
||||||
# - empty or unset, interpreted as "all"
|
# - the name of a single mkinitcpio preset
|
||||||
# - the literal string "$uname" (without quotes, with dollar),
|
# - empty or unset
|
||||||
# which will use the output of `uname -r` to determine the
|
# - the literal string "all"
|
||||||
# running kernel, and use that.
|
|
||||||
# - any other string.
|
|
||||||
#
|
#
|
||||||
# Whatever is set, that string is passed as *preset* argument to the
|
# If kernel is set to "all" or empty/unset then mkinitpio is called for all
|
||||||
# `-p` option of *mkinitcpio*. Take care that both "$uname" operates
|
# kernels. Otherwise it is called with a single preset with the value
|
||||||
# in the host system, and might not be correct if the target system is
|
# contained in kernel.
|
||||||
# updated (to a newer kernel) as part of the installation.
|
|
||||||
#
|
#
|
||||||
# Note that "all" is probably not a good preset to use either.
|
kernel: linux
|
||||||
kernel: linux312
|
|
||||||
|
|
||||||
# Set this to true to turn off mitigations for lax file
|
# Set this to true to turn off mitigations for lax file
|
||||||
# permissions on initramfs (which, in turn, can compromise
|
# permissions on initramfs (which, in turn, can compromise
|
||||||
# your LUKS encryption keys, CVS-2019-13179).
|
# your LUKS encryption keys, CVS-2019-13179).
|
||||||
|
#
|
||||||
|
# If your initramfs are stored in the EFI partition or another non-POSIX
|
||||||
|
# filesystem, this has no effect as the file permissions cannot be changed.
|
||||||
|
# In this case, ensure the partition is mounted securely.
|
||||||
|
#
|
||||||
be_unsafe: false
|
be_unsafe: false
|
||||||
|
@ -183,7 +183,8 @@ def find_initcpio_features(partitions, root_mount_point):
|
|||||||
if partition["fs"] == "btrfs":
|
if partition["fs"] == "btrfs":
|
||||||
uses_btrfs = True
|
uses_btrfs = True
|
||||||
|
|
||||||
if partition["fs"] == "zfs":
|
# In addition to checking the filesystem, check to ensure that zfs is enabled
|
||||||
|
if partition["fs"] == "zfs" and libcalamares.globalstorage.contains("zfsPoolInfo"):
|
||||||
uses_zfs = True
|
uses_zfs = True
|
||||||
|
|
||||||
if "lvm2" in partition["fs"]:
|
if "lvm2" in partition["fs"]:
|
||||||
|
@ -81,6 +81,7 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
m_kernel = QStringLiteral( "all" );
|
||||||
cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation
|
cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation
|
||||||
<< r.getExitCode() << r.getOutput();
|
<< r.getExitCode() << r.getOutput();
|
||||||
}
|
}
|
||||||
|
@ -221,6 +221,11 @@ Config::setCurrentLocation()
|
|||||||
{
|
{
|
||||||
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
|
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
|
||||||
}
|
}
|
||||||
|
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||||
|
{
|
||||||
|
auto newLocale = automaticLocaleConfiguration();
|
||||||
|
setLanguage( newLocale.language() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -252,15 +257,21 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName )
|
|||||||
void
|
void
|
||||||
Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location )
|
Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location )
|
||||||
{
|
{
|
||||||
if ( location != m_currentLocation )
|
const bool updateLocation = ( location != m_currentLocation );
|
||||||
|
if ( updateLocation )
|
||||||
{
|
{
|
||||||
m_currentLocation = location;
|
m_currentLocation = location;
|
||||||
// Overwrite those settings that have not been made explicit.
|
}
|
||||||
|
|
||||||
|
// lang should be always be updated
|
||||||
auto newLocale = automaticLocaleConfiguration();
|
auto newLocale = automaticLocaleConfiguration();
|
||||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||||
{
|
{
|
||||||
setLanguage( newLocale.language() );
|
setLanguage( newLocale.language() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( updateLocation )
|
||||||
|
{
|
||||||
if ( !m_selectedLocaleConfiguration.explicit_lc )
|
if ( !m_selectedLocaleConfiguration.explicit_lc )
|
||||||
{
|
{
|
||||||
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;
|
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
|
# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
|
||||||
# use LOSH all over the place as a shorthand.
|
# use LOSH all over the place as a shorthand.
|
||||||
calamares_add_plugin( luksopenswaphook
|
calamares_add_plugin( luksopenswaphookcfg
|
||||||
TYPE job
|
TYPE job
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "PackageModel.h"
|
#include "PackageModel.h"
|
||||||
#include "ui_page_netinst.h"
|
#include "ui_page_netinst.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
|
|
||||||
#include "network/Manager.h"
|
#include "network/Manager.h"
|
||||||
@ -62,4 +63,19 @@ void
|
|||||||
NetInstallPage::onActivate()
|
NetInstallPage::onActivate()
|
||||||
{
|
{
|
||||||
ui->groupswidget->setFocus();
|
ui->groupswidget->setFocus();
|
||||||
|
|
||||||
|
// The netinstallSelect global storage value can be used to make additional items selected by default
|
||||||
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
const QStringList selectNames = gs->value( "netinstallSelect" ).toStringList();
|
||||||
|
if ( !selectNames.isEmpty() )
|
||||||
|
{
|
||||||
|
m_config->model()->setSelections( selectNames );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If NetInstallAdd is found in global storage, add those items to the tree
|
||||||
|
const QVariantList groups = gs->value( "netinstallAdd" ).toList();
|
||||||
|
if ( !groups.isEmpty() )
|
||||||
|
{
|
||||||
|
m_config->model()->appendModelData( groups );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,43 @@
|
|||||||
#include "utils/Variant.h"
|
#include "utils/Variant.h"
|
||||||
#include "utils/Yaml.h"
|
#include "utils/Yaml.h"
|
||||||
|
|
||||||
|
/// Recursive helper for setSelections()
|
||||||
|
static void
|
||||||
|
setSelections( const QStringList& selectNames, PackageTreeItem* item )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < item->childCount(); i++ )
|
||||||
|
{
|
||||||
|
auto* child = item->child( i );
|
||||||
|
setSelections( selectNames, child );
|
||||||
|
}
|
||||||
|
if ( item->isGroup() && selectNames.contains( item->name() ) )
|
||||||
|
{
|
||||||
|
item->setSelected( Qt::CheckState::Checked );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Collects all the "source" values from @p groupList
|
||||||
|
*
|
||||||
|
* Iterates over @p groupList and returns all nonempty "source"
|
||||||
|
* values from the maps.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static QStringList
|
||||||
|
collectSources( const QVariantList& groupList )
|
||||||
|
{
|
||||||
|
QStringList sources;
|
||||||
|
for ( const QVariant& group : groupList )
|
||||||
|
{
|
||||||
|
QVariantMap groupMap = group.toMap();
|
||||||
|
if ( !groupMap[ "source" ].toString().isEmpty() )
|
||||||
|
{
|
||||||
|
sources.append( groupMap[ "source" ].toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
PackageModel::PackageModel( QObject* parent )
|
PackageModel::PackageModel( QObject* parent )
|
||||||
: QAbstractItemModel( parent )
|
: QAbstractItemModel( parent )
|
||||||
{
|
{
|
||||||
@ -170,6 +207,15 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageModel::setSelections( const QStringList& selectNames )
|
||||||
|
{
|
||||||
|
if ( m_rootItem )
|
||||||
|
{
|
||||||
|
::setSelections( selectNames, m_rootItem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PackageTreeItem::List
|
PackageTreeItem::List
|
||||||
PackageModel::getPackages() const
|
PackageModel::getPackages() const
|
||||||
{
|
{
|
||||||
@ -303,9 +349,43 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa
|
|||||||
void
|
void
|
||||||
PackageModel::setupModelData( const QVariantList& l )
|
PackageModel::setupModelData( const QVariantList& l )
|
||||||
{
|
{
|
||||||
emit beginResetModel();
|
Q_EMIT beginResetModel();
|
||||||
delete m_rootItem;
|
delete m_rootItem;
|
||||||
m_rootItem = new PackageTreeItem();
|
m_rootItem = new PackageTreeItem();
|
||||||
setupModelData( l, m_rootItem );
|
setupModelData( l, m_rootItem );
|
||||||
emit endResetModel();
|
Q_EMIT endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageModel::appendModelData( const QVariantList& groupList )
|
||||||
|
{
|
||||||
|
if ( m_rootItem )
|
||||||
|
{
|
||||||
|
Q_EMIT beginResetModel();
|
||||||
|
|
||||||
|
const QStringList sources = collectSources( groupList );
|
||||||
|
|
||||||
|
if ( !sources.isEmpty() )
|
||||||
|
{
|
||||||
|
// Prune any existing data from the same source
|
||||||
|
QList< int > removeList;
|
||||||
|
for ( int i = 0; i < m_rootItem->childCount(); i++ )
|
||||||
|
{
|
||||||
|
PackageTreeItem* child = m_rootItem->child( i );
|
||||||
|
if ( sources.contains( child->source() ) )
|
||||||
|
{
|
||||||
|
removeList.insert( 0, i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( const int& item : qAsConst( removeList ) )
|
||||||
|
{
|
||||||
|
m_rootItem->removeChild( item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new data to the model
|
||||||
|
setupModelData( groupList, m_rootItem );
|
||||||
|
|
||||||
|
Q_EMIT endResetModel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,33 @@ public:
|
|||||||
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
|
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||||
int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
|
int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||||
|
|
||||||
|
/** @brief Sets the checked flag on matching groups in the tree
|
||||||
|
*
|
||||||
|
* Recursively traverses the tree pointed to by m_rootItem and
|
||||||
|
* checks if a group name matches any of the items in @p selectNames.
|
||||||
|
* If a match is found, set check the box for that group and it's children.
|
||||||
|
*
|
||||||
|
* Individual packages will not be matched.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void setSelections( const QStringList& selectNames );
|
||||||
|
|
||||||
PackageTreeItem::List getPackages() const;
|
PackageTreeItem::List getPackages() const;
|
||||||
PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const;
|
PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const;
|
||||||
|
|
||||||
|
/** @brief Appends groups to the tree
|
||||||
|
*
|
||||||
|
* Uses the data from @p groupList to add elements to the
|
||||||
|
* existing tree that m_rootItem points to. If m_rootItem
|
||||||
|
* is not valid, it does nothing
|
||||||
|
*
|
||||||
|
* Before adding anything to the model, it ensures that there
|
||||||
|
* is no existing data from the same source. If there is, that
|
||||||
|
* data is pruned first
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void appendModelData( const QVariantList& groupList );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ItemTests;
|
friend class ItemTests;
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ PackageTreeItem::PackageTreeItem( const QVariantMap& groupData, GroupTag&& paren
|
|||||||
, m_description( CalamaresUtils::getString( groupData, "description" ) )
|
, m_description( CalamaresUtils::getString( groupData, "description" ) )
|
||||||
, m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) )
|
, m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) )
|
||||||
, m_postScript( CalamaresUtils::getString( groupData, "post-install" ) )
|
, m_postScript( CalamaresUtils::getString( groupData, "post-install" ) )
|
||||||
|
, m_source( CalamaresUtils::getString( groupData, "source" ) )
|
||||||
, m_isGroup( true )
|
, m_isGroup( true )
|
||||||
, m_isCritical( parentCriticality( groupData, parent.parent ) )
|
, m_isCritical( parentCriticality( groupData, parent.parent ) )
|
||||||
, m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) )
|
, m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) )
|
||||||
@ -248,6 +249,19 @@ PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageTreeItem::removeChild( int row )
|
||||||
|
{
|
||||||
|
if ( 0 <= row && row < m_childItems.count() )
|
||||||
|
{
|
||||||
|
m_childItems.removeAt( row );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Attempt to remove invalid child in removeChild() at row " << row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PackageTreeItem::type() const
|
PackageTreeItem::type() const
|
||||||
{
|
{
|
||||||
|
@ -56,6 +56,7 @@ public:
|
|||||||
QString description() const { return m_description; }
|
QString description() const { return m_description; }
|
||||||
QString preScript() const { return m_preScript; }
|
QString preScript() const { return m_preScript; }
|
||||||
QString postScript() const { return m_postScript; }
|
QString postScript() const { return m_postScript; }
|
||||||
|
QString source() const { return m_source; }
|
||||||
|
|
||||||
/** @brief Is this item a group-item?
|
/** @brief Is this item a group-item?
|
||||||
*
|
*
|
||||||
@ -124,6 +125,8 @@ public:
|
|||||||
void setSelected( Qt::CheckState isSelected );
|
void setSelected( Qt::CheckState isSelected );
|
||||||
void setChildrenSelected( Qt::CheckState isSelected );
|
void setChildrenSelected( Qt::CheckState isSelected );
|
||||||
|
|
||||||
|
void removeChild( int row );
|
||||||
|
|
||||||
/** @brief Update selectedness based on the children's states
|
/** @brief Update selectedness based on the children's states
|
||||||
*
|
*
|
||||||
* This only makes sense for groups, which might have packages
|
* This only makes sense for groups, which might have packages
|
||||||
@ -157,6 +160,7 @@ private:
|
|||||||
QString m_description;
|
QString m_description;
|
||||||
QString m_preScript;
|
QString m_preScript;
|
||||||
QString m_postScript;
|
QString m_postScript;
|
||||||
|
QString m_source;
|
||||||
bool m_isGroup = false;
|
bool m_isGroup = false;
|
||||||
bool m_isCritical = false;
|
bool m_isCritical = false;
|
||||||
bool m_isHidden = false;
|
bool m_isHidden = false;
|
||||||
|
@ -27,6 +27,29 @@
|
|||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/Variant.h"
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
/** @brief This removes any values from @p groups that match @p source
|
||||||
|
*
|
||||||
|
* This is used to remove duplicates from the netinstallAdd structure
|
||||||
|
* It iterates over @p groups and for each map in the list, if the
|
||||||
|
* "source" element matches @p source, it is removed from the returned
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
static QVariantList
|
||||||
|
pruneNetinstallAdd( const QString& source, const QVariant& groups )
|
||||||
|
{
|
||||||
|
QVariantList newGroupList;
|
||||||
|
const QVariantList groupList = groups.toList();
|
||||||
|
for ( const QVariant& group : groupList )
|
||||||
|
{
|
||||||
|
QVariantMap groupMap = group.toMap();
|
||||||
|
if ( groupMap.value( "source", "" ).toString() != source )
|
||||||
|
{
|
||||||
|
newGroupList.append( groupMap );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newGroupList;
|
||||||
|
}
|
||||||
|
|
||||||
const NamedEnumTable< PackageChooserMode >&
|
const NamedEnumTable< PackageChooserMode >&
|
||||||
packageChooserModeNames()
|
packageChooserModeNames()
|
||||||
{
|
{
|
||||||
@ -55,6 +78,8 @@ PackageChooserMethodNames()
|
|||||||
{ "custom", PackageChooserMethod::Legacy },
|
{ "custom", PackageChooserMethod::Legacy },
|
||||||
{ "contextualprocess", PackageChooserMethod::Legacy },
|
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||||
{ "packages", PackageChooserMethod::Packages },
|
{ "packages", PackageChooserMethod::Packages },
|
||||||
|
{ "netinstall-add", PackageChooserMethod::NetAdd },
|
||||||
|
{ "netinstall-select", PackageChooserMethod::NetSelect },
|
||||||
};
|
};
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
@ -121,6 +146,47 @@ Config::updateGlobalStorage( const QStringList& selected ) const
|
|||||||
CalamaresUtils::Packages::setGSPackageAdditions(
|
CalamaresUtils::Packages::setGSPackageAdditions(
|
||||||
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
||||||
}
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::NetAdd )
|
||||||
|
{
|
||||||
|
QVariantList netinstallDataList = m_model->getNetinstallDataForNames( selected );
|
||||||
|
if ( netinstallDataList.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "No netinstall information found for " << selected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( gs->contains( "netinstallAdd" ) )
|
||||||
|
{
|
||||||
|
netinstallDataList
|
||||||
|
+= pruneNetinstallAdd( QStringLiteral( "packageChooser" ), gs->value( "netinstallAdd" ) );
|
||||||
|
}
|
||||||
|
gs->insert( "netinstallAdd", netinstallDataList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::NetSelect )
|
||||||
|
{
|
||||||
|
cDebug() << m_defaultId << "groups to select in netinstall" << selected;
|
||||||
|
QStringList newSelected = selected;
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
|
||||||
|
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||||
|
if ( gs->contains( "netinstallSelect" ) )
|
||||||
|
{
|
||||||
|
auto selectedOrig = gs->value( "netinstallSelect" );
|
||||||
|
if ( selectedOrig.canConvert( QVariant::StringList ) )
|
||||||
|
{
|
||||||
|
newSelected += selectedOrig.toStringList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Invalid NetinstallSelect data in global storage. Earlier selections purged";
|
||||||
|
}
|
||||||
|
gs->remove( "netinstallSelect" );
|
||||||
|
}
|
||||||
|
gs->insert( "netinstallSelect", newSelected );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||||
|
@ -33,6 +33,8 @@ enum class PackageChooserMethod
|
|||||||
{
|
{
|
||||||
Legacy, // use contextualprocess or other custom
|
Legacy, // use contextualprocess or other custom
|
||||||
Packages, // use the packages module
|
Packages, // use the packages module
|
||||||
|
NetAdd, // adds packages to the netinstall module
|
||||||
|
NetSelect, // makes selections in the netinstall module
|
||||||
};
|
};
|
||||||
|
|
||||||
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||||
|
@ -15,6 +15,16 @@
|
|||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
/** @brief A wrapper for CalamaresUtils::getSubMap that excludes the success param
|
||||||
|
*/
|
||||||
|
static QVariantMap
|
||||||
|
getSubMap( const QVariantMap& map, const QString& key )
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
return CalamaresUtils::getSubMap( map, key, success );
|
||||||
|
}
|
||||||
|
|
||||||
static QPixmap
|
static QPixmap
|
||||||
loadScreenshot( const QString& path )
|
loadScreenshot( const QString& path )
|
||||||
{
|
{
|
||||||
@ -51,12 +61,13 @@ PackageItem::PackageItem( const QString& a_id,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageItem::PackageItem::PackageItem( const QVariantMap& item_map )
|
PackageItem::PackageItem( const QVariantMap& item_map )
|
||||||
: id( CalamaresUtils::getString( item_map, "id" ) )
|
: id( CalamaresUtils::getString( item_map, "id" ) )
|
||||||
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
||||||
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
||||||
, screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) )
|
, screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) )
|
||||||
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
||||||
|
, netinstallData( getSubMap( item_map, "netinstall" ) )
|
||||||
{
|
{
|
||||||
if ( name.isEmpty() && id.isEmpty() )
|
if ( name.isEmpty() && id.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -125,6 +136,25 @@ PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantList
|
||||||
|
PackageListModel::getNetinstallDataForNames( const QStringList& ids ) const
|
||||||
|
{
|
||||||
|
QVariantList l;
|
||||||
|
for ( auto& p : m_packages )
|
||||||
|
{
|
||||||
|
if ( ids.contains( p.id ) )
|
||||||
|
{
|
||||||
|
if ( !p.netinstallData.isEmpty() )
|
||||||
|
{
|
||||||
|
QVariantMap newData = p.netinstallData;
|
||||||
|
newData[ "source" ] = QStringLiteral( "packageChooser" );
|
||||||
|
l.append( newData );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PackageListModel::rowCount( const QModelIndex& index ) const
|
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@ struct PackageItem
|
|||||||
CalamaresUtils::Locale::TranslatedString description;
|
CalamaresUtils::Locale::TranslatedString description;
|
||||||
QPixmap screenshot;
|
QPixmap screenshot;
|
||||||
QStringList packageNames;
|
QStringList packageNames;
|
||||||
|
QVariantMap netinstallData;
|
||||||
|
|
||||||
/// @brief Create blank PackageItem
|
/// @brief Create blank PackageItem
|
||||||
PackageItem();
|
PackageItem();
|
||||||
@ -111,6 +112,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
||||||
|
|
||||||
|
/** @brief Does a name lookup (based on id) and returns the netinstall data
|
||||||
|
*
|
||||||
|
* If there is a package with an id in @p ids, returns their netinstall data
|
||||||
|
*
|
||||||
|
* returns a list of netinstall data or an emply list if none is found
|
||||||
|
*/
|
||||||
|
QVariantList getNetinstallDataForNames( const QStringList& ids ) const;
|
||||||
|
|
||||||
enum Roles : int
|
enum Roles : int
|
||||||
{
|
{
|
||||||
NameRole = Qt::DisplayRole,
|
NameRole = Qt::DisplayRole,
|
||||||
|
@ -33,6 +33,15 @@ mode: required
|
|||||||
# in the `exec` section. These package settings will then be handed
|
# in the `exec` section. These package settings will then be handed
|
||||||
# off to whatever package manager is configured there.
|
# off to whatever package manager is configured there.
|
||||||
#
|
#
|
||||||
|
# - "netinstall-select"
|
||||||
|
# When this is set, the id(s) selected are passed to the netinstall module.
|
||||||
|
# Any id that matches a group name in that module is set to checked
|
||||||
|
#
|
||||||
|
# - "netinstall-add"
|
||||||
|
# With this method, the packagechooser module is used to add groups to the
|
||||||
|
# netinstall module. For this to hav=e any effect. You must set netinstall,
|
||||||
|
# which is described below.
|
||||||
|
#
|
||||||
# There is no need to put this module in the `exec` section. There
|
# There is no need to put this module in the `exec` section. There
|
||||||
# are no jobs that this module provides. You should put **other**
|
# are no jobs that this module provides. You should put **other**
|
||||||
# modules, either *contextualprocess* or *packages* or some custom
|
# modules, either *contextualprocess* or *packages* or some custom
|
||||||
@ -101,13 +110,19 @@ labels:
|
|||||||
# an additional attempt is made to load the image from the **branding**
|
# an additional attempt is made to load the image from the **branding**
|
||||||
# directory.
|
# directory.
|
||||||
#
|
#
|
||||||
# The following field is **optional** for an item:
|
# The following fields are **optional** for an item:
|
||||||
#
|
#
|
||||||
# - *packages* :
|
# - *packages* :
|
||||||
# List of package names for the product. If using the *method*
|
# List of package names for the product. If using the *method*
|
||||||
# "packages", consider this item mandatory (because otherwise
|
# "packages", consider this item mandatory (because otherwise
|
||||||
# selecting the item would install no packages).
|
# selecting the item would install no packages).
|
||||||
#
|
#
|
||||||
|
# - *netinstall* :
|
||||||
|
# The data in this field should follow the format of a group
|
||||||
|
# from the netinstall module documented in
|
||||||
|
# src/modules/netinstall/netinstall.conf. This is only used
|
||||||
|
# when method is set to "netinstall-add"
|
||||||
|
#
|
||||||
# # AppData Items #
|
# # AppData Items #
|
||||||
#
|
#
|
||||||
# For data provided by AppData XML: the item has an *appdata*
|
# For data provided by AppData XML: the item has an *appdata*
|
||||||
|
@ -382,7 +382,7 @@ class PMPacman(PackageManager):
|
|||||||
|
|
||||||
def line_cb(line):
|
def line_cb(line):
|
||||||
if line.startswith(":: "):
|
if line.startswith(":: "):
|
||||||
self.in_package_changes = "package changes" in line
|
self.in_package_changes = "package" in line or "hooks" in line
|
||||||
else:
|
else:
|
||||||
if self.in_package_changes and line.endswith("...\n"):
|
if self.in_package_changes and line.endswith("...\n"):
|
||||||
# Update the message, untranslated; do not change the
|
# Update the message, untranslated; do not change the
|
||||||
@ -444,8 +444,12 @@ class PMPacman(PackageManager):
|
|||||||
else:
|
else:
|
||||||
command.append("-S")
|
command.append("-S")
|
||||||
|
|
||||||
|
# Don't ask for user intervention, take the default action
|
||||||
command.append("--noconfirm")
|
command.append("--noconfirm")
|
||||||
|
|
||||||
|
# Don't report download progress for each file
|
||||||
|
command.append("--noprogressbar")
|
||||||
|
|
||||||
if self.pacman_needed_only is True:
|
if self.pacman_needed_only is True:
|
||||||
command.append("--needed")
|
command.append("--needed")
|
||||||
|
|
||||||
|
@ -345,6 +345,11 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
if ( !m_swapChoices.contains( m_initialSwapChoice ) )
|
if ( !m_swapChoices.contains( m_initialSwapChoice ) )
|
||||||
{
|
{
|
||||||
cWarning() << "Configuration for *initialSwapChoice* is not one of the *userSwapChoices*";
|
cWarning() << "Configuration for *initialSwapChoice* is not one of the *userSwapChoices*";
|
||||||
|
if ( nameFound )
|
||||||
|
{
|
||||||
|
cWarning() << Logger::SubEntry << "Choice" << swapChoiceNames().find( m_initialSwapChoice ) << "added.";
|
||||||
|
m_swapChoices.insert( m_initialSwapChoice );
|
||||||
|
}
|
||||||
m_initialSwapChoice = pickOne( m_swapChoices );
|
m_initialSwapChoice = pickOne( m_swapChoices );
|
||||||
}
|
}
|
||||||
setSwapChoice( m_initialSwapChoice );
|
setSwapChoice( m_initialSwapChoice );
|
||||||
|
@ -675,7 +675,11 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
// because it could take a while. Then when it's done, we can set up the widgets
|
// because it could take a while. Then when it's done, we can set up the widgets
|
||||||
// and remove the spinner.
|
// and remove the spinner.
|
||||||
m_future = new QFutureWatcher< void >();
|
m_future = new QFutureWatcher< void >();
|
||||||
connect( m_future, &QFutureWatcher< void >::finished, this, [this] {
|
connect( m_future,
|
||||||
|
&QFutureWatcher< void >::finished,
|
||||||
|
this,
|
||||||
|
[ this ]
|
||||||
|
{
|
||||||
continueLoading();
|
continueLoading();
|
||||||
this->m_future->deleteLater();
|
this->m_future->deleteLater();
|
||||||
this->m_future = nullptr;
|
this->m_future = nullptr;
|
||||||
|
@ -41,6 +41,10 @@ hasRootPartition( Device* device )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Check if @p path holds an iso9660 filesystem
|
||||||
|
*
|
||||||
|
* The @p path should point to a device; blkid is used to check the FS type.
|
||||||
|
*/
|
||||||
static bool
|
static bool
|
||||||
blkIdCheckIso9660( const QString& path )
|
blkIdCheckIso9660( const QString& path )
|
||||||
{
|
{
|
||||||
@ -49,6 +53,18 @@ blkIdCheckIso9660( const QString& path )
|
|||||||
return r.getOutput().contains( "iso9660" );
|
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
|
static bool
|
||||||
isIso9660( const Device* device )
|
isIso9660( const Device* device )
|
||||||
{
|
{
|
||||||
@ -64,13 +80,8 @@ isIso9660( const Device* device )
|
|||||||
|
|
||||||
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
|
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
|
||||||
{
|
{
|
||||||
for ( const Partition* partition : device->partitionTable()->children() )
|
const auto& p = device->partitionTable()->children();
|
||||||
{
|
return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P );
|
||||||
if ( blkIdCheckIso9660( partition->partitionPath() ) )
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
static void
|
static void
|
||||||
sortDevices( DeviceModel::DeviceList& l )
|
sortDevices( DeviceModel::DeviceList& l )
|
||||||
{
|
{
|
||||||
std::sort( l.begin(), l.end(), []( const Device* dev1, const Device* dev2 ) {
|
std::sort( l.begin(),
|
||||||
return dev1->deviceNode() < dev2->deviceNode();
|
l.end(),
|
||||||
} );
|
[]( const Device* dev1, const Device* dev2 ) { return dev1->deviceNode() < dev2->deviceNode(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceModel::DeviceModel( QObject* parent )
|
DeviceModel::DeviceModel( QObject* parent )
|
||||||
|
@ -262,9 +262,7 @@ PartitionCoreModule::doInit()
|
|||||||
// Gives ownership of the Device* to the DeviceInfo object
|
// Gives ownership of the Device* to the DeviceInfo object
|
||||||
auto deviceInfo = new DeviceInfo( device );
|
auto deviceInfo = new DeviceInfo( device );
|
||||||
m_deviceInfos << deviceInfo;
|
m_deviceInfos << deviceInfo;
|
||||||
cDebug() << Logger::SubEntry
|
cDebug() << Logger::SubEntry << device->deviceNode() << device->capacity()
|
||||||
<< device->deviceNode()
|
|
||||||
<< device->capacity()
|
|
||||||
<< Logger::RedactedName( "DevName", device->name() )
|
<< Logger::RedactedName( "DevName", device->name() )
|
||||||
<< Logger::RedactedName( "DevNamePretty", device->prettyName() );
|
<< Logger::RedactedName( "DevNamePretty", device->prettyName() );
|
||||||
}
|
}
|
||||||
@ -685,9 +683,8 @@ PartitionCoreModule::lvmPVs() const
|
|||||||
bool
|
bool
|
||||||
PartitionCoreModule::hasVGwithThisName( const QString& name ) const
|
PartitionCoreModule::hasVGwithThisName( const QString& name ) const
|
||||||
{
|
{
|
||||||
auto condition = [name]( DeviceInfo* d ) {
|
auto condition = [ name ]( DeviceInfo* d )
|
||||||
return dynamic_cast< LvmDevice* >( d->device.data() ) && d->device.data()->name() == name;
|
{ return dynamic_cast< LvmDevice* >( d->device.data() ) && d->device.data()->name() == name; };
|
||||||
};
|
|
||||||
|
|
||||||
return std::find_if( m_deviceInfos.begin(), m_deviceInfos.end(), condition ) != m_deviceInfos.end();
|
return std::find_if( m_deviceInfos.begin(), m_deviceInfos.end(), condition ) != m_deviceInfos.end();
|
||||||
}
|
}
|
||||||
@ -695,7 +692,8 @@ PartitionCoreModule::hasVGwithThisName( const QString& name ) const
|
|||||||
bool
|
bool
|
||||||
PartitionCoreModule::isInVG( const Partition* partition ) const
|
PartitionCoreModule::isInVG( const Partition* partition ) const
|
||||||
{
|
{
|
||||||
auto condition = [partition]( DeviceInfo* d ) {
|
auto condition = [ partition ]( DeviceInfo* d )
|
||||||
|
{
|
||||||
LvmDevice* vg = dynamic_cast< LvmDevice* >( d->device.data() );
|
LvmDevice* vg = dynamic_cast< LvmDevice* >( d->device.data() );
|
||||||
return vg && vg->physicalVolumes().contains( partition );
|
return vg && vg->physicalVolumes().contains( partition );
|
||||||
};
|
};
|
||||||
@ -1089,7 +1087,11 @@ void
|
|||||||
PartitionCoreModule::asyncRevertDevice( Device* dev, std::function< void() > callback )
|
PartitionCoreModule::asyncRevertDevice( Device* dev, std::function< void() > callback )
|
||||||
{
|
{
|
||||||
QFutureWatcher< void >* watcher = new QFutureWatcher< void >();
|
QFutureWatcher< void >* watcher = new QFutureWatcher< void >();
|
||||||
connect( watcher, &QFutureWatcher< void >::finished, this, [watcher, callback] {
|
connect( watcher,
|
||||||
|
&QFutureWatcher< void >::finished,
|
||||||
|
this,
|
||||||
|
[ watcher, callback ]
|
||||||
|
{
|
||||||
callback();
|
callback();
|
||||||
watcher->deleteLater();
|
watcher->deleteLater();
|
||||||
} );
|
} );
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
* to bother with one-byte accuracy (and anyway, a double has at least 50 bits
|
* to bother with one-byte accuracy (and anyway, a double has at least 50 bits
|
||||||
* at which point we're printing giga (or gibi) bytes).
|
* at which point we're printing giga (or gibi) bytes).
|
||||||
*/
|
*/
|
||||||
static inline QString formatByteSize( qint64 sizeValue )
|
static inline QString
|
||||||
|
formatByteSize( qint64 sizeValue )
|
||||||
{
|
{
|
||||||
return Capacity::formatByteSize( static_cast< double >( sizeValue ) );
|
return Capacity::formatByteSize( static_cast< double >( sizeValue ) );
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,11 @@ ChoicePage::init( PartitionCoreModule* core )
|
|||||||
|
|
||||||
|
|
||||||
// We need to do this because a PCM revert invalidates the deviceModel.
|
// We need to do this because a PCM revert invalidates the deviceModel.
|
||||||
connect( core, &PartitionCoreModule::reverted, this, [=] {
|
connect( core,
|
||||||
|
&PartitionCoreModule::reverted,
|
||||||
|
this,
|
||||||
|
[ = ]
|
||||||
|
{
|
||||||
setModelToComboBox( m_drivesCombo, core->deviceModel() );
|
setModelToComboBox( m_drivesCombo, core->deviceModel() );
|
||||||
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex );
|
||||||
} );
|
} );
|
||||||
@ -303,7 +307,11 @@ ChoicePage::setupChoices()
|
|||||||
#else
|
#else
|
||||||
auto buttonSignal = &QButtonGroup::idToggled;
|
auto buttonSignal = &QButtonGroup::idToggled;
|
||||||
#endif
|
#endif
|
||||||
connect( m_grp, buttonSignal, this, [this]( int id, bool checked ) {
|
connect( m_grp,
|
||||||
|
buttonSignal,
|
||||||
|
this,
|
||||||
|
[ this ]( int id, bool checked )
|
||||||
|
{
|
||||||
if ( checked ) // An action was picked.
|
if ( checked ) // An action was picked.
|
||||||
{
|
{
|
||||||
m_config->setInstallChoice( id );
|
m_config->setInstallChoice( id );
|
||||||
@ -401,7 +409,9 @@ ChoicePage::applyDeviceChoice()
|
|||||||
if ( m_core->isDirty() )
|
if ( m_core->isDirty() )
|
||||||
{
|
{
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run( [=] {
|
QtConcurrent::run(
|
||||||
|
[ = ]
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_coreMutex );
|
QMutexLocker locker( &m_coreMutex );
|
||||||
m_core->revertAllDevices();
|
m_core->revertAllDevices();
|
||||||
} ),
|
} ),
|
||||||
@ -493,11 +503,14 @@ ChoicePage::applyActionChoice( InstallChoice choice )
|
|||||||
if ( m_core->isDirty() )
|
if ( m_core->isDirty() )
|
||||||
{
|
{
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run( [=] {
|
QtConcurrent::run(
|
||||||
|
[ = ]
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_coreMutex );
|
QMutexLocker locker( &m_coreMutex );
|
||||||
m_core->revertDevice( selectedDevice() );
|
m_core->revertDevice( selectedDevice() );
|
||||||
} ),
|
} ),
|
||||||
[=] {
|
[ = ]
|
||||||
|
{
|
||||||
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
PartitionActions::doAutopartition( m_core, selectedDevice(), options );
|
||||||
Q_EMIT deviceChosen();
|
Q_EMIT deviceChosen();
|
||||||
},
|
},
|
||||||
@ -514,7 +527,9 @@ ChoicePage::applyActionChoice( InstallChoice choice )
|
|||||||
if ( m_core->isDirty() )
|
if ( m_core->isDirty() )
|
||||||
{
|
{
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run( [=] {
|
QtConcurrent::run(
|
||||||
|
[ = ]
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_coreMutex );
|
QMutexLocker locker( &m_coreMutex );
|
||||||
m_core->revertDevice( selectedDevice() );
|
m_core->revertDevice( selectedDevice() );
|
||||||
} ),
|
} ),
|
||||||
@ -532,11 +547,14 @@ ChoicePage::applyActionChoice( InstallChoice choice )
|
|||||||
if ( m_core->isDirty() )
|
if ( m_core->isDirty() )
|
||||||
{
|
{
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run( [=] {
|
QtConcurrent::run(
|
||||||
|
[ = ]
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_coreMutex );
|
QMutexLocker locker( &m_coreMutex );
|
||||||
m_core->revertDevice( selectedDevice() );
|
m_core->revertDevice( selectedDevice() );
|
||||||
} ),
|
} ),
|
||||||
[this] {
|
[ this ]
|
||||||
|
{
|
||||||
// We need to reupdate after reverting because the splitter widget is
|
// We need to reupdate after reverting because the splitter widget is
|
||||||
// not a true view.
|
// not a true view.
|
||||||
updateActionChoicePreview( m_config->installChoice() );
|
updateActionChoicePreview( m_config->installChoice() );
|
||||||
@ -772,7 +790,8 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current )
|
|||||||
|
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run(
|
QtConcurrent::run(
|
||||||
[this, current, homePartitionPath]( bool doReuseHomePartition ) {
|
[ this, current, homePartitionPath ]( bool doReuseHomePartition )
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_coreMutex );
|
QMutexLocker locker( &m_coreMutex );
|
||||||
|
|
||||||
if ( m_core->isDirty() )
|
if ( m_core->isDirty() )
|
||||||
@ -853,7 +872,8 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current )
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
m_reuseHomeCheckBox->isChecked() ),
|
m_reuseHomeCheckBox->isChecked() ),
|
||||||
[this, homePartitionPath] {
|
[ this, homePartitionPath ]
|
||||||
|
{
|
||||||
m_reuseHomeCheckBox->setVisible( !homePartitionPath->isEmpty() );
|
m_reuseHomeCheckBox->setVisible( !homePartitionPath->isEmpty() );
|
||||||
if ( !homePartitionPath->isEmpty() )
|
if ( !homePartitionPath->isEmpty() )
|
||||||
m_reuseHomeCheckBox->setText( tr( "Reuse %1 as home partition for %2." )
|
m_reuseHomeCheckBox->setText( tr( "Reuse %1 as home partition for %2." )
|
||||||
@ -1006,7 +1026,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
|||||||
connect( m_afterPartitionSplitterWidget,
|
connect( m_afterPartitionSplitterWidget,
|
||||||
&PartitionSplitterWidget::partitionResized,
|
&PartitionSplitterWidget::partitionResized,
|
||||||
this,
|
this,
|
||||||
[this, sizeLabel]( const QString& path, qint64 size, qint64 sizeNext ) {
|
[ this, sizeLabel ]( const QString& path, qint64 size, qint64 sizeNext )
|
||||||
|
{
|
||||||
Q_UNUSED( path )
|
Q_UNUSED( path )
|
||||||
sizeLabel->setText(
|
sizeLabel->setText(
|
||||||
tr( "%1 will be shrunk to %2MiB and a new "
|
tr( "%1 will be shrunk to %2MiB and a new "
|
||||||
@ -1020,7 +1041,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
|||||||
m_previewAfterFrame->show();
|
m_previewAfterFrame->show();
|
||||||
m_previewAfterLabel->show();
|
m_previewAfterLabel->show();
|
||||||
|
|
||||||
SelectionFilter filter = []( const QModelIndex& index ) {
|
SelectionFilter filter = []( const QModelIndex& index )
|
||||||
|
{
|
||||||
return PartUtils::canBeResized(
|
return PartUtils::canBeResized(
|
||||||
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ),
|
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ),
|
||||||
Logger::Once() );
|
Logger::Once() );
|
||||||
@ -1069,17 +1091,22 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
|||||||
eraseBootloaderLabel->setText( tr( "Boot loader location:" ) );
|
eraseBootloaderLabel->setText( tr( "Boot loader location:" ) );
|
||||||
|
|
||||||
m_bootloaderComboBox = createBootloaderComboBox( eraseWidget );
|
m_bootloaderComboBox = createBootloaderComboBox( eraseWidget );
|
||||||
connect( m_core->bootLoaderModel(), &QAbstractItemModel::modelReset, [this]() {
|
connect( m_core->bootLoaderModel(),
|
||||||
|
&QAbstractItemModel::modelReset,
|
||||||
|
[ this ]()
|
||||||
|
{
|
||||||
if ( !m_bootloaderComboBox.isNull() )
|
if ( !m_bootloaderComboBox.isNull() )
|
||||||
{
|
{
|
||||||
Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox, m_core->bootLoaderInstallPath() );
|
Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox,
|
||||||
|
m_core->bootLoaderInstallPath() );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
connect(
|
connect(
|
||||||
m_core,
|
m_core,
|
||||||
&PartitionCoreModule::deviceReverted,
|
&PartitionCoreModule::deviceReverted,
|
||||||
this,
|
this,
|
||||||
[this]( Device* dev ) {
|
[ this ]( Device* dev )
|
||||||
|
{
|
||||||
Q_UNUSED( dev )
|
Q_UNUSED( dev )
|
||||||
if ( !m_bootloaderComboBox.isNull() )
|
if ( !m_bootloaderComboBox.isNull() )
|
||||||
{
|
{
|
||||||
@ -1110,7 +1137,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SelectionFilter filter = []( const QModelIndex& index ) {
|
SelectionFilter filter = []( const QModelIndex& index )
|
||||||
|
{
|
||||||
return PartUtils::canBeReplaced(
|
return PartUtils::canBeReplaced(
|
||||||
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ),
|
static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ),
|
||||||
Logger::Once() );
|
Logger::Once() );
|
||||||
@ -1217,7 +1245,11 @@ ChoicePage::createBootloaderComboBox( QWidget* parent )
|
|||||||
comboForBootloader->setModel( m_core->bootLoaderModel() );
|
comboForBootloader->setModel( m_core->bootLoaderModel() );
|
||||||
|
|
||||||
// When the chosen bootloader device changes, we update the choice in the PCM
|
// When the chosen bootloader device changes, we update the choice in the PCM
|
||||||
connect( comboForBootloader, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, [this]( int newIndex ) {
|
connect( comboForBootloader,
|
||||||
|
QOverload< int >::of( &QComboBox::currentIndexChanged ),
|
||||||
|
this,
|
||||||
|
[ this ]( int newIndex )
|
||||||
|
{
|
||||||
QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() );
|
QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() );
|
||||||
if ( bootloaderCombo )
|
if ( bootloaderCombo )
|
||||||
{
|
{
|
||||||
|
@ -325,16 +325,10 @@ CreatePartitionDialog::updateMountPointUi()
|
|||||||
void
|
void
|
||||||
CreatePartitionDialog::checkMountPointSelection()
|
CreatePartitionDialog::checkMountPointSelection()
|
||||||
{
|
{
|
||||||
if ( m_usedMountPoints.contains( selectedMountPoint( m_ui->mountPointComboBox ) ) )
|
validateMountPoint( selectedMountPoint( m_ui->mountPointComboBox ),
|
||||||
{
|
m_usedMountPoints,
|
||||||
m_ui->labelMountPoint->setText( tr( "Mountpoint already in use. Please select another one." ) );
|
m_ui->mountPointExplanation,
|
||||||
m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
|
m_ui->buttonBox->button( QDialogButtonBox::Ok ) );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->labelMountPoint->setText( QString() );
|
|
||||||
m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( true );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -68,7 +68,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="primaryRadioButton">
|
<widget class="QRadioButton" name="primaryRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Primary</string>
|
<string>Primar&y</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -171,6 +171,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QComboBox" name="mountPointComboBox">
|
<widget class="QComboBox" name="mountPointComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="editable">
|
<property name="editable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -179,21 +185,14 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="1">
|
<item row="12" column="0">
|
||||||
<widget class="QLabel" name="labelMountPoint">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="11" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Flags:</string>
|
<string>Flags:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="1">
|
<item row="12" column="1">
|
||||||
<widget class="QListWidget" name="m_listFlags">
|
<widget class="QListWidget" name="m_listFlags">
|
||||||
<property name="alternatingRowColors">
|
<property name="alternatingRowColors">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -206,7 +205,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="0">
|
<item row="13" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -219,14 +218,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QLineEdit" name="filesystemLabelEdit">
|
<widget class="QLineEdit" name="filesystemLabelEdit">
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>150</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Label for the filesystem</string>
|
<string>Label for the filesystem</string>
|
||||||
</property>
|
</property>
|
||||||
@ -235,13 +228,20 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0">
|
<item row="10" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>FS Label:</string>
|
<string>FS Label:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QLabel" name="mountPointExplanation">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -69,7 +69,10 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device,
|
|||||||
|
|
||||||
replacePartResizerWidget();
|
replacePartResizerWidget();
|
||||||
|
|
||||||
connect( m_ui->formatRadioButton, &QAbstractButton::toggled, [this]( bool doFormat ) {
|
connect( m_ui->formatRadioButton,
|
||||||
|
&QAbstractButton::toggled,
|
||||||
|
[ this ]( bool doFormat )
|
||||||
|
{
|
||||||
replacePartResizerWidget();
|
replacePartResizerWidget();
|
||||||
|
|
||||||
m_ui->fileSystemLabel->setEnabled( doFormat );
|
m_ui->fileSystemLabel->setEnabled( doFormat );
|
||||||
@ -295,14 +298,8 @@ EditExistingPartitionDialog::updateMountPointPicker()
|
|||||||
void
|
void
|
||||||
EditExistingPartitionDialog::checkMountPointSelection()
|
EditExistingPartitionDialog::checkMountPointSelection()
|
||||||
{
|
{
|
||||||
if ( m_usedMountPoints.contains( selectedMountPoint( m_ui->mountPointComboBox ) ) )
|
validateMountPoint( selectedMountPoint( m_ui->mountPointComboBox ),
|
||||||
{
|
m_usedMountPoints,
|
||||||
m_ui->labelMountPoint->setText( tr( "Mountpoint already in use. Please select another one." ) );
|
m_ui->mountPointExplanation,
|
||||||
m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
|
m_ui->buttonBox->button( QDialogButtonBox::Ok ) );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ui->labelMountPoint->setText( QString() );
|
|
||||||
m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( true );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Content:</string>
|
<string>Con&tent:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>keepRadioButton</cstring>
|
<cstring>keepRadioButton</cstring>
|
||||||
@ -109,6 +109,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QComboBox" name="mountPointComboBox">
|
<widget class="QComboBox" name="mountPointComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="editable">
|
<property name="editable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -147,14 +153,14 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<item row="5" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QComboBox" name="fileSystemComboBox"/>
|
<widget class="QComboBox" name="fileSystemComboBox"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0">
|
<item row="10" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Flags:</string>
|
<string>Flags:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QListWidget" name="m_listFlags">
|
<widget class="QListWidget" name="m_listFlags">
|
||||||
<property name="alternatingRowColors">
|
<property name="alternatingRowColors">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -168,20 +174,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QLabel" name="labelMountPoint">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="1">
|
|
||||||
<widget class="QLineEdit" name="fileSystemLabelEdit">
|
<widget class="QLineEdit" name="fileSystemLabelEdit">
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>150</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Label for the filesystem</string>
|
<string>Label for the filesystem</string>
|
||||||
</property>
|
</property>
|
||||||
@ -190,13 +183,20 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="8" column="0">
|
||||||
<widget class="QLabel" name="fileSystemLabelLabel">
|
<widget class="QLabel" name="fileSystemLabelLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>FS Label:</string>
|
<string>FS Label:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QLabel" name="mountPointExplanation">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -13,9 +13,27 @@
|
|||||||
|
|
||||||
#include "ui_EncryptWidget.h"
|
#include "ui_EncryptWidget.h"
|
||||||
|
|
||||||
|
#include "Branding.h"
|
||||||
#include "utils/CalamaresUtilsGui.h"
|
#include "utils/CalamaresUtilsGui.h"
|
||||||
#include "utils/Retranslator.h"
|
#include "utils/Retranslator.h"
|
||||||
|
|
||||||
|
/** @brief Does this system support whole-disk encryption?
|
||||||
|
*
|
||||||
|
* Returns @c true if the system is likely to support encryption
|
||||||
|
* with sufficient performance to be usable. A machine that can't
|
||||||
|
* doe hardware-assisted AES is **probably** too slow, so we could
|
||||||
|
* warn the user that ticking the "encrypt system" box is a bad
|
||||||
|
* idea.
|
||||||
|
*
|
||||||
|
* Since we don't have an oracle that can answer that question,
|
||||||
|
* just pretend every system can do it.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
systemSupportsEncryptionAcceptably()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
EncryptWidget::EncryptWidget( QWidget* parent )
|
EncryptWidget::EncryptWidget( QWidget* parent )
|
||||||
: QWidget( parent )
|
: QWidget( parent )
|
||||||
, m_ui( new Ui::EncryptWidget )
|
, m_ui( new Ui::EncryptWidget )
|
||||||
@ -27,6 +45,18 @@ EncryptWidget::EncryptWidget( QWidget* parent )
|
|||||||
m_ui->m_passphraseLineEdit->hide();
|
m_ui->m_passphraseLineEdit->hide();
|
||||||
m_ui->m_confirmLineEdit->hide();
|
m_ui->m_confirmLineEdit->hide();
|
||||||
m_ui->m_iconLabel->hide();
|
m_ui->m_iconLabel->hide();
|
||||||
|
// TODO: this deserves better rendering, an icon or something, but that will
|
||||||
|
// depend on having a non-bogus implementation of systemSupportsEncryptionAcceptably
|
||||||
|
if ( systemSupportsEncryptionAcceptably() )
|
||||||
|
{
|
||||||
|
m_ui->m_encryptionUnsupportedLabel->hide();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is really ugly, but the character is unicode "unlocked"
|
||||||
|
m_ui->m_encryptionUnsupportedLabel->setText( QStringLiteral( "🔓" ) );
|
||||||
|
m_ui->m_encryptionUnsupportedLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
connect( m_ui->m_encryptCheckBox, &QCheckBox::stateChanged, this, &EncryptWidget::onCheckBoxStateChanged );
|
connect( m_ui->m_encryptCheckBox, &QCheckBox::stateChanged, this, &EncryptWidget::onCheckBoxStateChanged );
|
||||||
connect( m_ui->m_passphraseLineEdit, &QLineEdit::textEdited, this, &EncryptWidget::onPassphraseEdited );
|
connect( m_ui->m_passphraseLineEdit, &QLineEdit::textEdited, this, &EncryptWidget::onPassphraseEdited );
|
||||||
|
@ -37,6 +37,19 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="m_encryptionUnsupportedLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Your system does not seem to support encryption well enough to encrypt the entire system. You may enable encryption, but performance may suffer.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">🔓</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="m_passphraseLineEdit">
|
<widget class="QLineEdit" name="m_passphraseLineEdit">
|
||||||
<property name="echoMode">
|
<property name="echoMode">
|
||||||
@ -57,6 +70,19 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="m_iconLabel">
|
<widget class="QLabel" name="m_iconLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -54,9 +54,10 @@ PartitionBarsView::PartitionBarsView( QWidget* parent )
|
|||||||
setSelectionMode( QAbstractItemView::SingleSelection );
|
setSelectionMode( QAbstractItemView::SingleSelection );
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
connect( this, &PartitionBarsView::clicked, this, [=]( const QModelIndex& index ) {
|
connect( this,
|
||||||
cDebug() << "Clicked row" << index.row();
|
&PartitionBarsView::clicked,
|
||||||
} );
|
this,
|
||||||
|
[ = ]( const QModelIndex& index ) { cDebug() << "Clicked row" << index.row(); } );
|
||||||
setMouseTracking( true );
|
setMouseTracking( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +411,8 @@ PartitionBarsView::setSelectionFilter( std::function< bool( const QModelIndex& )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QModelIndex PartitionBarsView::moveCursor( CursorAction, Qt::KeyboardModifiers )
|
QModelIndex
|
||||||
|
PartitionBarsView::moveCursor( CursorAction, Qt::KeyboardModifiers )
|
||||||
{
|
{
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,17 @@
|
|||||||
#include "PartitionDialogHelpers.h"
|
#include "PartitionDialogHelpers.h"
|
||||||
|
|
||||||
#include "core/PartUtils.h"
|
#include "core/PartUtils.h"
|
||||||
|
#include "gui/CreatePartitionDialog.h"
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
QStringList
|
QStringList
|
||||||
standardMountPoints()
|
standardMountPoints()
|
||||||
@ -37,7 +41,7 @@ void
|
|||||||
standardMountPoints( QComboBox& combo )
|
standardMountPoints( QComboBox& combo )
|
||||||
{
|
{
|
||||||
combo.clear();
|
combo.clear();
|
||||||
combo.addItem( QObject::tr( "(no mount point)" ) );
|
combo.lineEdit()->setPlaceholderText( QObject::tr( "(no mount point)" ) );
|
||||||
combo.addItems( standardMountPoints() );
|
combo.addItems( standardMountPoints() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +55,6 @@ standardMountPoints( QComboBox& combo, const QString& selected )
|
|||||||
QString
|
QString
|
||||||
selectedMountPoint( QComboBox& combo )
|
selectedMountPoint( QComboBox& combo )
|
||||||
{
|
{
|
||||||
if ( combo.currentIndex() == 0 )
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
return combo.currentText();
|
return combo.currentText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ setSelectedMountPoint( QComboBox& combo, const QString& selected )
|
|||||||
{
|
{
|
||||||
if ( selected.isEmpty() )
|
if ( selected.isEmpty() )
|
||||||
{
|
{
|
||||||
combo.setCurrentIndex( 0 ); // (no mount point)
|
combo.setCurrentIndex( -1 ); // (no mount point)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -80,6 +80,34 @@ setSelectedMountPoint( QComboBox& combo, const QString& selected )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
validateMountPoint( const QString& mountPoint, const QStringList& inUse, QLabel* label, QPushButton* button )
|
||||||
|
{
|
||||||
|
QString msg;
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
if ( inUse.contains( mountPoint ) )
|
||||||
|
{
|
||||||
|
msg = CreatePartitionDialog::tr( "Mountpoint already in use. Please select another one." );
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
else if ( !mountPoint.isEmpty() && !mountPoint.startsWith( '/' ) )
|
||||||
|
{
|
||||||
|
msg = CreatePartitionDialog::tr( "Mountpoint must start with a <tt>/</tt>." );
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( label )
|
||||||
|
{
|
||||||
|
label->setText( msg );
|
||||||
|
}
|
||||||
|
if ( button )
|
||||||
|
{
|
||||||
|
button->setEnabled( ok );
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PartitionTable::Flags
|
PartitionTable::Flags
|
||||||
flagsFromList( const QListWidget& list )
|
flagsFromList( const QListWidget& list )
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
class QLabel;
|
||||||
class QListWidget;
|
class QListWidget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,6 +60,16 @@ setSelectedMountPoint( QComboBox* combo, const QString& selected )
|
|||||||
setSelectedMountPoint( *combo, selected );
|
setSelectedMountPoint( *combo, selected );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Validate a @p mountPoint and adjust the UI
|
||||||
|
*
|
||||||
|
* If @p mountPoint is valid -- unused and starts with a /, for instance --
|
||||||
|
* then the button is enabled, label is cleared, and returns @c true.
|
||||||
|
*
|
||||||
|
* If it is not valid, returns @c false and sets the UI
|
||||||
|
* to explain why.
|
||||||
|
*/
|
||||||
|
bool validateMountPoint( const QString& mountPoint, const QStringList& inUse, QLabel* label, QPushButton* button );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the flags that have been checked in the list widget.
|
* Get the flags that have been checked in the list widget.
|
||||||
*/
|
*/
|
||||||
|
@ -451,7 +451,9 @@ void
|
|||||||
PartitionPage::onRevertClicked()
|
PartitionPage::onRevertClicked()
|
||||||
{
|
{
|
||||||
ScanningDialog::run(
|
ScanningDialog::run(
|
||||||
QtConcurrent::run( [this] {
|
QtConcurrent::run(
|
||||||
|
[ this ]
|
||||||
|
{
|
||||||
QMutexLocker locker( &m_revertMutex );
|
QMutexLocker locker( &m_revertMutex );
|
||||||
|
|
||||||
int oldIndex = m_ui->deviceComboBox->currentIndex();
|
int oldIndex = m_ui->deviceComboBox->currentIndex();
|
||||||
@ -459,7 +461,8 @@ PartitionPage::onRevertClicked()
|
|||||||
m_ui->deviceComboBox->setCurrentIndex( ( oldIndex < 0 ) ? 0 : oldIndex );
|
m_ui->deviceComboBox->setCurrentIndex( ( oldIndex < 0 ) ? 0 : oldIndex );
|
||||||
updateFromCurrentDevice();
|
updateFromCurrentDevice();
|
||||||
} ),
|
} ),
|
||||||
[this] {
|
[ this ]
|
||||||
|
{
|
||||||
m_lastSelectedBootLoaderIndex = -1;
|
m_lastSelectedBootLoaderIndex = -1;
|
||||||
if ( m_ui->bootLoaderComboBox->currentIndex() < 0 )
|
if ( m_ui->bootLoaderComboBox->currentIndex() < 0 )
|
||||||
{
|
{
|
||||||
@ -606,7 +609,8 @@ PartitionPage::updateFromCurrentDevice()
|
|||||||
m_ui->partitionBarsView->selectionModel(),
|
m_ui->partitionBarsView->selectionModel(),
|
||||||
&QItemSelectionModel::currentChanged,
|
&QItemSelectionModel::currentChanged,
|
||||||
this,
|
this,
|
||||||
[=] {
|
[ = ]
|
||||||
|
{
|
||||||
QModelIndex selectedIndex = m_ui->partitionBarsView->selectionModel()->currentIndex();
|
QModelIndex selectedIndex = m_ui->partitionBarsView->selectionModel()->currentIndex();
|
||||||
selectedIndex = selectedIndex.sibling( selectedIndex.row(), 0 );
|
selectedIndex = selectedIndex.sibling( selectedIndex.row(), 0 );
|
||||||
m_ui->partitionBarsView->setCurrentIndex( selectedIndex );
|
m_ui->partitionBarsView->setCurrentIndex( selectedIndex );
|
||||||
|
@ -159,7 +159,9 @@ PartitionSplitterWidget::setSplitPartition( const QString& path, qint64 minSize,
|
|||||||
m_itemToResizePath.clear();
|
m_itemToResizePath.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
PartitionSplitterItem itemToResize = _findItem( m_items, [path]( PartitionSplitterItem& item ) -> bool {
|
PartitionSplitterItem itemToResize = _findItem( m_items,
|
||||||
|
[ path ]( PartitionSplitterItem& item ) -> bool
|
||||||
|
{
|
||||||
if ( path == item.itemPath )
|
if ( path == item.itemPath )
|
||||||
{
|
{
|
||||||
item.status = PartitionSplitterItem::Resizing;
|
item.status = PartitionSplitterItem::Resizing;
|
||||||
@ -184,7 +186,9 @@ PartitionSplitterWidget::setSplitPartition( const QString& path, qint64 minSize,
|
|||||||
|
|
||||||
qint64 newSize = m_itemToResize.size - preferredSize;
|
qint64 newSize = m_itemToResize.size - preferredSize;
|
||||||
m_itemToResize.size = preferredSize;
|
m_itemToResize.size = preferredSize;
|
||||||
int opCount = _eachItem( m_items, [preferredSize]( PartitionSplitterItem& item ) -> bool {
|
int opCount = _eachItem( m_items,
|
||||||
|
[ preferredSize ]( PartitionSplitterItem& item ) -> bool
|
||||||
|
{
|
||||||
if ( item.status == PartitionSplitterItem::Resizing )
|
if ( item.status == PartitionSplitterItem::Resizing )
|
||||||
{
|
{
|
||||||
item.size = preferredSize;
|
item.size = preferredSize;
|
||||||
@ -358,7 +362,9 @@ PartitionSplitterWidget::mouseMoveEvent( QMouseEvent* event )
|
|||||||
|
|
||||||
m_itemToResize.size = qRound64( span * percent );
|
m_itemToResize.size = qRound64( span * percent );
|
||||||
m_itemToResizeNext.size -= m_itemToResize.size - oldsize;
|
m_itemToResizeNext.size -= m_itemToResize.size - oldsize;
|
||||||
_eachItem( m_items, [this]( PartitionSplitterItem& item ) -> bool {
|
_eachItem( m_items,
|
||||||
|
[ this ]( PartitionSplitterItem& item ) -> bool
|
||||||
|
{
|
||||||
if ( item.status == PartitionSplitterItem::Resizing )
|
if ( item.status == PartitionSplitterItem::Resizing )
|
||||||
{
|
{
|
||||||
item.size = m_itemToResize.size;
|
item.size = m_itemToResize.size;
|
||||||
|
@ -46,9 +46,10 @@ ReplaceWidget::ReplaceWidget( PartitionCoreModule* core, QComboBox* devicesCombo
|
|||||||
m_ui->bootStatusLabel->clear();
|
m_ui->bootStatusLabel->clear();
|
||||||
|
|
||||||
updateFromCurrentDevice( devicesComboBox );
|
updateFromCurrentDevice( devicesComboBox );
|
||||||
connect( devicesComboBox, &QComboBox::currentTextChanged, this, [=]( const QString& /* text */ ) {
|
connect( devicesComboBox,
|
||||||
updateFromCurrentDevice( devicesComboBox );
|
&QComboBox::currentTextChanged,
|
||||||
} );
|
this,
|
||||||
|
[ = ]( const QString& /* text */ ) { updateFromCurrentDevice( devicesComboBox ); } );
|
||||||
|
|
||||||
CALAMARES_RETRANSLATE( onPartitionSelected(); );
|
CALAMARES_RETRANSLATE( onPartitionSelected(); );
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,11 @@ ScanningDialog::run( const QFuture< void >& future,
|
|||||||
theDialog->show();
|
theDialog->show();
|
||||||
|
|
||||||
QFutureWatcher< void >* watcher = new QFutureWatcher< void >();
|
QFutureWatcher< void >* watcher = new QFutureWatcher< void >();
|
||||||
connect( watcher, &QFutureWatcher< void >::finished, theDialog, [watcher, theDialog, callback] {
|
connect( watcher,
|
||||||
|
&QFutureWatcher< void >::finished,
|
||||||
|
theDialog,
|
||||||
|
[ watcher, theDialog, callback ]
|
||||||
|
{
|
||||||
watcher->deleteLater();
|
watcher->deleteLater();
|
||||||
theDialog->hide();
|
theDialog->hide();
|
||||||
theDialog->deleteLater();
|
theDialog->deleteLater();
|
||||||
|
@ -45,12 +45,20 @@ VolumeGroupBaseDialog::VolumeGroupBaseDialog( QString& vgName, QVector< const Pa
|
|||||||
updateOkButton();
|
updateOkButton();
|
||||||
updateTotalSize();
|
updateTotalSize();
|
||||||
|
|
||||||
connect( ui->pvList, &QListWidget::itemChanged, this, [&]( QListWidgetItem* ) {
|
connect( ui->pvList,
|
||||||
|
&QListWidget::itemChanged,
|
||||||
|
this,
|
||||||
|
[ & ]( QListWidgetItem* )
|
||||||
|
{
|
||||||
updateTotalSize();
|
updateTotalSize();
|
||||||
updateOkButton();
|
updateOkButton();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
connect( ui->peSize, qOverload< int >( &QSpinBox::valueChanged ), this, [&]( int ) {
|
connect( ui->peSize,
|
||||||
|
qOverload< int >( &QSpinBox::valueChanged ),
|
||||||
|
this,
|
||||||
|
[ & ]( int )
|
||||||
|
{
|
||||||
updateTotalSectors();
|
updateTotalSectors();
|
||||||
updateOkButton();
|
updateOkButton();
|
||||||
} );
|
} );
|
||||||
|
@ -26,7 +26,9 @@ Calamares::JobResult
|
|||||||
AutoMountManagementJob::exec()
|
AutoMountManagementJob::exec()
|
||||||
{
|
{
|
||||||
cVerbose() << "this" << Logger::Pointer( this ) << "value" << Logger::Pointer( m_stored )
|
cVerbose() << "this" << Logger::Pointer( this ) << "value" << Logger::Pointer( m_stored )
|
||||||
<< ( m_stored ? "restore" : m_disable ? "disable" : "enable" );
|
<< ( m_stored ? "restore"
|
||||||
|
: m_disable ? "disable"
|
||||||
|
: "enable" );
|
||||||
if ( m_stored )
|
if ( m_stored )
|
||||||
{
|
{
|
||||||
CalamaresUtils::Partition::automountRestore( m_stored );
|
CalamaresUtils::Partition::automountRestore( m_stored );
|
||||||
|
@ -157,9 +157,11 @@ getLVMVolumes()
|
|||||||
QStringList lvscanLines = QString::fromLocal8Bit( process.readAllStandardOutput() ).split( '\n' );
|
QStringList lvscanLines = QString::fromLocal8Bit( process.readAllStandardOutput() ).split( '\n' );
|
||||||
// Get the second column (`value(1)`) sinec that is the device name,
|
// Get the second column (`value(1)`) sinec that is the device name,
|
||||||
// remove quoting.
|
// remove quoting.
|
||||||
std::transform( lvscanLines.begin(), lvscanLines.end(), lvscanLines.begin(), []( const QString& lvscanLine ) {
|
std::transform( lvscanLines.begin(),
|
||||||
return lvscanLine.simplified().split( ' ' ).value( 1 ).replace( '\'', "" );
|
lvscanLines.end(),
|
||||||
} );
|
lvscanLines.begin(),
|
||||||
|
[]( const QString& lvscanLine )
|
||||||
|
{ return lvscanLine.simplified().split( ' ' ).value( 1 ).replace( '\'', "" ); } );
|
||||||
return lvscanLines;
|
return lvscanLines;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "ClearTempMountsJob.h"
|
#include "ClearTempMountsJob.h"
|
||||||
|
|
||||||
|
#include "partition/Mount.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/String.h"
|
#include "utils/String.h"
|
||||||
|
|
||||||
@ -45,51 +46,23 @@ ClearTempMountsJob::exec()
|
|||||||
{
|
{
|
||||||
Logger::Once o;
|
Logger::Once o;
|
||||||
// Fetch a list of current mounts to Calamares temporary directories.
|
// Fetch a list of current mounts to Calamares temporary directories.
|
||||||
QList< QPair< QString, QString > > lst;
|
using MtabInfo = CalamaresUtils::Partition::MtabInfo;
|
||||||
QFile mtab( "/etc/mtab" );
|
auto targetMounts = MtabInfo::fromMtabFilteredByPrefix( QStringLiteral( "/tmp/calamares-" ) );
|
||||||
if ( !mtab.open( QFile::ReadOnly | QFile::Text ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::error( tr( "Cannot get list of temporary mounts." ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
cVerbose() << o << "Opened mtab. Lines:";
|
if ( targetMounts.isEmpty() )
|
||||||
QTextStream in( &mtab );
|
|
||||||
QString lineIn = in.readLine();
|
|
||||||
while ( !lineIn.isNull() )
|
|
||||||
{
|
|
||||||
QStringList line = lineIn.split( ' ', SplitSkipEmptyParts );
|
|
||||||
cVerbose() << o << line.join( ' ' );
|
|
||||||
QString device = line.at( 0 );
|
|
||||||
QString mountPoint = line.at( 1 );
|
|
||||||
if ( mountPoint.startsWith( "/tmp/calamares-" ) )
|
|
||||||
{
|
|
||||||
lst.append( qMakePair( device, mountPoint ) );
|
|
||||||
}
|
|
||||||
lineIn = in.readLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( lst.empty() )
|
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::ok();
|
return Calamares::JobResult::ok();
|
||||||
}
|
}
|
||||||
|
std::sort( targetMounts.begin(), targetMounts.end(), MtabInfo::mountPointOrder );
|
||||||
std::sort(
|
|
||||||
lst.begin(), lst.end(), []( const QPair< QString, QString >& a, const QPair< QString, QString >& b ) -> bool {
|
|
||||||
return a.first > b.first;
|
|
||||||
} );
|
|
||||||
|
|
||||||
QStringList goodNews;
|
QStringList goodNews;
|
||||||
QProcess process;
|
for ( const auto& m : qAsConst( targetMounts ) )
|
||||||
|
|
||||||
for ( const auto& line : qAsConst( lst ) )
|
|
||||||
{
|
{
|
||||||
QString partPath = line.second;
|
cDebug() << o << "Will try to umount path" << m.mountPoint;
|
||||||
cDebug() << o << "Will try to umount path" << partPath;
|
if ( CalamaresUtils::Partition::unmount( m.mountPoint, { "-lv" } ) == 0 )
|
||||||
process.start( "umount", { "-lv", partPath } );
|
|
||||||
process.waitForFinished();
|
|
||||||
if ( process.exitCode() == 0 )
|
|
||||||
{
|
{
|
||||||
goodNews.append( QString( "Successfully unmounted %1." ).arg( partPath ) );
|
// Returns the program's exit code, so 0 is success
|
||||||
|
goodNews.append( QString( "Successfully unmounted %1." ).arg( m.mountPoint ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "core/KPMHelpers.h"
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include "partition/FileSystem.h"
|
#include "partition/FileSystem.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
@ -67,7 +68,18 @@ FormatPartitionJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
FormatPartitionJob::exec()
|
FormatPartitionJob::exec()
|
||||||
{
|
{
|
||||||
return KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, m_partition->fileSystem().type() ),
|
const auto fsType = m_partition->fileSystem().type();
|
||||||
|
auto r = KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, fsType ),
|
||||||
tr( "The installer failed to format partition %1 on disk '%2'." )
|
tr( "The installer failed to format partition %1 on disk '%2'." )
|
||||||
.arg( m_partition->partitionPath(), m_device->name() ) );
|
.arg( m_partition->partitionPath(), m_device->name() ) );
|
||||||
|
if ( fsType == FileSystem::Xfs && r.succeeded() )
|
||||||
|
{
|
||||||
|
// We are going to try to set modern timestamps for the filesystem,
|
||||||
|
// (ignoring whether this succeeds). Requires a sufficiently-new
|
||||||
|
// xfs_admin and xfs_repair and might be made obsolete by newer
|
||||||
|
// kpmcore releases.
|
||||||
|
CalamaresUtils::System::runCommand( { "xfs_admin", "-O", "bigtime=1", m_partition->partitionPath() },
|
||||||
|
std::chrono::seconds( 60 ) );
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,9 @@ getPartitionsForDevice_other( const QString& deviceName )
|
|||||||
{
|
{
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.setProgram( "sh" );
|
process.setProgram( "sh" );
|
||||||
process.setArguments(
|
process.setArguments( { "-c",
|
||||||
{ "-c",
|
QString( "echo $(awk '{print \"/dev/\"$4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' "
|
||||||
QString( "echo $(awk '{print \"/dev/\"$4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' -e '/[1-9]/!d' | grep %1)" )
|
"-e '/[1-9]/!d' | grep %1)" )
|
||||||
.arg( deviceName ) } );
|
.arg( deviceName ) } );
|
||||||
process.start();
|
process.start();
|
||||||
process.waitForFinished();
|
process.waitForFinished();
|
||||||
|
19
src/modules/umount/CMakeLists.txt
Normal file
19
src/modules/umount/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
calamares_add_plugin( umount
|
||||||
|
TYPE job
|
||||||
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
|
SOURCES
|
||||||
|
UmountJob.cpp
|
||||||
|
SHARED_LIB
|
||||||
|
EMERGENCY
|
||||||
|
)
|
||||||
|
|
||||||
|
calamares_add_test(
|
||||||
|
umounttest
|
||||||
|
SOURCES
|
||||||
|
Tests.cpp
|
||||||
|
)
|
52
src/modules/umount/Tests.cpp
Normal file
52
src/modules/umount/Tests.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* === 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
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UmountJob.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
// Internals of UmountJob.cpp
|
||||||
|
|
||||||
|
// Actual tests
|
||||||
|
class UmountTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
UmountTests() {}
|
||||||
|
~UmountTests() override {}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
void testTrue();
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountTests::initTestCase()
|
||||||
|
{
|
||||||
|
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountTests::testTrue()
|
||||||
|
{
|
||||||
|
QVERIFY( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN( UmountTests )
|
||||||
|
|
||||||
|
#include "utils/moc-warnings.h"
|
||||||
|
|
||||||
|
#include "Tests.moc"
|
158
src/modules/umount/UmountJob.cpp
Normal file
158
src/modules/umount/UmountJob.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* Tags from the Python version of this module:
|
||||||
|
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2016 Anke Boersma <demm@kaosx.us>
|
||||||
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
|
* Tags for the C++ version of this module:
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UmountJob.h"
|
||||||
|
|
||||||
|
#include "partition/Mount.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
UmountJob::UmountJob( QObject* parent )
|
||||||
|
: Calamares::CppJob( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UmountJob::~UmountJob() {}
|
||||||
|
|
||||||
|
QString
|
||||||
|
UmountJob::prettyName() const
|
||||||
|
{
|
||||||
|
return tr( "Unmount file systems." );
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
unmountTargetMounts( const QString& rootMountPoint )
|
||||||
|
{
|
||||||
|
QDir targetMount( rootMountPoint );
|
||||||
|
if ( !targetMount.exists() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(), "Could not unmount target system." ),
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"The target system is not mounted at '%1'." )
|
||||||
|
.arg( rootMountPoint ),
|
||||||
|
Calamares::JobResult::GenericError );
|
||||||
|
}
|
||||||
|
QString targetMountPath = targetMount.absolutePath();
|
||||||
|
if ( !targetMountPath.endsWith( '/' ) )
|
||||||
|
{
|
||||||
|
targetMountPath.append( '/' );
|
||||||
|
}
|
||||||
|
|
||||||
|
using MtabInfo = CalamaresUtils::Partition::MtabInfo;
|
||||||
|
auto targetMounts = MtabInfo::fromMtabFilteredByPrefix( targetMountPath );
|
||||||
|
std::sort( targetMounts.begin(), targetMounts.end(), MtabInfo::mountPointOrder );
|
||||||
|
|
||||||
|
for ( const auto& m : qAsConst( targetMounts ) )
|
||||||
|
{
|
||||||
|
if ( CalamaresUtils::Partition::unmount( m.mountPoint, { "-lv" } ) )
|
||||||
|
{
|
||||||
|
// Returns the program's exit code, so 0 is success
|
||||||
|
return Calamares::JobResult::error(
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"Could not unmount target system." ),
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"The device '%1' is mounted in the target system. It is mounted at '%2'. "
|
||||||
|
"The device could not be unmounted." )
|
||||||
|
.arg( m.device, m.mountPoint ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
exportZFSPools( const QString& rootMountPoint )
|
||||||
|
{
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
QStringList poolNames;
|
||||||
|
{
|
||||||
|
// The pools are dictionaries / VariantMaps
|
||||||
|
auto zfs_pool_list = gs->value( "zfsPoolInfo" ).toList();
|
||||||
|
for ( const auto& v : zfs_pool_list )
|
||||||
|
{
|
||||||
|
auto m = v.toMap();
|
||||||
|
QString poolName = m.value( "poolName" ).toString();
|
||||||
|
if ( !poolName.isEmpty() )
|
||||||
|
{
|
||||||
|
poolNames.append( poolName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poolNames.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& poolName : poolNames )
|
||||||
|
{
|
||||||
|
auto result = CalamaresUtils::System::runCommand( { "zpool", "export", poolName }, std::chrono::seconds( 30 ) );
|
||||||
|
if ( result.getExitCode() )
|
||||||
|
{
|
||||||
|
cWarning() << "Failed to export pool" << result.getOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Exporting ZFS pools does not cause the install to fail
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Calamares::JobResult
|
||||||
|
UmountJob::exec()
|
||||||
|
{
|
||||||
|
const auto* sys = CalamaresUtils::System::instance();
|
||||||
|
if ( !sys )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
"UMount", 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(
|
||||||
|
"UMount", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the unmounting of target-system filesystems
|
||||||
|
{
|
||||||
|
auto r = unmountTargetMounts( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
if ( !r )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For ZFS systems, export the pools
|
||||||
|
{
|
||||||
|
auto r = exportZFSPools( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
if ( !r )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountJob::setConfigurationMap( const QVariantMap& map )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( UmountJobFactory, registerPlugin< UmountJob >(); )
|
41
src/modules/umount/UmountJob.h
Normal file
41
src/modules/umount/UmountJob.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* === 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
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UMOUNTJOB_H
|
||||||
|
#define UMOUNTJOB_H
|
||||||
|
|
||||||
|
#include "CppJob.h"
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
/** @brief Write 'random' data: machine id, entropy, UUIDs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class PLUGINDLLEXPORT UmountJob : public Calamares::CppJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UmountJob( QObject* parent = nullptr );
|
||||||
|
~UmountJob() override;
|
||||||
|
|
||||||
|
QString prettyName() const override;
|
||||||
|
|
||||||
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( UmountJobFactory )
|
||||||
|
|
||||||
|
#endif // UMOUNTJOB_H
|
@ -1,123 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2016 Anke Boersma <demm@kaosx.us>
|
|
||||||
# SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
import libcalamares
|
|
||||||
from libcalamares.utils import gettext_path, gettext_languages
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
_translation = gettext.translation("calamares-python",
|
|
||||||
localedir=gettext_path(),
|
|
||||||
languages=gettext_languages(),
|
|
||||||
fallback=True)
|
|
||||||
_ = _translation.gettext
|
|
||||||
_n = _translation.ngettext
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_name():
|
|
||||||
return _( "Unmount file systems." )
|
|
||||||
|
|
||||||
|
|
||||||
def list_mounts(root_mount_point):
|
|
||||||
""" List mount points.
|
|
||||||
|
|
||||||
:param root_mount_point:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
lst = []
|
|
||||||
|
|
||||||
root_mount_point = os.path.normpath(root_mount_point)
|
|
||||||
for line in open("/etc/mtab").readlines():
|
|
||||||
device, mount_point, _ = line.split(" ", 2)
|
|
||||||
|
|
||||||
if os.path.commonprefix([root_mount_point, mount_point]) == root_mount_point:
|
|
||||||
lst.append((device, mount_point))
|
|
||||||
|
|
||||||
return lst
|
|
||||||
|
|
||||||
|
|
||||||
def export_zpools(root_mount_point):
|
|
||||||
""" Exports the zpools if defined in global storage
|
|
||||||
|
|
||||||
:param root_mount_point: The absolute path to the root of the install
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
zfs_pool_list = libcalamares.globalstorage.value("zfsPoolInfo")
|
|
||||||
zfs_pool_list.sort(reverse=True, key=lambda x: x["poolName"])
|
|
||||||
if zfs_pool_list:
|
|
||||||
for zfs_pool in zfs_pool_list:
|
|
||||||
try:
|
|
||||||
libcalamares.utils.host_env_process_output(['zpool', 'export', zfs_pool["poolName"]])
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
libcalamares.utils.warning("Failed to export zpool")
|
|
||||||
except Exception as e:
|
|
||||||
# If this fails it shouldn't cause the installation to fail
|
|
||||||
libcalamares.utils.warning("Received exception while exporting zpools: " + format(e))
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
""" Unmounts given mountpoints in decreasing order.
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
|
|
||||||
|
|
||||||
if(libcalamares.job.configuration and
|
|
||||||
"srcLog" in libcalamares.job.configuration and
|
|
||||||
"destLog" in libcalamares.job.configuration):
|
|
||||||
libcalamares.utils.warning("Log-file preserving is **deprecated** in the *umount* module")
|
|
||||||
log_source = libcalamares.job.configuration["srcLog"]
|
|
||||||
log_destination = libcalamares.job.configuration["destLog"]
|
|
||||||
# Relocate log_destination into target system
|
|
||||||
log_destination = '{!s}/{!s}'.format(root_mount_point, log_destination)
|
|
||||||
# Make sure source is a string
|
|
||||||
log_source = '{!s}'.format(log_source)
|
|
||||||
|
|
||||||
# copy installation log before umount
|
|
||||||
if os.path.exists(log_source):
|
|
||||||
try:
|
|
||||||
shutil.copy2(log_source, log_destination)
|
|
||||||
except Exception as e:
|
|
||||||
libcalamares.utils.warning("Could not preserve file {!s}, "
|
|
||||||
"error {!s}".format(log_source, e))
|
|
||||||
|
|
||||||
if not root_mount_point:
|
|
||||||
return ("No mount point for root partition in globalstorage",
|
|
||||||
"globalstorage does not contain a \"rootMountPoint\" key, "
|
|
||||||
"doing nothing")
|
|
||||||
|
|
||||||
if not os.path.exists(root_mount_point):
|
|
||||||
return ("Bad mount point for root partition in globalstorage",
|
|
||||||
"globalstorage[\"rootMountPoint\"] is \"{}\", which does not "
|
|
||||||
"exist, doing nothing".format(root_mount_point))
|
|
||||||
|
|
||||||
lst = list_mounts(root_mount_point)
|
|
||||||
# Sort the list by mount point in decreasing order. This way we can be sure
|
|
||||||
# we unmount deeper dirs first.
|
|
||||||
lst.sort(key=lambda x: x[1], reverse=True)
|
|
||||||
|
|
||||||
for device, mount_point in lst:
|
|
||||||
# On success, no output; if the command fails, its output is
|
|
||||||
# in the exception object.
|
|
||||||
subprocess.check_output(["umount", "-lv", mount_point], stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
export_zpools(root_mount_point)
|
|
||||||
|
|
||||||
os.rmdir(root_mount_point)
|
|
||||||
|
|
||||||
return None
|
|
@ -1,7 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
---
|
|
||||||
type: "job"
|
|
||||||
name: "umount"
|
|
||||||
interface: "python"
|
|
||||||
script: "main.py"
|
|
@ -4,27 +4,11 @@
|
|||||||
### Umount Module
|
### Umount Module
|
||||||
#
|
#
|
||||||
# This module represents the last part of the installation, the unmounting
|
# This module represents the last part of the installation, the unmounting
|
||||||
# of partitions used for the install. It is also the last place where it
|
# of partitions used for the install. After this, there is no regular way
|
||||||
# is possible to copy files to the target system.
|
# to modify the target system anymore.
|
||||||
#
|
|
||||||
# The "copy log files" functionality is deprecated; use the *preservefiles*
|
|
||||||
# module instead, which is more flexible.
|
|
||||||
#
|
|
||||||
#
|
#
|
||||||
|
|
||||||
---
|
---
|
||||||
# This is a **deprecated** example. Use the *preservefiles* module
|
# Setting emergency to true will make it so this module is still run
|
||||||
# instead, where the equivalent configuration is this:
|
# when a prior module fails
|
||||||
#
|
emergency: false
|
||||||
# files:
|
|
||||||
# - from: log
|
|
||||||
# dest: /var/log/installation.log
|
|
||||||
#
|
|
||||||
# Note that the "equivalent configuration" always finds the log,
|
|
||||||
# and is not dependent on specific user names or the vagaries of
|
|
||||||
# polkit configuration -- so it is a **better** "equivalent".
|
|
||||||
#
|
|
||||||
# example when using a log created by `sudo calamares -d`:
|
|
||||||
#srcLog: "/home/live/installation.log"
|
|
||||||
#destLog: "/var/log/installation.log"
|
|
||||||
srcLog: "/bogus/just/do/not/use/this/anymore.txt"
|
|
||||||
|
@ -6,5 +6,4 @@ $id: https://calamares.io/schemas/umount
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
srcLog: { type: string }
|
emergency: { type: boolean }
|
||||||
destLog: { type: string }
|
|
||||||
|
@ -428,14 +428,16 @@ def run():
|
|||||||
if not root_mount_point:
|
if not root_mount_point:
|
||||||
libcalamares.utils.warning("No mount point for root partition")
|
libcalamares.utils.warning("No mount point for root partition")
|
||||||
return (_("No mount point for root partition"),
|
return (_("No mount point for root partition"),
|
||||||
_("globalstorage does not contain a \"rootMountPoint\" key, "
|
_("globalstorage does not contain a \"rootMountPoint\" key."))
|
||||||
"doing nothing"))
|
|
||||||
|
|
||||||
if not os.path.exists(root_mount_point):
|
if not os.path.exists(root_mount_point):
|
||||||
libcalamares.utils.warning("Bad root mount point \"{}\"".format(root_mount_point))
|
libcalamares.utils.warning("Bad root mount point \"{}\"".format(root_mount_point))
|
||||||
return (_("Bad mount point for root partition"),
|
return (_("Bad mount point for root partition"),
|
||||||
_("rootMountPoint is \"{}\", which does not "
|
_("rootMountPoint is \"{}\", which does not exist.".format(root_mount_point)))
|
||||||
"exist, doing nothing").format(root_mount_point))
|
|
||||||
|
if libcalamares.job.configuration.get("unpack", None) is None:
|
||||||
|
libcalamares.utils.warning("No *unpack* key in job configuration.")
|
||||||
|
return (_("Bad unpackfs configuration"),
|
||||||
|
_("There is no configuration information."))
|
||||||
|
|
||||||
supported_filesystems = get_supported_filesystems()
|
supported_filesystems = get_supported_filesystems()
|
||||||
|
|
||||||
@ -450,17 +452,17 @@ def run():
|
|||||||
if sourcefs not in supported_filesystems:
|
if sourcefs not in supported_filesystems:
|
||||||
libcalamares.utils.warning("The filesystem for \"{}\" ({}) is not supported by your current kernel".format(source, sourcefs))
|
libcalamares.utils.warning("The filesystem for \"{}\" ({}) is not supported by your current kernel".format(source, sourcefs))
|
||||||
libcalamares.utils.warning(" ... modprobe {} may solve the problem".format(sourcefs))
|
libcalamares.utils.warning(" ... modprobe {} may solve the problem".format(sourcefs))
|
||||||
return (_("Bad unsquash configuration"),
|
return (_("Bad unpackfs configuration"),
|
||||||
_("The filesystem for \"{}\" ({}) is not supported by your current kernel").format(source, sourcefs))
|
_("The filesystem for \"{}\" ({}) is not supported by your current kernel").format(source, sourcefs))
|
||||||
if not os.path.exists(source):
|
if not os.path.exists(source):
|
||||||
libcalamares.utils.warning("The source filesystem \"{}\" does not exist".format(source))
|
libcalamares.utils.warning("The source filesystem \"{}\" does not exist".format(source))
|
||||||
return (_("Bad unsquash configuration"),
|
return (_("Bad unpackfs configuration"),
|
||||||
_("The source filesystem \"{}\" does not exist").format(source))
|
_("The source filesystem \"{}\" does not exist").format(source))
|
||||||
if sourcefs == "squashfs":
|
if sourcefs == "squashfs":
|
||||||
if shutil.which("unsquashfs") is None:
|
if shutil.which("unsquashfs") is None:
|
||||||
libcalamares.utils.warning("Failed to find unsquashfs")
|
libcalamares.utils.warning("Failed to find unsquashfs")
|
||||||
|
|
||||||
return (_("Bad unsquash configuration"),
|
return (_("Bad unpackfs configuration"),
|
||||||
_("Failed to find unsquashfs, make sure you have the squashfs-tools package installed.") +
|
_("Failed to find unsquashfs, make sure you have the squashfs-tools package installed.") +
|
||||||
" " + _("Failed to unpack image \"{}\"").format(source))
|
" " + _("Failed to unpack image \"{}\"").format(source))
|
||||||
|
|
||||||
@ -475,7 +477,7 @@ def run():
|
|||||||
if not os.path.isdir(destination) and sourcefs != "file":
|
if not os.path.isdir(destination) and sourcefs != "file":
|
||||||
libcalamares.utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination))
|
libcalamares.utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination))
|
||||||
if is_first:
|
if is_first:
|
||||||
return (_("Bad unsquash configuration"),
|
return (_("Bad unpackfs configuration"),
|
||||||
_("The destination \"{}\" in the target system is not a directory").format(destination))
|
_("The destination \"{}\" in the target system is not a directory").format(destination))
|
||||||
else:
|
else:
|
||||||
libcalamares.utils.debug(".. assuming that the previous targets will create that directory.")
|
libcalamares.utils.debug(".. assuming that the previous targets will create that directory.")
|
||||||
|
Loading…
Reference in New Issue
Block a user