diff --git a/.clang-format b/.clang-format index 2cd8d678a..0965e5724 100644 --- a/.clang-format +++ b/.clang-format @@ -28,8 +28,9 @@ PointerAlignment: Left ReflowComments: "false" SortIncludes: "true" SpaceAfterCStyleCast: "false" +SpaceInEmptyBlock: "false" SpacesBeforeTrailingComments: "2" SpacesInAngles: "true" SpacesInParentheses: "true" SpacesInSquareBrackets: "true" -Standard: Cpp11 +Standard: c++17 diff --git a/.clang-format.base b/.clang-format.base deleted file mode 100644 index 2cd8d678a..000000000 --- a/.clang-format.base +++ /dev/null @@ -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 diff --git a/CHANGES-3.2 b/CHANGES-3.2 index 52342e95b..01da2a00e 100644 --- a/CHANGES-3.2 +++ b/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 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): - - Erik Dubois + - No external contributors yet ## Core ## - No core changes yet ## Modules ## + - No module changes yet + + +# 3.2.51 (2022-02-01) # + +This release contains contributions from (alphabetically by first name): + - Evan James + +**WARNING** The *umount* module has been rewritten in C++. Check your +configuration if you previously used the copy-a-log functionality. + +## Core ## + - Evan has made a start on documenting which Global Storage keys there + are and how they tie modules together. This can be found in the + `src/modules/README.md` documentation. + +## Modules ## + - *bootloader* can now be configured to try to generate a unique + suffix for the bootloader-id. #1820 + - *grubcfg* now has a configurable default for kernel parameters, + which allows distributions to change the value from `quiet`. + The default, if nothing is set, remains `quiet`. Use an explicitly- + empty list to specify no-arguments-at-all. + - *packagechooser* can now export its choices for use by the *netinstall* + module. This makes it possible to use *packagechooser* for large-scale + choices, followed by *netinstall* for fine-grained control. (Thanks Evan) + - When the *partition* module has a conflicting configuration for the + swap choices, it prints a warning and uses the configured choice, rather + than always using "suspend". #1881 + - The *umount* module has been re-written in C++. The copy-a-log-file + functionality has been removed. Use the *preservefiles* module for that. + + +# 3.2.50 (2022-01-18) # + +This release contains contributions from (alphabetically by first name): + - Anke Boersma + - Erik Dubois + - Evan James + - Johannes Kamprad + - Taejun Park (new contributor, welcome!) + +**Replacement notice:** The *umount* module will be replaced by a C++ +implementation in the next release. The "preserve log file" feature +will be removed in that release. Use the *preservefiles* module instead. + +## Core ## + - No core changes yet + +## Modules ## + - *initcpiocfg* mentioned a special kernel-name "all", which did not work, + and a special kernel-name "$uname" which cannot work. Fixed the former + and removed the "$uname" special key. (Thanks Evan) + - *luksswaphookcfg* has been converted to a C++ module. - *networkcfg* could fail to update the NetworkManager configuration if the SSID or username contained non-ASCII characters **and** the default Python text-file encoding was set to ASCII. The files are now read and written in UTF-8, explicitly. #1848 + - *partition* always sets *bigtime* option on XFS filesystems, if possible. + Requires sufficiently-recent xfsprogs. #1874 - *preservefiles* was missing some necessary features, needed for it to replace the deprecated log-file-saving functionality in the *umount* module. (Thanks Erik and Joe for testing) #1851 + - *umount* is now marked as an emergency module in the example configuration, + since it should **probably** be run as a cleanup. (Thanks Evan) + - *welcome* and *locale* could be confusing, together, and configure + the target system with a language that does not match the installer + language, even though the user did not make any explicit choice. + (Thanks Taejun) #1864 # 3.2.49.1 (2021-12-11) # diff --git a/ci/RELEASE.sh b/ci/RELEASE.sh index f09285fb7..e46ca2cc2 100755 --- a/ci/RELEASE.sh +++ b/ci/RELEASE.sh @@ -75,7 +75,7 @@ fi # # BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.) -KEY_ID="CFDDC96F12B1915C" +KEY_ID="328D742D8807A435" # Try to make gpg cache the signing key, so we can leave the process # to run and sign. diff --git a/ci/calamaresstyle b/ci/calamaresstyle index ffcfe0902..f5bcd2bb9 100755 --- a/ci/calamaresstyle +++ b/ci/calamaresstyle @@ -19,12 +19,12 @@ BASEDIR=$(dirname $0) TOPDIR=$( cd $BASEDIR/.. && pwd -P ) test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; } test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; } -test -f "$TOPDIR/.clang-format.base" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; } +test -f "$TOPDIR/.clang-format" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; } AS=$( which astyle ) # Allow specifying CF_VERSIONS outside already -CF_VERSIONS="$CF_VERSIONS clang-format-8 clang-format80 clang-format90 clang-format-9.0.1 clang-format" +CF_VERSIONS="$CF_VERSIONS clang-format13 clang-format12 clang-format" for _cf in $CF_VERSIONS do # Not an error if this particular clang-format isn't found @@ -40,31 +40,19 @@ test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; } ### CLANG-FORMAT-WRANGLING # # Version 7 and earlier doesn't understand all the options we would like -# Version 8 is ok -# Version 9 is ok -# Later versions change some defaults so need extra wrangling. -# .. there are extra files that are appended to the settings, per -# .. clang-format version. +# Version 12 handles lambdas nicely, so use that. +# Version 13 is also ok. format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1` case "$format_version" in - [0-7] ) - echo "! Clang-format version 8+ required" - exit 1 - ;; - [89] ) + 12|13 ) : ;; * ) - echo "! Clang-format version '$format_version' unsupported." + echo "! Clang-format version '$format_version' unsupported, version 12 required." exit 1 ;; esac -_fmt="$TOPDIR/.clang-format" -cp "$_fmt.base" "$_fmt" -for f in "$extra_settings" ; do - test -f "$_fmt.$f" && cat "$_fmt.$f" >> "$_fmt" -done ### FILE PROCESSING @@ -98,8 +86,3 @@ if test "x$any_dirs" = "xyes" ; then else style_some "$@" fi - -### CLANG-FORMAT-WRANGLING -# -# Restore the original .clang-format -cp "$_fmt.base" "$_fmt" diff --git a/lang/calamares_cs_CZ.ts b/lang/calamares_cs_CZ.ts index 4525d7418..b61f36b81 100644 --- a/lang/calamares_cs_CZ.ts +++ b/lang/calamares_cs_CZ.ts @@ -693,27 +693,27 @@ Instalační program bude ukončen a všechny změny ztraceny. Successfully unmounted %1. - + Úspěšně odpojeno %1. Successfully disabled swap %1. - + Úspěšně vypnut swap %1. Successfully cleared swap %1. - + Úspěšně vyčištěn swap %1. Successfully closed mapper device %1. - + Úspěšně zavřeno mapper zařízení %1. Successfully disabled volume group %1. - + Úspěšně vypnuta skupina svazků %1. diff --git a/lang/calamares_en.ts b/lang/calamares_en.ts index 544fd4e71..f92210abd 100644 --- a/lang/calamares_en.ts +++ b/lang/calamares_en.ts @@ -171,7 +171,7 @@ Calamares::JobThread - + Done Done @@ -187,17 +187,17 @@ Calamares::ProcessJob - + Run command '%1' in target system. Run command '%1' in target system. - + Run command '%1'. Run command '%1'. - + Running command %1 %2 Running command %1 %2 @@ -205,32 +205,32 @@ Calamares::PythonJob - + Running %1 operation. Running %1 operation. - + Bad working directory path Bad working directory path - + Working directory %1 for python job %2 is not readable. Working directory %1 for python job %2 is not readable. - + Bad main script file Bad main script file - + Main script file %1 for python job %2 is not readable. Main script file %1 for python job %2 is not readable. - + Boost.Python error in job "%1". Boost.Python error in job "%1". @@ -285,52 +285,47 @@ Calamares::ViewManager - + Setup Failed Setup Failed - + Installation Failed Installation Failed - Would you like to paste the install log to the web? - Would you like to paste the install log to the web? - - - Error Error - + &Yes &Yes - + &No &No - + &Close &Close - + Install Log Paste URL Install Log Paste URL - + The upload was unsuccessful. No web-paste was done. The upload was unsuccessful. No web-paste was done. - + Install log posted to %1 @@ -343,124 +338,124 @@ Link copied to clipboard Link copied to clipboard - + Calamares Initialization Failed Calamares Initialization Failed - + %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. - + <br/>The following modules could not be loaded: <br/>The following modules could not be loaded: - + Continue with setup? Continue with setup? - + Continue with installation? Continue with installation? - + The %1 setup program is about to make changes to your disk in order to set up %2.<br/><strong>You will not be able to undo these changes.</strong> The %1 setup program is about to make changes to your disk in order to set up %2.<br/><strong>You will not be able to undo these changes.</strong> - + The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> - + &Set up now &Set up now - + &Install now &Install now - + Go &back Go &back - + &Set up &Set up - + &Install &Install - + Setup is complete. Close the setup program. Setup is complete. Close the setup program. - + The installation is complete. Close the installer. The installation is complete. Close the installer. - + Cancel setup without changing the system. Cancel setup without changing the system. - + Cancel installation without changing the system. Cancel installation without changing the system. - + &Next &Next - + &Back &Back - + &Done &Done - + &Cancel &Cancel - + Cancel setup? Cancel setup? - + Cancel installation? Cancel installation? - + Do you really want to cancel the current setup process? The setup program will quit and all changes will be lost. Do you really want to cancel the current setup process? The setup program will quit and all changes will be lost. - + Do you really want to cancel the current install process? The installer will quit and all changes will be lost. Do you really want to cancel the current install process? @@ -470,22 +465,22 @@ The installer will quit and all changes will be lost. CalamaresPython::Helper - + Unknown exception type Unknown exception type - + unparseable Python error unparseable Python error - + unparseable Python traceback unparseable Python traceback - + Unfetchable Python error. Unfetchable Python error. @@ -537,149 +532,149 @@ The installer will quit and all changes will be lost. Form - + Select storage de&vice: Select storage de&vice: - - - - + + + + Current: Current: - + After: After: - + <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. - + Reuse %1 as home partition for %2. Reuse %1 as home partition for %2. - + <strong>Select a partition to shrink, then drag the bottom bar to resize</strong> <strong>Select a partition to shrink, then drag the bottom bar to resize</strong> - + %1 will be shrunk to %2MiB and a new %3MiB partition will be created for %4. %1 will be shrunk to %2MiB and a new %3MiB partition will be created for %4. - + Boot loader location: Boot loader location: - + <strong>Select a partition to install on</strong> <strong>Select a partition to install on</strong> - + An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. - + The EFI system partition at %1 will be used for starting %2. The EFI system partition at %1 will be used for starting %2. - + EFI system partition: EFI system partition: - + This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - - - - + + + + <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. - - - + + + <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. - - - - + + + + <strong>Replace a partition</strong><br/>Replaces a partition with %1. <strong>Replace a partition</strong><br/>Replaces a partition with %1. - + This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> - + This storage device has one of its partitions <strong>mounted</strong>. This storage device has one of its partitions <strong>mounted</strong>. - + This storage device is a part of an <strong>inactive RAID</strong> device. This storage device is a part of an <strong>inactive RAID</strong> device. - + No Swap No Swap - + Reuse Swap Reuse Swap - + Swap (no Hibernate) Swap (no Hibernate) - + Swap (with Hibernate) Swap (with Hibernate) - + Swap to file Swap to file @@ -687,42 +682,42 @@ The installer will quit and all changes will be lost. ClearMountsJob - + Successfully unmounted %1. Successfully unmounted %1. - + Successfully disabled swap %1. Successfully disabled swap %1. - + Successfully cleared swap %1. Successfully cleared swap %1. - + Successfully closed mapper device %1. Successfully closed mapper device %1. - + Successfully disabled volume group %1. Successfully disabled volume group %1. - + Clear mounts for partitioning operations on %1 Clear mounts for partitioning operations on %1 - + Clearing mounts for partitioning operations on %1. Clearing mounts for partitioning operations on %1. - + Cleared all mounts for %1 Cleared all mounts for %1 @@ -730,22 +725,17 @@ The installer will quit and all changes will be lost. ClearTempMountsJob - + Clear all temporary mounts. Clear all temporary mounts. - + Clearing all temporary mounts. Clearing all temporary mounts. - - Cannot get list of temporary mounts. - Cannot get list of temporary mounts. - - - + Cleared all temporary mounts. Cleared all temporary mounts. @@ -782,17 +772,17 @@ The installer will quit and all changes will be lost. Set keyboard layout to %1/%2. - + Set timezone to %1/%2. Set timezone to %1/%2. - + The system language will be set to %1. The system language will be set to %1. - + The numbers and dates locale will be set to %1. The numbers and dates locale will be set to %1. @@ -962,22 +952,22 @@ The installer will quit and all changes will be lost. The installation of %1 is complete. - + Package Selection Package Selection - + Please pick a product from the list. The selected product will be installed. Please pick a product from the list. The selected product will be installed. - + Install option: <strong>%1</strong> Install option: <strong>%1</strong> - + None None @@ -1029,8 +1019,8 @@ The installer will quit and all changes will be lost. - &Primary - &Primary + Primar&y + @@ -1053,86 +1043,91 @@ The installer will quit and all changes will be lost. &Mount Point: - + Flags: Flags: - + Label for the filesystem Label for the filesystem - + FS Label: FS Label: - + En&crypt En&crypt - + Logical Logical - + Primary Primary - + GPT GPT - + Mountpoint already in use. Please select another one. Mountpoint already in use. Please select another one. + + + Mountpoint must start with a <tt>/</tt>. + + CreatePartitionJob - + Create new %1MiB partition on %3 (%2) with entries %4. Create new %1MiB partition on %3 (%2) with entries %4. - + Create new %1MiB partition on %3 (%2). Create new %1MiB partition on %3 (%2). - + Create new %2MiB partition on %4 (%3) with file system %1. Create new %2MiB partition on %4 (%3) with file system %1. - + Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2) with entries <em>%4</em>. Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2) with entries <em>%4</em>. - + Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2). Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2). - + Create new <strong>%2MiB</strong> partition on <strong>%4</strong> (%3) with file system <strong>%1</strong>. Create new <strong>%2MiB</strong> partition on <strong>%4</strong> (%3) with file system <strong>%1</strong>. - - + + Creating new %1 partition on %2. Creating new %1 partition on %2. - + The installer failed to create partition on disk '%1'. The installer failed to create partition on disk '%1'. @@ -1168,22 +1163,22 @@ The installer will quit and all changes will be lost. CreatePartitionTableJob - + Create new %1 partition table on %2. Create new %1 partition table on %2. - + Create new <strong>%1</strong> partition table on <strong>%2</strong> (%3). Create new <strong>%1</strong> partition table on <strong>%2</strong> (%3). - + Creating new %1 partition table on %2. Creating new %1 partition table on %2. - + The installer failed to create a partition table on %1. The installer failed to create a partition table on %1. @@ -1191,33 +1186,33 @@ The installer will quit and all changes will be lost. CreateUserJob - + Create user %1 Create user %1 - + Create user <strong>%1</strong>. Create user <strong>%1</strong>. - + Preserving home directory Preserving home directory - - + + Creating user %1 Creating user %1 - + Configuring user %1 Configuring user %1 - + Setting file permissions Setting file permissions @@ -1233,22 +1228,22 @@ The installer will quit and all changes will be lost. CreateVolumeGroupJob - + Create new volume group named %1. Create new volume group named %1. - + Create new volume group named <strong>%1</strong>. Create new volume group named <strong>%1</strong>. - + Creating new volume group named %1. Creating new volume group named %1. - + The installer failed to create a volume group named '%1'. The installer failed to create a volume group named '%1'. @@ -1256,18 +1251,18 @@ The installer will quit and all changes will be lost. DeactivateVolumeGroupJob - - + + Deactivate volume group named %1. Deactivate volume group named %1. - + Deactivate volume group named <strong>%1</strong>. Deactivate volume group named <strong>%1</strong>. - + The installer failed to deactivate a volume group named %1. The installer failed to deactivate a volume group named %1. @@ -1275,22 +1270,22 @@ The installer will quit and all changes will be lost. DeletePartitionJob - + Delete partition %1. Delete partition %1. - + Delete partition <strong>%1</strong>. Delete partition <strong>%1</strong>. - + Deleting partition %1. Deleting partition %1. - + The installer failed to delete partition %1. The installer failed to delete partition %1. @@ -1298,32 +1293,32 @@ The installer will quit and all changes will be lost. DeviceInfoWidget - + This device has a <strong>%1</strong> partition table. This device has a <strong>%1</strong> partition table. - + This is a <strong>loop</strong> device.<br><br>It is a pseudo-device with no partition table that makes a file accessible as a block device. This kind of setup usually only contains a single filesystem. This is a <strong>loop</strong> device.<br><br>It is a pseudo-device with no partition table that makes a file accessible as a block device. This kind of setup usually only contains a single filesystem. - + This installer <strong>cannot detect a partition table</strong> on the selected storage device.<br><br>The device either has no partition table, or the partition table is corrupted or of an unknown type.<br>This installer can create a new partition table for you, either automatically, or through the manual partitioning page. This installer <strong>cannot detect a partition table</strong> on the selected storage device.<br><br>The device either has no partition table, or the partition table is corrupted or of an unknown type.<br>This installer can create a new partition table for you, either automatically, or through the manual partitioning page. - + <br><br>This is the recommended partition table type for modern systems which start from an <strong>EFI</strong> boot environment. <br><br>This is the recommended partition table type for modern systems which start from an <strong>EFI</strong> boot environment. - + <br><br>This partition table type is only advisable on older systems which start from a <strong>BIOS</strong> boot environment. GPT is recommended in most other cases.<br><br><strong>Warning:</strong> the MBR partition table is an obsolete MS-DOS era standard.<br>Only 4 <em>primary</em> partitions may be created, and of those 4, one can be an <em>extended</em> partition, which may in turn contain many <em>logical</em> partitions. <br><br>This partition table type is only advisable on older systems which start from a <strong>BIOS</strong> boot environment. GPT is recommended in most other cases.<br><br><strong>Warning:</strong> the MBR partition table is an obsolete MS-DOS era standard.<br>Only 4 <em>primary</em> partitions may be created, and of those 4, one can be an <em>extended</em> partition, which may in turn contain many <em>logical</em> partitions. - + The type of <strong>partition table</strong> on the selected storage device.<br><br>The only way to change the partition table type is to erase and recreate the partition table from scratch, which destroys all data on the storage device.<br>This installer will keep the current partition table unless you explicitly choose otherwise.<br>If unsure, on modern systems GPT is preferred. The type of <strong>partition table</strong> on the selected storage device.<br><br>The only way to change the partition table type is to erase and recreate the partition table from scratch, which destroys all data on the storage device.<br>This installer will keep the current partition table unless you explicitly choose otherwise.<br>If unsure, on modern systems GPT is preferred. @@ -1331,13 +1326,13 @@ The installer will quit and all changes will be lost. DeviceModel - + %1 - %2 (%3) device[name] - size[number] (device-node[name]) %1 - %2 (%3) - + %1 - (%2) device[name] - (device-node[name]) %1 - (%2) @@ -1364,7 +1359,7 @@ The installer will quit and all changes will be lost. DummyCppJob - + Dummy C++ Job Dummy C++ Job @@ -1378,8 +1373,8 @@ The installer will quit and all changes will be lost. - Content: - Content: + Con&tent: + @@ -1402,40 +1397,35 @@ The installer will quit and all changes will be lost. &Mount Point: - + Si&ze: Si&ze: - + MiB MiB - + Fi&le System: Fi&le System: - + Flags: Flags: - + Label for the filesystem Label for the filesystem - + FS Label: FS Label: - - - Mountpoint already in use. Please select another one. - Mountpoint already in use. Please select another one. - EncryptWidget @@ -1450,76 +1440,94 @@ The installer will quit and all changes will be lost. En&crypt system - + + Your system does not seem to support encryption well enough to encrypt the entire system. You may enable encryption, but performance may suffer. + + + + Passphrase Passphrase - + Confirm passphrase Confirm passphrase - - + + Please enter the same passphrase in both boxes. Please enter the same passphrase in both boxes. + + ErrorDialog + + + Details: + + + + + Would you like to paste the install log to the web? + Would you like to paste the install log to the web? + + FillGlobalStorageJob - + Set partition information Set partition information - + Install %1 on <strong>new</strong> %2 system partition with features <em>%3</em> Install %1 on <strong>new</strong> %2 system partition with features <em>%3</em> - + Install %1 on <strong>new</strong> %2 system partition. Install %1 on <strong>new</strong> %2 system partition. - + Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong> and features <em>%3</em>. Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong> and features <em>%3</em>. - + Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong>%3. Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong>%3. - + Install %2 on %3 system partition <strong>%1</strong> with features <em>%4</em>. Install %2 on %3 system partition <strong>%1</strong> with features <em>%4</em>. - + Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong> and features <em>%4</em>. Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong> and features <em>%4</em>. - + Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong>%4. Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong>%4. - + Install %2 on %3 system partition <strong>%1</strong>. Install %2 on %3 system partition <strong>%1</strong>. - + Install boot loader on <strong>%1</strong>. Install boot loader on <strong>%1</strong>. - + Setting up mount points. Setting up mount points. @@ -1586,22 +1594,22 @@ The installer will quit and all changes will be lost. FormatPartitionJob - + Format partition %1 (file system: %2, size: %3 MiB) on %4. Format partition %1 (file system: %2, size: %3 MiB) on %4. - + Format <strong>%3MiB</strong> partition <strong>%1</strong> with file system <strong>%2</strong>. Format <strong>%3MiB</strong> partition <strong>%1</strong> with file system <strong>%2</strong>. - + Formatting partition %1 with file system %2. Formatting partition %1 with file system %2. - + The installer failed to format partition %1 on disk '%2'. The installer failed to format partition %1 on disk '%2'. @@ -1716,7 +1724,7 @@ The installer will quit and all changes will be lost. InitcpioJob - + Creating initramfs with mkinitcpio. Creating initramfs with mkinitcpio. @@ -1732,17 +1740,17 @@ The installer will quit and all changes will be lost. InteractiveTerminalPage - + Konsole not installed Konsole not installed - + Please install KDE Konsole and try again! Please install KDE Konsole and try again! - + Executing script: &nbsp;<code>%1</code> Executing script: &nbsp;<code>%1</code> @@ -1794,6 +1802,29 @@ The installer will quit and all changes will be lost. &OK + + LOSHJob + + + Configuring encrypted swap. + + + + + No target system available. + + + + + No rootMountPoint is set. + + + + + No configFilePath is set. + + + LicensePage @@ -2513,12 +2544,12 @@ The installer will quit and all changes will be lost. PackageModel - + Name Name - + Description Description @@ -2641,42 +2672,42 @@ The installer will quit and all changes will be lost. PartitionLabelsView - + Root Root - + Home Home - + Boot Boot - + EFI system EFI system - + Swap Swap - + New partition for %1 New partition for %1 - + New partition New partition - + %1 %2 size[number] filesystem[name] %1 %2 @@ -2685,39 +2716,39 @@ The installer will quit and all changes will be lost. PartitionModel - - + + Free Space Free Space - - + + New partition New partition - + Name Name - + File System File System - + File System Label File System Label - + Mount Point Mount Point - + Size Size @@ -2813,82 +2844,82 @@ The installer will quit and all changes will be lost. Partitions - + Current: Current: - + After: After: - + No EFI system partition configured No EFI system partition configured - + EFI system partition configured incorrectly EFI system partition configured incorrectly - + An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a suitable filesystem. An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a suitable filesystem. - + The filesystem must be mounted on <strong>%1</strong>. The filesystem must be mounted on <strong>%1</strong>. - + The filesystem must have type FAT32. The filesystem must have type FAT32. - + The filesystem must be at least %1 MiB in size. The filesystem must be at least %1 MiB in size. - + The filesystem must have flag <strong>%1</strong> set. The filesystem must have flag <strong>%1</strong> set. - + You can continue without setting up an EFI system partition but your system may fail to start. You can continue without setting up an EFI system partition but your system may fail to start. - + Option to use GPT on BIOS Option to use GPT on BIOS - + A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. - + Boot partition not encrypted Boot partition not encrypted - + A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. - + has at least one disk device available. has at least one disk device available. - + There are no partitions to install on. There are no partitions to install on. @@ -2936,17 +2967,17 @@ The installer will quit and all changes will be lost. PreserveFiles - + Saving files for later ... Saving files for later ... - + No files configured to save for later. No files configured to save for later. - + Not all of the configured files could be preserved. Not all of the configured files could be preserved. @@ -2954,14 +2985,14 @@ The installer will quit and all changes will be lost. ProcessResult - + There was no output from the command. There was no output from the command. - + Output: @@ -2970,52 +3001,52 @@ Output: - + External command crashed. External command crashed. - + Command <i>%1</i> crashed. Command <i>%1</i> crashed. - + External command failed to start. External command failed to start. - + Command <i>%1</i> failed to start. Command <i>%1</i> failed to start. - + Internal error when starting command. Internal error when starting command. - + Bad parameters for process job call. Bad parameters for process job call. - + External command failed to finish. External command failed to finish. - + Command <i>%1</i> failed to finish in %2 seconds. Command <i>%1</i> failed to finish in %2 seconds. - + External command finished with errors. External command finished with errors. - + Command <i>%1</i> finished with exit code %2. Command <i>%1</i> finished with exit code %2. @@ -3028,22 +3059,22 @@ Output: %1 (%2) - + unknown unknown - + extended extended - + unformatted unformatted - + swap swap @@ -3078,12 +3109,12 @@ Output: Could not create new random file <pre>%1</pre>. - + No product No product - + No description provided. No description provided. @@ -3093,7 +3124,7 @@ Output: (no mount point) - + Unpartitioned space or unknown partition table Unpartitioned space or unknown partition table @@ -3119,18 +3150,18 @@ Output: RemoveVolumeGroupJob - - + + Remove Volume Group named %1. Remove Volume Group named %1. - + Remove Volume Group named <strong>%1</strong>. Remove Volume Group named <strong>%1</strong>. - + The installer failed to remove a volume group named '%1'. The installer failed to remove a volume group named '%1'. @@ -3143,69 +3174,69 @@ Output: Form - + Select where to install %1.<br/><font color="red">Warning: </font>this will delete all files on the selected partition. Select where to install %1.<br/><font color="red">Warning: </font>this will delete all files on the selected partition. - + The selected item does not appear to be a valid partition. The selected item does not appear to be a valid partition. - + %1 cannot be installed on empty space. Please select an existing partition. %1 cannot be installed on empty space. Please select an existing partition. - + %1 cannot be installed on an extended partition. Please select an existing primary or logical partition. %1 cannot be installed on an extended partition. Please select an existing primary or logical partition. - + %1 cannot be installed on this partition. %1 cannot be installed on this partition. - + Data partition (%1) Data partition (%1) - + Unknown system partition (%1) Unknown system partition (%1) - + %1 system partition (%2) %1 system partition (%2) - + <strong>%4</strong><br/><br/>The partition %1 is too small for %2. Please select a partition with capacity at least %3 GiB. <strong>%4</strong><br/><br/>The partition %1 is too small for %2. Please select a partition with capacity at least %3 GiB. - + <strong>%2</strong><br/><br/>An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. <strong>%2</strong><br/><br/>An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. - - - + + + <strong>%3</strong><br/><br/>%1 will be installed on %2.<br/><font color="red">Warning: </font>all data on partition %2 will be lost. <strong>%3</strong><br/><br/>%1 will be installed on %2.<br/><font color="red">Warning: </font>all data on partition %2 will be lost. - + The EFI system partition at %1 will be used for starting %2. The EFI system partition at %1 will be used for starting %2. - + EFI system partition: EFI system partition: @@ -3230,68 +3261,68 @@ Output: ResizeFSJob - + Resize Filesystem Job Resize Filesystem Job - + Invalid configuration Invalid configuration - + The file-system resize job has an invalid configuration and will not run. The file-system resize job has an invalid configuration and will not run. - + KPMCore not Available KPMCore not Available - + Calamares cannot start KPMCore for the file-system resize job. Calamares cannot start KPMCore for the file-system resize job. - - - - - + + + + + Resize Failed Resize Failed - + The filesystem %1 could not be found in this system, and cannot be resized. The filesystem %1 could not be found in this system, and cannot be resized. - + The device %1 could not be found in this system, and cannot be resized. The device %1 could not be found in this system, and cannot be resized. - - + + The filesystem %1 cannot be resized. The filesystem %1 cannot be resized. - - + + The device %1 cannot be resized. The device %1 cannot be resized. - + The filesystem %1 must be resized, but cannot. The filesystem %1 must be resized, but cannot. - + The device %1 must be resized, but cannot The device %1 must be resized, but cannot @@ -3299,17 +3330,17 @@ Output: ResizePartitionJob - + Resize partition %1. Resize partition %1. - + Resize <strong>%2MiB</strong> partition <strong>%1</strong> to <strong>%3MiB</strong>. Resize <strong>%2MiB</strong> partition <strong>%1</strong> to <strong>%3MiB</strong>. - + Resizing %2MiB partition %1 to %3MiB. Resizing %2MiB partition %1 to %3MiB. @@ -3330,18 +3361,18 @@ Output: ResizeVolumeGroupJob - - + + Resize volume group named %1 from %2 to %3. Resize volume group named %1 from %2 to %3. - + Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>. Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>. - + The installer failed to resize a volume group named '%1'. The installer failed to resize a volume group named '%1'. @@ -3362,12 +3393,12 @@ Output: ScanningDialog - + Scanning storage devices... Scanning storage devices... - + Partitioning Partitioning @@ -3435,82 +3466,82 @@ Output: SetPartFlagsJob - + Set flags on partition %1. Set flags on partition %1. - + Set flags on %1MiB %2 partition. Set flags on %1MiB %2 partition. - + Set flags on new partition. Set flags on new partition. - + Clear flags on partition <strong>%1</strong>. Clear flags on partition <strong>%1</strong>. - + Clear flags on %1MiB <strong>%2</strong> partition. Clear flags on %1MiB <strong>%2</strong> partition. - + Clear flags on new partition. Clear flags on new partition. - + Flag partition <strong>%1</strong> as <strong>%2</strong>. Flag partition <strong>%1</strong> as <strong>%2</strong>. - + Flag %1MiB <strong>%2</strong> partition as <strong>%3</strong>. Flag %1MiB <strong>%2</strong> partition as <strong>%3</strong>. - + Flag new partition as <strong>%1</strong>. Flag new partition as <strong>%1</strong>. - + Clearing flags on partition <strong>%1</strong>. Clearing flags on partition <strong>%1</strong>. - + Clearing flags on %1MiB <strong>%2</strong> partition. Clearing flags on %1MiB <strong>%2</strong> partition. - + Clearing flags on new partition. Clearing flags on new partition. - + Setting flags <strong>%2</strong> on partition <strong>%1</strong>. Setting flags <strong>%2</strong> on partition <strong>%1</strong>. - + Setting flags <strong>%3</strong> on %1MiB <strong>%2</strong> partition. Setting flags <strong>%3</strong> on %1MiB <strong>%2</strong> partition. - + Setting flags <strong>%1</strong> on new partition. Setting flags <strong>%1</strong> on new partition. - + The installer failed to set flags on partition %1. The installer failed to set flags on partition %1. @@ -3636,7 +3667,7 @@ Output: ShellProcessJob - + Shell Processes Job Shell Processes Job @@ -3653,27 +3684,27 @@ Output: StandardButtons - + &OK &OK - + &Yes &Yes - + &No &No - + &Cancel &Cancel - + &Close &Close @@ -3681,12 +3712,12 @@ Output: TrackingInstallJob - + Installation feedback Installation feedback - + Sending installation feedback. Sending installation feedback. @@ -3704,28 +3735,28 @@ Output: TrackingKUserFeedbackJob - + KDE user feedback KDE user feedback - + Configuring KDE user feedback. Configuring KDE user feedback. - + Error in KDE user feedback configuration. Error in KDE user feedback configuration. - + Could not configure KDE user feedback correctly, script error %1. Could not configure KDE user feedback correctly, script error %1. - + Could not configure KDE user feedback correctly, Calamares error %1. Could not configure KDE user feedback correctly, Calamares error %1. @@ -3744,17 +3775,17 @@ Output: - + Error in machine feedback configuration. Error in machine feedback configuration. - + Could not configure machine feedback correctly, script error %1. Could not configure machine feedback correctly, script error %1. - + Could not configure machine feedback correctly, Calamares error %1. Could not configure machine feedback correctly, Calamares error %1. @@ -3810,6 +3841,24 @@ Output: Feedback + + UmountJob + + + Unmount file systems. + + + + + No target system available. + + + + + No rootMountPoint is set. + + + UsersPage @@ -4022,6 +4071,50 @@ Output: Welcome + + ZfsJob + + + Create ZFS pools and datasets + + + + + Failed to create zpool on + + + + + Configuration Error + Configuration Error + + + + No partitions are available for Zfs. + + + + + Internal data missing + + + + + + Failed to create zpool + + + + + Failed to create dataset + + + + + The output was: + + + about @@ -4097,6 +4190,30 @@ Output: This log is copied to /var/log/installation.log of the target system.</p> + + finishedq@mobile + + + Installation Completed + Installation Completed + + + + %1 has been installed on your computer.<br/> + You may now restart your device. + + + + + Close + + + + + Restart + + + i18n diff --git a/lang/calamares_ja-Hira.ts b/lang/calamares_ja-Hira.ts new file mode 100644 index 000000000..ce8d59bf4 --- /dev/null +++ b/lang/calamares_ja-Hira.ts @@ -0,0 +1,4366 @@ + + + + + AutoMountManagementJob + + + Manage auto-mount settings + + + + + BootInfoWidget + + + The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. + + + + + This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. + + + + + This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. + + + + + BootLoaderModel + + + Master Boot Record of %1 + + + + + Boot Partition + + + + + System Partition + + + + + Do not install a boot loader + + + + + %1 (%2) + + + + + Calamares::BlankViewStep + + + Blank Page + + + + + Calamares::DebugWindow + + + Form + + + + + GlobalStorage + + + + + JobQueue + + + + + Modules + + + + + Type: + + + + + + none + + + + + Interface: + + + + + Crashes Calamares, so that Dr. Konqui can look at it. + + + + + Reloads the stylesheet from the branding directory. + + + + + Uploads the session log to the configured pastebin. + + + + + Send Session Log + + + + + Reload Stylesheet + + + + + Displays the tree of widget names in the log (for stylesheet debugging). + + + + + Widget Tree + + + + + Debug information + + + + + Calamares::ExecutionViewStep + + + Set up + + + + + Install + + + + + Calamares::FailJob + + + Job failed (%1) + + + + + Programmed job failure was explicitly requested. + + + + + Calamares::JobThread + + + Done + + + + + Calamares::NamedJob + + + Example job (%1) + + + + + Calamares::ProcessJob + + + Run command '%1' in target system. + + + + + Run command '%1'. + + + + + Running command %1 %2 + + + + + Calamares::PythonJob + + + Running %1 operation. + + + + + Bad working directory path + + + + + Working directory %1 for python job %2 is not readable. + + + + + Bad main script file + + + + + Main script file %1 for python job %2 is not readable. + + + + + Boost.Python error in job "%1". + + + + + Calamares::QmlViewStep + + + Loading ... + + + + + QML Step <i>%1</i>. + + + + + Loading failed. + + + + + Calamares::RequirementsChecker + + + Requirements checking for module <i>%1</i> is complete. + + + + + Waiting for %n module(s). + + + + + + + (%n second(s)) + + + + + + + System-requirements checking is complete. + + + + + Calamares::ViewManager + + + Setup Failed + + + + + Installation Failed + + + + + Would you like to paste the install log to the web? + + + + + Error + + + + + &Yes + + + + + &No + + + + + &Close + + + + + Install Log Paste URL + + + + + The upload was unsuccessful. No web-paste was done. + + + + + Install log posted to + +%1 + +Link copied to clipboard + + + + + Calamares Initialization Failed + + + + + %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. + + + + + <br/>The following modules could not be loaded: + + + + + Continue with setup? + + + + + Continue with installation? + + + + + The %1 setup program is about to make changes to your disk in order to set up %2.<br/><strong>You will not be able to undo these changes.</strong> + + + + + The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> + + + + + &Set up now + + + + + &Install now + + + + + Go &back + + + + + &Set up + + + + + &Install + + + + + Setup is complete. Close the setup program. + + + + + The installation is complete. Close the installer. + + + + + Cancel setup without changing the system. + + + + + Cancel installation without changing the system. + + + + + &Next + + + + + &Back + + + + + &Done + + + + + &Cancel + + + + + Cancel setup? + + + + + Cancel installation? + + + + + Do you really want to cancel the current setup process? +The setup program will quit and all changes will be lost. + + + + + Do you really want to cancel the current install process? +The installer will quit and all changes will be lost. + + + + + CalamaresPython::Helper + + + Unknown exception type + + + + + unparseable Python error + + + + + unparseable Python traceback + + + + + Unfetchable Python error. + + + + + CalamaresWindow + + + %1 Setup Program + + + + + %1 Installer + + + + + ChangeFilesystemLabelJob + + + Set filesystem label on %1. + + + + + Set filesystem label <strong>%1</strong> to partition <strong>%2</strong>. + + + + + The installer failed to update partition table on disk '%1'. + + + + + CheckerContainer + + + Gathering system information... + + + + + ChoicePage + + + Form + + + + + Select storage de&vice: + + + + + + + + Current: + + + + + After: + + + + + <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. + + + + + Reuse %1 as home partition for %2. + + + + + <strong>Select a partition to shrink, then drag the bottom bar to resize</strong> + + + + + %1 will be shrunk to %2MiB and a new %3MiB partition will be created for %4. + + + + + Boot loader location: + + + + + <strong>Select a partition to install on</strong> + + + + + An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. + + + + + The EFI system partition at %1 will be used for starting %2. + + + + + EFI system partition: + + + + + This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + + + + + + + + <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. + + + + + + + + <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. + + + + + + + + <strong>Replace a partition</strong><br/>Replaces a partition with %1. + + + + + This storage device has %1 on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + + + + + This storage device already has an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + + + + + This storage device has multiple operating systems on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. + + + + + This storage device already has an operating system on it, but the partition table <strong>%1</strong> is different from the needed <strong>%2</strong>.<br/> + + + + + This storage device has one of its partitions <strong>mounted</strong>. + + + + + This storage device is a part of an <strong>inactive RAID</strong> device. + + + + + No Swap + + + + + Reuse Swap + + + + + Swap (no Hibernate) + + + + + Swap (with Hibernate) + + + + + Swap to file + + + + + ClearMountsJob + + + Successfully unmounted %1. + + + + + Successfully disabled swap %1. + + + + + Successfully cleared swap %1. + + + + + Successfully closed mapper device %1. + + + + + Successfully disabled volume group %1. + + + + + Clear mounts for partitioning operations on %1 + + + + + Clearing mounts for partitioning operations on %1. + + + + + Cleared all mounts for %1 + + + + + ClearTempMountsJob + + + Clear all temporary mounts. + + + + + Clearing all temporary mounts. + + + + + Cannot get list of temporary mounts. + + + + + Cleared all temporary mounts. + + + + + CommandList + + + + Could not run command. + + + + + The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined. + + + + + The command needs to know the user's name, but no username is defined. + + + + + Config + + + Set keyboard model to %1.<br/> + + + + + Set keyboard layout to %1/%2. + + + + + Set timezone to %1/%2. + + + + + The system language will be set to %1. + + + + + The numbers and dates locale will be set to %1. + + + + + Network Installation. (Disabled: Incorrect configuration) + + + + + Network Installation. (Disabled: Received invalid groups data) + + + + + Network Installation. (Disabled: Internal error) + + + + + Network Installation. (Disabled: No package list) + + + + + Package selection + + + + + Network Installation. (Disabled: Unable to fetch package lists, check your network connection) + + + + + This computer does not satisfy the minimum requirements for setting up %1.<br/>Setup cannot continue. <a href="#details">Details...</a> + + + + + This computer does not satisfy the minimum requirements for installing %1.<br/>Installation cannot continue. <a href="#details">Details...</a> + + + + + This computer does not satisfy some of the recommended requirements for setting up %1.<br/>Setup can continue, but some features might be disabled. + + + + + This computer does not satisfy some of the recommended requirements for installing %1.<br/>Installation can continue, but some features might be disabled. + + + + + This program will ask you some questions and set up %2 on your computer. + + + + + <h1>Welcome to the Calamares setup program for %1</h1> + + + + + <h1>Welcome to %1 setup</h1> + + + + + <h1>Welcome to the Calamares installer for %1</h1> + + + + + <h1>Welcome to the %1 installer</h1> + + + + + Your username is too long. + + + + + '%1' is not allowed as username. + + + + + Your username must start with a lowercase letter or underscore. + + + + + Only lowercase letters, numbers, underscore and hyphen are allowed. + + + + + Your hostname is too short. + + + + + Your hostname is too long. + + + + + '%1' is not allowed as hostname. + + + + + Only letters, numbers, underscore and hyphen are allowed. + + + + + Your passwords do not match! + + + + + OK! + + + + + Setup Failed + + + + + Installation Failed + + + + + The setup of %1 did not complete successfully. + + + + + The installation of %1 did not complete successfully. + + + + + Setup Complete + + + + + Installation Complete + + + + + The setup of %1 is complete. + + + + + The installation of %1 is complete. + + + + + Package Selection + + + + + Please pick a product from the list. The selected product will be installed. + + + + + Install option: <strong>%1</strong> + + + + + None + + + + + Summary + + + + + This is an overview of what will happen once you start the setup procedure. + + + + + This is an overview of what will happen once you start the install procedure. + + + + + ContextualProcessJob + + + Contextual Processes Job + + + + + CreatePartitionDialog + + + Create a Partition + + + + + Si&ze: + + + + + MiB + + + + + Partition &Type: + + + + + &Primary + + + + + E&xtended + + + + + Fi&le System: + + + + + LVM LV name + + + + + &Mount Point: + + + + + Flags: + + + + + Label for the filesystem + + + + + FS Label: + + + + + En&crypt + + + + + Logical + + + + + Primary + + + + + GPT + + + + + Mountpoint already in use. Please select another one. + + + + + CreatePartitionJob + + + Create new %1MiB partition on %3 (%2) with entries %4. + + + + + Create new %1MiB partition on %3 (%2). + + + + + Create new %2MiB partition on %4 (%3) with file system %1. + + + + + Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2) with entries <em>%4</em>. + + + + + Create new <strong>%1MiB</strong> partition on <strong>%3</strong> (%2). + + + + + Create new <strong>%2MiB</strong> partition on <strong>%4</strong> (%3) with file system <strong>%1</strong>. + + + + + + Creating new %1 partition on %2. + + + + + The installer failed to create partition on disk '%1'. + + + + + CreatePartitionTableDialog + + + Create Partition Table + + + + + Creating a new partition table will delete all existing data on the disk. + + + + + What kind of partition table do you want to create? + + + + + Master Boot Record (MBR) + + + + + GUID Partition Table (GPT) + + + + + CreatePartitionTableJob + + + Create new %1 partition table on %2. + + + + + Create new <strong>%1</strong> partition table on <strong>%2</strong> (%3). + + + + + Creating new %1 partition table on %2. + + + + + The installer failed to create a partition table on %1. + + + + + CreateUserJob + + + Create user %1 + + + + + Create user <strong>%1</strong>. + + + + + Preserving home directory + + + + + + Creating user %1 + + + + + Configuring user %1 + + + + + Setting file permissions + + + + + CreateVolumeGroupDialog + + + Create Volume Group + + + + + CreateVolumeGroupJob + + + Create new volume group named %1. + + + + + Create new volume group named <strong>%1</strong>. + + + + + Creating new volume group named %1. + + + + + The installer failed to create a volume group named '%1'. + + + + + DeactivateVolumeGroupJob + + + + Deactivate volume group named %1. + + + + + Deactivate volume group named <strong>%1</strong>. + + + + + The installer failed to deactivate a volume group named %1. + + + + + DeletePartitionJob + + + Delete partition %1. + + + + + Delete partition <strong>%1</strong>. + + + + + Deleting partition %1. + + + + + The installer failed to delete partition %1. + + + + + DeviceInfoWidget + + + This device has a <strong>%1</strong> partition table. + + + + + This is a <strong>loop</strong> device.<br><br>It is a pseudo-device with no partition table that makes a file accessible as a block device. This kind of setup usually only contains a single filesystem. + + + + + This installer <strong>cannot detect a partition table</strong> on the selected storage device.<br><br>The device either has no partition table, or the partition table is corrupted or of an unknown type.<br>This installer can create a new partition table for you, either automatically, or through the manual partitioning page. + + + + + <br><br>This is the recommended partition table type for modern systems which start from an <strong>EFI</strong> boot environment. + + + + + <br><br>This partition table type is only advisable on older systems which start from a <strong>BIOS</strong> boot environment. GPT is recommended in most other cases.<br><br><strong>Warning:</strong> the MBR partition table is an obsolete MS-DOS era standard.<br>Only 4 <em>primary</em> partitions may be created, and of those 4, one can be an <em>extended</em> partition, which may in turn contain many <em>logical</em> partitions. + + + + + The type of <strong>partition table</strong> on the selected storage device.<br><br>The only way to change the partition table type is to erase and recreate the partition table from scratch, which destroys all data on the storage device.<br>This installer will keep the current partition table unless you explicitly choose otherwise.<br>If unsure, on modern systems GPT is preferred. + + + + + DeviceModel + + + %1 - %2 (%3) + device[name] - size[number] (device-node[name]) + + + + + %1 - (%2) + device[name] - (device-node[name]) + + + + + DracutLuksCfgJob + + + Write LUKS configuration for Dracut to %1 + + + + + Skip writing LUKS configuration for Dracut: "/" partition is not encrypted + + + + + Failed to open %1 + + + + + DummyCppJob + + + Dummy C++ Job + + + + + EditExistingPartitionDialog + + + Edit Existing Partition + + + + + Content: + + + + + &Keep + + + + + Format + + + + + Warning: Formatting the partition will erase all existing data. + + + + + &Mount Point: + + + + + Si&ze: + + + + + MiB + + + + + Fi&le System: + + + + + Flags: + + + + + Label for the filesystem + + + + + FS Label: + + + + + Mountpoint already in use. Please select another one. + + + + + EncryptWidget + + + Form + + + + + En&crypt system + + + + + Passphrase + + + + + Confirm passphrase + + + + + + Please enter the same passphrase in both boxes. + + + + + FillGlobalStorageJob + + + Set partition information + + + + + Install %1 on <strong>new</strong> %2 system partition with features <em>%3</em> + + + + + Install %1 on <strong>new</strong> %2 system partition. + + + + + Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong> and features <em>%3</em>. + + + + + Set up <strong>new</strong> %2 partition with mount point <strong>%1</strong>%3. + + + + + Install %2 on %3 system partition <strong>%1</strong> with features <em>%4</em>. + + + + + Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong> and features <em>%4</em>. + + + + + Set up %3 partition <strong>%1</strong> with mount point <strong>%2</strong>%4. + + + + + Install %2 on %3 system partition <strong>%1</strong>. + + + + + Install boot loader on <strong>%1</strong>. + + + + + Setting up mount points. + + + + + FinishedPage + + + Form + + + + + &Restart now + + + + + <h1>All done.</h1><br/>%1 has been set up on your computer.<br/>You may now start using your new system. + + + + + <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the setup program.</p></body></html> + + + + + <h1>All done.</h1><br/>%1 has been installed on your computer.<br/>You may now restart into your new system, or continue using the %2 Live environment. + + + + + <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style="font-style:italic;">Done</span> or close the installer.</p></body></html> + + + + + <h1>Setup Failed</h1><br/>%1 has not been set up on your computer.<br/>The error message was: %2. + + + + + <h1>Installation Failed</h1><br/>%1 has not been installed on your computer.<br/>The error message was: %2. + + + + + FinishedQmlViewStep + + + Finish + + + + + FinishedViewStep + + + Finish + + + + + FormatPartitionJob + + + Format partition %1 (file system: %2, size: %3 MiB) on %4. + + + + + Format <strong>%3MiB</strong> partition <strong>%1</strong> with file system <strong>%2</strong>. + + + + + Formatting partition %1 with file system %2. + + + + + The installer failed to format partition %1 on disk '%2'. + + + + + GeneralRequirements + + + has at least %1 GiB available drive space + + + + + There is not enough drive space. At least %1 GiB is required. + + + + + has at least %1 GiB working memory + + + + + The system does not have enough working memory. At least %1 GiB is required. + + + + + is plugged in to a power source + + + + + The system is not plugged in to a power source. + + + + + is connected to the Internet + + + + + The system is not connected to the Internet. + + + + + is running the installer as an administrator (root) + + + + + The setup program is not running with administrator rights. + + + + + The installer is not running with administrator rights. + + + + + has a screen large enough to show the whole installer + + + + + The screen is too small to display the setup program. + + + + + The screen is too small to display the installer. + + + + + HostInfoJob + + + Collecting information about your machine. + + + + + IDJob + + + + + + OEM Batch Identifier + + + + + Could not create directories <code>%1</code>. + + + + + Could not open file <code>%1</code>. + + + + + Could not write to file <code>%1</code>. + + + + + InitcpioJob + + + Creating initramfs with mkinitcpio. + + + + + InitramfsJob + + + Creating initramfs. + + + + + InteractiveTerminalPage + + + Konsole not installed + + + + + Please install KDE Konsole and try again! + + + + + Executing script: &nbsp;<code>%1</code> + + + + + InteractiveTerminalViewStep + + + Script + + + + + KeyboardQmlViewStep + + + Keyboard + + + + + KeyboardViewStep + + + Keyboard + + + + + LCLocaleDialog + + + System locale setting + + + + + The system locale setting affects the language and character set for some command line user interface elements.<br/>The current setting is <strong>%1</strong>. + + + + + &Cancel + + + + + &OK + + + + + LicensePage + + + Form + + + + + <h1>License Agreement</h1> + + + + + I accept the terms and conditions above. + + + + + Please review the End User License Agreements (EULAs). + + + + + This setup procedure will install proprietary software that is subject to licensing terms. + + + + + If you do not agree with the terms, the setup procedure cannot continue. + + + + + This setup procedure can install proprietary software that is subject to licensing terms in order to provide additional features and enhance the user experience. + + + + + If you do not agree with the terms, proprietary software will not be installed, and open source alternatives will be used instead. + + + + + LicenseViewStep + + + License + + + + + LicenseWidget + + + URL: %1 + + + + + <strong>%1 driver</strong><br/>by %2 + %1 is an untranslatable product name, example: Creative Audigy driver + + + + + <strong>%1 graphics driver</strong><br/><font color="Grey">by %2</font> + %1 is usually a vendor name, example: Nvidia graphics driver + + + + + <strong>%1 browser plugin</strong><br/><font color="Grey">by %2</font> + + + + + <strong>%1 codec</strong><br/><font color="Grey">by %2</font> + + + + + <strong>%1 package</strong><br/><font color="Grey">by %2</font> + + + + + <strong>%1</strong><br/><font color="Grey">by %2</font> + + + + + File: %1 + + + + + Hide license text + + + + + Show the license text + + + + + Open license agreement in browser. + + + + + LocalePage + + + Region: + + + + + Zone: + + + + + + &Change... + + + + + LocaleQmlViewStep + + + Location + + + + + LocaleTests + + + Quit + + + + + LocaleViewStep + + + Location + + + + + LuksBootKeyFileJob + + + Configuring LUKS key file. + + + + + + No partitions are defined. + + + + + + + Encrypted rootfs setup error + + + + + Root partition %1 is LUKS but no passphrase has been set. + + + + + Could not create LUKS key file for root partition %1. + + + + + Could not configure LUKS key file on partition %1. + + + + + MachineIdJob + + + Generate machine-id. + + + + + Configuration Error + + + + + No root mount point is set for MachineId. + + + + + Map + + + Timezone: %1 + + + + + Please select your preferred location on the map so the installer can suggest the locale + and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging + to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. + + + + + NetInstallViewStep + + + Package selection + + + + + Office software + + + + + Office package + + + + + Browser software + + + + + Browser package + + + + + Web browser + + + + + Kernel + + + + + Services + + + + + Login + + + + + Desktop + + + + + Applications + + + + + Communication + + + + + Development + + + + + Office + + + + + Multimedia + + + + + Internet + + + + + Theming + + + + + Gaming + + + + + Utilities + + + + + NotesQmlViewStep + + + Notes + + + + + OEMPage + + + Ba&tch: + + + + + <html><head/><body><p>Enter a batch-identifier here. This will be stored in the target system.</p></body></html> + + + + + <html><head/><body><h1>OEM Configuration</h1><p>Calamares will use OEM settings while configuring the target system.</p></body></html> + + + + + OEMViewStep + + + OEM Configuration + + + + + Set the OEM Batch Identifier to <code>%1</code>. + + + + + Offline + + + Select your preferred Region, or use the default settings. + + + + + + + Timezone: %1 + + + + + Select your preferred Zone within your Region. + + + + + Zones + + + + + You can fine-tune Language and Locale settings below. + + + + + PWQ + + + Password is too short + + + + + Password is too long + + + + + Password is too weak + + + + + Memory allocation error when setting '%1' + + + + + Memory allocation error + + + + + The password is the same as the old one + + + + + The password is a palindrome + + + + + The password differs with case changes only + + + + + The password is too similar to the old one + + + + + The password contains the user name in some form + + + + + The password contains words from the real name of the user in some form + + + + + The password contains forbidden words in some form + + + + + The password contains too few digits + + + + + The password contains too few uppercase letters + + + + + The password contains fewer than %n lowercase letters + + + + + + + The password contains too few lowercase letters + + + + + The password contains too few non-alphanumeric characters + + + + + The password is too short + + + + + The password does not contain enough character classes + + + + + The password contains too many same characters consecutively + + + + + The password contains too many characters of the same class consecutively + + + + + The password contains fewer than %n digits + + + + + + + The password contains fewer than %n uppercase letters + + + + + + + The password contains fewer than %n non-alphanumeric characters + + + + + + + The password is shorter than %n characters + + + + + + + The password is a rotated version of the previous one + + + + + The password contains fewer than %n character classes + + + + + + + The password contains more than %n same characters consecutively + + + + + + + The password contains more than %n characters of the same class consecutively + + + + + + + The password contains monotonic sequence longer than %n characters + + + + + + + The password contains too long of a monotonic character sequence + + + + + No password supplied + + + + + Cannot obtain random numbers from the RNG device + + + + + Password generation failed - required entropy too low for settings + + + + + The password fails the dictionary check - %1 + + + + + The password fails the dictionary check + + + + + Unknown setting - %1 + + + + + Unknown setting + + + + + Bad integer value of setting - %1 + + + + + Bad integer value + + + + + Setting %1 is not of integer type + + + + + Setting is not of integer type + + + + + Setting %1 is not of string type + + + + + Setting is not of string type + + + + + Opening the configuration file failed + + + + + The configuration file is malformed + + + + + Fatal failure + + + + + Unknown error + + + + + Password is empty + + + + + PackageChooserPage + + + Form + + + + + Product Name + + + + + TextLabel + + + + + Long Product Description + + + + + Package Selection + + + + + Please pick a product from the list. The selected product will be installed. + + + + + PackageChooserQmlViewStep + + + Packages + + + + + PackageChooserViewStep + + + Packages + + + + + PackageModel + + + Name + + + + + Description + + + + + Page_Keyboard + + + Form + + + + + Keyboard Model: + + + + + Type here to test your keyboard + + + + + Page_UserSetup + + + Form + + + + + What is your name? + + + + + Your Full Name + + + + + What name do you want to use to log in? + + + + + login + + + + + What is the name of this computer? + + + + + <small>This name will be used if you make the computer visible to others on a network.</small> + + + + + Computer Name + + + + + Choose a password to keep your account safe. + + + + + + <small>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</small> + + + + + + Password + + + + + + Repeat Password + + + + + When this box is checked, password-strength checking is done and you will not be able to use a weak password. + + + + + Require strong passwords. + + + + + Log in automatically without asking for the password. + + + + + Use the same password for the administrator account. + + + + + Choose a password for the administrator account. + + + + + + <small>Enter the same password twice, so that it can be checked for typing errors.</small> + + + + + PartitionLabelsView + + + Root + + + + + Home + + + + + Boot + + + + + EFI system + + + + + Swap + + + + + New partition for %1 + + + + + New partition + + + + + %1 %2 + size[number] filesystem[name] + + + + + PartitionModel + + + + Free Space + + + + + + New partition + + + + + Name + + + + + File System + + + + + File System Label + + + + + Mount Point + + + + + Size + + + + + PartitionPage + + + Form + + + + + Storage de&vice: + + + + + &Revert All Changes + + + + + New Partition &Table + + + + + Cre&ate + + + + + &Edit + + + + + &Delete + + + + + New Volume Group + + + + + Resize Volume Group + + + + + Deactivate Volume Group + + + + + Remove Volume Group + + + + + I&nstall boot loader on: + + + + + Are you sure you want to create a new partition table on %1? + + + + + Can not create new partition + + + + + The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead. + + + + + PartitionViewStep + + + Gathering system information... + + + + + Partitions + + + + + Current: + + + + + After: + + + + + No EFI system partition configured + + + + + EFI system partition configured incorrectly + + + + + An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a suitable filesystem. + + + + + The filesystem must be mounted on <strong>%1</strong>. + + + + + The filesystem must have type FAT32. + + + + + The filesystem must be at least %1 MiB in size. + + + + + The filesystem must have flag <strong>%1</strong> set. + + + + + You can continue without setting up an EFI system partition but your system may fail to start. + + + + + Option to use GPT on BIOS + + + + + A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.<br/><br/>To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the <strong>bios_grub</strong> flag enabled.<br/><br/>An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT. + + + + + Boot partition not encrypted + + + + + A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.<br/><br/>There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.<br/>You may continue if you wish, but filesystem unlocking will happen later during system startup.<br/>To encrypt the boot partition, go back and recreate it, selecting <strong>Encrypt</strong> in the partition creation window. + + + + + has at least one disk device available. + + + + + There are no partitions to install on. + + + + + PlasmaLnfJob + + + Plasma Look-and-Feel Job + + + + + + Could not select KDE Plasma Look-and-Feel package + + + + + PlasmaLnfPage + + + Form + + + + + Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is set up. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel. + + + + + Please choose a look-and-feel for the KDE Plasma Desktop. You can also skip this step and configure the look-and-feel once the system is installed. Clicking on a look-and-feel selection will give you a live preview of that look-and-feel. + + + + + PlasmaLnfViewStep + + + Look-and-Feel + + + + + PreserveFiles + + + Saving files for later ... + + + + + No files configured to save for later. + + + + + Not all of the configured files could be preserved. + + + + + ProcessResult + + + +There was no output from the command. + + + + + +Output: + + + + + + External command crashed. + + + + + Command <i>%1</i> crashed. + + + + + External command failed to start. + + + + + Command <i>%1</i> failed to start. + + + + + Internal error when starting command. + + + + + Bad parameters for process job call. + + + + + External command failed to finish. + + + + + Command <i>%1</i> failed to finish in %2 seconds. + + + + + External command finished with errors. + + + + + Command <i>%1</i> finished with exit code %2. + + + + + QObject + + + %1 (%2) + + + + + unknown + + + + + extended + + + + + unformatted + + + + + swap + + + + + + Default + + + + + + + + File not found + + + + + Path <pre>%1</pre> must be an absolute path. + + + + + Directory not found + + + + + + Could not create new random file <pre>%1</pre>. + + + + + No product + + + + + No description provided. + + + + + (no mount point) + + + + + Unpartitioned space or unknown partition table + + + + + Recommended + + + <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> + Setup can continue, but some features might be disabled.</p> + + + + + RemoveUserJob + + + Remove live user from target system + + + + + RemoveVolumeGroupJob + + + + Remove Volume Group named %1. + + + + + Remove Volume Group named <strong>%1</strong>. + + + + + The installer failed to remove a volume group named '%1'. + + + + + ReplaceWidget + + + Form + + + + + Select where to install %1.<br/><font color="red">Warning: </font>this will delete all files on the selected partition. + + + + + The selected item does not appear to be a valid partition. + + + + + %1 cannot be installed on empty space. Please select an existing partition. + + + + + %1 cannot be installed on an extended partition. Please select an existing primary or logical partition. + + + + + %1 cannot be installed on this partition. + + + + + Data partition (%1) + + + + + Unknown system partition (%1) + + + + + %1 system partition (%2) + + + + + <strong>%4</strong><br/><br/>The partition %1 is too small for %2. Please select a partition with capacity at least %3 GiB. + + + + + <strong>%2</strong><br/><br/>An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. + + + + + + + <strong>%3</strong><br/><br/>%1 will be installed on %2.<br/><font color="red">Warning: </font>all data on partition %2 will be lost. + + + + + The EFI system partition at %1 will be used for starting %2. + + + + + EFI system partition: + + + + + Requirements + + + <p>This computer does not satisfy the minimum requirements for installing %1.<br/> + Installation cannot continue.</p> + + + + + <p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/> + Setup can continue, but some features might be disabled.</p> + + + + + ResizeFSJob + + + Resize Filesystem Job + + + + + Invalid configuration + + + + + The file-system resize job has an invalid configuration and will not run. + + + + + KPMCore not Available + + + + + Calamares cannot start KPMCore for the file-system resize job. + + + + + + + + + Resize Failed + + + + + The filesystem %1 could not be found in this system, and cannot be resized. + + + + + The device %1 could not be found in this system, and cannot be resized. + + + + + + The filesystem %1 cannot be resized. + + + + + + The device %1 cannot be resized. + + + + + The filesystem %1 must be resized, but cannot. + + + + + The device %1 must be resized, but cannot + + + + + ResizePartitionJob + + + Resize partition %1. + + + + + Resize <strong>%2MiB</strong> partition <strong>%1</strong> to <strong>%3MiB</strong>. + + + + + Resizing %2MiB partition %1 to %3MiB. + + + + + The installer failed to resize partition %1 on disk '%2'. + + + + + ResizeVolumeGroupDialog + + + Resize Volume Group + + + + + ResizeVolumeGroupJob + + + + Resize volume group named %1 from %2 to %3. + + + + + Resize volume group named <strong>%1</strong> from <strong>%2</strong> to <strong>%3</strong>. + + + + + The installer failed to resize a volume group named '%1'. + + + + + ResultsListDialog + + + For best results, please ensure that this computer: + + + + + System requirements + + + + + ScanningDialog + + + Scanning storage devices... + + + + + Partitioning + + + + + SetHostNameJob + + + Set hostname %1 + + + + + Set hostname <strong>%1</strong>. + + + + + Setting hostname %1. + + + + + + Internal Error + + + + + + Cannot write hostname to target system + + + + + SetKeyboardLayoutJob + + + Set keyboard model to %1, layout to %2-%3 + + + + + Failed to write keyboard configuration for the virtual console. + + + + + + + Failed to write to %1 + + + + + Failed to write keyboard configuration for X11. + + + + + Failed to write keyboard configuration to existing /etc/default directory. + + + + + SetPartFlagsJob + + + Set flags on partition %1. + + + + + Set flags on %1MiB %2 partition. + + + + + Set flags on new partition. + + + + + Clear flags on partition <strong>%1</strong>. + + + + + Clear flags on %1MiB <strong>%2</strong> partition. + + + + + Clear flags on new partition. + + + + + Flag partition <strong>%1</strong> as <strong>%2</strong>. + + + + + Flag %1MiB <strong>%2</strong> partition as <strong>%3</strong>. + + + + + Flag new partition as <strong>%1</strong>. + + + + + Clearing flags on partition <strong>%1</strong>. + + + + + Clearing flags on %1MiB <strong>%2</strong> partition. + + + + + Clearing flags on new partition. + + + + + Setting flags <strong>%2</strong> on partition <strong>%1</strong>. + + + + + Setting flags <strong>%3</strong> on %1MiB <strong>%2</strong> partition. + + + + + Setting flags <strong>%1</strong> on new partition. + + + + + The installer failed to set flags on partition %1. + + + + + SetPasswordJob + + + Set password for user %1 + + + + + Setting password for user %1. + + + + + Bad destination system path. + + + + + rootMountPoint is %1 + + + + + Cannot disable root account. + + + + + passwd terminated with error code %1. + + + + + Cannot set password for user %1. + + + + + usermod terminated with error code %1. + + + + + SetTimezoneJob + + + Set timezone to %1/%2 + + + + + Cannot access selected timezone path. + + + + + Bad path: %1 + + + + + Cannot set timezone. + + + + + Link creation failed, target: %1; link name: %2 + + + + + Cannot set timezone, + + + + + Cannot open /etc/timezone for writing + + + + + SetupGroupsJob + + + Preparing groups. + + + + + + Could not create groups in target system + + + + + These groups are missing in the target system: %1 + + + + + SetupSudoJob + + + Configure <pre>sudo</pre> users. + + + + + Cannot chmod sudoers file. + + + + + Cannot create sudoers file for writing. + + + + + ShellProcessJob + + + Shell Processes Job + + + + + SlideCounter + + + %L1 / %L2 + slide counter, %1 of %2 (numeric) + + + + + StandardButtons + + + &OK + + + + + &Yes + + + + + &No + + + + + &Cancel + + + + + &Close + + + + + TrackingInstallJob + + + Installation feedback + + + + + Sending installation feedback. + + + + + Internal error in install-tracking. + + + + + HTTP request timed out. + + + + + TrackingKUserFeedbackJob + + + KDE user feedback + + + + + Configuring KDE user feedback. + + + + + + Error in KDE user feedback configuration. + + + + + Could not configure KDE user feedback correctly, script error %1. + + + + + Could not configure KDE user feedback correctly, Calamares error %1. + + + + + TrackingMachineUpdateManagerJob + + + Machine feedback + + + + + Configuring machine feedback. + + + + + + Error in machine feedback configuration. + + + + + Could not configure machine feedback correctly, script error %1. + + + + + Could not configure machine feedback correctly, Calamares error %1. + + + + + TrackingPage + + + Form + + + + + Placeholder + + + + + <html><head/><body><p>Click here to send <span style=" font-weight:600;">no information at all</span> about your installation.</p></body></html> + + + + + <html><head/><body><p><a href="placeholder"><span style=" text-decoration: underline; color:#2980b9;">Click here for more information about user feedback</span></a></p></body></html> + + + + + Tracking helps %1 to see how often it is installed, what hardware it is installed on and which applications are used. To see what will be sent, please click the help icon next to each area. + + + + + By selecting this you will send information about your installation and hardware. This information will only be sent <b>once</b> after the installation finishes. + + + + + By selecting this you will periodically send information about your <b>machine</b> installation, hardware and applications, to %1. + + + + + By selecting this you will regularly send information about your <b>user</b> installation, hardware, applications and application usage patterns, to %1. + + + + + TrackingViewStep + + + Feedback + + + + + UsersPage + + + <small>If more than one person will use this computer, you can create multiple accounts after setup.</small> + + + + + <small>If more than one person will use this computer, you can create multiple accounts after installation.</small> + + + + + UsersQmlViewStep + + + Users + + + + + UsersViewStep + + + Users + + + + + VariantModel + + + Key + Column header for key/value + + + + + Value + Column header for key/value + + + + + VolumeGroupBaseDialog + + + Create Volume Group + + + + + List of Physical Volumes + + + + + Volume Group Name: + + + + + Volume Group Type: + + + + + Physical Extent Size: + + + + + MiB + + + + + Total Size: + + + + + Used Size: + + + + + Total Sectors: + + + + + Quantity of LVs: + + + + + WelcomePage + + + Form + + + + + + Select application and system language + + + + + &About + + + + + Open donations website + + + + + &Donate + + + + + Open help and support website + + + + + &Support + + + + + Open issues and bug-tracking website + + + + + &Known issues + + + + + Open release notes website + + + + + &Release notes + + + + + <h1>Welcome to the Calamares setup program for %1.</h1> + + + + + <h1>Welcome to %1 setup.</h1> + + + + + <h1>Welcome to the Calamares installer for %1.</h1> + + + + + <h1>Welcome to the %1 installer.</h1> + + + + + %1 support + + + + + About %1 setup + + + + + About %1 installer + + + + + <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. + + + + + WelcomeQmlViewStep + + + Welcome + + + + + WelcomeViewStep + + + Welcome + + + + + about + + + <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. + + + + + Back + + + + + calamares-sidebar + + + Show debug information + + + + + finishedq + + + Installation Completed + + + + + %1 has been installed on your computer.<br/> + You may now restart into your new system, or continue using the Live environment. + + + + + Close Installer + + + + + Restart System + + + + + <p>A full log of the install is available as installation.log in the home directory of the Live user.<br/> + This log is copied to /var/log/installation.log of the target system.</p> + + + + + i18n + + + <h1>Languages</h1> </br> + The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>. + + + + + <h1>Locales</h1> </br> + The system locale setting affects the numbers and dates format. The current setting is <strong>%1</strong>. + + + + + Back + + + + + keyboardq + + + To activate keyboard preview, select a layout. + + + + + Keyboard Model: + + + + + Layouts + + + + + Type here to test your keyboard + + + + + Variants + + + + + localeq + + + Change + + + + + notesqml + + + <h3>%1</h3> + <p>These are example release notes.</p> + + + + + packagechooserq + + + LibreOffice is a powerful and free office suite, used by millions of people around the world. It includes several applications that make it the most versatile Free and Open Source office suite on the market.<br/> + Default option. + + + + + LibreOffice + + + + + If you don't want to install an office suite, just select No Office Suite. You can always add one (or more) later on your installed system as the need arrives. + + + + + No Office Suite + + + + + Create a minimal Desktop install, remove all extra applications and decide later on what you would like to add to your system. Examples of what won't be on such an install, there will be no Office Suite, no media players, no image viewer or print support. It will be just a desktop, file browser, package manager, text editor and simple web-browser. + + + + + Minimal Install + + + + + Please select an option for your install, or use the default: LibreOffice included. + + + + + release_notes + + + <h3>%1</h3> + <p>This an example QML file, showing options in RichText with Flickable content.</p> + + <p>QML with RichText can use HTML tags, Flickable content is useful for touchscreens.</p> + + <p><b>This is bold text</b></p> + <p><i>This is italic text</i></p> + <p><u>This is underlined text</u></p> + <p><center>This text will be center-aligned.</center></p> + <p><s>This is strikethrough</s></p> + + <p>Code example: + <code>ls -l /home</code></p> + + <p><b>Lists:</b></p> + <ul> + <li>Intel CPU systems</li> + <li>AMD CPU systems</li> + </ul> + + <p>The vertical scrollbar is adjustable, current width set to 10.</p> + + + + + Back + + + + + usersq + + + Pick your user name and credentials to login and perform admin tasks + + + + + What is your name? + + + + + Your Full Name + + + + + What name do you want to use to log in? + + + + + Login Name + + + + + If more than one person will use this computer, you can create multiple accounts after installation. + + + + + Only lowercase letters, numbers, underscore and hyphen are allowed. + + + + + root is not allowed as username. + + + + + What is the name of this computer? + + + + + Computer Name + + + + + This name will be used if you make the computer visible to others on a network. + + + + + localhost is not allowed as hostname. + + + + + Choose a password to keep your account safe. + + + + + Password + + + + + Repeat Password + + + + + Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals. + + + + + Validate passwords quality + + + + + When this box is checked, password-strength checking is done and you will not be able to use a weak password. + + + + + Log in automatically without asking for the password + + + + + Only letters, numbers, underscore and hyphen are allowed, minimal of two characters. + + + + + Reuse user password as root password + + + + + Use the same password for the administrator account. + + + + + Choose a root password to keep your account safe. + + + + + Root Password + + + + + Repeat Root Password + + + + + Enter the same password twice, so that it can be checked for typing errors. + + + + + welcomeq + + + <h3>Welcome to the %1 <quote>%2</quote> installer</h3> + <p>This program will ask you some questions and set up %1 on your computer.</p> + + + + + About + + + + + Support + + + + + Known issues + + + + + Release notes + + + + + Donate + + + + diff --git a/lang/calamares_pt_PT.ts b/lang/calamares_pt_PT.ts index 951645ab1..3ec8b295e 100644 --- a/lang/calamares_pt_PT.ts +++ b/lang/calamares_pt_PT.ts @@ -2014,7 +2014,7 @@ O instalador será encerrado e todas as alterações serão perdidas.Please select your preferred location on the map so the installer can suggest the locale and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming. - Por favor selecione o seu local preferido no mapa para que o instalador possa sugerir a localização + Selecione o seu local preferido no mapa para que o instalador possa sugerir a localização e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom. @@ -4003,7 +4003,7 @@ Saída de Dados: <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. - <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. + <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. diff --git a/lang/calamares_ro.ts b/lang/calamares_ro.ts index 39573886d..a4ac28ce6 100644 --- a/lang/calamares_ro.ts +++ b/lang/calamares_ro.ts @@ -104,17 +104,17 @@ Crashes Calamares, so that Dr. Konqui can look at it. - + Dă crash lui Calamares, pentru ca doctorul Konqui să se uite la el. Reloads the stylesheet from the branding directory. - + Reîncarcă foaia de stil din directorul branding. Uploads the session log to the configured pastebin. - + Încarcă jurnalul sesiunii pe pastebin-ul configurat. @@ -134,7 +134,7 @@ Widget Tree - Lista widget + Arborele de widget diff --git a/lang/calamares_tg.ts b/lang/calamares_tg.ts index 1c64c5d8c..b4124be17 100644 --- a/lang/calamares_tg.ts +++ b/lang/calamares_tg.ts @@ -6,7 +6,7 @@ Manage auto-mount settings - + Идора кардани танзимоти васлкунии худкор diff --git a/lang/calamares_zh_CN.ts b/lang/calamares_zh_CN.ts index 5b58024ad..df04d1dd6 100644 --- a/lang/calamares_zh_CN.ts +++ b/lang/calamares_zh_CN.ts @@ -688,27 +688,27 @@ The installer will quit and all changes will be lost. Successfully unmounted %1. - + 成功卸载了 %1。 Successfully disabled swap %1. - + 成功禁用了交换空间 %1。 Successfully cleared swap %1. - + 成功清理了交换空间 %1。 Successfully closed mapper device %1. - + 成功关闭了映射设备 %1。 Successfully disabled volume group %1. - + 成功禁用了卷组 %1。 diff --git a/lang/python.pot b/lang/python.pot index 63372044e..86647241b 100644 --- a/lang/python.pot +++ b/lang/python.pot @@ -2,409 +2,403 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 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" +"POT-Creation-Date: 2022-02-01 17:27+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: src/modules/initramfscfg/main.py:32 msgid "Configuring initramfs." -msgstr "Configuring initramfs." +msgstr "" #: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89 -#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361 -#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105 -#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231 -#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144 +#: src/modules/fstab/main.py:360 src/modules/fstab/main.py:366 +#: src/modules/fstab/main.py:393 src/modules/networkcfg/main.py:105 +#: src/modules/initcpiocfg/main.py:235 src/modules/initcpiocfg/main.py:239 +#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:229 #: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72 #: src/modules/openrcdmcryptcfg/main.py:76 -#: src/modules/luksopenswaphookcfg/main.py:86 -#: src/modules/luksopenswaphookcfg/main.py:90 msgid "Configuration Error" -msgstr "Configuration Error" +msgstr "" -#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356 -#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145 +#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:361 +#: src/modules/initcpiocfg/main.py:236 src/modules/mount/main.py:230 #: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73 -#: src/modules/luksopenswaphookcfg/main.py:87 msgid "No partitions are defined for
{!s}
to use." -msgstr "No partitions are defined for
{!s}
to use." +msgstr "" -#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362 -#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232 +#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:367 +#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:240 #: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77 -#: src/modules/luksopenswaphookcfg/main.py:91 msgid "No root mount point is given for
{!s}
to use." -msgstr "No root mount point is given for
{!s}
to use." +msgstr "" #: src/modules/grubcfg/main.py:28 msgid "Configure GRUB." -msgstr "Configure GRUB." +msgstr "" #: src/modules/bootloader/main.py:43 msgid "Install bootloader." -msgstr "Install bootloader." - -#: src/modules/bootloader/main.py:508 -msgid "Bootloader installation error" -msgstr "Bootloader installation error" - -#: src/modules/bootloader/main.py:509 -msgid "" -"The bootloader could not be installed. The installation command " -"
{!s}
returned error code {!s}." msgstr "" -"The bootloader could not be installed. The installation command " -"
{!s}
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
{!s} returned error code {!s}."
+msgstr ""
 
 #: src/modules/fstab/main.py:29
 msgid "Writing fstab."
-msgstr "Writing fstab."
+msgstr ""
 
-#: src/modules/fstab/main.py:389
+#: src/modules/fstab/main.py:394
 msgid "No 
{!s}
configuration is given for
{!s}
to use." -msgstr "No
{!s}
configuration is given for
{!s}
to use." +msgstr "" #: src/modules/dracut/main.py:27 msgid "Creating initramfs with dracut." -msgstr "Creating initramfs with dracut." +msgstr "" #: src/modules/dracut/main.py:49 msgid "Failed to run dracut on the target" -msgstr "Failed to run dracut on the target" +msgstr "" #: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50 msgid "The exit code was {}" -msgstr "The exit code was {}" +msgstr "" -#: src/modules/displaymanager/main.py:526 +#: src/modules/displaymanager/main.py:524 msgid "Cannot write KDM configuration file" -msgstr "Cannot write KDM configuration file" +msgstr "" -#: src/modules/displaymanager/main.py:527 +#: src/modules/displaymanager/main.py:525 msgid "KDM config file {!s} does not exist" -msgstr "KDM config file {!s} does not exist" +msgstr "" -#: src/modules/displaymanager/main.py:588 +#: src/modules/displaymanager/main.py:586 msgid "Cannot write LXDM configuration file" -msgstr "Cannot write LXDM configuration file" +msgstr "" -#: src/modules/displaymanager/main.py:589 +#: src/modules/displaymanager/main.py:587 msgid "LXDM config file {!s} does not exist" -msgstr "LXDM config file {!s} does not exist" +msgstr "" -#: src/modules/displaymanager/main.py:672 +#: src/modules/displaymanager/main.py:670 msgid "Cannot write LightDM configuration file" -msgstr "Cannot write LightDM configuration file" +msgstr "" -#: src/modules/displaymanager/main.py:673 +#: src/modules/displaymanager/main.py:671 msgid "LightDM config file {!s} does not exist" -msgstr "LightDM config file {!s} does not exist" +msgstr "" -#: src/modules/displaymanager/main.py:747 +#: src/modules/displaymanager/main.py:745 msgid "Cannot configure LightDM" -msgstr "Cannot configure LightDM" +msgstr "" -#: src/modules/displaymanager/main.py:748 +#: src/modules/displaymanager/main.py:746 msgid "No LightDM greeter installed." -msgstr "No LightDM greeter installed." +msgstr "" -#: src/modules/displaymanager/main.py:779 +#: src/modules/displaymanager/main.py:777 msgid "Cannot write SLIM configuration file" -msgstr "Cannot write SLIM configuration file" +msgstr "" -#: src/modules/displaymanager/main.py:780 +#: src/modules/displaymanager/main.py:778 msgid "SLIM config file {!s} does not exist" -msgstr "SLIM config file {!s} does not exist" +msgstr "" -#: src/modules/displaymanager/main.py:906 +#: src/modules/displaymanager/main.py:991 msgid "No display managers selected for the displaymanager module." -msgstr "No display managers selected for the displaymanager module." +msgstr "" -#: src/modules/displaymanager/main.py:907 +#: src/modules/displaymanager/main.py:992 msgid "" "The displaymanagers list is empty or undefined in both globalstorage and " "displaymanager.conf." msgstr "" -"The displaymanagers list is empty or undefined in both globalstorage and " -"displaymanager.conf." -#: src/modules/displaymanager/main.py:989 +#: src/modules/displaymanager/main.py:1074 msgid "Display manager configuration was incomplete" -msgstr "Display manager configuration was incomplete" +msgstr "" #: src/modules/services-openrc/main.py:29 msgid "Configure OpenRC services" -msgstr "Configure OpenRC services" +msgstr "" #: src/modules/services-openrc/main.py:57 msgid "Cannot add service {name!s} to run-level {level!s}." -msgstr "Cannot add service {name!s} to run-level {level!s}." +msgstr "" #: src/modules/services-openrc/main.py:59 msgid "Cannot remove service {name!s} from run-level {level!s}." -msgstr "Cannot remove service {name!s} from run-level {level!s}." +msgstr "" #: src/modules/services-openrc/main.py:61 msgid "" "Unknown service-action {arg!s} for service {name!s} in run-" "level {level!s}." msgstr "" -"Unknown service-action {arg!s} for service {name!s} in run-" -"level {level!s}." #: src/modules/services-openrc/main.py:93 #: src/modules/services-systemd/main.py:59 msgid "Cannot modify service" -msgstr "Cannot modify service" +msgstr "" #: src/modules/services-openrc/main.py:94 msgid "" "rc-update {arg!s} call in chroot returned error code {num!s}." msgstr "" -"rc-update {arg!s} call in chroot returned error code {num!s}." #: src/modules/services-openrc/main.py:101 msgid "Target runlevel does not exist" -msgstr "Target runlevel does not exist" +msgstr "" #: src/modules/services-openrc/main.py:102 msgid "" "The path for runlevel {level!s} is {path!s}, which does not " "exist." msgstr "" -"The path for runlevel {level!s} is {path!s}, which does not " -"exist." #: src/modules/services-openrc/main.py:110 msgid "Target service does not exist" -msgstr "Target service does not exist" +msgstr "" #: src/modules/services-openrc/main.py:111 msgid "" -"The path for service {name!s} is {path!s}, which does not " -"exist." +"The path for service {name!s} is {path!s}, which does not exist." msgstr "" -"The path for service {name!s} is {path!s}, which does not " -"exist." #: src/modules/networkcfg/main.py:29 msgid "Saving network configuration." -msgstr "Saving network configuration." +msgstr "" -#: src/modules/packages/main.py:50 src/modules/packages/main.py:59 -#: src/modules/packages/main.py:69 +#: src/modules/packages/main.py:54 src/modules/packages/main.py:65 +#: src/modules/packages/main.py:75 msgid "Install packages." -msgstr "Install packages." +msgstr "" -#: src/modules/packages/main.py:57 +#: src/modules/packages/main.py:63 #, python-format msgid "Processing packages (%(count)d / %(total)d)" -msgstr "Processing packages (%(count)d / %(total)d)" +msgstr "" -#: src/modules/packages/main.py:62 +#: src/modules/packages/main.py:68 #, python-format msgid "Installing one package." msgid_plural "Installing %(num)d packages." -msgstr[0] "Installing one package." -msgstr[1] "Installing %(num)d packages." +msgstr[0] "" +msgstr[1] "" -#: src/modules/packages/main.py:65 +#: src/modules/packages/main.py:71 #, python-format msgid "Removing one package." msgid_plural "Removing %(num)d packages." -msgstr[0] "Removing one package." -msgstr[1] "Removing %(num)d packages." +msgstr[0] "" +msgstr[1] "" -#: src/modules/packages/main.py:638 src/modules/packages/main.py:650 -#: src/modules/packages/main.py:678 +#: src/modules/packages/main.py:725 src/modules/packages/main.py:737 +#: src/modules/packages/main.py:765 msgid "Package Manager error" -msgstr "Package Manager error" +msgstr "" -#: src/modules/packages/main.py:639 +#: src/modules/packages/main.py:726 msgid "" "The package manager could not prepare updates. The command
{!s}
" "returned error code {!s}." msgstr "" -"The package manager could not prepare updates. The command
{!s}
" + +#: src/modules/packages/main.py:738 +msgid "" +"The package manager could not update the system. The command
{!s}
" "returned error code {!s}." - -#: src/modules/packages/main.py:651 -msgid "" -"The package manager could not update the system. The command
{!s}
" -" returned error code {!s}." msgstr "" -"The package manager could not update the system. The command
{!s}
" -" returned error code {!s}." -#: src/modules/packages/main.py:679 +#: src/modules/packages/main.py:766 msgid "" "The package manager could not make changes to the installed system. The " "command
{!s}
returned error code {!s}." msgstr "" -"The package manager could not make changes to the installed system. The " -"command
{!s}
returned error code {!s}." #: src/modules/plymouthcfg/main.py:27 msgid "Configure Plymouth theme" -msgstr "Configure Plymouth theme" +msgstr "" #: src/modules/initcpiocfg/main.py:28 msgid "Configuring mkinitcpio." -msgstr "Configuring mkinitcpio." +msgstr "" #: src/modules/localecfg/main.py:30 msgid "Configuring locales." -msgstr "Configuring locales." +msgstr "" -#: src/modules/mount/main.py:30 +#: src/modules/mount/main.py:42 msgid "Mounting partitions." -msgstr "Mounting partitions." +msgstr "" + +#: src/modules/mount/main.py:88 src/modules/mount/main.py:124 +msgid "Internal error mounting zfs datasets" +msgstr "" + +#: src/modules/mount/main.py:100 +msgid "Failed to import zpool" +msgstr "" + +#: src/modules/mount/main.py:116 +msgid "Failed to unlock zpool" +msgstr "" + +#: src/modules/mount/main.py:133 src/modules/mount/main.py:138 +msgid "Failed to set zfs mountpoint" +msgstr "" + +#: src/modules/mount/main.py:253 +msgid "zfs mounting error" +msgstr "" #: src/modules/rawfs/main.py:26 msgid "Installing data." -msgstr "Installing data." +msgstr "" #: src/modules/dummypython/main.py:35 msgid "Dummy python job." -msgstr "Dummy python job." +msgstr "" #: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93 #: src/modules/dummypython/main.py:94 msgid "Dummy python step {}" -msgstr "Dummy python step {}" +msgstr "" #: src/modules/hwclock/main.py:26 msgid "Setting hardware clock." -msgstr "Setting hardware clock." - -#: src/modules/umount/main.py:31 -msgid "Unmount file systems." -msgstr "Unmount file systems." +msgstr "" #: src/modules/openrcdmcryptcfg/main.py:26 msgid "Configuring OpenRC dmcrypt service." -msgstr "Configuring OpenRC dmcrypt service." +msgstr "" #: src/modules/services-systemd/main.py:26 msgid "Configure systemd services" -msgstr "Configure systemd services" +msgstr "" #: src/modules/services-systemd/main.py:60 msgid "" "systemctl {arg!s} call in chroot returned error code {num!s}." msgstr "" -"systemctl {arg!s} call in chroot returned error code {num!s}." #: src/modules/services-systemd/main.py:63 #: src/modules/services-systemd/main.py:69 msgid "Cannot enable systemd service {name!s}." -msgstr "Cannot enable systemd service {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:65 msgid "Cannot enable systemd target {name!s}." -msgstr "Cannot enable systemd target {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:67 msgid "Cannot enable systemd timer {name!s}." -msgstr "Cannot enable systemd timer {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:71 msgid "Cannot disable systemd target {name!s}." -msgstr "Cannot disable systemd target {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:73 msgid "Cannot mask systemd unit {name!s}." -msgstr "Cannot mask systemd unit {name!s}." +msgstr "" #: src/modules/services-systemd/main.py:75 msgid "" -"Unknown systemd commands {command!s} and " -"{suffix!s} for unit {name!s}." +"Unknown systemd commands {command!s} and {suffix!s} for unit {name!s}." msgstr "" -"Unknown systemd commands {command!s} and " -"{suffix!s} for unit {name!s}." #: src/modules/mkinitfs/main.py:27 msgid "Creating initramfs with mkinitfs." -msgstr "Creating initramfs with mkinitfs." +msgstr "" #: src/modules/mkinitfs/main.py:49 msgid "Failed to run mkinitfs on the target" -msgstr "Failed to run mkinitfs on the target" +msgstr "" #: src/modules/unpackfs/main.py:34 msgid "Filling up filesystems." -msgstr "Filling up filesystems." +msgstr "" #: src/modules/unpackfs/main.py:254 msgid "rsync failed with error code {}." -msgstr "rsync failed with error code {}." +msgstr "" #: src/modules/unpackfs/main.py:299 msgid "Unpacking image {}/{}, file {}/{}" -msgstr "Unpacking image {}/{}, file {}/{}" +msgstr "" #: src/modules/unpackfs/main.py:314 msgid "Starting to unpack {}" -msgstr "Starting to unpack {}" +msgstr "" -#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465 +#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:467 msgid "Failed to unpack image \"{}\"" -msgstr "Failed to unpack image \"{}\"" +msgstr "" #: src/modules/unpackfs/main.py:430 msgid "No mount point for root partition" -msgstr "No mount point for root partition" +msgstr "" #: src/modules/unpackfs/main.py:431 -msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" -msgstr "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" +msgid "globalstorage does not contain a \"rootMountPoint\" key." +msgstr "" -#: src/modules/unpackfs/main.py:436 +#: src/modules/unpackfs/main.py:434 msgid "Bad mount point for root partition" -msgstr "Bad mount point for root partition" +msgstr "" -#: src/modules/unpackfs/main.py:437 -msgid "rootMountPoint is \"{}\", which does not exist, doing nothing" -msgstr "rootMountPoint is \"{}\", which does not exist, doing nothing" +#: src/modules/unpackfs/main.py:435 +msgid "rootMountPoint is \"{}\", which does not exist." +msgstr "" -#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457 -#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478 -msgid "Bad unsquash configuration" -msgstr "Bad unsquash configuration" +#: src/modules/unpackfs/main.py:439 src/modules/unpackfs/main.py:455 +#: src/modules/unpackfs/main.py:459 src/modules/unpackfs/main.py:465 +#: src/modules/unpackfs/main.py:480 +msgid "Bad unpackfs configuration" +msgstr "" -#: src/modules/unpackfs/main.py:454 +#: src/modules/unpackfs/main.py:440 +msgid "There is no configuration information." +msgstr "" + +#: src/modules/unpackfs/main.py:456 msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel" -msgstr "The filesystem for \"{}\" ({}) is not supported by your current kernel" +msgstr "" -#: src/modules/unpackfs/main.py:458 +#: src/modules/unpackfs/main.py:460 msgid "The source filesystem \"{}\" does not exist" -msgstr "The source filesystem \"{}\" does not exist" +msgstr "" -#: src/modules/unpackfs/main.py:464 +#: src/modules/unpackfs/main.py:466 msgid "" "Failed to find unsquashfs, make sure you have the squashfs-tools package " "installed." msgstr "" -"Failed to find unsquashfs, make sure you have the squashfs-tools package " -"installed." -#: src/modules/unpackfs/main.py:479 +#: src/modules/unpackfs/main.py:481 msgid "The destination \"{}\" in the target system is not a directory" -msgstr "The destination \"{}\" in the target system is not a directory" - -#: src/modules/luksopenswaphookcfg/main.py:26 -msgid "Configuring encrypted swap." -msgstr "Configuring encrypted swap." +msgstr "" diff --git a/lang/python/cs_CZ/LC_MESSAGES/python.po b/lang/python/cs_CZ/LC_MESSAGES/python.po index 70e9d5b77..23737551a 100644 --- a/lang/python/cs_CZ/LC_MESSAGES/python.po +++ b/lang/python/cs_CZ/LC_MESSAGES/python.po @@ -6,7 +6,7 @@ # Translators: # pavelrz, 2017 # LiberteCzech , 2020 -# Pavel Borecki , 2021 +# Pavel Borecki , 2022 # #, fuzzy msgid "" @@ -15,7 +15,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-11-02 15:45+0100\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n" -"Last-Translator: Pavel Borecki , 2021\n" +"Last-Translator: Pavel Borecki , 2022\n" "Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -331,7 +331,7 @@ msgstr "Nedaří se zapnout systemd službu {name!s}." #: src/modules/services-systemd/main.py:67 msgid "Cannot enable systemd timer {name!s}." -msgstr "" +msgstr "Nedaří se zapnout systemd časovač {name!s}." #: src/modules/services-systemd/main.py:71 msgid "Cannot disable systemd target {name!s}." @@ -413,6 +413,8 @@ msgid "" "Failed to find unsquashfs, make sure you have the squashfs-tools package " "installed." msgstr "" +"Nepodařilo se nalézt nástroj unsquashfs – ověřte, že je nainstalovaný " +"balíček squashfs-tools." #: src/modules/unpackfs/main.py:479 msgid "The destination \"{}\" in the target system is not a directory" diff --git a/lang/python/ja-Hira/LC_MESSAGES/python.po b/lang/python/ja-Hira/LC_MESSAGES/python.po new file mode 100644 index 000000000..9a869c5bc --- /dev/null +++ b/lang/python/ja-Hira/LC_MESSAGES/python.po @@ -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 , 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
{!s}
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
{!s}
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 " +"
{!s}
returned error code {!s}." +msgstr "" + +#: src/modules/fstab/main.py:29 +msgid "Writing fstab." +msgstr "" + +#: src/modules/fstab/main.py:389 +msgid "No
{!s}
configuration is given for
{!s}
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 {arg!s} 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 "" +"rc-update {arg!s} 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 {path!s}, 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 {path!s}, 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
{!s}
" +"returned error code {!s}." +msgstr "" + +#: src/modules/packages/main.py:651 +msgid "" +"The package manager could not update the system. The command
{!s}
" +" 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
{!s}
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 "" +"systemctl {arg!s} 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 {name!s}." +msgstr "" + +#: src/modules/services-systemd/main.py:65 +msgid "Cannot enable systemd target {name!s}." +msgstr "" + +#: src/modules/services-systemd/main.py:67 +msgid "Cannot enable systemd timer {name!s}." +msgstr "" + +#: src/modules/services-systemd/main.py:71 +msgid "Cannot disable systemd target {name!s}." +msgstr "" + +#: src/modules/services-systemd/main.py:73 +msgid "Cannot mask systemd unit {name!s}." +msgstr "" + +#: src/modules/services-systemd/main.py:75 +msgid "" +"Unknown systemd commands {command!s} and " +"{suffix!s} 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 "" diff --git a/lang/python/zh_CN/LC_MESSAGES/python.po b/lang/python/zh_CN/LC_MESSAGES/python.po index 706b02d24..c6972b0f5 100644 --- a/lang/python/zh_CN/LC_MESSAGES/python.po +++ b/lang/python/zh_CN/LC_MESSAGES/python.po @@ -9,6 +9,7 @@ # Feng Chao , 2020 # Bobby Rong , 2020 # 玉堂白鹤 , 2021 +# Giovanni Schiano-Moriello, 2022 # #, fuzzy msgid "" @@ -17,7 +18,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-11-02 15:45+0100\n" "PO-Revision-Date: 2017-08-09 10:34+0000\n" -"Last-Translator: 玉堂白鹤 , 2021\n" +"Last-Translator: Giovanni Schiano-Moriello, 2022\n" "Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -305,7 +306,7 @@ msgstr "无法启用 systemd 目标 {name!s}." #: src/modules/services-systemd/main.py:67 msgid "Cannot enable systemd timer {name!s}." -msgstr "" +msgstr "无法启用 systemd 计时器 {name!s}。" #: src/modules/services-systemd/main.py:71 msgid "Cannot disable systemd target {name!s}." @@ -384,7 +385,7 @@ msgstr "源文件系统 \"{}\" 不存在" msgid "" "Failed to find unsquashfs, make sure you have the squashfs-tools package " "installed." -msgstr "" +msgstr "寻找 unsquashfs 失败,请确定您已安装 squashfs-tools 软体包。" #: src/modules/unpackfs/main.py:479 msgid "The destination \"{}\" in the target system is not a directory" diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp index 9d0189031..ecbf77888 100644 --- a/src/calamares/testmain.cpp +++ b/src/calamares/testmain.cpp @@ -485,7 +485,7 @@ main( int argc, char* argv[] ) return 1; } - cDebug() << Logger::SubEntry << " .. got" << m->name() << m->typeString() << m->interfaceString(); + cDebug() << Logger::SubEntry << "got" << m->name() << m->typeString() << m->interfaceString(); if ( m->type() == Calamares::Module::Type::View ) { // If we forgot the --ui, any ViewModule will core dump as it @@ -535,7 +535,7 @@ main( int argc, char* argv[] ) using TR = Logger::DebugRow< const char*, const QString >; - cDebug() << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) + cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) << TR( "interface", m->interfaceString() ); Calamares::JobList jobList = m->jobs(); @@ -543,6 +543,8 @@ main( int argc, char* argv[] ) unsigned int count = 1; for ( const auto& p : jobList ) { + // This doesn't get a SubEntry because the jobs may log a bunch of + // things; print the function-header to make clear that we're back in main. cDebug() << "Job #" << count << "name" << p->prettyName(); Calamares::JobResult r = p->exec(); if ( !r ) diff --git a/src/libcalamares/Job.h b/src/libcalamares/Job.h index 33965e15f..dc89f1c49 100644 --- a/src/libcalamares/Job.h +++ b/src/libcalamares/Job.h @@ -47,7 +47,7 @@ public: /** @brief Is this JobResult a success? * - * Equivalent to errorCode() == 0, might be named isValid(). + * Equivalent to errorCode() == 0, see succeeded(). */ virtual operator bool() const; @@ -58,6 +58,11 @@ public: virtual void setDetails( const QString& details ); int errorCode() const { return m_number; } + /** @brief Is this JobResult a success? + * + * Equivalent to errorCode() == 0. + */ + bool succeeded() const { return this->operator bool(); } /// @brief an "ok status" result static JobResult ok(); diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp index 039a28e26..d7078c6d2 100644 --- a/src/libcalamares/JobQueue.cpp +++ b/src/libcalamares/JobQueue.cpp @@ -122,8 +122,9 @@ public: } else { - cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName() - << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')'; + cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) + << jobitem.job->prettyName() << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() + << ')'; o.refresh(); // So next time it shows the function header again emitProgress( 0.0 ); // 0% for *this job* connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress ); diff --git a/src/libcalamares/PythonJob.cpp b/src/libcalamares/PythonJob.cpp index b1373f5f3..ec17c31f3 100644 --- a/src/libcalamares/PythonJob.cpp +++ b/src/libcalamares/PythonJob.cpp @@ -100,7 +100,7 @@ BOOST_PYTHON_MODULE( libcalamares ) bp::args( "s" ), "Writes the given string to the Calamares warning stream." ); bp::def( - "error", &CalamaresPython::warning, bp::args( "s" ), "Writes the given string to the Calamares error stream." ); + "error", &CalamaresPython::error, bp::args( "s" ), "Writes the given string to the Calamares error stream." ); // .. YAML functions diff --git a/src/libcalamares/partition/Mount.cpp b/src/libcalamares/partition/Mount.cpp index 89e17a885..6bc3a7cd2 100644 --- a/src/libcalamares/partition/Mount.cpp +++ b/src/libcalamares/partition/Mount.cpp @@ -14,6 +14,7 @@ #include "partition/Sync.h" #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" +#include "utils/String.h" #include #include @@ -92,7 +93,7 @@ struct TemporaryMount::Private TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options ) - : m_d( std::make_unique() ) + : m_d( std::make_unique< Private >() ) { m_d->m_devicePath = devicePath; m_d->m_mountDir.setAutoRemove( false ); @@ -123,5 +124,32 @@ TemporaryMount::path() const return m_d ? m_d->m_mountDir.path() : QString(); } +QList< MtabInfo > +MtabInfo::fromMtabFilteredByPrefix( const QString& mountPrefix, const QString& mtabPath ) +{ + QFile f( mtabPath.isEmpty() ? "/etc/mtab" : mtabPath ); + if ( !f.open( QIODevice::ReadOnly ) ) + { + return {}; + } + + QTextStream in( &f ); + QList< MtabInfo > l; + while ( !f.atEnd() ) + { + QStringList line = in.readLine().split( ' ', SplitSkipEmptyParts ); + if ( line.length() == 3 && !line[ 0 ].startsWith( '#' ) ) + { + // Lines have format: , so check + // the mountpoint field. Everything starts with an empty string. + if ( line[ 1 ].startsWith( mountPrefix ) ) + { + l.append( { line[ 0 ], line[ 1 ] } ); + } + } + } + return l; +} + } // namespace Partition } // namespace CalamaresUtils diff --git a/src/libcalamares/partition/Mount.h b/src/libcalamares/partition/Mount.h index d088b108f..f772c33a4 100644 --- a/src/libcalamares/partition/Mount.h +++ b/src/libcalamares/partition/Mount.h @@ -14,6 +14,7 @@ #include "DllMacro.h" +#include #include #include @@ -50,6 +51,13 @@ DLLEXPORT int mount( const QString& devicePath, */ DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() ); + +/** @brief Mount and automatically unmount a device + * + * The TemporaryMount object mounts a filesystem, and is like calling + * the mount() function, above. When the object is destroyed, unmount() + * is called with suitable options to undo the original mount. + */ class DLLEXPORT TemporaryMount { public: @@ -68,6 +76,36 @@ private: std::unique_ptr< Private > m_d; }; + +/** @brief Information about a mount point from /etc/mtab + * + * Entries in /etc/mtab are of the form: + * This struct only stores device and mountpoint. + * + * The main way of getting these structs is to call fromMtab() to read + * an /etc/mtab-like file and storing all of the entries from it. + */ +struct DLLEXPORT MtabInfo +{ + QString device; + QString mountPoint; + + /** @brief Reads an mtab-like file and returns the entries from it + * + * When @p mtabPath is given, that file is read. If the given name is + * empty (e.g. the default) then /etc/mtab is read, instead. + * + * If @p mountPrefix is given, then only entries that have a mount point + * that starts with that prefix are returned. + */ + static QList< MtabInfo > fromMtabFilteredByPrefix( const QString& mountPrefix = QString(), + const QString& mtabPath = QString() ); + /// @brief Predicate to sort MtabInfo objects by device-name + static bool deviceOrder( const MtabInfo& a, const MtabInfo& b ) { return a.device > b.device; } + /// @brief Predicate to sort MtabInfo objects by mount-point + static bool mountPointOrder( const MtabInfo& a, const MtabInfo& b ) { return a.mountPoint > b.mountPoint; } +}; + } // namespace Partition } // namespace CalamaresUtils diff --git a/src/libcalamares/utils/Logger.cpp b/src/libcalamares/utils/Logger.cpp index d35d6891b..adb082687 100644 --- a/src/libcalamares/utils/Logger.cpp +++ b/src/libcalamares/utils/Logger.cpp @@ -259,21 +259,22 @@ operator<<( QDebug& s, const RedactedCommand& l ) * Identical strings with the same context will be hashed the same, * so that they can be logged and still recognized as the-same. */ -static uint insertRedactedName( const QString& context, const QString& s ) +static uint +insertRedactedName( const QString& context, const QString& s ) { static uint salt = QRandomGenerator::global()->generate(); // Just once - uint val = qHash(context, salt); - return qHash(s, val); + uint val = qHash( context, salt ); + return qHash( s, val ); } RedactedName::RedactedName( const QString& context, const QString& s ) - : m_id( insertRedactedName(context, s) ), - m_context(context) + : m_id( insertRedactedName( context, s ) ) + , m_context( context ) { } -RedactedName::RedactedName(const char *context, const QString& s ) +RedactedName::RedactedName( const char* context, const QString& s ) : RedactedName( QString::fromLatin1( context ), s ) { } diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h index 0d7d5c870..f4079388d 100644 --- a/src/libcalamares/utils/Logger.h +++ b/src/libcalamares/utils/Logger.h @@ -71,8 +71,11 @@ private: inline CDebug& operator<<( CDebug&& s, const FuncSuppressor& f ) { - s.m_funcinfo = nullptr; - s << f.m_s; + if ( s.m_funcinfo ) + { + s.m_funcinfo = nullptr; + s.m_msg = QString( f.m_s ); + } return s; } @@ -244,7 +247,8 @@ private: const QString m_context; }; -inline QDebug& operator<<( QDebug& s, const RedactedName& n ) +inline QDebug& +operator<<( QDebug& s, const RedactedName& n ) { return s << NoQuote << QString( n ) << Quote; } diff --git a/src/libcalamares/utils/Retranslator.h b/src/libcalamares/utils/Retranslator.h index efe12ef8a..8bb044983 100644 --- a/src/libcalamares/utils/Retranslator.h +++ b/src/libcalamares/utils/Retranslator.h @@ -29,7 +29,8 @@ namespace CalamaresUtils * @param locale the new locale (names as defined by Calamares). * @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding. */ -DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& brandingTranslationsPrefix ); +DLLEXPORT void installTranslator( const CalamaresUtils::Locale::Translation::Id& locale, + const QString& brandingTranslationsPrefix ); /** @brief Initializes the translations with the current system settings */ @@ -56,7 +57,8 @@ DLLEXPORT CalamaresUtils::Locale::Translation::Id translatorLocaleName(); * * @returns @c true on success */ -DLLEXPORT bool loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator ); +DLLEXPORT bool +loadTranslator( const CalamaresUtils::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator ); /** @brief Set @p allow to true to load translations from current dir. * @@ -88,7 +90,7 @@ public: static Retranslator* instance(); /// @brief Helper function for attaching lambdas - static void attach( QObject* o, std::function< void( void ) > f); + static void attach( QObject* o, std::function< void( void ) > f ); signals: void languageChanged(); @@ -138,8 +140,11 @@ private: #define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \ do \ { \ - connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, this, slotfunc ); \ - (this->*slotfunc)(); \ + connect( CalamaresUtils::Retranslator::instance(), \ + &CalamaresUtils::Retranslator::languageChanged, \ + this, \ + slotfunc ); \ + ( this->*slotfunc )(); \ } while ( false ) #endif diff --git a/src/modules/README.md b/src/modules/README.md index 0b6b87953..9d6f49a12 100644 --- a/src/modules/README.md +++ b/src/modules/README.md @@ -67,7 +67,7 @@ Note that process modules are not recommended. Module descriptors **may** have the following keys: - *emergency* (a boolean value, set to true to mark the module - as an emergency module) + as an emergency module; see the section *Emergency Modules*, below) - *noconfig* (a boolean value, set to true to state that the module has no configuration file; defaults to false) - *requiredModules* (a list of modules which are required for this module @@ -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 must **also** set the *emergency* key to *true* in its configuration file (see below). If it does not, the module is not considered to be an emergency -module after all (this is so that you can have modules that have several -instances, only some of which are actually needed for emergencies). +module after all. This is so that you can have modules that have several +instances, only some of which are actually needed for emergencies. + +In summary: +- in `module.desc`, write `emergency: true` to make it **possible** to + run the module in emergency mode, +- in `.conf`, write `emergency: true` to make that specific + module run in emergency mode. ### Module-specific configuration @@ -112,6 +118,10 @@ named `.conf`. If such a file is present in the module's directory, it can be shipped as a *default* configuration file. This only happens if the CMake-time option `INSTALL_CONFIG` is on. +The name of the configuration file for a given module can be +influenced by the `settings.conf` of the overall Calamares configuration. +By default, though, the module's own name is used. + Modules that have *noconfig* set to true will not attempt to read a configuration file, and will not warn that one is missing; conversely if *noconfig* is set to false (or is missing, since @@ -169,6 +179,26 @@ it is possible to take the whole installation-process into account for determining the relative weights there. +## Global storage keys +Some modules place values in global storage so that they can be referenced later by other modules or even other parts of the same module. The following table represents a partial list of the values available as well as where they originate from and which module consume them. + +Key|Source|Consumers|Description +---|---|---|--- +btrfsSubvolumes|mount|fstab|List of maps containing the mountpoint and btrtfs subvolume +btrfsRootSubvolume|mount|bootloader, luksopenswaphook|String containing the subvolume mounted at root +efiSystemPartition|partition|bootloader, fstab|String containing the path to the ESP relative to the installed system +extraMounts|mount|unpackfs|List of maps holding metadata for the temporary mountpoints used by the installer +hostname|users||A string containing the hostname of the new system +netinstallAdd|packagechooser|netinstall|Data to add to netinstall tree. Same format as netinstall.yaml +netinstallSelect|packagechooser|netinstall|List of group names to select in the netinstall tree +partitions|partition, rawfs|numerous modules|List of maps of metadata about each partition +rootMountPoint|mount|numerous modules|A string with the absolute path to the root mountpoint +username|users|networkcfg, plasmainf, preservefiles|A string containing the username of the new user +zfsDatasets|zfs|bootloader, grubcfg, mount|List of maps of zfs datasets including the name and mount information +zfsInfo|partition|mount, zfs|List of encrypted zfs partitions and the encription info +zfsPoolInfo|zfs|mount, umount|List of maps of zfs pool info including the name and mountpoint + + ## C++ modules > Type: viewmodule, jobmodule diff --git a/src/modules/bootloader/bootloader.conf b/src/modules/bootloader/bootloader.conf index 60235e5d2..ac2943e3c 100644 --- a/src/modules/bootloader/bootloader.conf +++ b/src/modules/bootloader/bootloader.conf @@ -48,6 +48,16 @@ efiBootMgr: "efibootmgr" # setting the option here, keep in mind that the name is sanitized # (problematic characters, see above, are replaced). # +# There are some special words possible at the end of *efiBootloaderId*: +# @@SERIAL@@ can be used to obtain a uniquely-numbered suffix +# that is added to the Id (yielding, e.g., `dirname1` or `dirname72`) +# @@RANDOM@@ can be used to obtain a unique 4-digit hex suffix +# @@PHRASE@@ can be used to obtain a unique 1-to-3-word suffix +# from a dictionary of space-themed words +# Note that these must be at the **end** of the *efiBootloaderId* value. +# There must also be at most one of them. If there is none, no suffix- +# processing is done and the *efiBootloaderId* is used unchanged. +# # efiBootloaderId: "dirname" # Optionally install a copy of the GRUB EFI bootloader as the EFI diff --git a/src/modules/bootloader/main.py b/src/modules/bootloader/main.py index e71823dc6..b5fc14f29 100644 --- a/src/modules/bootloader/main.py +++ b/src/modules/bootloader/main.py @@ -285,10 +285,166 @@ def create_loader(loader_path, entry): loader_file.write(line) -def efi_label(): +class suffix_iterator(object): + """ + Wrapper for one of the "generator" classes below to behave like + a proper Python iterator. The iterator is initialized with a + maximum number of attempts to generate a new suffix. + """ + def __init__(self, attempts, generator): + self.generator = generator + self.attempts = attempts + self.counter = 0 + + def __iter__(self): + return self + + def __next__(self): + self.counter += 1 + if self.counter <= self.attempts: + return self.generator.next() + raise StopIteration + + +class serialEfi(object): + """ + EFI Id generator that appends a serial number to the given name. + """ + def __init__(self, name): + self.name = name + # So the first call to next() will bump it to 0 + self.counter = -1 + + def next(self): + self.counter += 1 + if self.counter > 0: + return "{!s}{!s}".format(self.name, self.counter) + else: + return self.name + + +def render_in_base(value, base_values, length=-1): + """ + Renders @p value in base-N, where N is the number of + items in @p base_values. When rendering, use the items + of @p base_values (e.g. use "0123456789" to get regular decimal + rendering, or "ABCDEFGHIJ" for letters-as-numbers 'encoding'). + + If length is positive, pads out to at least that long with + leading "zeroes", whatever base_values[0] is. + """ + if value < 0: + raise ValueError("Cannot render negative values") + if len(base_values) < 2: + raise ValueError("Insufficient items for base-N rendering") + if length < 1: + length = 1 + digits = [] + base = len(base_values) + while value > 0: + place = value % base + value = value // base + digits.append(base_values[place]) + while len(digits) < length: + digits.append(base_values[0]) + return "".join(reversed(digits)) + + +class randomEfi(object): + """ + EFI Id generator that appends a random 4-digit hex number to the given name. + """ + def __init__(self, name): + self.name = name + # So the first call to next() will bump it to 0 + self.counter = -1 + + def next(self): + self.counter += 1 + if self.counter > 0: + import random + v = random.randint(0, 65535) # 16 bits + return "{!s}{!s}".format(self.name, render_in_base(v, "0123456789ABCDEF", 4)) + else: + return self.name + + +class phraseEfi(object): + """ + EFI Id generator that appends a random phrase to the given name. + """ + words = ("Sun", "Moon", "Mars", "Soyuz", "Falcon", "Kuaizhou", "Gaganyaan") + + def __init__(self, name): + self.name = name + # So the first call to next() will bump it to 0 + self.counter = -1 + + def next(self): + self.counter += 1 + if self.counter > 0: + import random + desired_length = 1 + self.counter // 5 + v = random.randint(0, len(self.words) ** desired_length) + return "{!s}{!s}".format(self.name, render_in_base(v, self.words)) + else: + return self.name + + +def get_efi_suffix_generator(name): + """ + Handle EFI bootloader Ids with @@@@ 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 @@@@ suffix marker + in the given id, tries to generate a unique label. + """ + if bootloader_id.endswith("@@"): + # Do 10 attempts with any suffix generator + g = suffix_iterator(10, get_efi_suffix_generator(bootloader_id)) + else: + # Just one attempt + g = [bootloader_id] + + for candidate_name in g: + if not os.path.exists(os.path.join(efi_directory, candidate_name)): + return candidate_name + return bootloader_id + + +def efi_label(efi_directory): + """ + Returns a sanitized label, possibly unique, that can be + used within @p efi_directory. + """ if "efiBootloaderId" in libcalamares.job.configuration: - efi_bootloader_id = libcalamares.job.configuration[ - "efiBootloaderId"] + efi_bootloader_id = change_efi_suffix( efi_directory, libcalamares.job.configuration["efiBootloaderId"] ) else: branding = libcalamares.globalstorage.value("branding") efi_bootloader_id = branding["bootloaderEntryName"] @@ -427,7 +583,7 @@ def run_grub_mkconfig(partitions, output_file): check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file]) -def run_grub_install(fw_type, partitions, efi_directory=None): +def run_grub_install(fw_type, partitions, efi_directory): """ Runs grub-install in the target environment @@ -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"]) if fw_type == "efi": - efi_bootloader_id = efi_label() + assert efi_directory is not None + efi_bootloader_id = efi_label(efi_directory) efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters() if is_zfs: @@ -458,6 +615,7 @@ def run_grub_install(fw_type, partitions, efi_directory=None): "--bootloader-id=" + efi_bootloader_id, "--force"]) else: + assert efi_directory is None if libcalamares.globalstorage.value("bootLoader") is None: return @@ -499,7 +657,7 @@ def install_grub(efi_directory, fw_type): if not os.path.isdir(install_efi_directory): os.makedirs(install_efi_directory) - efi_bootloader_id = efi_label() + efi_bootloader_id = efi_label(efi_directory) efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters() @@ -534,7 +692,7 @@ def install_grub(efi_directory, fw_type): shutil.copy2(efi_file_source, efi_file_target) else: libcalamares.utils.debug("Bootloader: grub (bios)") - run_grub_install(fw_type, partitions) + run_grub_install(fw_type, partitions, None) run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"]) @@ -543,7 +701,7 @@ def install_secureboot(efi_directory): """ Installs the secureboot shim in the system by calling efibootmgr. """ - efi_bootloader_id = efi_label() + efi_bootloader_id = efi_label(efi_directory) installation_root_path = libcalamares.globalstorage.value("rootMountPoint") install_efi_directory = installation_root_path + efi_directory diff --git a/src/modules/bootloader/tests/CMakeTests.txt b/src/modules/bootloader/tests/CMakeTests.txt new file mode 100644 index 000000000..5b16d5009 --- /dev/null +++ b/src/modules/bootloader/tests/CMakeTests.txt @@ -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} +) diff --git a/src/modules/bootloader/tests/test-bootloader-efiname.py b/src/modules/bootloader/tests/test-bootloader-efiname.py new file mode 100644 index 000000000..67cb91747 --- /dev/null +++ b/src/modules/bootloader/tests/test-bootloader-efiname.py @@ -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") diff --git a/src/modules/fstab/test2.yaml b/src/modules/fstab/test2.yaml new file mode 100644 index 000000000..0e91bf649 --- /dev/null +++ b/src/modules/fstab/test2.yaml @@ -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" diff --git a/src/modules/grubcfg/grubcfg.conf b/src/modules/grubcfg/grubcfg.conf index 33c2a72ab..afc5e89b8 100644 --- a/src/modules/grubcfg/grubcfg.conf +++ b/src/modules/grubcfg/grubcfg.conf @@ -29,8 +29,16 @@ prefer_grub_d: false # kept, not updated to the *bootloaderEntryName* from the branding file. # Use this if the GRUB_DISTRIBUTOR setting in the file is "smart" in # some way (e.g. uses shell-command substitution). +# +# TODO:3.3:snake-case this key keepDistributor: false +# The default kernel params that should always be applied. +# This is an array of strings. If it is unset, the default is +# `["quiet"]`. To avoid the default, explicitly set this key +# to an empty list, `[]`. +kernel_params: [ "quiet" ] + # Default entries to write to /etc/default/grub if it does not exist yet or if # we are overwriting it. # diff --git a/src/modules/grubcfg/grubcfg.schema.yaml b/src/modules/grubcfg/grubcfg.schema.yaml index f1bf2cc03..35d63c063 100644 --- a/src/modules/grubcfg/grubcfg.schema.yaml +++ b/src/modules/grubcfg/grubcfg.schema.yaml @@ -7,8 +7,10 @@ additionalProperties: false type: object properties: overwrite: { type: boolean, default: false } + # TODO:3.3:snake-case this key keepDistributor: { type: boolean, default: false } prefer_grub_d: { type: boolean, default: false } + kernel_params: { type: array, items: { type: string } } defaults: type: object additionalProperties: true # Other fields are acceptable diff --git a/src/modules/grubcfg/main.py b/src/modules/grubcfg/main.py index 6bc1735ed..d7e581da6 100644 --- a/src/modules/grubcfg/main.py +++ b/src/modules/grubcfg/main.py @@ -170,7 +170,7 @@ def modify_grub_default(partitions, root_mount_point, distributor): if partition["fs"] == "zfs" and partition["mountPoint"] == "/": zfs_root_path = get_zfs_root() - kernel_params = ["quiet"] + kernel_params = libcalamares.job.configuration.get("kernel_params", ["quiet"]) # Currently, grub doesn't detect this properly so it must be set manually if zfs_root_path: diff --git a/src/modules/initcpio/InitcpioJob.cpp b/src/modules/initcpio/InitcpioJob.cpp index b96f3b316..df995ccbf 100644 --- a/src/modules/initcpio/InitcpioJob.cpp +++ b/src/modules/initcpio/InitcpioJob.cpp @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * SPDX-FileCopyrightText: 2019 Adriaan de Groot + * SPDX-FileCopyrightText: 2022 Evan James * SPDX-License-Identifier: GPL-3.0-or-later * * Calamares is Free Software: see the License-Identifier above. @@ -31,15 +32,22 @@ InitcpioJob::prettyName() const return tr( "Creating initramfs with mkinitcpio." ); } +/** @brief Sets secure permissions on each initramfs + * + * Iterates over each initramfs contained directly in the directory @p d. + * For each initramfs found, the permissions are set to owner read/write only. + * + */ void fixPermissions( const QDir& d ) { - for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) ) + const auto initramList = d.entryInfoList( { "initramfs*" }, QDir::Files ); + for ( const auto& fi : initramList ) { QFile f( fi.absoluteFilePath() ); if ( f.exists() ) { - cDebug() << "initcpio fixing permissions for" << f.fileName(); + cDebug() << "initcpio setting permissions for" << f.fileName(); f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner ); } } @@ -63,9 +71,19 @@ InitcpioJob::exec() } } + // If the kernel option isn't set to a specific kernel, run mkinitcpio on all kernels + QStringList command = { "mkinitcpio" }; + if ( m_kernel.isEmpty() || m_kernel == "all" ) + { + command.append( "-P" ); + } + else + { + command.append( { "-p", m_kernel } ); + } + cDebug() << "Updating initramfs with kernel" << m_kernel; - auto r = CalamaresUtils::System::instance()->targetEnvCommand( - { "mkinitcpio", "-p", m_kernel }, QString(), QString() /* no timeout , 0 */ ); + auto r = CalamaresUtils::System::instance()->targetEnvCommand( command, QString(), QString() /* no timeout , 0 */ ); return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ ); } @@ -73,28 +91,6 @@ void InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap ) { m_kernel = CalamaresUtils::getString( configurationMap, "kernel" ); - if ( m_kernel.isEmpty() ) - { - m_kernel = QStringLiteral( "all" ); - } - else if ( m_kernel == "$uname" ) - { - auto r = CalamaresUtils::System::runCommand( CalamaresUtils::System::RunLocation::RunInHost, - { "/bin/uname", "-r" }, - QString(), - QString(), - std::chrono::seconds( 3 ) ); - if ( r.getExitCode() == 0 ) - { - m_kernel = r.getOutput(); - cDebug() << "*initcpio* using running kernel" << m_kernel; - } - else - { - cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation - << r.getExitCode() << r.getOutput(); - } - } m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false ); } diff --git a/src/modules/initcpio/initcpio.conf b/src/modules/initcpio/initcpio.conf index 717a511df..d2a126864 100644 --- a/src/modules/initcpio/initcpio.conf +++ b/src/modules/initcpio/initcpio.conf @@ -5,21 +5,22 @@ --- # This key defines the kernel to be loaded. # It can have the following values: -# - empty or unset, interpreted as "all" -# - the literal string "$uname" (without quotes, with dollar), -# which will use the output of `uname -r` to determine the -# running kernel, and use that. -# - any other string. +# - the name of a single mkinitcpio preset +# - empty or unset +# - the literal string "all" # -# Whatever is set, that string is passed as *preset* argument to the -# `-p` option of *mkinitcpio*. Take care that both "$uname" operates -# in the host system, and might not be correct if the target system is -# updated (to a newer kernel) as part of the installation. +# If kernel is set to "all" or empty/unset then mkinitpio is called for all +# kernels. Otherwise it is called with a single preset with the value +# contained in kernel. # -# Note that "all" is probably not a good preset to use either. -kernel: linux312 +kernel: linux # Set this to true to turn off mitigations for lax file # permissions on initramfs (which, in turn, can compromise # your LUKS encryption keys, CVS-2019-13179). +# +# If your initramfs are stored in the EFI partition or another non-POSIX +# filesystem, this has no effect as the file permissions cannot be changed. +# In this case, ensure the partition is mounted securely. +# be_unsafe: false diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index ba4b4ece1..6f94594aa 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -183,7 +183,8 @@ def find_initcpio_features(partitions, root_mount_point): if partition["fs"] == "btrfs": uses_btrfs = True - if partition["fs"] == "zfs": + # In addition to checking the filesystem, check to ensure that zfs is enabled + if partition["fs"] == "zfs" and libcalamares.globalstorage.contains("zfsPoolInfo"): uses_zfs = True if "lvm2" in partition["fs"]: diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index 1b10a1a05..d83b4673c 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -81,6 +81,7 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap ) } else { + m_kernel = QStringLiteral( "all" ); cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation << r.getExitCode() << r.getOutput(); } diff --git a/src/modules/locale/Config.cpp b/src/modules/locale/Config.cpp index ce48edd82..8593f8385 100644 --- a/src/modules/locale/Config.cpp +++ b/src/modules/locale/Config.cpp @@ -221,6 +221,11 @@ Config::setCurrentLocation() { setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second ); } + if ( !m_selectedLocaleConfiguration.explicit_lang ) + { + auto newLocale = automaticLocaleConfiguration(); + setLanguage( newLocale.language() ); + } } void @@ -252,15 +257,21 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName ) void Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location ) { - if ( location != m_currentLocation ) + const bool updateLocation = ( location != m_currentLocation ); + if ( updateLocation ) { m_currentLocation = location; - // Overwrite those settings that have not been made explicit. - auto newLocale = automaticLocaleConfiguration(); - if ( !m_selectedLocaleConfiguration.explicit_lang ) - { - setLanguage( newLocale.language() ); - } + } + + // lang should be always be updated + auto newLocale = automaticLocaleConfiguration(); + if ( !m_selectedLocaleConfiguration.explicit_lang ) + { + setLanguage( newLocale.language() ); + } + + if ( updateLocation ) + { if ( !m_selectedLocaleConfiguration.explicit_lc ) { m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric; diff --git a/src/modules/luksopenswaphookcfg/CMakeLists.txt b/src/modules/luksopenswaphookcfg/CMakeLists.txt index 6d80df815..caede06a7 100644 --- a/src/modules/luksopenswaphookcfg/CMakeLists.txt +++ b/src/modules/luksopenswaphookcfg/CMakeLists.txt @@ -6,7 +6,7 @@ # Because LUKS Open Swap Hook (Job) is such a mouthful, we'll # use LOSH all over the place as a shorthand. -calamares_add_plugin( luksopenswaphook +calamares_add_plugin( luksopenswaphookcfg TYPE job EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES diff --git a/src/modules/netinstall/NetInstallPage.cpp b/src/modules/netinstall/NetInstallPage.cpp index a1a86294e..f7a2f66fc 100644 --- a/src/modules/netinstall/NetInstallPage.cpp +++ b/src/modules/netinstall/NetInstallPage.cpp @@ -15,6 +15,7 @@ #include "PackageModel.h" #include "ui_page_netinst.h" +#include "GlobalStorage.h" #include "JobQueue.h" #include "network/Manager.h" @@ -62,4 +63,19 @@ void NetInstallPage::onActivate() { ui->groupswidget->setFocus(); + + // The netinstallSelect global storage value can be used to make additional items selected by default + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + const QStringList selectNames = gs->value( "netinstallSelect" ).toStringList(); + if ( !selectNames.isEmpty() ) + { + m_config->model()->setSelections( selectNames ); + } + + // If NetInstallAdd is found in global storage, add those items to the tree + const QVariantList groups = gs->value( "netinstallAdd" ).toList(); + if ( !groups.isEmpty() ) + { + m_config->model()->appendModelData( groups ); + } } diff --git a/src/modules/netinstall/PackageModel.cpp b/src/modules/netinstall/PackageModel.cpp index d4887b6c2..256a77afd 100644 --- a/src/modules/netinstall/PackageModel.cpp +++ b/src/modules/netinstall/PackageModel.cpp @@ -14,6 +14,43 @@ #include "utils/Variant.h" #include "utils/Yaml.h" +/// Recursive helper for setSelections() +static void +setSelections( const QStringList& selectNames, PackageTreeItem* item ) +{ + for ( int i = 0; i < item->childCount(); i++ ) + { + auto* child = item->child( i ); + setSelections( selectNames, child ); + } + if ( item->isGroup() && selectNames.contains( item->name() ) ) + { + item->setSelected( Qt::CheckState::Checked ); + } +} + +/** @brief Collects all the "source" values from @p groupList + * + * Iterates over @p groupList and returns all nonempty "source" + * values from the maps. + * + */ +static QStringList +collectSources( const QVariantList& groupList ) +{ + QStringList sources; + for ( const QVariant& group : groupList ) + { + QVariantMap groupMap = group.toMap(); + if ( !groupMap[ "source" ].toString().isEmpty() ) + { + sources.append( groupMap[ "source" ].toString() ); + } + } + + return sources; +} + PackageModel::PackageModel( QObject* parent ) : QAbstractItemModel( parent ) { @@ -170,6 +207,15 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c return QVariant(); } +void +PackageModel::setSelections( const QStringList& selectNames ) +{ + if ( m_rootItem ) + { + ::setSelections( selectNames, m_rootItem ); + } +} + PackageTreeItem::List PackageModel::getPackages() const { @@ -303,9 +349,43 @@ PackageModel::setupModelData( const QVariantList& groupList, PackageTreeItem* pa void PackageModel::setupModelData( const QVariantList& l ) { - emit beginResetModel(); + Q_EMIT beginResetModel(); delete m_rootItem; m_rootItem = new PackageTreeItem(); setupModelData( l, m_rootItem ); - emit endResetModel(); + Q_EMIT endResetModel(); +} + +void +PackageModel::appendModelData( const QVariantList& groupList ) +{ + if ( m_rootItem ) + { + Q_EMIT beginResetModel(); + + const QStringList sources = collectSources( groupList ); + + if ( !sources.isEmpty() ) + { + // Prune any existing data from the same source + QList< int > removeList; + for ( int i = 0; i < m_rootItem->childCount(); i++ ) + { + PackageTreeItem* child = m_rootItem->child( i ); + if ( sources.contains( child->source() ) ) + { + removeList.insert( 0, i ); + } + } + for ( const int& item : qAsConst( removeList ) ) + { + m_rootItem->removeChild( item ); + } + } + + // Add the new data to the model + setupModelData( groupList, m_rootItem ); + + Q_EMIT endResetModel(); + } } diff --git a/src/modules/netinstall/PackageModel.h b/src/modules/netinstall/PackageModel.h index 998f42c38..e97359a46 100644 --- a/src/modules/netinstall/PackageModel.h +++ b/src/modules/netinstall/PackageModel.h @@ -54,9 +54,33 @@ public: int rowCount( const QModelIndex& parent = QModelIndex() ) const override; int columnCount( const QModelIndex& parent = QModelIndex() ) const override; + /** @brief Sets the checked flag on matching groups in the tree + * + * Recursively traverses the tree pointed to by m_rootItem and + * checks if a group name matches any of the items in @p selectNames. + * If a match is found, set check the box for that group and it's children. + * + * Individual packages will not be matched. + * + */ + void setSelections( const QStringList& selectNames ); + PackageTreeItem::List getPackages() const; PackageTreeItem::List getItemPackages( PackageTreeItem* item ) const; + /** @brief Appends groups to the tree + * + * Uses the data from @p groupList to add elements to the + * existing tree that m_rootItem points to. If m_rootItem + * is not valid, it does nothing + * + * Before adding anything to the model, it ensures that there + * is no existing data from the same source. If there is, that + * data is pruned first + * + */ + void appendModelData( const QVariantList& groupList ); + private: friend class ItemTests; diff --git a/src/modules/netinstall/PackageTreeItem.cpp b/src/modules/netinstall/PackageTreeItem.cpp index b30cdf915..5841606c4 100644 --- a/src/modules/netinstall/PackageTreeItem.cpp +++ b/src/modules/netinstall/PackageTreeItem.cpp @@ -70,6 +70,7 @@ PackageTreeItem::PackageTreeItem( const QVariantMap& groupData, GroupTag&& paren , m_description( CalamaresUtils::getString( groupData, "description" ) ) , m_preScript( CalamaresUtils::getString( groupData, "pre-install" ) ) , m_postScript( CalamaresUtils::getString( groupData, "post-install" ) ) + , m_source( CalamaresUtils::getString( groupData, "source" ) ) , m_isGroup( true ) , m_isCritical( parentCriticality( groupData, parent.parent ) ) , m_isHidden( CalamaresUtils::getBool( groupData, "hidden", false ) ) @@ -248,6 +249,19 @@ PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected ) } } +void +PackageTreeItem::removeChild( int row ) +{ + if ( 0 <= row && row < m_childItems.count() ) + { + m_childItems.removeAt( row ); + } + else + { + cWarning() << "Attempt to remove invalid child in removeChild() at row " << row; + } +} + int PackageTreeItem::type() const { diff --git a/src/modules/netinstall/PackageTreeItem.h b/src/modules/netinstall/PackageTreeItem.h index c04b9a21d..2a0fca83e 100644 --- a/src/modules/netinstall/PackageTreeItem.h +++ b/src/modules/netinstall/PackageTreeItem.h @@ -56,6 +56,7 @@ public: QString description() const { return m_description; } QString preScript() const { return m_preScript; } QString postScript() const { return m_postScript; } + QString source() const { return m_source; } /** @brief Is this item a group-item? * @@ -124,6 +125,8 @@ public: void setSelected( Qt::CheckState isSelected ); void setChildrenSelected( Qt::CheckState isSelected ); + void removeChild( int row ); + /** @brief Update selectedness based on the children's states * * This only makes sense for groups, which might have packages @@ -157,6 +160,7 @@ private: QString m_description; QString m_preScript; QString m_postScript; + QString m_source; bool m_isGroup = false; bool m_isCritical = false; bool m_isHidden = false; diff --git a/src/modules/netinstall/Tests.cpp b/src/modules/netinstall/Tests.cpp index df5d5ad60..6b1db020c 100644 --- a/src/modules/netinstall/Tests.cpp +++ b/src/modules/netinstall/Tests.cpp @@ -410,7 +410,7 @@ ItemTests::testUrlFallback() QEventLoop loop; connect( &c, &Config::statusReady, &loop, &QEventLoop::quit ); QSignalSpy spy( &c, &Config::statusReady ); - QTimer::singleShot( std::chrono::seconds(1), &loop, &QEventLoop::quit ); + QTimer::singleShot( std::chrono::seconds( 1 ), &loop, &QEventLoop::quit ); loop.exec(); // Check it didn't time out diff --git a/src/modules/packagechooser/Config.cpp b/src/modules/packagechooser/Config.cpp index 5c0db5d91..491fe5c25 100644 --- a/src/modules/packagechooser/Config.cpp +++ b/src/modules/packagechooser/Config.cpp @@ -27,6 +27,29 @@ #include "utils/Logger.h" #include "utils/Variant.h" +/** @brief This removes any values from @p groups that match @p source + * + * This is used to remove duplicates from the netinstallAdd structure + * It iterates over @p groups and for each map in the list, if the + * "source" element matches @p source, it is removed from the returned + * list. + */ +static QVariantList +pruneNetinstallAdd( const QString& source, const QVariant& groups ) +{ + QVariantList newGroupList; + const QVariantList groupList = groups.toList(); + for ( const QVariant& group : groupList ) + { + QVariantMap groupMap = group.toMap(); + if ( groupMap.value( "source", "" ).toString() != source ) + { + newGroupList.append( groupMap ); + } + } + return newGroupList; +} + const NamedEnumTable< PackageChooserMode >& packageChooserModeNames() { @@ -55,6 +78,8 @@ PackageChooserMethodNames() { "custom", PackageChooserMethod::Legacy }, { "contextualprocess", PackageChooserMethod::Legacy }, { "packages", PackageChooserMethod::Packages }, + { "netinstall-add", PackageChooserMethod::NetAdd }, + { "netinstall-select", PackageChooserMethod::NetSelect }, }; return names; } @@ -121,6 +146,47 @@ Config::updateGlobalStorage( const QStringList& selected ) const CalamaresUtils::Packages::setGSPackageAdditions( Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames ); } + else if ( m_method == PackageChooserMethod::NetAdd ) + { + QVariantList netinstallDataList = m_model->getNetinstallDataForNames( selected ); + if ( netinstallDataList.isEmpty() ) + { + cWarning() << "No netinstall information found for " << selected; + } + else + { + // If an earlier packagechooser instance added this data to global storage, combine them + auto* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( gs->contains( "netinstallAdd" ) ) + { + netinstallDataList + += pruneNetinstallAdd( QStringLiteral( "packageChooser" ), gs->value( "netinstallAdd" ) ); + } + gs->insert( "netinstallAdd", netinstallDataList ); + } + } + else if ( m_method == PackageChooserMethod::NetSelect ) + { + cDebug() << m_defaultId << "groups to select in netinstall" << selected; + QStringList newSelected = selected; + auto* gs = Calamares::JobQueue::instance()->globalStorage(); + + // If an earlier packagechooser instance added this data to global storage, combine them + if ( gs->contains( "netinstallSelect" ) ) + { + auto selectedOrig = gs->value( "netinstallSelect" ); + if ( selectedOrig.canConvert( QVariant::StringList ) ) + { + newSelected += selectedOrig.toStringList(); + } + else + { + cWarning() << "Invalid NetinstallSelect data in global storage. Earlier selections purged"; + } + gs->remove( "netinstallSelect" ); + } + gs->insert( "netinstallSelect", newSelected ); + } else { cWarning() << "Unknown packagechooser method" << smash( m_method ); diff --git a/src/modules/packagechooser/Config.h b/src/modules/packagechooser/Config.h index 32f1e8b57..b04b1c30b 100644 --- a/src/modules/packagechooser/Config.h +++ b/src/modules/packagechooser/Config.h @@ -33,6 +33,8 @@ enum class PackageChooserMethod { Legacy, // use contextualprocess or other custom Packages, // use the packages module + NetAdd, // adds packages to the netinstall module + NetSelect, // makes selections in the netinstall module }; const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames(); diff --git a/src/modules/packagechooser/PackageModel.cpp b/src/modules/packagechooser/PackageModel.cpp index 8a0b13e51..f1d1184ad 100644 --- a/src/modules/packagechooser/PackageModel.cpp +++ b/src/modules/packagechooser/PackageModel.cpp @@ -15,6 +15,16 @@ #include +/** @brief A wrapper for CalamaresUtils::getSubMap that excludes the success param + */ +static QVariantMap +getSubMap( const QVariantMap& map, const QString& key ) +{ + bool success; + + return CalamaresUtils::getSubMap( map, key, success ); +} + static QPixmap loadScreenshot( const QString& path ) { @@ -51,12 +61,13 @@ PackageItem::PackageItem( const QString& a_id, { } -PackageItem::PackageItem::PackageItem( const QVariantMap& item_map ) +PackageItem::PackageItem( const QVariantMap& item_map ) : id( CalamaresUtils::getString( item_map, "id" ) ) , name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) ) , description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) ) , screenshot( loadScreenshot( CalamaresUtils::getString( item_map, "screenshot" ) ) ) , packageNames( CalamaresUtils::getStringList( item_map, "packages" ) ) + , netinstallData( getSubMap( item_map, "netinstall" ) ) { if ( name.isEmpty() && id.isEmpty() ) { @@ -125,6 +136,25 @@ PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const return l; } +QVariantList +PackageListModel::getNetinstallDataForNames( const QStringList& ids ) const +{ + QVariantList l; + for ( auto& p : m_packages ) + { + if ( ids.contains( p.id ) ) + { + if ( !p.netinstallData.isEmpty() ) + { + QVariantMap newData = p.netinstallData; + newData[ "source" ] = QStringLiteral( "packageChooser" ); + l.append( newData ); + } + } + } + return l; +} + int PackageListModel::rowCount( const QModelIndex& index ) const { diff --git a/src/modules/packagechooser/PackageModel.h b/src/modules/packagechooser/PackageModel.h index 71003197d..18682a121 100644 --- a/src/modules/packagechooser/PackageModel.h +++ b/src/modules/packagechooser/PackageModel.h @@ -26,6 +26,7 @@ struct PackageItem CalamaresUtils::Locale::TranslatedString description; QPixmap screenshot; QStringList packageNames; + QVariantMap netinstallData; /// @brief Create blank PackageItem PackageItem(); @@ -111,6 +112,14 @@ public: */ QStringList getInstallPackagesForNames( const QStringList& ids ) const; + /** @brief Does a name lookup (based on id) and returns the netinstall data + * + * If there is a package with an id in @p ids, returns their netinstall data + * + * returns a list of netinstall data or an emply list if none is found + */ + QVariantList getNetinstallDataForNames( const QStringList& ids ) const; + enum Roles : int { NameRole = Qt::DisplayRole, diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf index bb982916e..ca458042b 100644 --- a/src/modules/packagechooser/packagechooser.conf +++ b/src/modules/packagechooser/packagechooser.conf @@ -33,6 +33,15 @@ mode: required # in the `exec` section. These package settings will then be handed # off to whatever package manager is configured there. # +# - "netinstall-select" +# When this is set, the id(s) selected are passed to the netinstall module. +# Any id that matches a group name in that module is set to checked +# +# - "netinstall-add" +# With this method, the packagechooser module is used to add groups to the +# netinstall module. For this to hav=e any effect. You must set netinstall, +# which is described below. +# # There is no need to put this module in the `exec` section. There # are no jobs that this module provides. You should put **other** # modules, either *contextualprocess* or *packages* or some custom @@ -101,13 +110,19 @@ labels: # an additional attempt is made to load the image from the **branding** # directory. # -# The following field is **optional** for an item: +# The following fields are **optional** for an item: # # - *packages* : # List of package names for the product. If using the *method* # "packages", consider this item mandatory (because otherwise # selecting the item would install no packages). # +# - *netinstall* : +# The data in this field should follow the format of a group +# from the netinstall module documented in +# src/modules/netinstall/netinstall.conf. This is only used +# when method is set to "netinstall-add" +# # # AppData Items # # # For data provided by AppData XML: the item has an *appdata* diff --git a/src/modules/packages/main.py b/src/modules/packages/main.py index 10371777e..59777cedb 100644 --- a/src/modules/packages/main.py +++ b/src/modules/packages/main.py @@ -382,7 +382,7 @@ class PMPacman(PackageManager): def line_cb(line): if line.startswith(":: "): - self.in_package_changes = "package changes" in line + self.in_package_changes = "package" in line or "hooks" in line else: if self.in_package_changes and line.endswith("...\n"): # Update the message, untranslated; do not change the @@ -392,7 +392,7 @@ class PMPacman(PackageManager): global custom_status_message custom_status_message = "pacman: " + line.strip() libcalamares.job.setprogress(self.progress_fraction) - libcalamares.utils.debug(line) + libcalamares.utils.debug(line) self.in_package_changes = False self.line_cb = line_cb @@ -444,8 +444,12 @@ class PMPacman(PackageManager): else: command.append("-S") + # Don't ask for user intervention, take the default action command.append("--noconfirm") + # Don't report download progress for each file + command.append("--noprogressbar") + if self.pacman_needed_only is True: command.append("--needed") diff --git a/src/modules/partition/Config.cpp b/src/modules/partition/Config.cpp index 155622570..550e17460 100644 --- a/src/modules/partition/Config.cpp +++ b/src/modules/partition/Config.cpp @@ -345,6 +345,11 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) if ( !m_swapChoices.contains( m_initialSwapChoice ) ) { cWarning() << "Configuration for *initialSwapChoice* is not one of the *userSwapChoices*"; + if ( nameFound ) + { + cWarning() << Logger::SubEntry << "Choice" << swapChoiceNames().find( m_initialSwapChoice ) << "added."; + m_swapChoices.insert( m_initialSwapChoice ); + } m_initialSwapChoice = pickOne( m_swapChoices ); } setSwapChoice( m_initialSwapChoice ); diff --git a/src/modules/partition/PartitionViewStep.cpp b/src/modules/partition/PartitionViewStep.cpp index 2285d55eb..c5e2f6c8f 100644 --- a/src/modules/partition/PartitionViewStep.cpp +++ b/src/modules/partition/PartitionViewStep.cpp @@ -675,11 +675,15 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) // because it could take a while. Then when it's done, we can set up the widgets // and remove the spinner. m_future = new QFutureWatcher< void >(); - connect( m_future, &QFutureWatcher< void >::finished, this, [this] { - continueLoading(); - this->m_future->deleteLater(); - this->m_future = nullptr; - } ); + connect( m_future, + &QFutureWatcher< void >::finished, + this, + [ this ] + { + continueLoading(); + this->m_future->deleteLater(); + this->m_future = nullptr; + } ); QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); m_future->setFuture( future ); diff --git a/src/modules/partition/core/DeviceList.cpp b/src/modules/partition/core/DeviceList.cpp index 423c3b4ee..adbbddd68 100644 --- a/src/modules/partition/core/DeviceList.cpp +++ b/src/modules/partition/core/DeviceList.cpp @@ -41,6 +41,10 @@ hasRootPartition( Device* device ) return false; } +/** @brief Check if @p path holds an iso9660 filesystem + * + * The @p path should point to a device; blkid is used to check the FS type. + */ static bool blkIdCheckIso9660( const QString& path ) { @@ -49,6 +53,18 @@ blkIdCheckIso9660( const QString& path ) return r.getOutput().contains( "iso9660" ); } +/// @brief Convenience to check if @p partition holds an iso9660 filesystem +static bool +blkIdCheckIso9660P( const Partition* partition ) +{ + return blkIdCheckIso9660( partition->partitionPath() ); +} + +/** @brief Check if the @p device is an iso9660 device + * + * An iso9660 device is **probably** a CD-ROM. If the device holds an + * iso9660 FS, or any of its partitions do, then we call it an iso9660 device. + */ static bool isIso9660( const Device* device ) { @@ -64,13 +80,8 @@ isIso9660( const Device* device ) if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() ) { - for ( const Partition* partition : device->partitionTable()->children() ) - { - if ( blkIdCheckIso9660( partition->partitionPath() ) ) - { - return true; - } - } + const auto& p = device->partitionTable()->children(); + return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P ); } return false; } diff --git a/src/modules/partition/core/DeviceModel.cpp b/src/modules/partition/core/DeviceModel.cpp index 25bdbff6c..6959ac9c2 100644 --- a/src/modules/partition/core/DeviceModel.cpp +++ b/src/modules/partition/core/DeviceModel.cpp @@ -28,9 +28,9 @@ static void sortDevices( DeviceModel::DeviceList& l ) { - std::sort( l.begin(), l.end(), []( const Device* dev1, const Device* dev2 ) { - return dev1->deviceNode() < dev2->deviceNode(); - } ); + std::sort( l.begin(), + l.end(), + []( const Device* dev1, const Device* dev2 ) { return dev1->deviceNode() < dev2->deviceNode(); } ); } DeviceModel::DeviceModel( QObject* parent ) diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 16e5a7ea1..989327ef0 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -262,11 +262,9 @@ PartitionCoreModule::doInit() // Gives ownership of the Device* to the DeviceInfo object auto deviceInfo = new DeviceInfo( device ); m_deviceInfos << deviceInfo; - cDebug() << Logger::SubEntry - << device->deviceNode() - << device->capacity() - << Logger::RedactedName( "DevName", device->name() ) - << Logger::RedactedName( "DevNamePretty", device->prettyName() ); + cDebug() << Logger::SubEntry << device->deviceNode() << device->capacity() + << Logger::RedactedName( "DevName", device->name() ) + << Logger::RedactedName( "DevNamePretty", device->prettyName() ); } else { @@ -685,9 +683,8 @@ PartitionCoreModule::lvmPVs() const bool PartitionCoreModule::hasVGwithThisName( const QString& name ) const { - auto condition = [name]( DeviceInfo* d ) { - return dynamic_cast< LvmDevice* >( d->device.data() ) && d->device.data()->name() == name; - }; + auto condition = [ name ]( DeviceInfo* d ) + { 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(); } @@ -695,7 +692,8 @@ PartitionCoreModule::hasVGwithThisName( const QString& name ) const bool PartitionCoreModule::isInVG( const Partition* partition ) const { - auto condition = [partition]( DeviceInfo* d ) { + auto condition = [ partition ]( DeviceInfo* d ) + { LvmDevice* vg = dynamic_cast< LvmDevice* >( d->device.data() ); return vg && vg->physicalVolumes().contains( partition ); }; @@ -964,9 +962,9 @@ PartitionCoreModule::layoutApply( Device* dev, const QString boot = QStringLiteral( "/boot" ); const QString root = QStringLiteral( "/" ); const auto is_boot - = [&]( Partition* p ) -> bool { return PartitionInfo::mountPoint( p ) == boot || p->mountPoint() == boot; }; + = [ & ]( Partition* p ) -> bool { return PartitionInfo::mountPoint( p ) == boot || p->mountPoint() == boot; }; const auto is_root - = [&]( Partition* p ) -> bool { return PartitionInfo::mountPoint( p ) == root || p->mountPoint() == root; }; + = [ & ]( Partition* p ) -> bool { return PartitionInfo::mountPoint( p ) == root || p->mountPoint() == root; }; const bool separate_boot_partition = std::find_if( partList.constBegin(), partList.constEnd(), is_boot ) != partList.constEnd(); @@ -1089,10 +1087,14 @@ void PartitionCoreModule::asyncRevertDevice( Device* dev, std::function< void() > callback ) { QFutureWatcher< void >* watcher = new QFutureWatcher< void >(); - connect( watcher, &QFutureWatcher< void >::finished, this, [watcher, callback] { - callback(); - watcher->deleteLater(); - } ); + connect( watcher, + &QFutureWatcher< void >::finished, + this, + [ watcher, callback ] + { + callback(); + watcher->deleteLater(); + } ); QFuture< void > future = QtConcurrent::run( this, &PartitionCoreModule::revertDevice, dev, true ); watcher->setFuture( future ); diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 3813207ef..765d9fffa 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -283,7 +283,7 @@ PartitionLayout::createPartitions( Device* dev, } } - auto correctFS = [d = m_defaultFsType]( FileSystem::Type t ) { return t == FileSystem::Type::Unknown ? d : t; }; + auto correctFS = [ d = m_defaultFsType ]( FileSystem::Type t ) { return t == FileSystem::Type::Unknown ? d : t; }; // Create the partitions. currentSector = firstSector; diff --git a/src/modules/partition/core/SizeUtils.h b/src/modules/partition/core/SizeUtils.h index d474656c9..155cbd923 100644 --- a/src/modules/partition/core/SizeUtils.h +++ b/src/modules/partition/core/SizeUtils.h @@ -19,7 +19,8 @@ * 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). */ -static inline QString formatByteSize( qint64 sizeValue ) +static inline QString +formatByteSize( qint64 sizeValue ) { return Capacity::formatByteSize( static_cast< double >( sizeValue ) ); } diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 9226eb3b6..588c1b643 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -176,10 +176,14 @@ ChoicePage::init( PartitionCoreModule* core ) // We need to do this because a PCM revert invalidates the deviceModel. - connect( core, &PartitionCoreModule::reverted, this, [=] { - setModelToComboBox( m_drivesCombo, core->deviceModel() ); - m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex ); - } ); + connect( core, + &PartitionCoreModule::reverted, + this, + [ = ] + { + setModelToComboBox( m_drivesCombo, core->deviceModel() ); + m_drivesCombo->setCurrentIndex( m_lastSelectedDeviceIndex ); + } ); setModelToComboBox( m_drivesCombo, core->deviceModel() ); connect( m_drivesCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, &ChoicePage::applyDeviceChoice ); @@ -303,26 +307,30 @@ ChoicePage::setupChoices() #else auto buttonSignal = &QButtonGroup::idToggled; #endif - connect( m_grp, buttonSignal, this, [this]( int id, bool checked ) { - if ( checked ) // An action was picked. - { - m_config->setInstallChoice( id ); - updateNextEnabled(); + connect( m_grp, + buttonSignal, + this, + [ this ]( int id, bool checked ) + { + if ( checked ) // An action was picked. + { + m_config->setInstallChoice( id ); + updateNextEnabled(); - Q_EMIT actionChosen(); - } - else // An action was unpicked, either on its own or because of another selection. - { - if ( m_grp->checkedButton() == nullptr ) // If no other action is chosen, we must - { - // set m_choice to NoChoice and reset previews. - m_config->setInstallChoice( InstallChoice::NoChoice ); - updateNextEnabled(); + Q_EMIT actionChosen(); + } + else // An action was unpicked, either on its own or because of another selection. + { + if ( m_grp->checkedButton() == nullptr ) // If no other action is chosen, we must + { + // set m_choice to NoChoice and reset previews. + m_config->setInstallChoice( InstallChoice::NoChoice ); + updateNextEnabled(); - Q_EMIT actionChosen(); - } - } - } ); + Q_EMIT actionChosen(); + } + } + } ); m_rightLayout->setStretchFactor( m_itemsLayout, 1 ); m_rightLayout->setStretchFactor( m_previewBeforeFrame, 0 ); @@ -401,11 +409,13 @@ ChoicePage::applyDeviceChoice() if ( m_core->isDirty() ) { ScanningDialog::run( - QtConcurrent::run( [=] { - QMutexLocker locker( &m_coreMutex ); - m_core->revertAllDevices(); - } ), - [this] { continueApplyDeviceChoice(); }, + QtConcurrent::run( + [ = ] + { + QMutexLocker locker( &m_coreMutex ); + m_core->revertAllDevices(); + } ), + [ this ] { continueApplyDeviceChoice(); }, this ); } else @@ -493,11 +503,14 @@ ChoicePage::applyActionChoice( InstallChoice choice ) if ( m_core->isDirty() ) { ScanningDialog::run( - QtConcurrent::run( [=] { - QMutexLocker locker( &m_coreMutex ); - m_core->revertDevice( selectedDevice() ); - } ), - [=] { + QtConcurrent::run( + [ = ] + { + QMutexLocker locker( &m_coreMutex ); + m_core->revertDevice( selectedDevice() ); + } ), + [ = ] + { PartitionActions::doAutopartition( m_core, selectedDevice(), options ); Q_EMIT deviceChosen(); }, @@ -514,10 +527,12 @@ ChoicePage::applyActionChoice( InstallChoice choice ) if ( m_core->isDirty() ) { ScanningDialog::run( - QtConcurrent::run( [=] { - QMutexLocker locker( &m_coreMutex ); - m_core->revertDevice( selectedDevice() ); - } ), + QtConcurrent::run( + [ = ] + { + QMutexLocker locker( &m_coreMutex ); + m_core->revertDevice( selectedDevice() ); + } ), [] {}, this ); } @@ -532,11 +547,14 @@ ChoicePage::applyActionChoice( InstallChoice choice ) if ( m_core->isDirty() ) { ScanningDialog::run( - QtConcurrent::run( [=] { - QMutexLocker locker( &m_coreMutex ); - m_core->revertDevice( selectedDevice() ); - } ), - [this] { + QtConcurrent::run( + [ = ] + { + QMutexLocker locker( &m_coreMutex ); + m_core->revertDevice( selectedDevice() ); + } ), + [ this ] + { // We need to reupdate after reverting because the splitter widget is // not a true view. updateActionChoicePreview( m_config->installChoice() ); @@ -772,7 +790,8 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) ScanningDialog::run( QtConcurrent::run( - [this, current, homePartitionPath]( bool doReuseHomePartition ) { + [ this, current, homePartitionPath ]( bool doReuseHomePartition ) + { QMutexLocker locker( &m_coreMutex ); if ( m_core->isDirty() ) @@ -853,7 +872,8 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) } }, m_reuseHomeCheckBox->isChecked() ), - [this, homePartitionPath] { + [ this, homePartitionPath ] + { m_reuseHomeCheckBox->setVisible( !homePartitionPath->isEmpty() ); if ( !homePartitionPath->isEmpty() ) m_reuseHomeCheckBox->setText( tr( "Reuse %1 as home partition for %2." ) @@ -1006,7 +1026,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) connect( m_afterPartitionSplitterWidget, &PartitionSplitterWidget::partitionResized, this, - [this, sizeLabel]( const QString& path, qint64 size, qint64 sizeNext ) { + [ this, sizeLabel ]( const QString& path, qint64 size, qint64 sizeNext ) + { Q_UNUSED( path ) sizeLabel->setText( tr( "%1 will be shrunk to %2MiB and a new " @@ -1020,7 +1041,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) m_previewAfterFrame->show(); m_previewAfterLabel->show(); - SelectionFilter filter = []( const QModelIndex& index ) { + SelectionFilter filter = []( const QModelIndex& index ) + { return PartUtils::canBeResized( static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ), Logger::Once() ); @@ -1069,17 +1091,22 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) eraseBootloaderLabel->setText( tr( "Boot loader location:" ) ); m_bootloaderComboBox = createBootloaderComboBox( eraseWidget ); - connect( m_core->bootLoaderModel(), &QAbstractItemModel::modelReset, [this]() { - if ( !m_bootloaderComboBox.isNull() ) - { - Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox, m_core->bootLoaderInstallPath() ); - } - } ); + connect( m_core->bootLoaderModel(), + &QAbstractItemModel::modelReset, + [ this ]() + { + if ( !m_bootloaderComboBox.isNull() ) + { + Calamares::restoreSelectedBootLoader( *m_bootloaderComboBox, + m_core->bootLoaderInstallPath() ); + } + } ); connect( m_core, &PartitionCoreModule::deviceReverted, this, - [this]( Device* dev ) { + [ this ]( Device* dev ) + { Q_UNUSED( dev ) if ( !m_bootloaderComboBox.isNull() ) { @@ -1110,7 +1137,8 @@ ChoicePage::updateActionChoicePreview( InstallChoice choice ) } else { - SelectionFilter filter = []( const QModelIndex& index ) { + SelectionFilter filter = []( const QModelIndex& index ) + { return PartUtils::canBeReplaced( static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() ), Logger::Once() ); @@ -1217,18 +1245,22 @@ ChoicePage::createBootloaderComboBox( QWidget* parent ) comboForBootloader->setModel( m_core->bootLoaderModel() ); // When the chosen bootloader device changes, we update the choice in the PCM - connect( comboForBootloader, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, [this]( int newIndex ) { - QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() ); - if ( bootloaderCombo ) - { - QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole ); - if ( !var.isValid() ) - { - return; - } - m_core->setBootLoaderInstallPath( var.toString() ); - } - } ); + connect( comboForBootloader, + QOverload< int >::of( &QComboBox::currentIndexChanged ), + this, + [ this ]( int newIndex ) + { + QComboBox* bootloaderCombo = qobject_cast< QComboBox* >( sender() ); + if ( bootloaderCombo ) + { + QVariant var = bootloaderCombo->itemData( newIndex, BootLoaderModel::BootLoaderPathRole ); + if ( !var.isValid() ) + { + return; + } + m_core->setBootLoaderInstallPath( var.toString() ); + } + } ); return comboForBootloader; } diff --git a/src/modules/partition/gui/CreatePartitionDialog.cpp b/src/modules/partition/gui/CreatePartitionDialog.cpp index 6bde9a148..c5b17c69e 100644 --- a/src/modules/partition/gui/CreatePartitionDialog.cpp +++ b/src/modules/partition/gui/CreatePartitionDialog.cpp @@ -325,16 +325,10 @@ CreatePartitionDialog::updateMountPointUi() void CreatePartitionDialog::checkMountPointSelection() { - if ( m_usedMountPoints.contains( selectedMountPoint( m_ui->mountPointComboBox ) ) ) - { - m_ui->labelMountPoint->setText( tr( "Mountpoint already in use. Please select another one." ) ); - m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false ); - } - else - { - m_ui->labelMountPoint->setText( QString() ); - m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( true ); - } + validateMountPoint( selectedMountPoint( m_ui->mountPointComboBox ), + m_usedMountPoints, + m_ui->mountPointExplanation, + m_ui->buttonBox->button( QDialogButtonBox::Ok ) ); } void diff --git a/src/modules/partition/gui/CreatePartitionDialog.ui b/src/modules/partition/gui/CreatePartitionDialog.ui index dad932101..0ee715fe0 100644 --- a/src/modules/partition/gui/CreatePartitionDialog.ui +++ b/src/modules/partition/gui/CreatePartitionDialog.ui @@ -68,7 +68,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - &Primary + Primar&y true @@ -171,6 +171,12 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + 0 + 0 + + true @@ -179,21 +185,14 @@ SPDX-License-Identifier: GPL-3.0-or-later - - - - - - - - + Flags: - + true @@ -206,7 +205,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - + Qt::Vertical @@ -219,14 +218,8 @@ SPDX-License-Identifier: GPL-3.0-or-later - + - - - 150 - 16777215 - - Label for the filesystem @@ -235,13 +228,20 @@ SPDX-License-Identifier: GPL-3.0-or-later - + FS Label: + + + + + + + diff --git a/src/modules/partition/gui/EditExistingPartitionDialog.cpp b/src/modules/partition/gui/EditExistingPartitionDialog.cpp index a3052b3b7..0bc35cabe 100644 --- a/src/modules/partition/gui/EditExistingPartitionDialog.cpp +++ b/src/modules/partition/gui/EditExistingPartitionDialog.cpp @@ -69,22 +69,25 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device, replacePartResizerWidget(); - connect( m_ui->formatRadioButton, &QAbstractButton::toggled, [this]( bool doFormat ) { - replacePartResizerWidget(); + connect( m_ui->formatRadioButton, + &QAbstractButton::toggled, + [ this ]( bool doFormat ) + { + replacePartResizerWidget(); - m_ui->fileSystemLabel->setEnabled( doFormat ); - m_ui->fileSystemComboBox->setEnabled( doFormat ); + m_ui->fileSystemLabel->setEnabled( doFormat ); + m_ui->fileSystemComboBox->setEnabled( doFormat ); - if ( !doFormat ) - { - m_ui->fileSystemComboBox->setCurrentText( userVisibleFS( m_partition->fileSystem() ) ); - } + if ( !doFormat ) + { + m_ui->fileSystemComboBox->setCurrentText( userVisibleFS( m_partition->fileSystem() ) ); + } - updateMountPointPicker(); - } ); + updateMountPointPicker(); + } ); connect( - m_ui->fileSystemComboBox, &QComboBox::currentTextChanged, [this]( QString ) { updateMountPointPicker(); } ); + m_ui->fileSystemComboBox, &QComboBox::currentTextChanged, [ this ]( QString ) { updateMountPointPicker(); } ); // File system QStringList fsNames; @@ -295,14 +298,8 @@ EditExistingPartitionDialog::updateMountPointPicker() void EditExistingPartitionDialog::checkMountPointSelection() { - if ( m_usedMountPoints.contains( selectedMountPoint( m_ui->mountPointComboBox ) ) ) - { - m_ui->labelMountPoint->setText( tr( "Mountpoint already in use. Please select another one." ) ); - m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false ); - } - else - { - m_ui->labelMountPoint->setText( QString() ); - m_ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( true ); - } + validateMountPoint( selectedMountPoint( m_ui->mountPointComboBox ), + m_usedMountPoints, + m_ui->mountPointExplanation, + m_ui->buttonBox->button( QDialogButtonBox::Ok ) ); } diff --git a/src/modules/partition/gui/EditExistingPartitionDialog.ui b/src/modules/partition/gui/EditExistingPartitionDialog.ui index 7599bc772..4a9982656 100644 --- a/src/modules/partition/gui/EditExistingPartitionDialog.ui +++ b/src/modules/partition/gui/EditExistingPartitionDialog.ui @@ -51,7 +51,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - Content: + Con&tent: keepRadioButton @@ -109,6 +109,12 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + 0 + 0 + + true @@ -147,14 +153,14 @@ SPDX-License-Identifier: GPL-3.0-or-later - + Flags: - + true @@ -168,20 +174,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - - - - - - - - - - 150 - 16777215 - - Label for the filesystem @@ -190,13 +183,20 @@ SPDX-License-Identifier: GPL-3.0-or-later - + FS Label: + + + + + + + diff --git a/src/modules/partition/gui/EncryptWidget.cpp b/src/modules/partition/gui/EncryptWidget.cpp index ee50e7d66..fe7623050 100644 --- a/src/modules/partition/gui/EncryptWidget.cpp +++ b/src/modules/partition/gui/EncryptWidget.cpp @@ -13,9 +13,27 @@ #include "ui_EncryptWidget.h" +#include "Branding.h" #include "utils/CalamaresUtilsGui.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 ) : QWidget( parent ) , m_ui( new Ui::EncryptWidget ) @@ -27,6 +45,18 @@ EncryptWidget::EncryptWidget( QWidget* parent ) m_ui->m_passphraseLineEdit->hide(); m_ui->m_confirmLineEdit->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_passphraseLineEdit, &QLineEdit::textEdited, this, &EncryptWidget::onPassphraseEdited ); diff --git a/src/modules/partition/gui/EncryptWidget.ui b/src/modules/partition/gui/EncryptWidget.ui index 212300291..a629163d3 100644 --- a/src/modules/partition/gui/EncryptWidget.ui +++ b/src/modules/partition/gui/EncryptWidget.ui @@ -37,6 +37,19 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + + Your system does not seem to support encryption well enough to encrypt the entire system. You may enable encryption, but performance may suffer. + + + 🔓 + + + Qt::AlignCenter + + + @@ -57,6 +70,19 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + + Qt::Horizontal + + + + 40 + 20 + + + + diff --git a/src/modules/partition/gui/PartitionBarsView.cpp b/src/modules/partition/gui/PartitionBarsView.cpp index 81f518acc..305184b13 100644 --- a/src/modules/partition/gui/PartitionBarsView.cpp +++ b/src/modules/partition/gui/PartitionBarsView.cpp @@ -54,9 +54,10 @@ PartitionBarsView::PartitionBarsView( QWidget* parent ) setSelectionMode( QAbstractItemView::SingleSelection ); // Debug - connect( this, &PartitionBarsView::clicked, this, [=]( const QModelIndex& index ) { - cDebug() << "Clicked row" << index.row(); - } ); + connect( this, + &PartitionBarsView::clicked, + this, + [ = ]( const QModelIndex& index ) { cDebug() << "Clicked row" << index.row(); } ); setMouseTracking( true ); } @@ -399,7 +400,7 @@ void PartitionBarsView::setSelectionModel( QItemSelectionModel* selectionModel ) { QAbstractItemView::setSelectionModel( selectionModel ); - connect( selectionModel, &QItemSelectionModel::selectionChanged, this, [=] { viewport()->repaint(); } ); + connect( selectionModel, &QItemSelectionModel::selectionChanged, this, [ = ] { viewport()->repaint(); } ); } @@ -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(); } diff --git a/src/modules/partition/gui/PartitionDialogHelpers.cpp b/src/modules/partition/gui/PartitionDialogHelpers.cpp index 65e88f898..1ba110338 100644 --- a/src/modules/partition/gui/PartitionDialogHelpers.cpp +++ b/src/modules/partition/gui/PartitionDialogHelpers.cpp @@ -12,13 +12,17 @@ #include "PartitionDialogHelpers.h" #include "core/PartUtils.h" +#include "gui/CreatePartitionDialog.h" #include "GlobalStorage.h" #include "JobQueue.h" #include "utils/Logger.h" #include +#include +#include #include +#include QStringList standardMountPoints() @@ -37,7 +41,7 @@ void standardMountPoints( QComboBox& combo ) { combo.clear(); - combo.addItem( QObject::tr( "(no mount point)" ) ); + combo.lineEdit()->setPlaceholderText( QObject::tr( "(no mount point)" ) ); combo.addItems( standardMountPoints() ); } @@ -51,10 +55,6 @@ standardMountPoints( QComboBox& combo, const QString& selected ) QString selectedMountPoint( QComboBox& combo ) { - if ( combo.currentIndex() == 0 ) - { - return QString(); - } return combo.currentText(); } @@ -63,7 +63,7 @@ setSelectedMountPoint( QComboBox& combo, const QString& selected ) { if ( selected.isEmpty() ) { - combo.setCurrentIndex( 0 ); // (no mount point) + combo.setCurrentIndex( -1 ); // (no mount point) } 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 /." ); + ok = false; + } + + if ( label ) + { + label->setText( msg ); + } + if ( button ) + { + button->setEnabled( ok ); + } + return ok; +} + PartitionTable::Flags flagsFromList( const QListWidget& list ) diff --git a/src/modules/partition/gui/PartitionDialogHelpers.h b/src/modules/partition/gui/PartitionDialogHelpers.h index 7761004b5..eea0998c4 100644 --- a/src/modules/partition/gui/PartitionDialogHelpers.h +++ b/src/modules/partition/gui/PartitionDialogHelpers.h @@ -16,7 +16,9 @@ #include +class QPushButton; class QComboBox; +class QLabel; class QListWidget; /** @@ -58,6 +60,16 @@ setSelectedMountPoint( QComboBox* combo, const QString& 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. */ diff --git a/src/modules/partition/gui/PartitionLabelsView.cpp b/src/modules/partition/gui/PartitionLabelsView.cpp index e73d7f4af..e3a50c576 100644 --- a/src/modules/partition/gui/PartitionLabelsView.cpp +++ b/src/modules/partition/gui/PartitionLabelsView.cpp @@ -519,7 +519,7 @@ void PartitionLabelsView::setSelectionModel( QItemSelectionModel* selectionModel ) { QAbstractItemView::setSelectionModel( selectionModel ); - connect( selectionModel, &QItemSelectionModel::selectionChanged, this, [=] { viewport()->repaint(); } ); + connect( selectionModel, &QItemSelectionModel::selectionChanged, this, [ = ] { viewport()->repaint(); } ); } diff --git a/src/modules/partition/gui/PartitionPage.cpp b/src/modules/partition/gui/PartitionPage.cpp index 9d7a2f0d7..0b3cf2478 100644 --- a/src/modules/partition/gui/PartitionPage.cpp +++ b/src/modules/partition/gui/PartitionPage.cpp @@ -451,15 +451,18 @@ void PartitionPage::onRevertClicked() { ScanningDialog::run( - QtConcurrent::run( [this] { - QMutexLocker locker( &m_revertMutex ); + QtConcurrent::run( + [ this ] + { + QMutexLocker locker( &m_revertMutex ); - int oldIndex = m_ui->deviceComboBox->currentIndex(); - m_core->revertAllDevices(); - m_ui->deviceComboBox->setCurrentIndex( ( oldIndex < 0 ) ? 0 : oldIndex ); - updateFromCurrentDevice(); - } ), - [this] { + int oldIndex = m_ui->deviceComboBox->currentIndex(); + m_core->revertAllDevices(); + m_ui->deviceComboBox->setCurrentIndex( ( oldIndex < 0 ) ? 0 : oldIndex ); + updateFromCurrentDevice(); + } ), + [ this ] + { m_lastSelectedBootLoaderIndex = -1; if ( m_ui->bootLoaderComboBox->currentIndex() < 0 ) { @@ -606,7 +609,8 @@ PartitionPage::updateFromCurrentDevice() m_ui->partitionBarsView->selectionModel(), &QItemSelectionModel::currentChanged, this, - [=] { + [ = ] + { QModelIndex selectedIndex = m_ui->partitionBarsView->selectionModel()->currentIndex(); selectedIndex = selectedIndex.sibling( selectedIndex.row(), 0 ); m_ui->partitionBarsView->setCurrentIndex( selectedIndex ); @@ -625,7 +629,7 @@ PartitionPage::updateFromCurrentDevice() // model changes connect( m_ui->partitionTreeView->selectionModel(), &QItemSelectionModel::currentChanged, - [this]( const QModelIndex&, const QModelIndex& ) { updateButtons(); } ); + [ this ]( const QModelIndex&, const QModelIndex& ) { updateButtons(); } ); connect( model, &QAbstractItemModel::modelReset, this, &PartitionPage::onPartitionModelReset ); } diff --git a/src/modules/partition/gui/PartitionSplitterWidget.cpp b/src/modules/partition/gui/PartitionSplitterWidget.cpp index 0cafe7814..e52afaa74 100644 --- a/src/modules/partition/gui/PartitionSplitterWidget.cpp +++ b/src/modules/partition/gui/PartitionSplitterWidget.cpp @@ -159,14 +159,16 @@ PartitionSplitterWidget::setSplitPartition( const QString& path, qint64 minSize, m_itemToResizePath.clear(); } - PartitionSplitterItem itemToResize = _findItem( m_items, [path]( PartitionSplitterItem& item ) -> bool { - if ( path == item.itemPath ) - { - item.status = PartitionSplitterItem::Resizing; - return true; - } - return false; - } ); + PartitionSplitterItem itemToResize = _findItem( m_items, + [ path ]( PartitionSplitterItem& item ) -> bool + { + if ( path == item.itemPath ) + { + item.status = PartitionSplitterItem::Resizing; + return true; + } + return false; + } ); if ( itemToResize.isNull() ) { @@ -184,14 +186,16 @@ PartitionSplitterWidget::setSplitPartition( const QString& path, qint64 minSize, qint64 newSize = m_itemToResize.size - preferredSize; m_itemToResize.size = preferredSize; - int opCount = _eachItem( m_items, [preferredSize]( PartitionSplitterItem& item ) -> bool { - if ( item.status == PartitionSplitterItem::Resizing ) - { - item.size = preferredSize; - return true; - } - return false; - } ); + int opCount = _eachItem( m_items, + [ preferredSize ]( PartitionSplitterItem& item ) -> bool + { + if ( item.status == PartitionSplitterItem::Resizing ) + { + item.size = preferredSize; + return true; + } + return false; + } ); cDebug() << "each splitter item opcount:" << opCount; m_itemMinSize = minSize; m_itemMaxSize = maxSize; @@ -358,19 +362,21 @@ PartitionSplitterWidget::mouseMoveEvent( QMouseEvent* event ) m_itemToResize.size = qRound64( span * percent ); m_itemToResizeNext.size -= m_itemToResize.size - oldsize; - _eachItem( m_items, [this]( PartitionSplitterItem& item ) -> bool { - if ( item.status == PartitionSplitterItem::Resizing ) - { - item.size = m_itemToResize.size; - return true; - } - else if ( item.status == PartitionSplitterItem::ResizingNext ) - { - item.size = m_itemToResizeNext.size; - return true; - } - return false; - } ); + _eachItem( m_items, + [ this ]( PartitionSplitterItem& item ) -> bool + { + if ( item.status == PartitionSplitterItem::Resizing ) + { + item.size = m_itemToResize.size; + return true; + } + else if ( item.status == PartitionSplitterItem::ResizingNext ) + { + item.size = m_itemToResizeNext.size; + return true; + } + return false; + } ); repaint(); diff --git a/src/modules/partition/gui/ReplaceWidget.cpp b/src/modules/partition/gui/ReplaceWidget.cpp index 2e5675a11..76f9ff963 100644 --- a/src/modules/partition/gui/ReplaceWidget.cpp +++ b/src/modules/partition/gui/ReplaceWidget.cpp @@ -46,9 +46,10 @@ ReplaceWidget::ReplaceWidget( PartitionCoreModule* core, QComboBox* devicesCombo m_ui->bootStatusLabel->clear(); updateFromCurrentDevice( devicesComboBox ); - connect( devicesComboBox, &QComboBox::currentTextChanged, this, [=]( const QString& /* text */ ) { - updateFromCurrentDevice( devicesComboBox ); - } ); + connect( devicesComboBox, + &QComboBox::currentTextChanged, + this, + [ = ]( const QString& /* text */ ) { updateFromCurrentDevice( devicesComboBox ); } ); CALAMARES_RETRANSLATE( onPartitionSelected(); ); } diff --git a/src/modules/partition/gui/ScanningDialog.cpp b/src/modules/partition/gui/ScanningDialog.cpp index 4dffa922b..56133e21f 100644 --- a/src/modules/partition/gui/ScanningDialog.cpp +++ b/src/modules/partition/gui/ScanningDialog.cpp @@ -47,12 +47,16 @@ ScanningDialog::run( const QFuture< void >& future, theDialog->show(); QFutureWatcher< void >* watcher = new QFutureWatcher< void >(); - connect( watcher, &QFutureWatcher< void >::finished, theDialog, [watcher, theDialog, callback] { - watcher->deleteLater(); - theDialog->hide(); - theDialog->deleteLater(); - callback(); - } ); + connect( watcher, + &QFutureWatcher< void >::finished, + theDialog, + [ watcher, theDialog, callback ] + { + watcher->deleteLater(); + theDialog->hide(); + theDialog->deleteLater(); + callback(); + } ); watcher->setFuture( future ); } diff --git a/src/modules/partition/gui/VolumeGroupBaseDialog.cpp b/src/modules/partition/gui/VolumeGroupBaseDialog.cpp index 48b44f68d..818a60483 100644 --- a/src/modules/partition/gui/VolumeGroupBaseDialog.cpp +++ b/src/modules/partition/gui/VolumeGroupBaseDialog.cpp @@ -45,17 +45,25 @@ VolumeGroupBaseDialog::VolumeGroupBaseDialog( QString& vgName, QVector< const Pa updateOkButton(); updateTotalSize(); - connect( ui->pvList, &QListWidget::itemChanged, this, [&]( QListWidgetItem* ) { - updateTotalSize(); - updateOkButton(); - } ); + connect( ui->pvList, + &QListWidget::itemChanged, + this, + [ & ]( QListWidgetItem* ) + { + updateTotalSize(); + updateOkButton(); + } ); - connect( ui->peSize, qOverload< int >( &QSpinBox::valueChanged ), this, [&]( int ) { - updateTotalSectors(); - updateOkButton(); - } ); + connect( ui->peSize, + qOverload< int >( &QSpinBox::valueChanged ), + this, + [ & ]( int ) + { + updateTotalSectors(); + updateOkButton(); + } ); - connect( ui->vgName, &QLineEdit::textChanged, this, [&]( const QString& ) { updateOkButton(); } ); + connect( ui->vgName, &QLineEdit::textChanged, this, [ & ]( const QString& ) { updateOkButton(); } ); } VolumeGroupBaseDialog::~VolumeGroupBaseDialog() diff --git a/src/modules/partition/jobs/AutoMountManagementJob.cpp b/src/modules/partition/jobs/AutoMountManagementJob.cpp index e276447db..29b197933 100644 --- a/src/modules/partition/jobs/AutoMountManagementJob.cpp +++ b/src/modules/partition/jobs/AutoMountManagementJob.cpp @@ -26,7 +26,9 @@ Calamares::JobResult AutoMountManagementJob::exec() { 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 ) { CalamaresUtils::Partition::automountRestore( m_stored ); diff --git a/src/modules/partition/jobs/ClearMountsJob.cpp b/src/modules/partition/jobs/ClearMountsJob.cpp index 2f5a8bd36..3d7b9d0de 100644 --- a/src/modules/partition/jobs/ClearMountsJob.cpp +++ b/src/modules/partition/jobs/ClearMountsJob.cpp @@ -157,9 +157,11 @@ getLVMVolumes() QStringList lvscanLines = QString::fromLocal8Bit( process.readAllStandardOutput() ).split( '\n' ); // Get the second column (`value(1)`) sinec that is the device name, // remove quoting. - std::transform( lvscanLines.begin(), lvscanLines.end(), lvscanLines.begin(), []( const QString& lvscanLine ) { - return lvscanLine.simplified().split( ' ' ).value( 1 ).replace( '\'', "" ); - } ); + std::transform( lvscanLines.begin(), + lvscanLines.end(), + lvscanLines.begin(), + []( const QString& lvscanLine ) + { return lvscanLine.simplified().split( ' ' ).value( 1 ).replace( '\'', "" ); } ); return lvscanLines; } else diff --git a/src/modules/partition/jobs/ClearTempMountsJob.cpp b/src/modules/partition/jobs/ClearTempMountsJob.cpp index ffbc35044..6219de004 100644 --- a/src/modules/partition/jobs/ClearTempMountsJob.cpp +++ b/src/modules/partition/jobs/ClearTempMountsJob.cpp @@ -9,6 +9,7 @@ #include "ClearTempMountsJob.h" +#include "partition/Mount.h" #include "utils/Logger.h" #include "utils/String.h" @@ -45,51 +46,23 @@ ClearTempMountsJob::exec() { Logger::Once o; // Fetch a list of current mounts to Calamares temporary directories. - QList< QPair< QString, QString > > lst; - QFile mtab( "/etc/mtab" ); - if ( !mtab.open( QFile::ReadOnly | QFile::Text ) ) - { - return Calamares::JobResult::error( tr( "Cannot get list of temporary mounts." ) ); - } + using MtabInfo = CalamaresUtils::Partition::MtabInfo; + auto targetMounts = MtabInfo::fromMtabFilteredByPrefix( QStringLiteral( "/tmp/calamares-" ) ); - cVerbose() << o << "Opened mtab. Lines:"; - 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() ) + if ( targetMounts.isEmpty() ) { return Calamares::JobResult::ok(); } - - std::sort( - lst.begin(), lst.end(), []( const QPair< QString, QString >& a, const QPair< QString, QString >& b ) -> bool { - return a.first > b.first; - } ); + std::sort( targetMounts.begin(), targetMounts.end(), MtabInfo::mountPointOrder ); QStringList goodNews; - QProcess process; - - for ( const auto& line : qAsConst( lst ) ) + for ( const auto& m : qAsConst( targetMounts ) ) { - QString partPath = line.second; - cDebug() << o << "Will try to umount path" << partPath; - process.start( "umount", { "-lv", partPath } ); - process.waitForFinished(); - if ( process.exitCode() == 0 ) + cDebug() << o << "Will try to umount path" << m.mountPoint; + if ( CalamaresUtils::Partition::unmount( m.mountPoint, { "-lv" } ) == 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 ) ); } } diff --git a/src/modules/partition/jobs/FormatPartitionJob.cpp b/src/modules/partition/jobs/FormatPartitionJob.cpp index 1ccc6e617..63d233426 100644 --- a/src/modules/partition/jobs/FormatPartitionJob.cpp +++ b/src/modules/partition/jobs/FormatPartitionJob.cpp @@ -14,6 +14,7 @@ #include "core/KPMHelpers.h" #include "partition/FileSystem.h" +#include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" #include @@ -67,7 +68,18 @@ FormatPartitionJob::prettyStatusMessage() const Calamares::JobResult FormatPartitionJob::exec() { - return KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, m_partition->fileSystem().type() ), - tr( "The installer failed to format partition %1 on disk '%2'." ) - .arg( m_partition->partitionPath(), m_device->name() ) ); + 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'." ) + .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; } diff --git a/src/modules/partition/tests/AutoMountTests.cpp b/src/modules/partition/tests/AutoMountTests.cpp index 45a7b4f12..103fe6f82 100644 --- a/src/modules/partition/tests/AutoMountTests.cpp +++ b/src/modules/partition/tests/AutoMountTests.cpp @@ -69,8 +69,8 @@ AutoMountJobTests::testRunQueue() QVERIFY( !q.isRunning() ); QEventLoop loop; - QTimer::singleShot( std::chrono::milliseconds( 100 ), [&q]() { q.start(); } ); - QTimer::singleShot( std::chrono::milliseconds( 5000 ), [&loop]() { loop.quit(); } ); + QTimer::singleShot( std::chrono::milliseconds( 100 ), [ &q ]() { q.start(); } ); + QTimer::singleShot( std::chrono::milliseconds( 5000 ), [ &loop ]() { loop.quit(); } ); connect( &q, &Calamares::JobQueue::finished, &loop, &QEventLoop::quit ); loop.exec(); diff --git a/src/modules/partition/tests/ClearMountsJobTests.cpp b/src/modules/partition/tests/ClearMountsJobTests.cpp index 3af400fde..17565e756 100644 --- a/src/modules/partition/tests/ClearMountsJobTests.cpp +++ b/src/modules/partition/tests/ClearMountsJobTests.cpp @@ -32,10 +32,10 @@ getPartitionsForDevice_other( const QString& deviceName ) { QProcess process; process.setProgram( "sh" ); - process.setArguments( - { "-c", - QString( "echo $(awk '{print \"/dev/\"$4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' -e '/[1-9]/!d' | grep %1)" ) - .arg( deviceName ) } ); + process.setArguments( { "-c", + QString( "echo $(awk '{print \"/dev/\"$4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' " + "-e '/[1-9]/!d' | grep %1)" ) + .arg( deviceName ) } ); process.start(); process.waitForFinished(); diff --git a/src/modules/umount/CMakeLists.txt b/src/modules/umount/CMakeLists.txt new file mode 100644 index 000000000..d72847007 --- /dev/null +++ b/src/modules/umount/CMakeLists.txt @@ -0,0 +1,19 @@ +# === This file is part of Calamares - === +# +# SPDX-FileCopyrightText: 2021 Adriaan de Groot +# 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 +) diff --git a/src/modules/umount/Tests.cpp b/src/modules/umount/Tests.cpp new file mode 100644 index 000000000..dc0198619 --- /dev/null +++ b/src/modules/umount/Tests.cpp @@ -0,0 +1,52 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * 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 +#include +#include + +// 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" diff --git a/src/modules/umount/UmountJob.cpp b/src/modules/umount/UmountJob.cpp new file mode 100644 index 000000000..b9d92fa87 --- /dev/null +++ b/src/modules/umount/UmountJob.cpp @@ -0,0 +1,158 @@ +/* === This file is part of Calamares - === + * + * Tags from the Python version of this module: + * SPDX-FileCopyrightText: 2014 Aurélien Gâteau + * SPDX-FileCopyrightText: 2016 Anke Boersma + * SPDX-FileCopyrightText: 2018 Adriaan de Groot + * Tags for the C++ version of this module: + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * 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 +#include +#include + +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 >(); ) diff --git a/src/modules/umount/UmountJob.h b/src/modules/umount/UmountJob.h new file mode 100644 index 000000000..6ca5428bc --- /dev/null +++ b/src/modules/umount/UmountJob.h @@ -0,0 +1,41 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * 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 +#include +#include + +/** @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 diff --git a/src/modules/umount/main.py b/src/modules/umount/main.py deleted file mode 100644 index 5fdb36014..000000000 --- a/src/modules/umount/main.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# === This file is part of Calamares - === -# -# SPDX-FileCopyrightText: 2014 Aurélien Gâteau -# SPDX-FileCopyrightText: 2016 Anke Boersma -# SPDX-FileCopyrightText: 2018 Adriaan de Groot -# 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 diff --git a/src/modules/umount/module.desc b/src/modules/umount/module.desc deleted file mode 100644 index a1c189a62..000000000 --- a/src/modules/umount/module.desc +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: no -# SPDX-License-Identifier: CC0-1.0 ---- -type: "job" -name: "umount" -interface: "python" -script: "main.py" diff --git a/src/modules/umount/umount.conf b/src/modules/umount/umount.conf index 7c11f4db6..9fb922740 100644 --- a/src/modules/umount/umount.conf +++ b/src/modules/umount/umount.conf @@ -4,27 +4,11 @@ ### Umount Module # # 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 -# is possible to copy files to the target system. -# -# The "copy log files" functionality is deprecated; use the *preservefiles* -# module instead, which is more flexible. -# +# of partitions used for the install. After this, there is no regular way +# to modify the target system anymore. # --- -# This is a **deprecated** example. Use the *preservefiles* module -# instead, where the equivalent configuration is this: -# -# 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" +# Setting emergency to true will make it so this module is still run +# when a prior module fails +emergency: false diff --git a/src/modules/umount/umount.schema.yaml b/src/modules/umount/umount.schema.yaml index 9b81db3d9..37771e5f6 100644 --- a/src/modules/umount/umount.schema.yaml +++ b/src/modules/umount/umount.schema.yaml @@ -6,5 +6,4 @@ $id: https://calamares.io/schemas/umount additionalProperties: false type: object properties: - srcLog: { type: string } - destLog: { type: string } + emergency: { type: boolean } diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py index 9f1bd822c..033073881 100644 --- a/src/modules/unpackfs/main.py +++ b/src/modules/unpackfs/main.py @@ -428,14 +428,16 @@ def run(): if not root_mount_point: libcalamares.utils.warning("No mount point for root partition") return (_("No mount point for root partition"), - _("globalstorage does not contain a \"rootMountPoint\" key, " - "doing nothing")) - + _("globalstorage does not contain a \"rootMountPoint\" key.")) if not os.path.exists(root_mount_point): libcalamares.utils.warning("Bad root mount point \"{}\"".format(root_mount_point)) return (_("Bad mount point for root partition"), - _("rootMountPoint is \"{}\", which does not " - "exist, doing nothing").format(root_mount_point)) + _("rootMountPoint is \"{}\", which does not exist.".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() @@ -450,17 +452,17 @@ def run(): 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(" ... 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)) if not os.path.exists(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)) if sourcefs == "squashfs": if shutil.which("unsquashfs") is None: 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 unpack image \"{}\"").format(source)) @@ -475,7 +477,7 @@ def run(): if not os.path.isdir(destination) and sourcefs != "file": libcalamares.utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination)) if is_first: - return (_("Bad unsquash configuration"), + return (_("Bad unpackfs configuration"), _("The destination \"{}\" in the target system is not a directory").format(destination)) else: libcalamares.utils.debug(".. assuming that the previous targets will create that directory.")