Compare commits
	
		
			161 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | f01b4ed2f8 | ||
|   | ea762b0945 | ||
|   | cae8acb4a4 | ||
|   | ae204d0108 | ||
|   | a2fae600c4 | ||
|   | 349acad491 | ||
|   | 9b4c4876bc | ||
|   | cc02baed9a | ||
|   | dfab089938 | ||
|   | 2dd9a7ba8a | ||
|   | 82f31f3cd9 | ||
|   | c5b01a574d | ||
|   | bc4789d57f | ||
|   | 0962b98494 | ||
|   | 108476c025 | ||
|   | 04a1bc9e2c | ||
|   | bff5e485f4 | ||
|   | 3c838436c2 | ||
|   | 644c9cf4f3 | ||
|   | dcaa378ddd | ||
|   | 14fd23dcef | ||
|   | f4bc7052e0 | ||
|   | 4f0f48d99d | ||
|   | 1344880f2e | ||
|   | 5704e146a0 | ||
|   | 85eb434b57 | ||
|   | 4b2ea61aa3 | ||
|   | 39d25eef1c | ||
|   | e82d32fe66 | ||
|   | a50ab49c22 | ||
|   | a66ab99ce8 | ||
|   | c3170a9dfb | ||
|   | 88437d3612 | ||
|   | 6db52a904e | ||
|   | 8f0403a3f8 | ||
|   | caf231b0d1 | ||
|   | 9ad86f81bb | ||
|   | 4d601f2e6a | ||
|   | 69f68d82e6 | ||
|   | 572a94e493 | ||
|   | 90454be1b9 | ||
|   | 6144404bd0 | ||
|   | 8f4d8d119c | ||
|   | e8c870205d | ||
|   | 081d7d47d1 | ||
|   | e92ecea3f5 | ||
|   | e158402478 | ||
|   | d242d077db | ||
|   | 5f9b46a820 | ||
|   | 9151d0fcee | ||
|   | 282f5bfade | ||
|   | eeb264f32e | ||
|   | 83606aaf9d | ||
|   | 322a7a212f | ||
|   | 40c7496f85 | ||
|   | f1fd52e790 | ||
|   | 12f6068622 | ||
|   | 16a3e2edb2 | ||
|   | 8fc9b907af | ||
|   | ecaf2c3076 | ||
|   | ea97927997 | ||
|   | 6795190216 | ||
|   | 51149e34d7 | ||
|   | a2674c652d | ||
|   | d4d6d17efe | ||
|   | b74d77a9c5 | ||
|   | 5074bebd32 | ||
|   | 76be9988fe | ||
|   | c85daf8f7b | ||
|   | 13e8b1e9b5 | ||
|   | e6ddf30512 | ||
|   | 9938d11ad1 | ||
|   | def4ee5c7e | ||
|   | 718f73c9c8 | ||
|   | 720415d8b7 | ||
|   | 0f0b9aa776 | ||
|   | 19d508ca2e | ||
|   | 7af1aeb132 | ||
|   | 3f7cabe832 | ||
|   | 341c9f4a7f | ||
|   | 03260efb3a | ||
|   | 18060db82d | ||
|   | b978f03618 | ||
|   | a4a6194a5d | ||
|   | 93cf06da82 | ||
|   | 901211c12d | ||
|   | e89a58a34b | ||
|   | fb36765982 | ||
|   | f1d2bfacce | ||
|   | 9703bd9058 | ||
|   | 0e2a178436 | ||
|   | fb70e29e29 | ||
|   | fbfa9d8038 | ||
|   | 59ab728502 | ||
|   | 476224d34e | ||
|   | 2aaf440fec | ||
|   | b416caa462 | ||
|   | 0c11b864e5 | ||
|   | 0f9ffb9e35 | ||
|   | 813d26ec4e | ||
|   | 5d44118b4b | ||
|   | 833e33f011 | ||
|   | ea3a03a8cc | ||
|   | 05bbeae2c3 | ||
|   | b9b923e69c | ||
|   | ff3391f67b | ||
|   | b60b21b680 | ||
|   | 8a533d22be | ||
|   | 6f32c18ef9 | ||
|   | f36f21c55c | ||
|   | bcacab531f | ||
|   | 85586293c8 | ||
|   | e71eb01feb | ||
|   | 3eb3e9c98d | ||
|   | 2bf5706f73 | ||
|   | 809491c969 | ||
|   | febeb3281e | ||
|   | 76885c7fe1 | ||
|   | fad0575e4d | ||
|   | 550f7d40ef | ||
|   | 6c07d39374 | ||
|   | 4285ccebd7 | ||
|   | 320d67a5ba | ||
|   | 6a80ce6dab | ||
|   | 33678a6a16 | ||
|   | 2c91dc4664 | ||
|   | b3cda8d7cb | ||
|   | 4611f2f9ea | ||
|   | 7acd4bb3d6 | ||
|   | 41b4b59a5e | ||
|   | 077320dc19 | ||
|   | c5eeeb7a50 | ||
|   | 52882df5ee | ||
|   | 616e51b3ee | ||
|   | f2e59e611f | ||
|   | a532b309b7 | ||
|   | 45ae6084d8 | ||
|   | e0cd044e5b | ||
|   | 2c1cbb7f85 | ||
|   | bf5e3d857a | ||
|   | e78bd936a3 | ||
|   | a53f9359f4 | ||
|   | 3a525359a5 | ||
|   | 7716052fbb | ||
|   | 5e7c6ef005 | ||
|   | 83da9b2485 | ||
|   | ceea4db418 | ||
|   | 86823162c6 | ||
|   | 19ffdc47bb | ||
|   | 0bd415f83e | ||
|   | 028042afe7 | ||
|   | 59556074cc | ||
|   | a6a9dc6890 | ||
|   | ed7d63d913 | ||
|   | 9b1da6ff8c | ||
|   | 7d3c483b35 | ||
|   | 0d057478b0 | ||
|   | 7f750cb145 | ||
|   | 86e77b975f | ||
|   | 70fa9fa766 | ||
|   | c43bd06860 | 
| @@ -8,6 +8,7 @@ AlignEscapedNewlines: DontAlign | ||||
| AllowAllParametersOfDeclarationOnNextLine: "false" | ||||
| AllowShortFunctionsOnASingleLine: Inline | ||||
| AllowShortIfStatementsOnASingleLine: "false" | ||||
| AllowShortLambdasOnASingleLine: All | ||||
| AllowShortLoopsOnASingleLine: "false" | ||||
| AlwaysBreakAfterReturnType: TopLevelDefinitions | ||||
| AlwaysBreakTemplateDeclarations: Yes | ||||
| @@ -28,7 +29,6 @@ ReflowComments: "false" | ||||
| SortIncludes: "true" | ||||
| SpaceAfterCStyleCast: "false" | ||||
| SpacesBeforeTrailingComments: "2" | ||||
| # SpaceInEmptyBlock: "true" | ||||
| SpacesInAngles: "true" | ||||
| SpacesInParentheses: "true" | ||||
| SpacesInSquareBrackets: "true" | ||||
|   | ||||
							
								
								
									
										35
									
								
								.clang-format.base
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | ||||
| #   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 | ||||
							
								
								
									
										60
									
								
								.github/workflows/nightly-neon.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | ||||
| name: nightly-neon-xtn | ||||
|  | ||||
| on: | ||||
|   schedule: | ||||
|     - cron: "52 1 * * *" | ||||
|   workflow_dispatch: | ||||
|  | ||||
| env: | ||||
|   BUILDDIR: /build | ||||
|   SRCDIR: ${{ github.workspace }} | ||||
|   CMAKE_ARGS: | | ||||
|     -DWEBVIEW_FORCE_WEBKIT=1 | ||||
|     -DKDE_INSTALL_USE_QT_SYS_PATHS=ON | ||||
|     -DWITH_PYTHONQT=OFF" | ||||
|     -DCMAKE_BUILD_TYPE=Debug | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: docker://kdeneon/plasma:user | ||||
|       options: --tmpfs /build:rw --user 0:0 | ||||
|     steps: | ||||
|       - name: "fetch artifacts" | ||||
|         uses: dawidd6/action-download-artifact@v2 | ||||
|         with: | ||||
|           workflow: nightly-neon.yml | ||||
|           workflow_conclusion: success | ||||
|           branch: calamares | ||||
|           name: calamares-tarball | ||||
|           path: ${{ env.BUILDDIR }} | ||||
|           repo: calamares/calamares | ||||
|       - name: "prepare env" | ||||
|         uses: calamares/actions/prepare-neon@v2 | ||||
|       - name: "prepare source" | ||||
|         uses: actions/checkout@v2 | ||||
|       - name: "prepare artifacts" | ||||
|         run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1 | ||||
|       - name: "build" | ||||
|         id: build | ||||
|         uses: calamares/actions/generic-build@v2 | ||||
|       - name: "notify: ok" | ||||
|         if: ${{ success() && github.repository == 'calamares/calamares-extensions' }} | ||||
|         uses: calamares/actions/matrix-notify@v2 | ||||
|         with: | ||||
|           token: ${{ secrets.MATRIX_TOKEN }} | ||||
|           room: ${{ secrets.MATRIX_ROOM }} | ||||
|           message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.build.outputs.git_summary }}" | ||||
|       - name: "notify: fail" | ||||
|         if: ${{ failure() && github.repository == 'calamares/calamares' }} | ||||
|         uses: calamares/actions/matrix-notify@v2 | ||||
|         with: | ||||
|           token: ${{ secrets.MATRIX_TOKEN }} | ||||
|           room: ${{ secrets.MATRIX_ROOM }} | ||||
|           message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.build.outputs.git_summary}}" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										66
									
								
								.github/workflows/push.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,66 @@ | ||||
| name: ci-push-xtn | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - calamares | ||||
|   pull_request: | ||||
|     types: | ||||
|       - opened | ||||
|       - reopened | ||||
|       - synchronize | ||||
|   workflow_dispatch: | ||||
|  | ||||
| env: | ||||
|   BUILDDIR: /build | ||||
|   SRCDIR: ${{ github.workspace }} | ||||
|   CMAKE_ARGS: | | ||||
|     -DWEBVIEW_FORCE_WEBKIT=1 | ||||
|     -DKDE_INSTALL_USE_QT_SYS_PATHS=ON | ||||
|     -DWITH_PYTHONQT=OFF" | ||||
|     -DCMAKE_BUILD_TYPE=Debug | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: docker://kdeneon/plasma:user | ||||
|       options: --tmpfs /build:rw --user 0:0 | ||||
|     steps: | ||||
|       - name: "fetch artifacts" | ||||
|         uses: dawidd6/action-download-artifact@v2 | ||||
|         with: | ||||
|           workflow: nightly-neon.yml | ||||
|           workflow_conclusion: success | ||||
|           branch: calamares | ||||
|           name: calamares-tarball | ||||
|           path: ${{ env.BUILDDIR }} | ||||
|           repo: calamares/calamares | ||||
|       - name: "prepare env" | ||||
|         uses: calamares/actions/prepare-neon@v2 | ||||
|       - name: "prepare source" | ||||
|         uses: actions/checkout@v2 | ||||
|       - name: "prepare artifacts" | ||||
|         run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1 | ||||
|       - name: "build" | ||||
|         id: build | ||||
|         uses: calamares/actions/generic-build@v2 | ||||
|       - name: "notify: ok" | ||||
|         if: ${{ success() && github.repository == 'calamares/calamares-extensions' }} | ||||
|         uses: calamares/actions/matrix-notify@v2 | ||||
|         with: | ||||
|           token: ${{ secrets.MATRIX_TOKEN }} | ||||
|           room: ${{ secrets.MATRIX_ROOM }} | ||||
|           message: | | ||||
|             OK ${{ github.workflow }} in ${{ github.repository }} by ${{ github.actor }} on ${{ github.event.ref }} | ||||
|             .. ${{ steps.build.outputs.git-summary }} | ||||
|       - name: "notify: fail" | ||||
|         if: ${{ failure() && github.repository == 'calamares/calamares-extensions' }} | ||||
|         uses: calamares/actions/matrix-notify@v2 | ||||
|         with: | ||||
|           token: ${{ secrets.MATRIX_TOKEN }} | ||||
|           room: ${{ secrets.MATRIX_ROOM }} | ||||
|           message: | | ||||
|             FAIL ${{ github.workflow }} in ${{ github.repository }} by ${{ github.actor }} on ${{ github.event.ref }} | ||||
|               .. ${{ steps.build.outputs.git-summary }} | ||||
|               .. ${{ github.event.compare }} | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,3 +1,6 @@ | ||||
| #   SPDX-FileCopyrightText: no | ||||
| #   SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| .kdev4/ | ||||
| build/ | ||||
| *.kdev4 | ||||
|   | ||||
							
								
								
									
										23
									
								
								.reuse/dep5
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | ||||
| Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ | ||||
| Upstream-Name: Calamares-Extensions | ||||
| Source: https://github.com/calamares/calamares-extensions.git | ||||
|  | ||||
| ### BUILD ARTIFACTS / NOT SOURCE | ||||
| # | ||||
| # QRC Files are basically build artifacts | ||||
| # | ||||
| FILES: modules/*/*.qrc | ||||
| License: CC0-1.0 | ||||
| Copyright: no | ||||
|  | ||||
| # GitHub issue templates are not part of the source | ||||
| # | ||||
| Files: .github/ISSUE_TEMPLATE/* | ||||
| License: CC0-1.0 | ||||
| Copyright: no | ||||
|  | ||||
| # GitHub actions are not part of the source | ||||
| Files: .github/workflows/*.yml | ||||
| License: CC0-1.0 | ||||
| Copyright: no | ||||
|  | ||||
							
								
								
									
										79
									
								
								CHANGES
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,79 @@ | ||||
| <!-- SPDX-FileCopyrightText: no | ||||
|      SPDX-License-Identifier: CC0-1.0 | ||||
| --> | ||||
|  | ||||
| This is the changelog for Calamares-Extensions. For each release, the major | ||||
| changes and contributors are listed. Note that Calamares-Extensions does not | ||||
| have a historical changelog -- this log starts with version 1.0.0. | ||||
|  | ||||
| # 1.2.1 (2021-11-16) | ||||
|  | ||||
| The 1.2.0 release had no release-notes for that version, and failed to | ||||
| credit Anke and Otus. | ||||
|  | ||||
| Changes and new modules in this release: | ||||
|  - *unpackfsc* can use `fsarchiver` and unpack that, instead of squashfs; | ||||
|    a distro might choose one tool or the other. Currently, only *savedir* / | ||||
|    *restdir* mode (i.e. directories, not block-devices) are supported. | ||||
|  | ||||
| # 1.2.0 (2021-11-16) | ||||
|  | ||||
| This release contains contributions from (alphabetically by first name): | ||||
|  - Anke Boersma | ||||
|  - Otus9051 | ||||
|  | ||||
| Changes and new modules in this release: | ||||
|  - *refind* is a new module that installs the rEFInd bootloader. It can | ||||
|    be used instead of the *bootloader* module from core Calamares. (Thanks Anke) | ||||
|  - *unpackfsc* is a new module that uses `unsquashfs` directly. This may | ||||
|    be faster or more convenient than the *unpackfs* module from core Calamares. | ||||
|    The configuration file supports only one entry, but is otherwise easy to | ||||
|    adapt from an existing `unpackfs.conf`. | ||||
|  | ||||
|  | ||||
| # 1.1.2 (2021-05-14) | ||||
|  | ||||
| This release contains contributions from (alphabetically by first name): | ||||
|  - Oliver Smith | ||||
|  | ||||
| Changes and new modules in this release: | ||||
|  - New *os-* modules are intended for OS-specific work. They don't | ||||
|    do anything concrete yet, though. | ||||
|  - The *mobile* module has new features thanks to Oliver, with | ||||
|    keyboard selection (numeric / alpha) for PIN / password entry among them. | ||||
|  | ||||
|  | ||||
| # 1.1.1 (2021-02-23) | ||||
|  | ||||
| This release contains contributions from (alphabetically by first name): | ||||
|  - Oliver Smith | ||||
|  - Undef | ||||
|  | ||||
| Changes and new modules in this release: | ||||
|  - Branding has a new example, *image-slideshow*, for a QML-based | ||||
|    slideshow with only images. | ||||
|  - CI now builds the extensions against a recent Calamares build. | ||||
|  - *mobile* add ability to select target filesystem. | ||||
|  - *mobile* rename `cmdMkfsRoot` to `cmdMkfsRootExt4`. | ||||
|  - *mobile* wait screen has been re-worded. | ||||
|  | ||||
|  | ||||
| # 1.1.0 (2021-01-04) | ||||
|  | ||||
| This release contains contributions from (alphabetically by first name): | ||||
|  - Oliver Smith | ||||
|  | ||||
| Changes and new modules in this release: | ||||
|  - *mobile* module bugfixes | ||||
|  - *mobile* module SSH daemon can be disabled | ||||
|  | ||||
|  | ||||
| # 1.0.0 (2020-12-05) | ||||
|  | ||||
| This release contains contributions from (alphabetically by first name): | ||||
|  - Oliver Smith | ||||
|  - ShalokShalom | ||||
|  | ||||
| Initial release of Calamares-Extensions as such, with one new module | ||||
|  - *mobile*, for PostmarketOS initial configuration | ||||
|  | ||||
							
								
								
									
										110
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						| @@ -1,20 +1,15 @@ | ||||
| # === This file is part of Calamares - <https://github.com/calamares> === | ||||
| # | ||||
| #   Calamares is free software: you can redistribute it and/or modify | ||||
| #   it under the terms of the GNU General Public License as published by | ||||
| #   the Free Software Foundation, either version 3 of the License, or | ||||
| #   (at your option) any later version. | ||||
| #   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: GPL-3.0-or-later | ||||
| # | ||||
| #   Calamares is distributed in the hope that it will be useful, | ||||
| #   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| #   GNU General Public License for more details. | ||||
| ### | ||||
| # | ||||
| #   You should have received a copy of the GNU General Public License | ||||
| #   along with Calamares. If not, see <http://www.gnu.org/licenses/>. | ||||
| #   Calamares-Examples is Free Software: see the License-Identifier above. | ||||
| # | ||||
| #   SPDX-License-Identifier: GPL-3.0+ | ||||
| #   License-Filename: LICENSE | ||||
| #   Individual files may have different licenses (like the CMake | ||||
| #   infrastructure, which is BSD-2-Clause licensed). Check the SPDX | ||||
| #   identifiers in each file. | ||||
| # | ||||
| ### | ||||
| # | ||||
| @@ -24,15 +19,73 @@ | ||||
| # distro can use an unmodified (upstream) Calamares package and a local | ||||
| # customisation package in tandem. | ||||
| # | ||||
| # Besides being an example repository, it is also a collection of modules | ||||
| # and branding that is usable in its own right. | ||||
| # | ||||
| ### CONFIGURING | ||||
| # | ||||
| # By default, all the branding examples and all the modules are built. | ||||
| # This can be influenced through: | ||||
| #   SKIP_MODULES    : a space or semicolon-separated list of directory names | ||||
| #                     under src/modules that should not be built. | ||||
| #   USE_*           : fills in SKIP_MODULES for modules called *-<something> | ||||
| # In this repository, there is just one "group" to which USE_* applies: | ||||
| #   USE_os          : operating-system-specific modules. | ||||
| # | ||||
| ### NOTES | ||||
| # | ||||
| # Call this CMake file in script mode, e.g. `cmake -P CMakeLists.txt` | ||||
| # to print out version information. Use `cmake -DVERSION_STYLE=short` | ||||
| # to get just the short versioning. | ||||
| # | ||||
| cmake_minimum_required(VERSION 3.3 FATAL_ERROR) | ||||
|  | ||||
| set( CALAMARES_EXTENSIONS_VERSION 1.2.1 ) | ||||
|  | ||||
| include( ${CMAKE_CURRENT_LIST_DIR}/CMakeModules/ExtendedVersion.cmake ) | ||||
| if ( CMAKE_SCRIPT_MODE_FILE ) | ||||
|     report_version( ${CALAMARES_EXTENSIONS_VERSION} ${CMAKE_CURRENT_LIST_DIR} ) | ||||
|     return() | ||||
| endif() | ||||
|  | ||||
| project(calamares-extensions | ||||
|     VERSION 1.0.0 | ||||
|     VERSION ${CALAMARES_EXTENSIONS_VERSION} | ||||
|     LANGUAGES CXX | ||||
| ) | ||||
|  | ||||
| find_package(Calamares 3.2.26 REQUIRED) | ||||
| set( CMAKE_CXX_STANDARD 17 ) | ||||
| set( CMAKE_CXX_STANDARD_REQUIRED ON ) | ||||
|  | ||||
| # On developer's machine, the user package registry breaks | ||||
| # consumers by loading the developer's config from a build | ||||
| # directory (which doesn't have the rest of the config | ||||
| # installed inside it). | ||||
| set( CALAMARES_VERSION_REQUIRED 3.2.46 ) | ||||
| find_package(Calamares ${CALAMARES_VERSION_REQUIRED} NO_CMAKE_PACKAGE_REGISTRY) | ||||
| if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui) | ||||
|     find_package(Calamares ${CALAMARES_VERSION_REQUIRED} REQUIRED) | ||||
| endif() | ||||
|  | ||||
| ### CMAKE SETUP | ||||
| # | ||||
| # Enable IN_LIST | ||||
| if( POLICY CMP0057 ) | ||||
|     cmake_policy( SET CMP0057 NEW ) | ||||
| endif() | ||||
| # Let ``AUTOMOC`` and ``AUTOUIC`` process ``GENERATED`` files. | ||||
| if( POLICY CMP0071 ) | ||||
|     cmake_policy( SET CMP0071 NEW ) | ||||
| endif() | ||||
| # Recognize more macros to trigger automoc | ||||
| if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.10.0") | ||||
|     list(APPEND CMAKE_AUTOMOC_MACRO_NAMES | ||||
|         "K_PLUGIN_FACTORY_WITH_JSON" | ||||
|         "K_EXPORT_PLASMA_DATAENGINE_WITH_JSON" | ||||
|         "K_EXPORT_PLASMA_RUNNER" | ||||
|     ) | ||||
| endif() | ||||
| include( CTest ) | ||||
|  | ||||
| find_package(YAMLCPP REQUIRED) | ||||
|  | ||||
| ### BRANDING | ||||
| # | ||||
| @@ -56,25 +109,16 @@ calamares_add_branding_subdirectory( branding/kaos_branding NAME kaos ) | ||||
| # | ||||
| # Add one of more modules, either C++ or Python. | ||||
| # | ||||
| set(SKIPPED_MODULES "") | ||||
| set(LIST_SKIPPED_MODULES "") | ||||
|  | ||||
| calamares_add_module_subdirectory( modules/filekeeper )  # C++ job | ||||
| calamares_add_module_subdirectory( modules/freebsddisk )  # C++ viewmodule | ||||
| calamares_add_module_subdirectory( modules/mobile ) | ||||
| calamares_add_module_subdirectory( modules/slowpython )  # Python job | ||||
| calamares_add_module_subdirectory( modules/freebsddisk LIST_SKIPPED_MODULES )  # C++ viewmodule | ||||
| calamares_add_module_subdirectory( modules/mobile LIST_SKIPPED_MODULES ) | ||||
| calamares_add_module_subdirectory( modules/os-freebsd LIST_SKIPPED_MODULES ) | ||||
| calamares_add_module_subdirectory( modules/os-nixos LIST_SKIPPED_MODULES ) | ||||
| calamares_add_module_subdirectory( modules/refind LIST_SKIPPED_MODULES ) | ||||
| calamares_add_module_subdirectory( modules/slowpython LIST_SKIPPED_MODULES )  # Python job | ||||
| calamares_add_module_subdirectory( modules/unpackfsc LIST_SKIPPED_MODULES ) | ||||
|  | ||||
| # If modules cannot be built, they usually call a macro | ||||
| # which builds a list of explanations; show that list. | ||||
| calamares_explain_skipped_modules( ${SKIPPED_MODULES} ) | ||||
|  | ||||
| set( CALAMARES_VERSION ${calamares-extensions_VERSION_MAJOR}.${calamares-extensions_VERSION_MINOR}.${calamares-extensions_VERSION_PATCH} ) | ||||
| # In rare cases we have hotfix-releases with a tweak | ||||
| if( calamares-extensions_VERSION_TWEAK ) | ||||
|     set( CALAMARES_VERSION "${calamares-extensions_VERSION}.${calamares-extensions_VERSION_TWEAK}" ) | ||||
| endif() | ||||
| set( CALAMARES_VERSION_SHORT "${CALAMARES_VERSION}" ) | ||||
|  | ||||
| add_custom_target(show-version | ||||
|     ${CMAKE_COMMAND} -E echo CALAMARES_VERSION=${CALAMARES_VERSION_SHORT} | ||||
|     USES_TERMINAL | ||||
| ) | ||||
| calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} ) | ||||
|   | ||||
							
								
								
									
										90
									
								
								CMakeModules/ExtendedVersion.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,90 @@ | ||||
| # === This file is part of Calamares - <https://calamares.io> === | ||||
| # | ||||
| #   SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org> | ||||
| #   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: BSD-2-Clause | ||||
| # | ||||
| ### | ||||
| # | ||||
| # This file defines one function for extending a VERSION-like value | ||||
| # with date and git information (if desired). | ||||
| # | ||||
| # - extend_version( version-string short_var long_var ) | ||||
| #   Calling this function will copy *version-string* (which would typically | ||||
| #   be a semver-style string, like "3.2.40") into the variable *short_var*. | ||||
| #   The *version-string* plus date and git information (if git is available), | ||||
| #   is copied into the varialbe *long_var*, in the format {version}-{date}-{hash} | ||||
| # | ||||
| # A helper function that may be used independently: | ||||
| # | ||||
| # - get_git_version_info( out_var ) | ||||
| #   If relevant and possible (e.g. it is a git checkout and git is availablle | ||||
| #   in the environment), put git versioning information in *out_var*. | ||||
| # | ||||
| # A convenience function for use from script-mode for version reporting: | ||||
| # | ||||
| # - report_version( version top_dir ) | ||||
| #   Call this with an intended version string (e.g. "1.1") and | ||||
| #   the top-level source directory (e.g. `${CMAKE_CURRENT_LIST_DIR}` | ||||
| #   or `${CMAKE_SOURCE_DIR}` .. in script mode, the latter is not defined). | ||||
| # | ||||
|  | ||||
| function( get_git_version_info out_var ) | ||||
|     set(CMAKE_VERSION_SOURCE "") | ||||
|     if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD) | ||||
|         find_program(GIT_EXECUTABLE NAMES git git.cmd) | ||||
|         mark_as_advanced(GIT_EXECUTABLE) | ||||
|         if(GIT_EXECUTABLE) | ||||
|             execute_process( | ||||
|                 COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=8 HEAD | ||||
|                 OUTPUT_VARIABLE head | ||||
|                 OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|                 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
|             ) | ||||
|             if(head) | ||||
|                 set(CMAKE_VERSION_SOURCE "${head}") | ||||
|                 execute_process( | ||||
|                     COMMAND ${GIT_EXECUTABLE} update-index -q --refresh | ||||
|                     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
|                 ) | ||||
|                 execute_process( | ||||
|                     COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- | ||||
|                     OUTPUT_VARIABLE dirty | ||||
|                     OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|                     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
|                 ) | ||||
|                 if(dirty) | ||||
|                     set(CMAKE_VERSION_SOURCE "${CMAKE_VERSION_SOURCE}-dirty") | ||||
|                 endif() | ||||
|             endif() | ||||
|         endif() | ||||
|     endif() | ||||
|     set( ${out_var} "${CMAKE_VERSION_SOURCE}" PARENT_SCOPE ) | ||||
| endfunction() | ||||
|  | ||||
| function( extend_version version short_var long_var ) | ||||
|     set( ${short_var} "${version}" PARENT_SCOPE ) | ||||
|  | ||||
|     # Additional info for non-release builds which want "long" version info | ||||
|     # with date and git information (commit, dirty status). | ||||
|     set( _v "${version}" ) | ||||
|     string( TIMESTAMP CALAMARES_VERSION_DATE "%Y%m%d" ) | ||||
|     if( CALAMARES_VERSION_DATE GREATER 0 ) | ||||
|         set( _v ${_v}.${CALAMARES_VERSION_DATE} ) | ||||
|     endif() | ||||
|     get_git_version_info( _gitv ) | ||||
|     if( _gitv ) | ||||
|         set( _v "${_v}-${_gitv}" ) | ||||
|     endif() | ||||
|     set( ${long_var} "${_v}" PARENT_SCOPE ) | ||||
| endfunction() | ||||
|  | ||||
| function( report_version version top_dir ) | ||||
|     set( CMAKE_SOURCE_DIR ${top_dir} ) | ||||
|     extend_version( ${version} _vshort _vlong ) | ||||
|     if ( "x${VERSION_STYLE}" STREQUAL "xshort" ) | ||||
|         message( "${_vshort}" ) | ||||
|     else() | ||||
|         message( "${_vlong}" ) | ||||
|     endif() | ||||
| endfunction() | ||||
							
								
								
									
										40
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | ||||
| <!-- SPDX-FileCopyrightText: no | ||||
|      SPDX-License-Identifier: CC0-1.0 | ||||
| --> | ||||
|  | ||||
| # Contributing to Calamares Extensions | ||||
|  | ||||
| Welcome to Calamares! We're happy that you would like to add | ||||
| something to Calamares -- by extending it! | ||||
| This contribution guide is minimal: | ||||
| all the **technical** parts of contributing to | ||||
| Calamares Extensions are the same as [contributing to Calamares](https://github.com/calamares/calamares/CONTRIBUTING.md). | ||||
|  | ||||
|  | ||||
| ## Code of Conduct | ||||
|  | ||||
| The Calamares community -- of developers, translators, and downstream (distro) users -- | ||||
| aims to be courteous, professional, and inclusive. Harrassment, discriminatory | ||||
| statements and abuse are not tolerated. In general, we apply the | ||||
| [KDE Code of Conduct](https://www.kde.org/code-of-conduct/) and the | ||||
| [GNOME Code of Conduct](https://wiki.gnome.org/Foundation/CodeOfConduct) (the | ||||
| rules of decent behavior in both communities are pretty much the same). | ||||
|  | ||||
| > See the [CoC section on the wiki](https://github.com/calamares/calamares/wiki#code-of-conduct) | ||||
| > for a longer text. To report a problem, please contact the maintainer, | ||||
| > Adriaan de Groot, or the KDE Community Working Group. | ||||
|  | ||||
|  | ||||
| ## Join the Conversation | ||||
|  | ||||
| GitHub Issues are **one** place for discussing Calamares and its extensions if there are concrete | ||||
| problems or a new feature to discuss. | ||||
| Issues are not a help channel. | ||||
| Visit Matrix for help with configuration or compilation. | ||||
|  | ||||
| Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/) | ||||
| room, `#calamares:kde.org`. Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. | ||||
| Matrix is persistent, and we'll see your message eventually. | ||||
|  | ||||
| * [](https://webchat.kde.org/#/room/%23calamares:kde.org) | ||||
							
								
								
									
										24
									
								
								LICENSES/BSD-2-Clause.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,24 @@ | ||||
|  | ||||
|  Copyright 2019 Adriaan de Groot <groot@kde.org> | ||||
|  | ||||
|  Redistribution and use in source and binary forms, with or without | ||||
|  modification, are permitted provided that the following conditions | ||||
|  are met: | ||||
|  | ||||
|    1. Redistributions of source code must retain the above copyright | ||||
|       notice, this list of conditions and the following disclaimer. | ||||
|    2. Redistributions in binary form must reproduce the above copyright | ||||
|       notice, this list of conditions and the following disclaimer in the | ||||
|       documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
|  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
|  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
|  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||
|  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
|  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
|  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
|  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
|  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
|  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
|  POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										119
									
								
								LICENSES/CC0-1.0.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,119 @@ | ||||
| Creative Commons Legal Code | ||||
|  | ||||
| CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES | ||||
| NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE | ||||
| AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION | ||||
| ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE | ||||
| OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS | ||||
| LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION | ||||
| OR WORKS PROVIDED HEREUNDER. | ||||
|  | ||||
| Statement of Purpose | ||||
|  | ||||
| The laws of most jurisdictions throughout the world automatically confer exclusive | ||||
| Copyright and Related Rights (defined below) upon the creator and subsequent | ||||
| owner(s) (each and all, an "owner") of an original work of authorship and/or | ||||
| a database (each, a "Work"). | ||||
|  | ||||
| Certain owners wish to permanently relinquish those rights to a Work for the | ||||
| purpose of contributing to a commons of creative, cultural and scientific | ||||
| works ("Commons") that the public can reliably and without fear of later claims | ||||
| of infringement build upon, modify, incorporate in other works, reuse and | ||||
| redistribute as freely as possible in any form whatsoever and for any purposes, | ||||
| including without limitation commercial purposes. These owners may contribute | ||||
| to the Commons to promote the ideal of a free culture and the further production | ||||
| of creative, cultural and scientific works, or to gain reputation or greater | ||||
| distribution for their Work in part through the use and efforts of others. | ||||
|  | ||||
| For these and/or other purposes and motivations, and without any expectation | ||||
| of additional consideration or compensation, the person associating CC0 with | ||||
| a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright | ||||
| and Related Rights in the Work, voluntarily elects to apply CC0 to the Work | ||||
| and publicly distribute the Work under its terms, with knowledge of his or | ||||
| her Copyright and Related Rights in the Work and the meaning and intended | ||||
| legal effect of CC0 on those rights. | ||||
|  | ||||
| 1. Copyright and Related Rights. A Work made available under CC0 may be protected | ||||
| by copyright and related or neighboring rights ("Copyright and Related Rights"). | ||||
| Copyright and Related Rights include, but are not limited to, the following: | ||||
|  | ||||
| i. the right to reproduce, adapt, distribute, perform, display, communicate, | ||||
| and translate a Work; | ||||
|  | ||||
|       ii. moral rights retained by the original author(s) and/or performer(s); | ||||
|  | ||||
| iii. publicity and privacy rights pertaining to a person's image or likeness | ||||
| depicted in a Work; | ||||
|  | ||||
| iv. rights protecting against unfair competition in regards to a Work, subject | ||||
| to the limitations in paragraph 4(a), below; | ||||
|  | ||||
| v. rights protecting the extraction, dissemination, use and reuse of data | ||||
| in a Work; | ||||
|  | ||||
| vi. database rights (such as those arising under Directive 96/9/EC of the | ||||
| European Parliament and of the Council of 11 March 1996 on the legal protection | ||||
| of databases, and under any national implementation thereof, including any | ||||
| amended or successor version of such directive); and | ||||
|  | ||||
| vii. other similar, equivalent or corresponding rights throughout the world | ||||
| based on applicable law or treaty, and any national implementations thereof. | ||||
|  | ||||
| 2. Waiver. To the greatest extent permitted by, but not in contravention of, | ||||
| applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and | ||||
| unconditionally waives, abandons, and surrenders all of Affirmer's Copyright | ||||
| and Related Rights and associated claims and causes of action, whether now | ||||
| known or unknown (including existing as well as future claims and causes of | ||||
| action), in the Work (i) in all territories worldwide, (ii) for the maximum | ||||
| duration provided by applicable law or treaty (including future time extensions), | ||||
| (iii) in any current or future medium and for any number of copies, and (iv) | ||||
| for any purpose whatsoever, including without limitation commercial, advertising | ||||
| or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the | ||||
| benefit of each member of the public at large and to the detriment of Affirmer's | ||||
| heirs and successors, fully intending that such Waiver shall not be subject | ||||
| to revocation, rescission, cancellation, termination, or any other legal or | ||||
| equitable action to disrupt the quiet enjoyment of the Work by the public | ||||
| as contemplated by Affirmer's express Statement of Purpose. | ||||
|  | ||||
| 3. Public License Fallback. Should any part of the Waiver for any reason be | ||||
| judged legally invalid or ineffective under applicable law, then the Waiver | ||||
| shall be preserved to the maximum extent permitted taking into account Affirmer's | ||||
| express Statement of Purpose. In addition, to the extent the Waiver is so | ||||
| judged Affirmer hereby grants to each affected person a royalty-free, non | ||||
| transferable, non sublicensable, non exclusive, irrevocable and unconditional | ||||
| license to exercise Affirmer's Copyright and Related Rights in the Work (i) | ||||
| in all territories worldwide, (ii) for the maximum duration provided by applicable | ||||
| law or treaty (including future time extensions), (iii) in any current or | ||||
| future medium and for any number of copies, and (iv) for any purpose whatsoever, | ||||
| including without limitation commercial, advertising or promotional purposes | ||||
| (the "License"). The License shall be deemed effective as of the date CC0 | ||||
| was applied by Affirmer to the Work. Should any part of the License for any | ||||
| reason be judged legally invalid or ineffective under applicable law, such | ||||
| partial invalidity or ineffectiveness shall not invalidate the remainder of | ||||
| the License, and in such case Affirmer hereby affirms that he or she will | ||||
| not (i) exercise any of his or her remaining Copyright and Related Rights | ||||
| in the Work or (ii) assert any associated claims and causes of action with | ||||
| respect to the Work, in either case contrary to Affirmer's express Statement | ||||
| of Purpose. | ||||
|  | ||||
|    4. Limitations and Disclaimers. | ||||
|  | ||||
| a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, | ||||
| licensed or otherwise affected by this document. | ||||
|  | ||||
| b. Affirmer offers the Work as-is and makes no representations or warranties | ||||
| of any kind concerning the Work, express, implied, statutory or otherwise, | ||||
| including without limitation warranties of title, merchantability, fitness | ||||
| for a particular purpose, non infringement, or the absence of latent or other | ||||
| defects, accuracy, or the present or absence of errors, whether or not discoverable, | ||||
| all to the greatest extent permissible under applicable law. | ||||
|  | ||||
| c. Affirmer disclaims responsibility for clearing rights of other persons | ||||
| that may apply to the Work or any use thereof, including without limitation | ||||
| any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims | ||||
| responsibility for obtaining any necessary consents, permissions or other | ||||
| rights required for any use of the Work. | ||||
|  | ||||
| d. Affirmer understands and acknowledges that Creative Commons is not a party | ||||
| to this document and has no duty or obligation with respect to this CC0 or | ||||
| use of the Work. | ||||
							
								
								
									
										84
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,10 +1,15 @@ | ||||
| <!-- SPDX-FileCopyrightText: no | ||||
|      SPDX-License-Identifier: CC0-1.0 | ||||
| --> | ||||
|  | ||||
| # Calamares Branding and Module Examples | ||||
|  | ||||
| > A *branding component* in Calamares is a description of the | ||||
| > produce (i.e. distribution) being installed along with a "slideshow"  | ||||
| > product (i.e. distribution) being installed along with a "slideshow" | ||||
| > that is displayed during the installation phase of Calamares. | ||||
| > This shapes the **look** of your installation. | ||||
| > | ||||
| > A *module* adds functionality to Calamares; modules may be written | ||||
| > A *module* adds **functionality** to Calamares; modules may be written | ||||
| > in C++ or Python, using Qt Widgets or QML for the UI (with C++) | ||||
| > if there is one. Both C++ and Python allow a full control over the | ||||
| > target system during the installation. | ||||
| @@ -13,11 +18,7 @@ This repository contains complete examples of branding and some | ||||
| modules for Calamares. | ||||
|  | ||||
| - [Branding](#branding) documentation | ||||
|   - [default](branding/default/branding.desc) branding example | ||||
|   - [fancy](branding/fancy/branding.desc) branding example | ||||
|   - [KaOS](branding/kaos_branding/branding.desc) branding example | ||||
|   - [SameGame](branding/samegame/branding.desc) branding example | ||||
| - [Module](#module) documentation | ||||
| - [Module](#modules) documentation | ||||
|  | ||||
| ## Branding | ||||
|  | ||||
| @@ -28,11 +29,23 @@ can be used for testing. The examples here show what can be done | ||||
| with QML in the context of Calamares branding, and provide examples | ||||
| and documentation for the framework that Calamares ships with. | ||||
|  | ||||
|  - `default/` is a copy of the default branding included with Calamares. | ||||
|  - `fancy/` has navigation buttons and a slide counter. | ||||
|  - `kaos_branding/` is a copy of the KaOS branding component, which | ||||
|    has translations and a bunch of fancy graphics. | ||||
|  - `samegame/` is a copy of the Qt Company "Same Game" QML demo. It | ||||
|  - [`default/`](branding/default/branding.desc) | ||||
|    is a copy of the default branding included with Calamares. | ||||
|  - [`fancy/`](branding/fancy/branding.desc) | ||||
|    has navigation buttons and a slide counter. | ||||
|  - [`image-slideshow/`](branding/image-slideshow/branding.desc) | ||||
|    is a variant of the *default* branding that implements its | ||||
|    own slide element for QML that supports a single image. | ||||
|    This is useful for straightforward images-only slideshows | ||||
|    (probably moreso than the default slideshow). | ||||
|  - [`kaos_branding/`](branding/kaos_branding/branding.desc) | ||||
|    is a copy of the KaOS branding component, which | ||||
|    has translations and a bunch of fancy graphics for the | ||||
|    slideshow. Plus it includes examples of using different | ||||
|    QML options for a vertical navigation bar and horizontal | ||||
|    sidebar. | ||||
|  - [`samegame/` ](branding/default/branding.desc) | ||||
|    is a copy of the Qt Company "Same Game" QML demo. It | ||||
|    shows that **any** QML can be used for branding purposes. | ||||
|  | ||||
| ### Writing your own Branding | ||||
| @@ -108,8 +121,11 @@ one of two "API styles". | ||||
|  | ||||
| - Version 1 is loaded when the slideshow starts. If the slideshow is | ||||
|   large, or contains remote content, then this may be slow. | ||||
|   The loading time may be visible as a "white flash" as the | ||||
|   QML component is displayed with no background until the | ||||
|   slideshow is loaded. | ||||
| - Version 2 is loaded asynchronously from the moment Calamares is | ||||
|   started. This may delay startup a little, but may appear more | ||||
|   started. This may delay startup a little, but appears more | ||||
|   responsive overall. | ||||
|  | ||||
| If the slideshow QML defines functions | ||||
| @@ -122,7 +138,18 @@ In addition, if the slideshow QML defines a property | ||||
| `activatedInCalamares` then it is set to `true` | ||||
| when the slideshow becomes visible, and to `false` when | ||||
| the installation is finished. This can also be used to | ||||
| start timers, etc. | ||||
| start timers, etc. The standard `Presentation.qml` included with | ||||
| Calamares has such a property. | ||||
|  | ||||
| A slideshow (`show.qml`) can be entirely independent, with bespoke code, | ||||
| or it can make use of files shipped as part of Calamares: a *Presentation* and | ||||
| a *Slide* element (and some others). There are also Calamares internals which | ||||
| can be used from QML: | ||||
| - `import calamares.slideshow 1.0` for the standard QML slideshow (e.g. *Presentation* element; | ||||
|   use *Slide* with this or write an API-equivalent element such as the one in `image-slideshow/`). | ||||
| - `import io.calamares.ui 1.0` for a *Branding* object which has an API to | ||||
|   get colors and strings that are used elsewhere in Calamares (e.g. to make the | ||||
|   slide background the same as the background defined in `branding.desc`). | ||||
|  | ||||
|  | ||||
| ## Modules | ||||
| @@ -135,6 +162,8 @@ listed in the *show* phase, and may run jobs if listed in the | ||||
| *exec*  phase) and a Python job module (no UI, runs in the *exec* | ||||
| phase). | ||||
|  | ||||
| ### Example Modules | ||||
|  | ||||
| - [filekeeper](modules/filekeeper/CMakeLists.txt) is a C++ **job** module | ||||
|   to copy files from the host (live) system to the target system at | ||||
|   the end of installation, like logfiles. (This module is made obsolete | ||||
| @@ -146,6 +175,18 @@ phase). | ||||
|   module that just serves to slow down an installation by delaying | ||||
|   a configurable (default 30 seconds) amount of time. | ||||
|  | ||||
| ### Functional Modules | ||||
|  | ||||
| - [mobile](modules/mobile/CMakeLists.txt) is a QML **view** that | ||||
|   takes over a number of other view steps. It is specific to | ||||
|   mobile phone use, and as of writing used by | ||||
|   [postmarketOS](https://postmarketos.org) and | ||||
|   [Mobian](https://mobian-project.org/).  Among other things, it | ||||
|   allows to set up full disk encryption and to configure the | ||||
|   default user's password.  Read the | ||||
|   [on-device installer](https://wiki.postmarketos.org/wiki/On-device_installer) | ||||
|   article for more information. | ||||
|  | ||||
| ### CMake Preparation | ||||
|  | ||||
| The single macro `calamares_add_module_subdirectory()` | ||||
| @@ -173,3 +214,18 @@ usually called `main.py` which defines a `run()` function. | ||||
|  | ||||
| The API is loosely documented in the | ||||
| [developer guide](https://github.com/calamares/calamares/wiki/Develop-Guide). | ||||
|  | ||||
| # Join the Conversation | ||||
|  | ||||
| GitHub Issues are **one** place for discussing Calamares (and Calamares Extensions) | ||||
| if there are concrete | ||||
| problems or a new feature to discuss. | ||||
| Issues are not a help channel. | ||||
| Visit Matrix for help with configuration or compilation. | ||||
|  | ||||
| Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/) | ||||
| room, `#calamares:kde.org`. Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. | ||||
| Matrix is persistent, and we'll see your message eventually. | ||||
|  | ||||
| * [](https://webchat.kde.org/#/room/%23calamares:kde.org) | ||||
|   | ||||
							
								
								
									
										64
									
								
								branding/image-slideshow/ImageSlide.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,64 @@ | ||||
| /* === This file is part of Calamares Extensions - <http://github.com/calamares-extensions> === | ||||
|  * | ||||
|  * SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
|  | ||||
| /* An *ImageSlide* is a *Slide* (it offers the API that *Presentation* | ||||
|  * expects) while displaying only a single image. This is useful | ||||
|  * for presentations that are all images, with no interaction or text. | ||||
|  */ | ||||
|  | ||||
| import QtQuick 2.5 | ||||
|  | ||||
| /* To use an *ImageSlide*, instantiate it inside your *Presentation* | ||||
|  * and set the *src* property to a path to an image file in a supported | ||||
|  * format. Relative paths are ok. | ||||
|  */ | ||||
| Item { | ||||
|     id: imageslide | ||||
|  | ||||
|     /* Slides should be non-visible at the start; the *Presentation* | ||||
|      * handles visibility (so that one slide at a time is visible). | ||||
|      */ | ||||
|     visible: false | ||||
|     /* Make this item fill up the parent, so that alignment of the | ||||
|      * image (below) works out to "middle of the parent". | ||||
|      */ | ||||
|     anchors.fill: parent | ||||
|  | ||||
|     /* The *Presentation* manages visibility of children that have | ||||
|      * attribute *isSlide* and *isSlide* is set to *true*. Other | ||||
|      * children are ignored, so we need to set this so that the | ||||
|      * *ImageSlide* elements are treated like slides. | ||||
|      */ | ||||
|     property bool isSlide: true; | ||||
|     /* The *Presentation* allows slides to have notes, so just leave | ||||
|      * an empty string here. | ||||
|      */ | ||||
|     property string notes; | ||||
|  | ||||
|  | ||||
|     /* This is the important property for *ImageSlide*: the path to the | ||||
|      * image to display. When instantiating *ImageSlide*, set this for | ||||
|      * each instance. Relative paths are ok. | ||||
|      */ | ||||
|     property string src; | ||||
|  | ||||
|     /* The image itself. It has fixed sizes (300x150px). You could set | ||||
|      * an aspect ratio here (e.g. `height: width / 2`) as well. | ||||
|      * | ||||
|      * This binds the image source (filename) to the string *src* | ||||
|      * in the *ImageSlide* element, for convenience in setting things | ||||
|      * up in the overall slideshow. If you want to make width and | ||||
|      * height configurable, add a property above and then bind to | ||||
|      * them from the Image element. | ||||
|      */ | ||||
|     Image { | ||||
|         id: image | ||||
|         source: src | ||||
|         width: 300 | ||||
|         height: 150 | ||||
|         anchors.centerIn: parent | ||||
|     } | ||||
| } | ||||
							
								
								
									
										40
									
								
								branding/image-slideshow/branding.desc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | ||||
| # SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
| # SPDX-License-Identifier: BSD-2-Clause | ||||
| --- | ||||
| componentName:  default | ||||
| # image-slideshow | ||||
|  | ||||
| # Branding must define some strings for the welcome page, | ||||
| # even though this example is about the slideshow, not the rest. | ||||
| strings: | ||||
|     productName:         Mirror Linux | ||||
|     shortProductName:    Mirror | ||||
|     version: | ||||
|     shortVersion: | ||||
|     versionedName:       Mirror Linux 1.0 | ||||
|     shortVersionedName:  Mirror 1.0 | ||||
|     bootloaderEntryName: Mirror | ||||
|  | ||||
| # These images do not exist in this branding example. | ||||
| images: | ||||
|     productLogo:         "logo.png" | ||||
|     productIcon:         "logo.png" | ||||
|     productWelcome:      "languages.png" | ||||
|  | ||||
| # Dark-mode for Calamares. The slideshow can access these color values | ||||
| # through the Branding object which is always available to QML inside Calamares. | ||||
| style: | ||||
|    sidebarBackground:    "#36393e" | ||||
|    sidebarText:          "#efefef" | ||||
|    sidebarTextSelect:    "#2eb69b" | ||||
|    sidebarTextHighlight: "#313338" | ||||
|  | ||||
| # The actual slideshow. API version 2 means that the QML is loaded at | ||||
| # startup. This is **slightly** slower at startup, but means that by | ||||
| # the time we reach the slideshow, it is loaded and ready-to-go. | ||||
| # | ||||
| # A v2 slideshow **may** have an onActivate() and onLeave() function, | ||||
| # although Calamares will complain if it does not. | ||||
| slideshow:               "show.qml" | ||||
| slideshowAPI:            2 | ||||
|  | ||||
							
								
								
									
										103
									
								
								branding/image-slideshow/show.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,103 @@ | ||||
| /* === This file is part of Calamares Extensions - <http://github.com/calamares-extensions> === | ||||
|  * | ||||
|  * SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
|  | ||||
| /* This is a simple slideshow for use during the *exec* phase of | ||||
|  * installation, that displays a handful of slides. It uses | ||||
|  * the *Presentation* QML components -- this allows, for instance, | ||||
|  * notes to be added to slides, and for arrow navigation to be | ||||
|  * used. But at its core it's just a bunch of images, repeating. | ||||
|  * | ||||
|  * For this kind of limited functionality, it may be better to | ||||
|  * use the "plain images" slideshow format in Calamares, although | ||||
|  * then you don't have any say in how things are animated. | ||||
|  * | ||||
|  * This slideshow is written for *slideshowAPI* version 1, so in | ||||
|  * `branding.desc` set that appropriately. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| import QtQuick 2.0  // Basic QML | ||||
| import calamares.slideshow 1.0  // Calamares slideshow: Presentation | ||||
| import io.calamares.ui 1.0  // Calamares internals: Branding | ||||
|  | ||||
| /* *Presentation* comes from the pre-installed calamares.slideshow | ||||
|  * that comes with Calamares itself. See `Presentation.qml` in the | ||||
|  * Calamares repository for details and documentation. | ||||
|  * | ||||
|  * The important parts of presentation are: | ||||
|  *  - it has a property *activatedInCalamares* which is set to *true* | ||||
|  *    when the slideshow becomes visible, *false* afterwards. | ||||
|  *  - it expects one or more children with a property *isSlide* | ||||
|  *    set to *true*. | ||||
|  *  - it has a function *goToNextSlide()* to do just that (where | ||||
|  *    "slides" is the sequence of children that have property | ||||
|  *    *isSlide* set to *true*. | ||||
|  * | ||||
|  */ | ||||
| Presentation | ||||
| { | ||||
|     id: presentation | ||||
|  | ||||
|     /* This timer ticks once per second (1000ms, set in *interval*) | ||||
|      * and calls *goToNextSlide()* each time. Note that it needs | ||||
|      * to know the *id* of the presentation, so keep *id* (above) | ||||
|      * matched with the function call. | ||||
|      * | ||||
|      * The timer starts when the presentation is activated; you could | ||||
|      * also set *running* to true, but that might cost extra resources. | ||||
|      */ | ||||
|     Timer { | ||||
|         interval: 1000 | ||||
|         running: presentation.activatedInCalamares | ||||
|         repeat: true | ||||
|         onTriggered: presentation.goToNextSlide() | ||||
|     } | ||||
|  | ||||
|     /* These functions are called when the presentation starts and | ||||
|      * ends, respectively. They could be used to start the timer, | ||||
|      * but that is done automatically through *activatedInCalamares*, | ||||
|      * so there's nothing **to** do. | ||||
|      * | ||||
|      * Leaving these functions out is fine, although Calamares will | ||||
|      * complain that they are missing, then. | ||||
|      */ | ||||
|     function onActivate() { } | ||||
|     function onLeave() { } | ||||
|  | ||||
|  | ||||
|     /* A presentation is an Item: it has no visual appearance at all. | ||||
|      * Give it a background, which fills the whole area of the presentation. | ||||
|      * Setting *z* to a low value places this rectangle **behind** other | ||||
|      * things in the presentation -- which is correct for a background. | ||||
|      * | ||||
|      * This uses the background set in the styles section of `branding.desc`. | ||||
|      */ | ||||
|     Rectangle { | ||||
|         id: mybackground | ||||
|         anchors.fill: parent | ||||
|         color: Branding.styleString(Branding.SidebarBackground) | ||||
|         z: -1 | ||||
|     } | ||||
|  | ||||
|     /* The *ImageSlide* is a component unique to this branding directory. | ||||
|      * The QML file `ImageSlide.qml` can be stored alongside `show.qml` | ||||
|      * and it will be loaded on-demand. See the documentation in that | ||||
|      * file for details, but it comes down to this: for each *ImageSlide*, | ||||
|      * set *src* to a suitable value (an image path in this directory) | ||||
|      * and that will be displayed. | ||||
|      */ | ||||
|     ImageSlide { | ||||
|         src: "slide1.png" | ||||
|     } | ||||
|  | ||||
|     ImageSlide { | ||||
|         src: "slide2.png" | ||||
|     } | ||||
|  | ||||
|     ImageSlide { | ||||
|         src: "slide3.png" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								branding/image-slideshow/slide1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								branding/image-slideshow/slide2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 31 KiB | 
							
								
								
									
										
											BIN
										
									
								
								branding/image-slideshow/slide3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 31 KiB | 
							
								
								
									
										101
									
								
								branding/kaos_branding/about.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,101 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2020 2022 Anke Boersma <demm@kaosx.us> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.7 | ||||
| import QtQuick.Controls 2.0 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import QtQuick.Window 2.3 | ||||
|  | ||||
| ApplicationWindow { | ||||
|     id: about | ||||
|     visible: true | ||||
|     width: 760 | ||||
|     height: 400 | ||||
|     title: qsTr("About Calamares") | ||||
|  | ||||
|     property var appName: "Calamares" | ||||
|     property var appVersion: "3.3 RC" | ||||
|  | ||||
|     Rectangle { | ||||
|         id: textArea | ||||
|         anchors.fill: parent | ||||
|         color: "#f2f2f2" | ||||
|  | ||||
|         Column { | ||||
|             id: column | ||||
|             anchors.centerIn: parent | ||||
|  | ||||
|  | ||||
|             Rectangle { | ||||
|                 width: 560 | ||||
|                 height: 250 | ||||
|                 radius: 10 | ||||
|                 border.width: 0 | ||||
|  | ||||
|                 Text { | ||||
|                     width: 400 | ||||
|                     height: 250 | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("<h1>%1</h1><br/> | ||||
|                         <strong>%2<br/> | ||||
|                         for %3</strong><br/><br/> | ||||
|                         Copyright 2014-2017 Teo Mrnjavac <teo@kde.org><br/> | ||||
|                         Copyright 2017-2022 Adriaan de Groot <groot@kde.org><br/> | ||||
|                         Thanks to <a href='https://calamares.io/team/'>the Calamares team</a> | ||||
|                         and the <a href=\"https://www.transifex.com/kaos/kaos/\">KaOS | ||||
|                         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." ) | ||||
|                         .arg(appName) | ||||
|                         .arg(appVersion) | ||||
|                         .arg(Branding.string(Branding.VersionedName)) | ||||
|  | ||||
|                         onLinkActivated: Qt.openUrlExternally(link) | ||||
|  | ||||
|                         MouseArea { | ||||
|                             anchors.fill: parent | ||||
|                             acceptedButtons: Qt.NoButton | ||||
|                             cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor | ||||
|                         } | ||||
|  | ||||
|                     font.pointSize: 10 | ||||
|                     anchors.verticalCenterOffset: 10 | ||||
|                     anchors.horizontalCenterOffset: 40 | ||||
|                     wrapMode: Text.WordWrap | ||||
|                 } | ||||
|  | ||||
|                 Image { | ||||
|                     id: image | ||||
|                     x: 8 | ||||
|                     y: 12 | ||||
|                     height: 100 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     source: "squid.png" | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         Button { | ||||
|             anchors.horizontalCenter: parent.horizontalCenter | ||||
|             anchors.bottom: parent.bottom | ||||
|             icon.name: "window-close" | ||||
|             text: qsTr("Close") | ||||
|             hoverEnabled: true | ||||
|             onClicked: about.close(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,22 +1,32 @@ | ||||
| --- | ||||
| componentName:  kaos | ||||
|  | ||||
| welcomeStyleCalamares:   false | ||||
|  | ||||
| # Should the welcome image (productWelcome, below) be scaled | ||||
| # up beyond its natural size? | ||||
| welcomeExpandingLogo:   true | ||||
|  | ||||
| windowExpanding:    normal | ||||
| windowSize: 920px,630px | ||||
| windowPlacement: center | ||||
|  | ||||
| sidebar: qml,bottom | ||||
| navigation: qml,right | ||||
|  | ||||
| strings: | ||||
|     productName:         KaOS | ||||
|     shortProductName:    KaOS | ||||
|     version:             2018.03 | ||||
|     version:             2022.08 | ||||
|     shortVersion:        KaOS | ||||
|     versionedName:       KaOS 2018.03 | ||||
|     versionedName:       KaOS 2022.08 | ||||
|     shortVersionedName:  KaOS 2018.03 | ||||
|     bootloaderEntryName: KaOS | ||||
|     productUrl:          https://kaosx.us/ | ||||
|     supportUrl:          https://kaosx.us/docs/ | ||||
|     knownIssuesUrl:      https://kaosx.us/pages/download/#known-issues | ||||
|     releaseNotesUrl:     https://kaosx.us/pages/release_notes | ||||
|     donateUrl:           https://kaosx.us/about/donors | ||||
|  | ||||
| images: | ||||
|     productLogo:         "kaos.png" | ||||
| @@ -27,6 +37,7 @@ slideshow:               "show.qml" | ||||
| slideshowAPI:            1 | ||||
|  | ||||
| style: | ||||
|    sidebarBackground:    "#bdc3c7" | ||||
|    sidebarText:          "#1F1F1F" | ||||
|    sidebarTextSelect:    "#3498DB" | ||||
|    SidebarBackground:    "#bdc3c7" | ||||
|    SidebarText:          "#1F1F1F" | ||||
|    SidebarTextCurrent:    "#3498DB" | ||||
|    SidebarBackgroundCurrent: "#eff0f1" | ||||
|   | ||||
							
								
								
									
										224
									
								
								branding/kaos_branding/calamares-navigation.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,224 @@ | ||||
| /* Sample of QML navigation. | ||||
|  | ||||
|    SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org> | ||||
|    SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us> | ||||
|    SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
|  | ||||
|    This navigation panel is for a "vertical" layout, with | ||||
|    mouse areas for next and previous and it includes the logo | ||||
|    plus About & Debug buttons. | ||||
| */ | ||||
| import io.calamares.ui 1.0 | ||||
| import io.calamares.core 1.0 | ||||
|  | ||||
| import QtQuick 2.3 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
|  | ||||
| Rectangle { | ||||
|     id: navigationBar; | ||||
|     color: Branding.styleString( Branding.SidebarBackground ); | ||||
|     height: parent.height; | ||||
|     width:64; | ||||
|  | ||||
|     ColumnLayout { | ||||
|         id: buttonBar | ||||
|         anchors.fill: parent; | ||||
|         spacing: 1 | ||||
|  | ||||
|         Image { | ||||
|             Layout.topMargin: 1; | ||||
|             Layout.bottomMargin:parent.height / 7; | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignTop | ||||
|             id: logo; | ||||
|             width: 62; | ||||
|             height: width;  // square | ||||
|             source: "file:/" + Branding.imagePath(Branding.ProductLogo); | ||||
|             sourceSize.width: width; | ||||
|             sourceSize.height: height; | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: backArea | ||||
|             Layout.fillWidth: true; | ||||
|             Layout.preferredHeight: parent.height / 7; | ||||
|             color: mouseBack.containsMouse ? "#e6e9ea" : "#d9dcde"; | ||||
|             enabled: ViewManager.backEnabled; | ||||
|             visible: ViewManager.backAndNextVisible; | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseBack | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|  | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Back") | ||||
|                     color: Branding.styleString( !backArea.enabled ? Branding.SidebarBackground : (mouseBack.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "pan-start-symbolic.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 32 | ||||
|                     opacity: backArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.back(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: nextArea | ||||
|             Layout.preferredHeight: parent.height / 7; | ||||
|             Layout.fillWidth: true | ||||
|             color: mouseNext.containsMouse ? "#f4f5f6" : "#e6e9ea"; | ||||
|             enabled: ViewManager.nextEnabled; | ||||
|             visible: ViewManager.backAndNextVisible; | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseNext | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Next") | ||||
|                     color: Branding.styleString( !nextArea.enabled ? Branding.SidebarBackground : (mouseNext.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "pan-end-symbolic.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 32 | ||||
|                     opacity: nextArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.next(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: cancelArea | ||||
|             height: parent.height / 7; | ||||
|             Layout.fillWidth: true | ||||
|             color: mouseCancel.containsMouse ? "#e6e9ea" : "#d9dcde"; | ||||
|  | ||||
|              /* | ||||
|              * The ViewManager has settings -- user-controlled via the | ||||
|              * branding component, and party based on program state -- | ||||
|              * whether the quit button should be enabled and visible. | ||||
|              * | ||||
|              * QML navigation *should* follow this pattern, but can also | ||||
|              * add other qualifications. For instance, you may have a | ||||
|              * "finished" module that handles quit in its own way, and | ||||
|              * want to hide the quit button then. The ViewManager has a | ||||
|              * current step and a total count, so compare them: | ||||
|              * | ||||
|              * visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); | ||||
|              */ | ||||
|  | ||||
|              enabled: ViewManager.quitEnabled; | ||||
|              visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); | ||||
|  | ||||
|             ToolTip { | ||||
|                 width: 59 | ||||
|                 visible: mouseCancel.containsMouse | ||||
|                 timeout: 5000 | ||||
|                 delay: 1000 | ||||
|                 text: ViewManager.quitTooltip; | ||||
|             } | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseCancel | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Cancel") | ||||
|                     color: Branding.styleString( !cancelArea.enabled ? Branding.SidebarBackground : (mouseCancel.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "draw-rectangle.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 9 | ||||
|                     opacity: cancelArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.quit(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Item { | ||||
|             Layout.fillHeight: true; | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: debugArea | ||||
|             Layout.fillWidth: true; | ||||
|             height: 35 | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom | ||||
|             color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground); | ||||
|             visible: debug.enabled | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseAreaDebug | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Debug") | ||||
|                     color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackground ); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: debug.toggle() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: aboutArea | ||||
|             Layout.fillWidth: true; | ||||
|             height: 35 | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom | ||||
|             color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground); | ||||
|             visible: true | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseAreaAbout | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("About") | ||||
|                     ToolTip { | ||||
|                         visible: mouseAreaAbout.containsMouse | ||||
|                         delay: 1000 | ||||
|                         text: qsTr("Info about Calamares") | ||||
|                     } | ||||
|                     color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent ); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|  | ||||
|                 property variant window; | ||||
|                 onClicked: { | ||||
|                     var component = Qt.createComponent("about.qml"); | ||||
|                     window = component.createObject(); | ||||
|                     window.show(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										72
									
								
								branding/kaos_branding/calamares-sidebar.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,72 @@ | ||||
| /* Sample of QML progress tree. | ||||
|  | ||||
|    SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org> | ||||
|    SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us> | ||||
|    SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
|  | ||||
|    The progress tree (actually a list) is "horizontal" in this example, | ||||
|    with the steps going to the right. | ||||
| */ | ||||
| import io.calamares.ui 1.0 | ||||
| import io.calamares.core 1.0 | ||||
|  | ||||
| import QtQuick 2.3 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import QtQuick.Controls 2.15 | ||||
|  | ||||
| Rectangle { | ||||
|     id: sideBar; | ||||
|     color: Branding.styleString( Branding.SidebarBackground ); | ||||
|     height: 48; | ||||
|     width: parent.width | ||||
|  | ||||
|     RowLayout { | ||||
|         anchors.fill: parent; | ||||
|         spacing: 2; | ||||
|  | ||||
|         Item { | ||||
|             Layout.fillHeight: true; | ||||
|         } | ||||
|  | ||||
|         Repeater { | ||||
|             model: ViewManager | ||||
|             Rectangle { | ||||
|                 Layout.leftMargin: 0; | ||||
|                 Layout.fillWidth: true; | ||||
|                 Layout.alignment: Qt.AlignTop; | ||||
|                 height: 42; | ||||
|                 radius: 0; | ||||
|                 color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground ); | ||||
|  | ||||
|                 Text { | ||||
|                     anchors.verticalCenter: parent.verticalCenter; | ||||
|                     anchors.horizontalCenter: parent.horizontalCenter | ||||
|                     x: parent.x + 12; | ||||
|                     color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText ); | ||||
|                     text: display; | ||||
|                     font.pointSize : index == ViewManager.currentStepIndex ? 10 : 9 | ||||
|                 } | ||||
|  | ||||
|                 Rectangle { | ||||
|                     height: 2 | ||||
|                     width: 800 | ||||
|                     anchors.bottom: parent.bottom; | ||||
|                     border.color: Branding.styleString(ViewManager.currentStepIndex === index ? Branding.SidebarTextCurrent : (ViewManager.currentStepIndex >= index ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent)) | ||||
|                     border.width: 3 | ||||
|  | ||||
|                     Image { | ||||
|                         source: "pan-up-symbolic.svg" | ||||
|                         id: image | ||||
|                         anchors.verticalCenter: parent.verticalCenter; | ||||
|                         anchors.verticalCenterOffset : -3 | ||||
|                         x: parent.x + 35; | ||||
|                         fillMode: Image.PreserveAspectFit | ||||
|                         height: 32 | ||||
|                         visible: index == ViewManager.currentStepIndex ? true : false | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								branding/kaos_branding/draw-rectangle.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><path d="m2 1034.36v16h16v-16z" fill="#566060" transform="translate(1-1031.36)"/></svg> | ||||
| After Width: | Height: | Size: 147 B | 
| @@ -1,3 +1,6 @@ | ||||
| #   SPDX-FileCopyrightText: no | ||||
| #   SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| foreach( lang ast ca cs de en es es_AR fr hu id_ID nl_NL pl pt_BR pt_PT ro_RO ru sr_RS tr_TR zh_CN ) | ||||
|    list( APPEND TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/calamares-${COMPONENT_NAME}_${lang}.ts" ) | ||||
| endforeach() | ||||
|   | ||||
| Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 106 KiB | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-end-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-445.0002,-129)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 451.0002,142 5,-5 -5,-5 z" id="path6412" sodipodi:nodetypes="cccc" fill="#555555"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 896 B | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-start-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-425.0002,-129)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 435.0002,142 -5,-5 5,-5 z" id="path6400-8" sodipodi:nodetypes="cccc" fill="#555555"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 898 B | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-up-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-465.0002,-129.00001)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 478.0002,139 -5,-5 -5,5 z" id="path6418" sodipodi:nodetypes="cccc" fill="#3498DB"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 902 B | 
| @@ -1,6 +1,7 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   Copyright 2015, Teo Mrnjavac <teo@kde.org> | ||||
|  *   Copyright 2015-2018, Anke Boersma <demm@kaosx.us> | ||||
|  * | ||||
|  *   Calamares is free software: you can redistribute it and/or modify | ||||
|  *   it under the terms of the GNU General Public License as published by | ||||
| @@ -24,7 +25,6 @@ Presentation | ||||
|     id: presentation | ||||
|  | ||||
|     Timer { | ||||
|         id: advanceTimer | ||||
|         interval: 5000 | ||||
|         running: false | ||||
|         repeat: true | ||||
| @@ -96,8 +96,8 @@ Presentation | ||||
|                 anchors.horizontalCenterOffset: -100 | ||||
|                 font.pixelSize: parent.width *.015 | ||||
|                 color: 'white' | ||||
|                 text: qsTr("The default Office Suite is Calligra.<br/>"+ | ||||
|                     "LibreOffice is available in the repositories. <br/>") | ||||
|                 text: qsTr("The default Office Suite is LibreOffice.<br/>"+ | ||||
|                     "Calligra is available in the repositories. <br/>") | ||||
|                 wrapMode: Text.WordWrap | ||||
|                 width: 450 | ||||
|                 horizontalAlignment: Text.AlignLeft | ||||
| @@ -120,7 +120,7 @@ Presentation | ||||
|                 font.pixelSize: parent.width *.015 | ||||
|                 color: 'white' | ||||
|                 text: qsTr("Qt/KDE specific internet applications include the <br/>"+ | ||||
|                     "Qupzilla web-browser and kde-telepathy for <br/>"+ | ||||
|                     "Falkon web-browser and kde-telepathy for <br/>"+ | ||||
|                     "chat and Instant Messaging. <br/>") | ||||
|                 wrapMode: Text.WordWrap | ||||
|                 width: 450 | ||||
| @@ -172,6 +172,4 @@ Presentation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Component.onCompleted: advanceTimer.running = true | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| # NOTE: this is largely a copy of the release script for Calamares, | ||||
| #       with not-applicable parts (such as translation-freeze) either | ||||
| #       commented-out, or skipped with if(false). | ||||
| # NOTE: this script contains Linuxisms (in particular, expects GNU mktemp(1)) | ||||
| # | ||||
| # This attempts to perform the different steps of the RELEASE.md | ||||
| # document automatically. It's not tested on other machines or | ||||
| @@ -31,6 +32,7 @@ | ||||
| #   * `-B` do not build (before tagging) | ||||
| #   * `-P` do not package (tag, sign, tarball) | ||||
| #   * `-T` do not respect string freeze | ||||
| #   * `-C <args>` set extra arguments to pass to CMake | ||||
| # | ||||
| # The build / package settings can be influenced via environment variables: | ||||
| #   * BUILD_DEFAULT set to `false` to avoid first build with gcc | ||||
| @@ -138,24 +140,28 @@ fi | ||||
| ### Get version number for this release | ||||
| # | ||||
| # | ||||
| V=$( cd "$BUILDDIR" && make show-version | grep ^CALAMARES_VERSION | sed s/^[A-Z_]*=// ) | ||||
| V=$( cmake -DVERSION_STYLE=short -P CMakeLists.txt 2>&1 ) | ||||
| test -n "$V" || { echo "Could not obtain version in $BUILDDIR ." ; exit 1 ; } | ||||
|  | ||||
| ### Create signed tag | ||||
| # | ||||
| # This is the signing key ID associated with the GitHub account adriaandegroot, | ||||
| # which is used to create all "verified" tags in the Calamares repo. | ||||
| # | ||||
| KEY_ID="CFDDC96F12B1915C" | ||||
| git tag -u "$KEY_ID" -m "Release v$V" "v$V" || { echo "Could not sign tag v$V." ; exit 1 ; } | ||||
|  | ||||
| ### Create the tarball | ||||
| # | ||||
| # Create the tarball, compute SHA256 for later reporting, and | ||||
| # sign the tarball so the signature can be uploaded separately. | ||||
| # | ||||
| TAR_V="$TARBALL_PREFIX-$V" | ||||
| TAR_FILE="$TAR_V.tar.gz" | ||||
| git archive -o "$TAR_FILE" --prefix "$TAR_V/" "v$V" || { echo "Could not create tarball." ; exit 1 ; } | ||||
| test -f "$TAR_FILE" || { echo "Tarball was not created." ; exit 1 ; } | ||||
| SHA256=$(sha256sum "$TAR_FILE" | cut -d" " -f1) | ||||
| gpg -s -u $KEY_ID --detach --armor $TAR_FILE  # Sign the tarball | ||||
|  | ||||
| ### Build the tarball | ||||
| # | ||||
| @@ -181,7 +187,6 @@ rm -rf "$TMPDIR"  # From tarball | ||||
| cat <<EOF | ||||
| # Next steps for this release: | ||||
|   git push origin v$V | ||||
|   gpg -s -u $KEY_ID --detach --armor $TAR_FILE  # Sign the tarball | ||||
|   # Upload tarball $TAR_FILE and the signature $TAR_FILE.asc | ||||
|   # Announce via https://github.com/calamares/$PROJECT_NAME/releases/new | ||||
|   # SHA256: $SHA256 | ||||
|   | ||||
							
								
								
									
										17
									
								
								ci/astylerc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| #   SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org> | ||||
| #   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: BSD-2-Clause | ||||
|  | ||||
| # Do not create a backup file | ||||
| suffix=none | ||||
|  | ||||
| indent=spaces=4 | ||||
|  | ||||
| # Brackets | ||||
| style=break | ||||
| add-brackets | ||||
|  | ||||
| # Spaces | ||||
| pad-paren-in | ||||
| pad-header | ||||
| align-pointer=type | ||||
							
								
								
									
										105
									
								
								ci/calamaresstyle
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,105 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| #   SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org> | ||||
| #   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: BSD-2-Clause | ||||
| # | ||||
| # Calls astyle with settings matching Calamares coding style | ||||
| # Requires astyle >= 2.04 and clang-format-8 or later | ||||
| # | ||||
| # You can pass in directory names, in which case the files | ||||
| # in that directory (NOT below it) are processed. | ||||
| # | ||||
| LANG=C | ||||
| LC_ALL=C | ||||
| LC_NUMERIC=C | ||||
| export LANG LC_ALL LC_NUMERIC | ||||
|  | ||||
| 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 ; } | ||||
|  | ||||
| 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" | ||||
| for _cf in $CF_VERSIONS | ||||
| do | ||||
| 	# Not an error if this particular clang-format isn't found | ||||
| 	CF=$( which $_cf 2> /dev/null || true ) | ||||
| 	test -n "$CF" && break | ||||
| done | ||||
|  | ||||
| test -n "$AS" || { echo "! No astyle found in PATH"; exit 1 ; } | ||||
| test -n "$CF" || { echo "! No clang-format ($CF_VERSIONS) found in PATH"; exit 1 ; } | ||||
| test -x "$AS" || { echo "! $AS is not executable."; exit 1 ; } | ||||
| 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. | ||||
|  | ||||
| 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] ) | ||||
| 		: | ||||
| 		;; | ||||
| 	* ) | ||||
| 		echo "! Clang-format version '$format_version' unsupported." | ||||
| 		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 | ||||
| # | ||||
| # | ||||
| set -e | ||||
|  | ||||
| any_dirs=no | ||||
| for d in "$@" | ||||
| do | ||||
| 	test -d "$d" && any_dirs=yes | ||||
| done | ||||
|  | ||||
| style_some() | ||||
| { | ||||
| 	if test -n "$*" ; then | ||||
| 		$AS --options=$BASEDIR/astylerc --quiet "$@" | ||||
| 		$CF -i -style=file "$@" | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| if test "x$any_dirs" = "xyes" ; then | ||||
| 	for d in "$@" | ||||
| 	do | ||||
| 		if test -d "$d"  ; then | ||||
| 			style_some $( find "$d" -maxdepth 1 -type f -name '*.cpp' -o -name '*.h' ) | ||||
| 		else | ||||
| 			style_some "$d" | ||||
| 		fi | ||||
| 	done | ||||
| else | ||||
| 	style_some "$@" | ||||
| fi | ||||
|  | ||||
| ### CLANG-FORMAT-WRANGLING | ||||
| # | ||||
| # Restore the original .clang-format | ||||
| cp "$_fmt.base" "$_fmt" | ||||
| @@ -1,11 +0,0 @@ | ||||
| # The FileKeeper plugin preserves files from the live system | ||||
| # to the target system. It is particularly suited for copying | ||||
| # the log file(s) for post-installation or post-mortem examination. | ||||
|  | ||||
| calamares_add_plugin( filekeeper | ||||
|     TYPE job | ||||
|     EXPORT_MACRO PLUGINDLLEXPORT_PRO | ||||
|     SOURCES | ||||
|         FileKeeper.cpp | ||||
|     SHARED_LIB | ||||
| ) | ||||
| @@ -1,58 +0,0 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   Copyright 2018, Adriaan de Groot <groot@kde.org> | ||||
|  * | ||||
|  *   Calamares is free software: you can redistribute it and/or modify | ||||
|  *   it under the terms of the GNU General Public License as published by | ||||
|  *   the Free Software Foundation, either version 3 of the License, or | ||||
|  *   (at your option) any later version. | ||||
|  * | ||||
|  *   Calamares is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
|  *   GNU General Public License for more details. | ||||
|  * | ||||
|  *   You should have received a copy of the GNU General Public License | ||||
|  *   along with Calamares. If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include "FileKeeper.h" | ||||
|  | ||||
| #include <QDateTime> | ||||
| #include <QProcess> | ||||
| #include <QThread> | ||||
|  | ||||
| #include <GlobalStorage.h> | ||||
| #include <JobQueue.h> | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
|  | ||||
| FileKeeperJob::FileKeeperJob( QObject* parent ) | ||||
|     : Calamares::CppJob( parent ) | ||||
| { | ||||
| } | ||||
|  | ||||
|  | ||||
| FileKeeperJob::~FileKeeperJob() {} | ||||
|  | ||||
|  | ||||
| QString | ||||
| FileKeeperJob::prettyName() const | ||||
| { | ||||
|     return tr( "File keeper Job" ); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FileKeeperJob::exec() | ||||
| { | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void | ||||
| FileKeeperJob::setConfigurationMap( const QVariantMap& configurationMap ) | ||||
| { | ||||
|     Q_UNUSED( configurationMap ); | ||||
| } | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DEFINITION( FileKeeperJobFactory, registerPlugin< FileKeeperJob >(); ) | ||||
| @@ -1,46 +0,0 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   Copyright 2018, Adriaan de Groot <groot@kde.org> | ||||
|  * | ||||
|  *   Calamares is free software: you can redistribute it and/or modify | ||||
|  *   it under the terms of the GNU General Public License as published by | ||||
|  *   the Free Software Foundation, either version 3 of the License, or | ||||
|  *   (at your option) any later version. | ||||
|  * | ||||
|  *   Calamares is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
|  *   GNU General Public License for more details. | ||||
|  * | ||||
|  *   You should have received a copy of the GNU General Public License | ||||
|  *   along with Calamares. If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #ifndef FILEKEEPER_H | ||||
| #define FILEKEEPER_H | ||||
|  | ||||
| #include <CppJob.h> | ||||
| #include <DllMacro.h> | ||||
| #include <utils/PluginFactory.h> | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QVariantMap> | ||||
|  | ||||
| class PLUGINDLLEXPORT FileKeeperJob : public Calamares::CppJob | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit FileKeeperJob( QObject* parent = nullptr ); | ||||
|     virtual ~FileKeeperJob() override; | ||||
|  | ||||
|     QString prettyName() const override; | ||||
|  | ||||
|     Calamares::JobResult exec() override; | ||||
|  | ||||
|     void setConfigurationMap( const QVariantMap& configurationMap ) override; | ||||
| }; | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DECLARATION( FileKeeperJobFactory ) | ||||
|  | ||||
| #endif | ||||
| @@ -1,3 +1,6 @@ | ||||
| #   SPDX-FileCopyrightText: no | ||||
| #   SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| if( NOT Calamares_WITH_QML ) | ||||
|     calamares_skip_module( "freebsddisk (QML is not supported in this build)" ) | ||||
|     return() | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # The *freebsddisk* module can be used to pick a disk | ||||
| # as an installer step. This module supports ZFSroot | ||||
| # on one whole disk, and UFSroot on one whole disk. | ||||
|   | ||||
| @@ -6,13 +6,9 @@ calamares_add_plugin( mobile | ||||
|     EXPORT_MACRO PLUGINDLLEXPORT_PRO | ||||
|     SOURCES | ||||
|         Config.cpp | ||||
|         Config.h | ||||
|         MobileQmlViewStep.cpp | ||||
|         MobileQmlViewStep.h | ||||
|         PartitionJob.cpp | ||||
|         PartitionJob.h | ||||
|         UsersJob.cpp | ||||
|         UsersJob.h | ||||
|     RESOURCES | ||||
|         mobile.qrc | ||||
|     SHARED_LIB | ||||
|   | ||||
| @@ -1,6 +1,13 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| #include "Config.h" | ||||
| #include "PartitionJob.h" | ||||
| #include "UsersJob.h" | ||||
|  | ||||
| #include "ViewManager.h" | ||||
| #include "utils/Logger.h" | ||||
| #include "utils/Variant.h" | ||||
|  | ||||
| #include <QVariant> | ||||
|  | ||||
| Config::Config( QObject* parent ) | ||||
| @@ -8,37 +15,138 @@ Config::Config( QObject* parent ) | ||||
| { | ||||
| } | ||||
|  | ||||
| QString | ||||
| cfgStr( const QVariantMap& cfgMap, QString key, QString defaultStr ) | ||||
| { | ||||
|     QString ret = cfgMap.value( key ).toString(); | ||||
|     if ( ret.isEmpty() ) | ||||
|     { | ||||
|         return defaultStr; | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setConfigurationMap( const QVariantMap& cfgMap ) | ||||
| { | ||||
|     m_osName = cfgStr( cfgMap, "osName", "(unknown)" ); | ||||
|     m_arch = cfgStr( cfgMap, "arch", "(unknown)" ); | ||||
|     m_device = cfgStr( cfgMap, "device", "(unknown)" ); | ||||
|     m_userInterface = cfgStr( cfgMap, "userInterface", "(unknown)" ); | ||||
|     m_version = cfgStr( cfgMap, "version", "(unknown)" ); | ||||
|     m_username = cfgStr( cfgMap, "username", "user" ); | ||||
|     using namespace CalamaresUtils; | ||||
|  | ||||
|     m_cmdLuksFormat = cfgStr( cfgMap, "cmdLuksFormat", "cryptsetup luksFormat --use-random" ); | ||||
|     m_cmdLuksOpen = cfgStr( cfgMap, "cmdLuksOpen", "cryptsetup luksOpen" ); | ||||
|     m_cmdMkfsRoot = cfgStr( cfgMap, "cmdMkfsRoot", "mkfs.ext4 -L 'unknownOS_root'" ); | ||||
|     m_cmdMount = cfgStr( cfgMap, "cmdMount", "mount" ); | ||||
|     m_targetDeviceRoot = cfgStr( cfgMap, "targetDeviceRoot", "/dev/unknown" ); | ||||
|     if ( getBool( cfgMap, "bogus", false ) ) | ||||
|     { | ||||
|         cWarning() << "Configuration key \"bogus\" is still set for *mobile*"; | ||||
|     } | ||||
|  | ||||
|     m_cmdPasswd = cfgStr( cfgMap, "cmdPasswd", "passwd" ); | ||||
|     m_cmdSshdEnable = cfgStr( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" ); | ||||
|     m_cmdSshdDisable = cfgStr( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" ); | ||||
|     m_cmdSshdUseradd = cfgStr( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" ); | ||||
|     m_osName = getString( cfgMap, "osName", "(unknown)" ); | ||||
|     m_arch = getString( cfgMap, "arch", "(unknown)" ); | ||||
|     m_device = getString( cfgMap, "device", "(unknown)" ); | ||||
|     m_userInterface = getString( cfgMap, "userInterface", "(unknown)" ); | ||||
|     m_version = getString( cfgMap, "version", "(unknown)" ); | ||||
|  | ||||
|     m_reservedUsernames = getStringList( cfgMap, "reservedUsernames", QStringList { "adm", "at ", "bin", "colord", | ||||
|             "cron", "cyrus", "daemon", "ftp", "games", "geoclue", "guest", "halt", "lightdm", "lp", "mail", "man", | ||||
|             "messagebus", "news", "nobody", "ntp", "operator", "polkitd", "postmaster", "pulse", "root", "shutdown", | ||||
|             "smmsp", "squid", "sshd", "sync", "uucp", "vpopmail", "xfs" } ); | ||||
|  | ||||
|     // ensure m_cmdUsermod matches m_username | ||||
|     m_username = getString( cfgMap, "username", "user" ); | ||||
|     m_userPasswordNumeric = getBool( cfgMap, "userPasswordNumeric", true ); | ||||
|  | ||||
|     m_builtinVirtualKeyboard = getBool( cfgMap, "builtinVirtualKeyboard", true ); | ||||
|  | ||||
|     m_featureSshd = getBool( cfgMap, "featureSshd", true ); | ||||
|     m_featureFsType = getBool( cfgMap, "featureFsType", false ); | ||||
|  | ||||
|     m_cmdLuksFormat = getString( cfgMap, "cmdLuksFormat", "cryptsetup luksFormat --use-random" ); | ||||
|     m_cmdLuksOpen = getString( cfgMap, "cmdLuksOpen", "cryptsetup luksOpen" ); | ||||
|     m_cmdMount = getString( cfgMap, "cmdMount", "mount" ); | ||||
|     m_targetDeviceRoot = getString( cfgMap, "targetDeviceRoot", "/dev/unknown" ); | ||||
|     m_targetDeviceRootInternal = getString( cfgMap, "targetDeviceRootInternal", "" ); | ||||
|  | ||||
|     m_cmdMkfsRootBtrfs = getString( cfgMap, "cmdMkfsRootBtrfs", "mkfs.btrfs -L 'unknownOS_root'" ); | ||||
|     m_cmdMkfsRootExt4 = getString( cfgMap, "cmdMkfsRootExt4", "mkfs.ext4 -L 'unknownOS_root'" ); | ||||
|     m_cmdMkfsRootF2fs = getString( cfgMap, "cmdMkfsRootF2fs", "mkfs.f2fs -l 'unknownOS_root'" ); | ||||
|     m_fsList = getStringList( cfgMap, "fsModel", QStringList { "ext4", "f2fs", "btrfs" } ); | ||||
|     m_defaultFs = getString( cfgMap, "defaultFs", "ext4" ); | ||||
|     m_fsIndex = m_fsList.indexOf( m_defaultFs ); | ||||
|     m_fsType = m_defaultFs; | ||||
|  | ||||
|     m_cmdInternalStoragePrepare = getString( cfgMap, "cmdInternalStoragePrepare", "ondev-internal-storage-prepare" ); | ||||
|     m_cmdPasswd = getString( cfgMap, "cmdPasswd", "passwd" ); | ||||
|     m_cmdUsermod = getString( cfgMap, "cmdUsermod", "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user"); | ||||
|  | ||||
|     m_cmdSshdEnable = getString( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" ); | ||||
|     m_cmdSshdDisable = getString( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" ); | ||||
|     m_cmdSshdUseradd = getString( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" ); | ||||
| } | ||||
|  | ||||
| Calamares::JobList | ||||
| Config::createJobs() | ||||
| { | ||||
|     QList< Calamares::job_ptr > list; | ||||
|     QString cmdSshd = m_isSshEnabled ? m_cmdSshdEnable : m_cmdSshdDisable; | ||||
|  | ||||
|     /* Put users job in queue (should run after unpackfs) */ | ||||
|     Calamares::Job* j = new UsersJob( m_featureSshd, | ||||
|                                       m_cmdPasswd, | ||||
|                                       m_cmdUsermod, | ||||
|                                       cmdSshd, | ||||
|                                       m_cmdSshdUseradd, | ||||
|                                       m_isSshEnabled, | ||||
|                                       m_username, | ||||
|                                       m_userPassword, | ||||
|                                       m_sshdUsername, | ||||
|                                       m_sshdPassword ); | ||||
|     list.append( Calamares::job_ptr( j ) ); | ||||
|  | ||||
|     return list; | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::runPartitionJobThenLeave( bool b ) | ||||
| { | ||||
|     Calamares::ViewManager* v = Calamares::ViewManager::instance(); | ||||
|     QString cmdMkfsRoot; | ||||
|     if ( m_fsType == QStringLiteral( "btrfs" ) ) | ||||
|     { | ||||
|         cmdMkfsRoot = m_cmdMkfsRootBtrfs; | ||||
|     } | ||||
|     else if ( m_fsType == QStringLiteral( "f2fs" ) ) | ||||
|     { | ||||
|         cmdMkfsRoot = m_cmdMkfsRootF2fs; | ||||
|     } | ||||
|     else if ( m_fsType == QStringLiteral( "ext4" ) ) | ||||
|     { | ||||
|         cmdMkfsRoot = m_cmdMkfsRootExt4; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         v->onInstallationFailed( "Unknown filesystem: '" + m_fsType + "'", "" ); | ||||
|     } | ||||
|     /* HACK: run partition job | ||||
|      * The "mobile" module has two jobs, the partition job and the users job. | ||||
|      * If we added both of them in Config::createJobs(), Calamares would run | ||||
|      * them right after each other. But we need the "unpackfs" module to run | ||||
|      * inbetween, that's why as workaround, the partition job is started here. | ||||
|      * To solve this properly, we would need to place the partition job in an | ||||
|      * own module and pass everything via globalstorage. But then we might as | ||||
|      * well refactor everything so we can unify the mobile's partition job with | ||||
|      * the proper partition job from Calamares. */ | ||||
|     Calamares::Job* j = new PartitionJob( m_cmdInternalStoragePrepare, | ||||
|                                           m_cmdLuksFormat, | ||||
|                                           m_cmdLuksOpen, | ||||
|                                           cmdMkfsRoot, | ||||
|                                           m_cmdMount, | ||||
|                                           m_targetDeviceRoot, | ||||
|                                           m_targetDeviceRootInternal, | ||||
|                                           m_installFromExternalToInternal, | ||||
|                                           m_isFdeEnabled, | ||||
|                                           m_fdePassword ); | ||||
|     Calamares::JobResult res = j->exec(); | ||||
|  | ||||
|     if ( res ) | ||||
|     { | ||||
|         v->next(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         v->onInstallationFailed( res.message(), res.details() ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setUsername( const QString& username ) | ||||
| { | ||||
|     m_username = username; | ||||
|     emit usernameChanged( m_username ); | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -80,3 +188,34 @@ Config::setIsFdeEnabled( const bool isFdeEnabled ) | ||||
| { | ||||
|     m_isFdeEnabled = isFdeEnabled; | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setInstallFromExternalToInternal( const bool val ) | ||||
| { | ||||
|     m_installFromExternalToInternal = val; | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setFsType( int idx ) | ||||
| { | ||||
|     if ( idx >= 0 && idx < m_fsList.length() ) | ||||
|     { | ||||
|         setFsType( m_fsList[ idx ] ); | ||||
|     } | ||||
| } | ||||
| void | ||||
| Config::setFsType( const QString& fsType ) | ||||
| { | ||||
|     if ( fsType != m_fsType ) | ||||
|     { | ||||
|         m_fsType = fsType; | ||||
|         emit fsTypeChanged( m_fsType ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setFsIndex( const int fsIndex ) | ||||
| { | ||||
|     m_fsIndex = fsIndex; | ||||
|     emit fsIndexChanged( m_fsIndex ); | ||||
| } | ||||
|   | ||||
| @@ -1,12 +1,18 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| #pragma once | ||||
|  | ||||
| #include "Job.h" | ||||
|  | ||||
| #include <QObject> | ||||
| #include <memory> | ||||
|  | ||||
| class Config : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
|     /* installer UI */ | ||||
|     Q_PROPERTY( bool builtinVirtualKeyboard READ builtinVirtualKeyboard CONSTANT FINAL ) | ||||
|  | ||||
|     /* welcome */ | ||||
|     Q_PROPERTY( QString osName READ osName CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString arch READ arch CONSTANT FINAL ) | ||||
| @@ -14,11 +20,16 @@ class Config : public QObject | ||||
|     Q_PROPERTY( QString userInterface READ userInterface CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString version READ version CONSTANT FINAL ) | ||||
|  | ||||
|     /* reserved usernames (user_pass, ssh_credentials )*/ | ||||
|     Q_PROPERTY( QStringList reservedUsernames READ reservedUsernames CONSTANT FINAL ) | ||||
|  | ||||
|     /* default user */ | ||||
|     Q_PROPERTY( QString username READ username CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString username READ username WRITE setUsername NOTIFY usernameChanged ) | ||||
|     Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged ) | ||||
|     Q_PROPERTY( bool userPasswordNumeric READ userPasswordNumeric CONSTANT FINAL ) | ||||
|  | ||||
|     /* ssh server + credentials */ | ||||
|     Q_PROPERTY( bool featureSshd READ featureSshd CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString sshdUsername READ sshdUsername WRITE setSshdUsername NOTIFY sshdUsernameChanged ) | ||||
|     Q_PROPERTY( QString sshdPassword READ sshdPassword WRITE setSshdPassword NOTIFY sshdPasswordChanged ) | ||||
|     Q_PROPERTY( bool isSshEnabled READ isSshEnabled WRITE setIsSshEnabled ) | ||||
| @@ -27,12 +38,23 @@ class Config : public QObject | ||||
|     Q_PROPERTY( QString fdePassword READ fdePassword WRITE setFdePassword NOTIFY fdePasswordChanged ) | ||||
|     Q_PROPERTY( bool isFdeEnabled READ isFdeEnabled WRITE setIsFdeEnabled ) | ||||
|  | ||||
|     /* filesystem selection */ | ||||
|     Q_PROPERTY( QString fsType READ fsType WRITE setFsType NOTIFY fsTypeChanged ) | ||||
|     Q_PROPERTY( bool featureFsType READ featureFsType CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QStringList fsList READ fsList CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString defaultFs READ defaultFs CONSTANT FINAL ) | ||||
|     Q_PROPERTY( int fsIndex READ fsIndex WRITE setFsIndex NOTIFY fsIndexChanged ) | ||||
|  | ||||
|     /* partition job */ | ||||
|     Q_PROPERTY( bool runPartitionJobThenLeave READ runPartitionJobThenLeaveDummy WRITE runPartitionJobThenLeave ) | ||||
|     Q_PROPERTY( QString cmdInternalStoragePrepare READ cmdInternalStoragePrepare CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString cmdLuksFormat READ cmdLuksFormat CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString cmdLuksOpen READ cmdLuksOpen CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString cmdMkfsRoot READ cmdMkfsRoot CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString cmdMount READ cmdMount CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString targetDeviceRoot READ targetDeviceRoot CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString targetDeviceRootInternal READ targetDeviceRootInternal CONSTANT FINAL ) | ||||
|     Q_PROPERTY( | ||||
|         bool installFromExternalToInternal READ installFromExternalToInternal WRITE setInstallFromExternalToInternal ) | ||||
|  | ||||
|     /* users job */ | ||||
|     Q_PROPERTY( QString cmdSshdEnable READ cmdSshdEnable CONSTANT FINAL ) | ||||
| @@ -41,6 +63,10 @@ class Config : public QObject | ||||
| public: | ||||
|     Config( QObject* parent = nullptr ); | ||||
|     void setConfigurationMap( const QVariantMap& ); | ||||
|     Calamares::JobList createJobs(); | ||||
|  | ||||
|     /* installer UI */ | ||||
|     bool builtinVirtualKeyboard() { return m_builtinVirtualKeyboard; } | ||||
|  | ||||
|     /* welcome */ | ||||
|     QString osName() const { return m_osName; } | ||||
| @@ -49,12 +75,18 @@ public: | ||||
|     QString userInterface() const { return m_userInterface; } | ||||
|     QString version() const { return m_version; } | ||||
|  | ||||
|     /* default user */ | ||||
|     /* reserved usernames (user_pass, ssh_credentials) */ | ||||
|     QStringList reservedUsernames() const { return m_reservedUsernames; }; | ||||
|  | ||||
|     /* user */ | ||||
|     QString username() const { return m_username; } | ||||
|     QString userPassword() const { return m_userPassword; } | ||||
|     void setUsername( const QString& username ); | ||||
|     void setUserPassword( const QString& userPassword ); | ||||
|     bool userPasswordNumeric() const { return m_userPasswordNumeric; } | ||||
|  | ||||
|     /* ssh server + credetials */ | ||||
|     /* ssh server + credentials */ | ||||
|     bool featureSshd() { return m_featureSshd; } | ||||
|     QString sshdUsername() const { return m_sshdUsername; } | ||||
|     QString sshdPassword() const { return m_sshdPassword; } | ||||
|     bool isSshEnabled() { return m_isSshEnabled; } | ||||
| @@ -68,20 +100,42 @@ public: | ||||
|     void setFdePassword( const QString& fdePassword ); | ||||
|     void setIsFdeEnabled( bool isFdeEnabled ); | ||||
|  | ||||
|     /* filesystem selection */ | ||||
|     bool featureFsType() { return m_featureFsType; }; | ||||
|     QString fsType() const { return m_fsType; }; | ||||
|     void setFsType( int idx ); | ||||
|     void setFsType( const QString& fsType ); | ||||
|     QStringList fsList() const { return m_fsList; }; | ||||
|     int fsIndex() const { return m_fsIndex; }; | ||||
|     void setFsIndex( const int fsIndex ); | ||||
|     QString defaultFs() const { return m_defaultFs; }; | ||||
|  | ||||
|     /* partition job */ | ||||
|     bool runPartitionJobThenLeaveDummy() { return 0; } | ||||
|     void runPartitionJobThenLeave( bool b ); | ||||
|     QString cmdInternalStoragePrepare() const { return m_cmdInternalStoragePrepare; } | ||||
|     QString cmdLuksFormat() const { return m_cmdLuksFormat; } | ||||
|     QString cmdLuksOpen() const { return m_cmdLuksOpen; } | ||||
|     QString cmdMkfsRoot() const { return m_cmdMkfsRoot; } | ||||
|     QString cmdMkfsRootBtrfs() const { return m_cmdMkfsRootBtrfs; } | ||||
|     QString cmdMkfsRootExt4() const { return m_cmdMkfsRootExt4; } | ||||
|     QString cmdMkfsRootF2fs() const { return m_cmdMkfsRootF2fs; } | ||||
|     QString cmdMount() const { return m_cmdMount; } | ||||
|     QString targetDeviceRoot() const { return m_targetDeviceRoot; } | ||||
|     QString targetDeviceRootInternal() const { return m_targetDeviceRootInternal; } | ||||
|     bool installFromExternalToInternal() { return m_installFromExternalToInternal; } | ||||
|     void setInstallFromExternalToInternal( const bool val ); | ||||
|  | ||||
|     /* users job */ | ||||
|     QString cmdPasswd() const { return m_cmdPasswd; } | ||||
|     QString cmdUsermod() const { return m_cmdUsermod; } | ||||
|     QString cmdSshdEnable() const { return m_cmdSshdEnable; } | ||||
|     QString cmdSshdDisable() const { return m_cmdSshdDisable; } | ||||
|     QString cmdSshdUseradd() const { return m_cmdSshdUseradd; } | ||||
|  | ||||
| private: | ||||
|     /* installer UI */ | ||||
|     bool m_builtinVirtualKeyboard; | ||||
|  | ||||
|     /* welcome */ | ||||
|     QString m_osName; | ||||
|     QString m_arch; | ||||
| @@ -89,41 +143,65 @@ private: | ||||
|     QString m_userInterface; | ||||
|     QString m_version; | ||||
|  | ||||
|     /* reserved usernames (user_pass, ssh_credentials) */ | ||||
|     QStringList m_reservedUsernames; | ||||
|  | ||||
|     /* default user */ | ||||
|     QString m_username; | ||||
|     QString m_userPassword; | ||||
|     bool m_userPasswordNumeric; | ||||
|  | ||||
|     /* ssh server + credetials */ | ||||
|     /* ssh server + credentials */ | ||||
|     bool m_featureSshd = false; | ||||
|     QString m_sshdUsername; | ||||
|     QString m_sshdPassword; | ||||
|     bool m_isSshEnabled; | ||||
|     bool m_isSshEnabled = false; | ||||
|  | ||||
|     /* full disk encryption */ | ||||
|     QString m_fdePassword = ""; | ||||
|     QString m_fdePassword; | ||||
|     bool m_isFdeEnabled = false; | ||||
|  | ||||
|     /* filesystem selection */ | ||||
|     bool m_featureFsType = false; | ||||
|     QString m_defaultFs; | ||||
|     QString m_fsType; | ||||
|     // Index of the currently selected filesystem in UI. | ||||
|     int m_fsIndex = -1; | ||||
|     QStringList m_fsList; | ||||
|  | ||||
|     /* partition job */ | ||||
|     QString m_cmdInternalStoragePrepare; | ||||
|     QString m_cmdLuksFormat; | ||||
|     QString m_cmdLuksOpen; | ||||
|     QString m_cmdMkfsRoot; | ||||
|     QString m_cmdMkfsRootBtrfs; | ||||
|     QString m_cmdMkfsRootExt4; | ||||
|     QString m_cmdMkfsRootF2fs; | ||||
|     QString m_cmdMount; | ||||
|     QString m_targetDeviceRoot; | ||||
|     QString m_targetDeviceRootInternal; | ||||
|     bool m_installFromExternalToInternal = false; | ||||
|  | ||||
|     /* users job */ | ||||
|     QString m_cmdPasswd; | ||||
|     QString m_cmdUsermod; | ||||
|     QString m_cmdSshdEnable; | ||||
|     QString m_cmdSshdDisable; | ||||
|     QString m_cmdSshdUseradd; | ||||
|  | ||||
| signals: | ||||
|     /* booleans we don't read from QML (like isSshEnabled) don't need a signal */ | ||||
|  | ||||
|     /* default user */ | ||||
|     void userPasswordChanged( QString userPassword ); | ||||
|     void usernameChanged( QString username ); | ||||
|  | ||||
|     /* ssh server + credetials */ | ||||
|     /* ssh server + credentials */ | ||||
|     void sshdUsernameChanged( QString sshdUsername ); | ||||
|     void sshdPasswordChanged( QString sshdPassword ); | ||||
|     /* isSshEnabled doesn't need a signal, we don't read it from QML */ | ||||
|  | ||||
|     /* full disk encryption */ | ||||
|     void fdePasswordChanged( QString fdePassword ); | ||||
|  | ||||
|     void fsTypeChanged( QString fsType ); | ||||
|     void fsIndexChanged( int fsIndex ); | ||||
| }; | ||||
|   | ||||
| @@ -1,20 +1,15 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| #include "MobileQmlViewStep.h" | ||||
| #include "PartitionJob.h" | ||||
| #include "UsersJob.h" | ||||
|  | ||||
| #include "Branding.h" | ||||
| #include "GlobalStorage.h" | ||||
| #include "JobQueue.h" | ||||
|  | ||||
| #include "locale/LabelModel.h" | ||||
| #include "locale/TranslationsModel.h" | ||||
| #include "modulesystem/ModuleManager.h" | ||||
| #include "utils/Dirs.h" | ||||
| #include "utils/Logger.h" | ||||
| #include "utils/Variant.h" | ||||
|  | ||||
| #include "Branding.h" | ||||
| #include "modulesystem/ModuleManager.h" | ||||
|  | ||||
| #include <QProcess> | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DEFINITION( MobileQmlViewStepFactory, registerPlugin< MobileQmlViewStep >(); ) | ||||
| @@ -35,34 +30,7 @@ MobileQmlViewStep::MobileQmlViewStep( QObject* parent ) | ||||
| void | ||||
| MobileQmlViewStep::onLeave() | ||||
| { | ||||
|     Calamares::Job *partition, *users; | ||||
|  | ||||
|     /* HACK: run partition job now */ | ||||
|     partition = new PartitionJob( m_config->cmdLuksFormat(), | ||||
|                                   m_config->cmdLuksOpen(), | ||||
|                                   m_config->cmdMkfsRoot(), | ||||
|                                   m_config->cmdMount(), | ||||
|                                   m_config->targetDeviceRoot(), | ||||
|                                   m_config->isFdeEnabled(), | ||||
|                                   m_config->fdePassword() ); | ||||
|     Calamares::JobResult res = partition->exec(); | ||||
|     if ( !res ) | ||||
|     { | ||||
|         cError() << "PARTITION JOB FAILED: " << res.message(); | ||||
|     } | ||||
|  | ||||
|     /* Put users job in queue (should run after unpackfs) */ | ||||
|     m_jobs.clear(); | ||||
|     QString cmdSshd = m_config->isSshEnabled() ? m_config->cmdSshdEnable() : m_config->cmdSshdDisable(); | ||||
|     users = new UsersJob( m_config->cmdPasswd(), | ||||
|                           cmdSshd, | ||||
|                           m_config->cmdSshdUseradd(), | ||||
|                           m_config->isSshEnabled(), | ||||
|                           m_config->username(), | ||||
|                           m_config->userPassword(), | ||||
|                           m_config->sshdUsername(), | ||||
|                           m_config->sshdPassword() ); | ||||
|     m_jobs.append( Calamares::job_ptr( users ) ); | ||||
|     return; | ||||
| } | ||||
|  | ||||
| bool | ||||
| @@ -95,7 +63,7 @@ MobileQmlViewStep::isAtEnd() const | ||||
| Calamares::JobList | ||||
| MobileQmlViewStep::jobs() const | ||||
| { | ||||
|     return m_jobs; | ||||
|     return m_config->createJobs(); | ||||
| } | ||||
|  | ||||
| QObject* | ||||
|   | ||||
| @@ -32,7 +32,6 @@ public: | ||||
|  | ||||
| private: | ||||
|     Config* m_config; | ||||
|     QList< Calamares::job_ptr > m_jobs; | ||||
| }; | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DECLARATION( MobileQmlViewStepFactory ) | ||||
|   | ||||
| @@ -12,19 +12,25 @@ | ||||
| #include <QFileInfo> | ||||
|  | ||||
|  | ||||
| PartitionJob::PartitionJob( QString cmdLuksFormat, | ||||
|                             QString cmdLuksOpen, | ||||
|                             QString cmdMkfsRoot, | ||||
|                             QString cmdMount, | ||||
|                             QString targetDeviceRoot, | ||||
| PartitionJob::PartitionJob( const QString& cmdInternalStoragePrepare, | ||||
|                             const QString& cmdLuksFormat, | ||||
|                             const QString& cmdLuksOpen, | ||||
|                             const QString& cmdMkfsRoot, | ||||
|                             const QString& cmdMount, | ||||
|                             const QString& targetDeviceRoot, | ||||
|                             const QString& targetDeviceRootInternal, | ||||
|                             bool installFromExternalToInternal, | ||||
|                             bool isFdeEnabled, | ||||
|                             const QString& password ) | ||||
|     : Calamares::Job() | ||||
|     , m_cmdInternalStoragePrepare( cmdInternalStoragePrepare ) | ||||
|     , m_cmdLuksFormat( cmdLuksFormat ) | ||||
|     , m_cmdLuksOpen( cmdLuksOpen ) | ||||
|     , m_cmdMkfsRoot( cmdMkfsRoot ) | ||||
|     , m_cmdMount( cmdMount ) | ||||
|     , m_targetDeviceRoot( targetDeviceRoot ) | ||||
|     , m_targetDeviceRootInternal( targetDeviceRootInternal ) | ||||
|     , m_installFromExternalToInternal( installFromExternalToInternal ) | ||||
|     , m_isFdeEnabled( isFdeEnabled ) | ||||
|     , m_password( password ) | ||||
| { | ||||
| @@ -77,10 +83,18 @@ PartitionJob::exec() | ||||
|     QString cryptDev = "/dev/mapper/" + cryptName; | ||||
|     QString passwordStdin = m_password + "\n"; | ||||
|     QString dev = m_targetDeviceRoot; | ||||
|     QList< QPair< QStringList, QString > > commands = {}; | ||||
|  | ||||
|     QList< QPair< QStringList, QString > > commands = { | ||||
|         { { "mkdir", "-p", pathMount }, QString() }, | ||||
|     }; | ||||
|     if ( m_installFromExternalToInternal ) | ||||
|     { | ||||
|         dev = m_targetDeviceRootInternal; | ||||
|  | ||||
|         commands.append( { | ||||
|             { { "sh", "-c", m_cmdInternalStoragePrepare }, QString() }, | ||||
|         } ); | ||||
|     } | ||||
|  | ||||
|     commands.append( { { { "mkdir", "-p", pathMount }, QString() } } ); | ||||
|  | ||||
|     if ( m_isFdeEnabled ) | ||||
|     { | ||||
| @@ -104,7 +118,7 @@ PartitionJob::exec() | ||||
|         const QString pathRoot = "/"; | ||||
|  | ||||
|         ProcessResult res | ||||
|             = System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 120 ) ); | ||||
|             = System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 600 ) ); | ||||
|         if ( res.getExitCode() ) | ||||
|         { | ||||
|             return JobResult::error( "Command failed:<br><br>" | ||||
|   | ||||
| @@ -8,11 +8,14 @@ class PartitionJob : public Calamares::Job | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     PartitionJob( QString cmdLuksFormat, | ||||
|                   QString cmdLuksOpen, | ||||
|                   QString cmdMkfsRoot, | ||||
|                   QString cmdMount, | ||||
|                   QString targetDeviceRoot, | ||||
|     PartitionJob( const QString& cmdInternalStoragePrepare, | ||||
|                   const QString& cmdLuksFormat, | ||||
|                   const QString& cmdLuksOpen, | ||||
|                   const QString& cmdMkfsRoot, | ||||
|                   const QString& cmdMount, | ||||
|                   const QString& targetDeviceRoot, | ||||
|                   const QString& targetDeviceRootInternal, | ||||
|                   bool installFromExternalToInternal, | ||||
|                   bool isFdeEnabled, | ||||
|                   const QString& password ); | ||||
|  | ||||
| @@ -22,11 +25,14 @@ public: | ||||
|     Calamares::JobList createJobs(); | ||||
|  | ||||
| private: | ||||
|     QString m_cmdInternalStoragePrepare; | ||||
|     QString m_cmdLuksFormat; | ||||
|     QString m_cmdLuksOpen; | ||||
|     QString m_cmdMkfsRoot; | ||||
|     QString m_cmdMount; | ||||
|     QString m_targetDeviceRoot; | ||||
|     QString m_targetDeviceRootInternal; | ||||
|     bool m_installFromExternalToInternal; | ||||
|     bool m_isFdeEnabled; | ||||
|     QString m_password; | ||||
| }; | ||||
|   | ||||
| @@ -12,16 +12,20 @@ | ||||
| #include <QFileInfo> | ||||
|  | ||||
|  | ||||
| UsersJob::UsersJob( QString cmdPasswd, | ||||
|                     QString cmdSshd, | ||||
|                     QString cmdSshdUseradd, | ||||
| UsersJob::UsersJob( bool featureSshd, | ||||
|                     const QString& cmdPasswd, | ||||
|                     const QString& cmdUsermod, | ||||
|                     const QString& cmdSshd, | ||||
|                     const QString& cmdSshdUseradd, | ||||
|                     bool isSshEnabled, | ||||
|                     QString username, | ||||
|                     QString password, | ||||
|                     QString sshdUsername, | ||||
|                     QString sshdPassword ) | ||||
|                     const QString& username, | ||||
|                     const QString& password, | ||||
|                     const QString& sshdUsername, | ||||
|                     const QString& sshdPassword ) | ||||
|     : Calamares::Job() | ||||
|     , m_featureSshd( featureSshd ) | ||||
|     , m_cmdPasswd( cmdPasswd ) | ||||
|     , m_cmdUsermod( cmdUsermod ) | ||||
|     , m_cmdSshd( cmdSshd ) | ||||
|     , m_cmdSshdUseradd( cmdSshdUseradd ) | ||||
|     , m_isSshEnabled( isSshEnabled ) | ||||
| @@ -47,16 +51,22 @@ UsersJob::exec() | ||||
|     using namespace std; | ||||
|  | ||||
|     QList< QPair< QStringList, QString > > commands = { | ||||
|         { { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" }, | ||||
|         { { "sh", "-c", m_cmdSshd }, QString() }, | ||||
|         { { "sh", "-c", m_cmdUsermod }, m_username + "\n" } | ||||
|     }; | ||||
|  | ||||
|     commands.append( { { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" } ); | ||||
|  | ||||
|     if ( m_featureSshd ) | ||||
|     { | ||||
|         commands.append( { { "sh", "-c", m_cmdSshd }, QString() } ); | ||||
|  | ||||
|         if ( m_isSshEnabled ) | ||||
|         { | ||||
|             commands.append( { { "sh", "-c", m_cmdSshdUseradd + " " + m_sshdUsername }, QString() } ); | ||||
|             commands.append( | ||||
|                 { { "sh", "-c", m_cmdPasswd + " " + m_sshdUsername }, m_sshdPassword + "\n" + m_sshdPassword + "\n" } ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     foreach ( auto command, commands ) | ||||
|     { | ||||
|   | ||||
| @@ -8,14 +8,16 @@ class UsersJob : public Calamares::Job | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     UsersJob( QString cmdPasswd, | ||||
|               QString cmdSshd, | ||||
|               QString cmdSshdUseradd, | ||||
|     UsersJob( bool featureSshd, | ||||
|               const QString& cmdPasswd, | ||||
|               const QString& cmdUsermod, | ||||
|               const QString& cmdSshd, | ||||
|               const QString& cmdSshdUseradd, | ||||
|               bool isSshEnabled, | ||||
|               QString username, | ||||
|               QString password, | ||||
|               QString sshdUsername, | ||||
|               QString sshdPassword ); | ||||
|               const QString& username, | ||||
|               const QString& password, | ||||
|               const QString& sshdUsername, | ||||
|               const QString& sshdPassword ); | ||||
|  | ||||
|     QString prettyName() const override; | ||||
|     Calamares::JobResult exec() override; | ||||
| @@ -23,7 +25,9 @@ public: | ||||
|     Calamares::JobList createJobs(); | ||||
|  | ||||
| private: | ||||
|     bool m_featureSshd; | ||||
|     QString m_cmdPasswd; | ||||
|     QString m_cmdUsermod; | ||||
|     QString m_cmdSshd; | ||||
|     QString m_cmdSshdUseradd; | ||||
|     bool m_isSshEnabled; | ||||
|   | ||||
| @@ -1,95 +0,0 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.10 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import org.kde.kirigami 2.7 as Kirigami | ||||
| import QtGraphicalEffects 1.0 | ||||
| import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
|     anchors.right: parent.right | ||||
|     width: parent.width | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: description | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: "Set the numeric password of your user. The lockscreen will" + | ||||
|               " ask for this PIN. This is <i>not</i> the PIN of your SIM" + | ||||
|               " card. Make sure to remember it." | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: userPin | ||||
|         anchors.top: description.bottom | ||||
|         placeholderText: qsTr("PIN") | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validatePin(userPin, userPinRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         /* Let the virtual keyboard change to digits only */ | ||||
|         inputMethodHints: Qt.ImhDigitsOnly | ||||
|         onActiveFocusChanged: { | ||||
|             if(activeFocus) { | ||||
|                 Qt.inputMethod.update(Qt.ImQueryInput) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: userPinRepeat | ||||
|         anchors.top: userPin.bottom | ||||
|         placeholderText: qsTr("PIN (repeat)") | ||||
|         inputMethodHints: Qt.ImhDigitsOnly | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validatePin(userPin, userPinRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Text { | ||||
|         anchors.top: userPinRepeat.bottom | ||||
|         id: errorText | ||||
|         visible: false | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: errorText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Continue") | ||||
|         onClicked: { | ||||
|             if (validatePin(userPin, userPinRepeat, errorText)) { | ||||
|                 config.userPassword = userPin.text; | ||||
|                 navTo("ssh_confirm"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -19,7 +19,7 @@ Item { | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: welcomeText | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
| @@ -37,29 +37,29 @@ Item { | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: enableButton | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: welcomeText.bottom | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Enable") | ||||
|         onClicked: { | ||||
|             config.isFdeEnabled = true; | ||||
|             navTo("fde_pass"); | ||||
|             navNext(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: enableButton.bottom | ||||
|         anchors.top: firstButton.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Disable") | ||||
|         onClicked: { | ||||
|             config.isFdeEnabled = false; | ||||
|             navTo("install_confirm"); | ||||
|             navNextFeature(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -73,7 +73,7 @@ Item { | ||||
|         onClicked: { | ||||
|             if (validatePassword(password, passwordRepeat, errorText)) { | ||||
|                 config.fdePassword = password.text; | ||||
|                 navTo("install_confirm"); | ||||
|                 navNext(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										59
									
								
								modules/mobile/fs_selection.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Undef <calamares@undef.tools> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.10 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import org.kde.kirigami 2.7 as Kirigami | ||||
| import QtGraphicalEffects 1.0 | ||||
| import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
|     anchors.right: parent.right | ||||
|     width: parent.width | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: "Select the filesystem for root partition. If unsure, leave the default." | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     ComboBox { | ||||
|         id: fsTypeCB | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|         height: 60 | ||||
|         editable: false | ||||
|         model: config.fsList | ||||
|         /* Save the current state on selection so it is there when the back button is pressed */ | ||||
|         onActivated: config.fsType = fsTypeCB.currentText; | ||||
|         Component.onCompleted: fsTypeCB.currentIndex = find( config.fsType, Qt.MatchContains ); | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: fsTypeCB.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Continue") | ||||
|         onClicked: { | ||||
|             config.fsType = fsTypeCB.currentText; | ||||
|             navNextFeature(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -19,25 +19,39 @@ Item { | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: welcomeText | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         anchors.topMargin: 25 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: "Once you hit 'install', the installation will begin. It will" + | ||||
|               " typically take a few minutes. Do not power off the device" + | ||||
|               " until it is done. Afterwards, it will reboot into the" + | ||||
|               " installed system." | ||||
|         text: (function() { | ||||
|             var ret = "Once you hit 'install', the installation will begin." + | ||||
|                 " It will typically take a few minutes. Do not power off the" + | ||||
|                 " device until it is done.<br>"; | ||||
|  | ||||
|         width: 500 | ||||
|             if (config.installFromExternalToInternal) { | ||||
|                 ret += "<b>After the installation, your device will shutdown" + | ||||
|                        " automatically. You must remove the external storage" + | ||||
|                        " (SD card) before booting again.</b>" + | ||||
|                        "<br><br>" + | ||||
|                        "Otherwise, your device will boot into the installer" + | ||||
|                        " again, and not into the installed system." | ||||
|             } else { | ||||
|                 ret += "Afterwards, it will reboot into the installed system."; | ||||
|             } | ||||
|  | ||||
|             return ret; | ||||
|         }()) | ||||
|  | ||||
|         width: 550 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: enableButton | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: welcomeText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 20 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Install") | ||||
|   | ||||
							
								
								
									
										64
									
								
								modules/mobile/install_target.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,64 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.10 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import org.kde.kirigami 2.7 as Kirigami | ||||
| import QtGraphicalEffects 1.0 | ||||
| import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
|     anchors.right: parent.right | ||||
|     width: parent.width | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: "The installation was started from an external storage medium." + | ||||
|               "<br>" + | ||||
|               "You can either install to the same medium and overwrite the" + | ||||
|               " installer, or install to the internal storage.<br>" + | ||||
|               "<br>" + | ||||
|               "Where would you like to install " + config.osName + "?" | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Internal (eMMC)") | ||||
|         onClicked: { | ||||
|             config.installFromExternalToInternal = true; | ||||
|             navNext(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: firstButton.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("External (SD card)") | ||||
|         onClicked: { | ||||
|             config.installFromExternalToInternal = false; | ||||
|             navNextFeature(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										58
									
								
								modules/mobile/install_target_confirm.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,58 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.10 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import org.kde.kirigami 2.7 as Kirigami | ||||
| import QtGraphicalEffects 1.0 | ||||
| import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
|     anchors.right: parent.right | ||||
|     width: parent.width | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
| 	text: "Are you sure that you want to overwrite the internal storage?" + | ||||
| 	      "<br><br>" + | ||||
| 	      "<b>All existing data on the device will be lost!</b>" | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Yes") | ||||
|         onClicked: { | ||||
|             navNext(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: firstButton.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("No") | ||||
|         onClicked: { | ||||
|             navBack(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,13 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # Commented out values are defaults. | ||||
| # All commands are running with 'sh -c'. | ||||
| --- | ||||
| # This entry exists only to keep the tests happy, remove it in | ||||
| # any production configuration. | ||||
| bogus: true | ||||
|  | ||||
| ####### | ||||
| ### Target OS information | ||||
| ####### | ||||
| @@ -11,12 +18,53 @@ | ||||
| ## User Interface name (e.g. Plasma Mobile) | ||||
| # userInterface: "(unknown)" | ||||
|  | ||||
| ## User Interface assumes that the password is numeric (as of writing, this is | ||||
| ## the case with Plasma Mobile and Phosh) | ||||
| # userPasswordNumeric: true | ||||
|  | ||||
| ## OS version | ||||
| # version: "(unknown)" | ||||
|  | ||||
| ## Default username (for which the password will be set) | ||||
| ## Ensure also cmdUsermod command matches the default user, so it can be changed if desired. | ||||
| # username: "user" | ||||
|  | ||||
| ## reserved usernames (for user_pass username prompt and ssh_credentials) | ||||
| # reservedUsernames: | ||||
| #        - adm | ||||
| #        - at | ||||
| #        - bin | ||||
| #        - colord | ||||
| #        - cron | ||||
| #        - cyrus | ||||
| #        - daemon | ||||
| #        - ftp | ||||
| #        - games | ||||
| #        - geoclue | ||||
| #        - guest | ||||
| #        - halt | ||||
| #        - lightdm | ||||
| #        - lp | ||||
| #        - mail | ||||
| #        - man | ||||
| #        - messagebus | ||||
| #        - news | ||||
| #        - nobody | ||||
| #        - ntp | ||||
| #        - operator | ||||
| #        - polkitd | ||||
| #        - postmaster | ||||
| #        - pulse | ||||
| #        - root | ||||
| #        - shutdown | ||||
| #        - smmsp | ||||
| #        - squid | ||||
| #        - sshd | ||||
| #        - sync | ||||
| #        - uucp | ||||
| #        - vpopmail | ||||
| #        - xfs | ||||
|  | ||||
| ####### | ||||
| ### Target device information | ||||
| ####### | ||||
| @@ -27,9 +75,47 @@ | ||||
| ## Name of the device (e.g. PinePhone) | ||||
| # device: "(unknown)" | ||||
|  | ||||
| ## Partition that will be formatted and mounted (optionally with FDE) for the rootfs | ||||
| ## Partition that will be formatted and mounted (optionally with FDE) for the | ||||
| ## rootfs | ||||
| # targetDeviceRoot: "/dev/unknown" | ||||
|  | ||||
| ## Partition that will be formatted and mounted (optionally with FDE) for the | ||||
| ## rootfs, on internal storage. The installer OS must not set this, if it was | ||||
| ## booted from the internal storage (this is not checked in the mobile | ||||
| ## module!). | ||||
| ## If this is set, the user gets asked whether they want to install on internal | ||||
| ## or external storage. If the user chose internal storage, | ||||
| ## cmdInternalStoragePrepare (see below) runs before this partition gets | ||||
| ## formatted (see below). A note is displayed, that the device is powered off | ||||
| ## after installation and that the user should remove the external storage | ||||
| ## medium. So you need to adjust the installer OS to poweroff in that case, and | ||||
| ## not reboot. See postmarketos-ondev.git for reference. | ||||
| # targetDeviceRootInternal: "" | ||||
|  | ||||
| ###### | ||||
| ### Installer Features | ||||
| ###### | ||||
|  | ||||
| ## Ask whether sshd should be enabled or not. If enabled, add a dedicated ssh | ||||
| ## user with proper username and password and suggest to change to key-based | ||||
| ## authentication after installation. | ||||
| # featureSshd: true | ||||
|  | ||||
| ## Ask the user, which filesystem to use. | ||||
| # featureFsType: false | ||||
| ## Filesystems that the user can choose from. | ||||
| #fsModel: | ||||
| #        - ext4 | ||||
| #        - f2fs | ||||
| #        - btrfs | ||||
| ## Default filesystem to display in the dialog. If featureFsType is disabled, | ||||
| ## this gets used without asking the user. | ||||
| # defaultFs: ext4 | ||||
|  | ||||
| ## Start Qt's virtual keyboard within the mobile module. Disable if you bring | ||||
| ## your own virtual keyboard (e.g. svkbd). | ||||
| # builtinVirtualKeyboard: true | ||||
|  | ||||
| ####### | ||||
| ### Commands running in the installer OS | ||||
| ####### | ||||
| @@ -46,16 +132,33 @@ | ||||
|  | ||||
| ## Format the rootfs with a file system | ||||
| ## Arguments: <device> | ||||
| # cmdMkfsRoot: "mkfs.ext4 -L 'unknownOS_root'" | ||||
| ## Btrfs: to allow snapshots to work on the root subvolume, it is recommended that this | ||||
| ## command be a script which will create a subvolume and make it default | ||||
| ## An example can be found at: | ||||
| ## https://gitlab.com/mobian1/calamares-settings-mobian/-/merge_requests/2/diffs#diff-content-dde34f5f1c89e3dea63608c553bbc452dedf428f | ||||
| # cmdMkfsRootBtrfs: "mkfs.btrfs -L 'unknownOS_root'" | ||||
| # cmdMkfsRootExt4: "mkfs.ext4 -L 'unknownOS_root'" | ||||
| # cmdMkfsRootF2fs: "mkfs.f2fs -l 'unknownOS_root'" | ||||
|  | ||||
| ## Mount the partition after formatting with file system | ||||
| ## Arguments: <device> <mountpoint> | ||||
| # cmdMount: "mount" | ||||
|  | ||||
| ## When user selects installation from external storage to internal storage | ||||
| ## (see targetDeviceRootInternal above), use this command to prepare the | ||||
| ## internal storage medium. The command must create a partition table with | ||||
| ## two partitions (boot, root) and fill the boot partition. See the | ||||
| ## ondev-internal-storage-prepare.sh in postmarketos-ondev as example. | ||||
| # cmdInternalStoragePrepare: "ondev-internal-storage-prepare" | ||||
|  | ||||
| ####### | ||||
| ### Commands running in the target OS (chroot) | ||||
| ####### | ||||
|  | ||||
| ## Change the username for the default user | ||||
| ## Stdin: username with \n | ||||
| # cmdUsermod: "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user" | ||||
|  | ||||
| ## Set the password for default user and sshd user | ||||
| ## Arguments: <username> | ||||
| ## Stdin: password twice, each time with \n | ||||
|   | ||||
| @@ -17,16 +17,46 @@ Page | ||||
|     property var screenPrevious: [] | ||||
|     property var titles: { | ||||
|         "welcome": null, /* titlebar disabled */ | ||||
|         "default_pin": "Lockscreen PIN", | ||||
|         "install_target": "Installation target", | ||||
|         "install_target_confirm": "Warning", | ||||
|         "user_pass": "User password", | ||||
|         "ssh_confirm": "SSH server", | ||||
|         "ssh_credentials": "SSH credentials", | ||||
|         "fs_selection": "Root filesystem", | ||||
|         "fde_confirm": "Full disk encryption", | ||||
|         "fde_pass": "Full disk encryption", | ||||
|         "install_confirm": "Ready to install", | ||||
|         "wait": null | ||||
|     } | ||||
|     /* Only allow characters, that can be typed in with the initramfs on-screen keyboard | ||||
|      * (osk-sdl: see src/keyboard.cpp). FIXME: make configurable, but keep this as default? */ | ||||
|     property var features: [ | ||||
|         {"name": "welcome", | ||||
|          "screens": ["welcome"]}, | ||||
|         {"name": "installTarget", | ||||
|          "screens": ["install_target", "install_target_confirm"]}, | ||||
|         {"name": "userPassword", | ||||
|          "screens": ["user_pass"]}, | ||||
|         {"name": "sshd", | ||||
|          "screens": ["ssh_confirm", "ssh_credentials"]}, | ||||
|         {"name": "fsType", | ||||
|          "screens": ["fs_selection"]}, | ||||
|         {"name": "fde", | ||||
|          "screens": ["fde_confirm", "fde_pass"]}, | ||||
|         {"name": "installConfirm", | ||||
|          "screens": ["install_confirm", "wait"]} | ||||
|     ] | ||||
|     property var featureIdByScreen: (function() { | ||||
|         /* Put "features" above into an index of screen name -> feature id: | ||||
|          * featureIdByScreen = {"welcome": 0, "user_pass": 1, ...} */ | ||||
|         var ret = {}; | ||||
|         for (var i=0; i<features.length; i++) { | ||||
|             for (var j=0; j<features[i]["screens"].length; j++) { | ||||
|                 ret[ features[i]["screens"][j] ] = i; | ||||
|             } | ||||
|         } | ||||
|         return ret; | ||||
|     }()) | ||||
|     /* Only allow characters, that can be typed in with osk-sdl | ||||
|      * (src/keyboard.cpp). Details in big comment in validatePassword(). */ | ||||
|      property var allowed_chars: | ||||
|         /* layer 0 */ "abcdefghijklmnopqrstuvwxyz" + | ||||
|         /* layer 1 */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + | ||||
| @@ -112,6 +142,7 @@ Page | ||||
|     InputPanel { | ||||
|         id: inputPanel | ||||
|         y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height | ||||
|         visible: config.builtinVirtualKeyboard | ||||
|         anchors.left: parent.left | ||||
|         anchors.right: parent.right | ||||
|     } | ||||
| @@ -120,8 +151,13 @@ Page | ||||
|         id: timer | ||||
|     } | ||||
|  | ||||
|     function skipFeatureInstallTarget() { | ||||
|         return config.targetDeviceRootInternal == ""; | ||||
|     } | ||||
|  | ||||
|     /* Navigation related */ | ||||
|     function navTo(name, historyPush=true) { | ||||
|         console.log("Navigating to screen: " + name); | ||||
|         if (historyPush) | ||||
|             screenPrevious.push(screen); | ||||
|         screen = name; | ||||
| @@ -131,15 +167,71 @@ Page | ||||
|         Qt.inputMethod.hide(); | ||||
|     } | ||||
|     function navFinish() { | ||||
|         /* Show a waiting screen and wait a second (so it can render), then let | ||||
|          * MobileQmlViewStep.cpp::onLeave() create the (encrypted) partition | ||||
|          * and mount it. We can't have this as proper job due to ondev#18. */ | ||||
|         /* Show a waiting screen and wait a second (so it can render). The big | ||||
|          * comment in Config.cpp::runPartitionJobThenLeave() explains why this | ||||
|          * is necessary. */ | ||||
|         navTo("wait"); | ||||
|         timer.interval = 1000; | ||||
|         timer.repeat = false; | ||||
|         timer.triggered.connect(ViewManager.next); | ||||
|         timer.triggered.connect(function() { | ||||
|             /* Trigger Config.cpp::runPartitionJobThenLeave(). (We could expose | ||||
|              * the function directly with qmlRegisterSingletonType somehow, but | ||||
|              * I haven't seen existing Calamares code do that with the Config | ||||
|              * object, so just use the side effect of setting the variable, as | ||||
|              * done in existing code of Calamares modules.) */ | ||||
|             config.runPartitionJobThenLeave = 1 | ||||
|         }); | ||||
|         timer.start(); | ||||
|     } | ||||
|     function navNextFeature() { | ||||
|         var id; | ||||
|  | ||||
|         /* Skip disabled features */ | ||||
|         for (id = featureIdByScreen[screen] + 1; id < features.length; id++) { | ||||
|             /* First letter uppercase */ | ||||
|             var name = features[id]["name"]; | ||||
|             var nameUp = name.charAt(0).toUpperCase() + name.slice(1); | ||||
|  | ||||
|             /* Check config.Feature<Name> */ | ||||
|             var configOption = "feature" + nameUp; | ||||
|             if (config[configOption] === false) { | ||||
|                 console.log("Skipping feature (disabled in config): " + name); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             /* Check skipFeature<Name>() */ | ||||
|             var funcName = "skipFeature" + nameUp; | ||||
|             if (eval("typeof " + funcName) === "function" | ||||
|                 && eval(funcName + "()")) { | ||||
|                 console.log("Skipping feature (skip function): " + name); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         console.log("Navigating to feature: " + features[id]["name"]); | ||||
|         return navTo(features[id]["screens"][0]); | ||||
|     } | ||||
|     function navNext() { | ||||
|         var featureId = featureIdByScreen[screen]; | ||||
|         var featureScreens = features[featureId]["screens"]; | ||||
|         for (var i = 0; i<featureScreens.length; i++) { | ||||
|             /* Seek ahead until i is current screen */ | ||||
|             if (featureScreens[i] != screen) | ||||
|                 continue; | ||||
|  | ||||
|             /* Navigate to next screen in same feature */ | ||||
|             if (i + 1 < featureScreens.length) { | ||||
|                 var screenNext = featureScreens[i + 1]; | ||||
|                 return navTo(screenNext); | ||||
|             } | ||||
|  | ||||
|             /* Screen is last in feature */ | ||||
|             return navNextFeature(); | ||||
|         } | ||||
|         console.log("ERROR: navNext() failed for screen: " + screen); | ||||
|     } | ||||
|     function navBack() { | ||||
|         if (screenPrevious.length) | ||||
|             return navTo(screenPrevious.pop(), false); | ||||
| @@ -161,7 +253,7 @@ Page | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /* Input validation: user-screens (default_pin, ssh_credentials) */ | ||||
|     /* Input validation: user-screens (fde_pass, user_pass, ssh_credentials) */ | ||||
|     function validatePin(userPin, userPinRepeat, errorText) { | ||||
|         var pin = userPin.text; | ||||
|         var repeat = userPinRepeat.text; | ||||
| @@ -186,44 +278,9 @@ Page | ||||
|  | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|     function validateSshdUsername(username, errorText) { | ||||
|     function validateUsername(username, errorText, extraReservedUsernames = []) { | ||||
|         var name = username.text; | ||||
|         var reserved = [ /* FIXME: make configurable */ | ||||
|             config.username, | ||||
|             "adm", | ||||
|             "at ", | ||||
|             "bin", | ||||
|             "colord", | ||||
|             "cron", | ||||
|             "cyrus", | ||||
|             "daemon", | ||||
|             "ftp", | ||||
|             "games", | ||||
|             "geoclue", | ||||
|             "guest", | ||||
|             "halt", | ||||
|             "lightdm", | ||||
|             "lp", | ||||
|             "mail", | ||||
|             "man", | ||||
|             "messagebus", | ||||
|             "news", | ||||
|             "nobody", | ||||
|             "ntp", | ||||
|             "operator", | ||||
|             "polkitd", | ||||
|             "postmaster", | ||||
|             "pulse", | ||||
|             "root", | ||||
|             "shutdown", | ||||
|             "smmsp", | ||||
|             "squid", | ||||
|             "sshd", | ||||
|             "sync", | ||||
|             "uucp", | ||||
|             "vpopmail", | ||||
|             "xfs", | ||||
|         ] | ||||
|         var reserved = config.reservedUsernames.concat(extraReservedUsernames); | ||||
|  | ||||
|         /* Validate characters */ | ||||
|         for (var i = 0; i < name.length; i++) { | ||||
| @@ -247,12 +304,16 @@ Page | ||||
|             if (name == reserved[i]) | ||||
|                 return validationFailure(errorText, "Username '" + | ||||
|                                                     reserved[i] + | ||||
|                                                     "' is reserved.") | ||||
|                                                     "' is reserved."); | ||||
|         } | ||||
|  | ||||
|         /* Passed */ | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|  | ||||
|     function validateSshdUsername(username, errorText) { | ||||
|         return validateUsername(username, errorText, [config.username]); | ||||
|     } | ||||
|     function validateSshdPassword(password, passwordRepeat, errorText) { | ||||
|         var pass = password.text; | ||||
|         var repeat = passwordRepeat.text; | ||||
| @@ -260,10 +321,10 @@ Page | ||||
|         if (pass == "") | ||||
|             return validationFailure(errorText); | ||||
|  | ||||
|         if (pass.length < 8) | ||||
|         if (pass.length < 6) | ||||
|             return validationFailure(errorText, | ||||
|                                      "Too short: needs at least 8" + | ||||
|                                      " characters."); | ||||
|                                      "Too short: needs at least 6" + | ||||
|                                      " digits/characters."); | ||||
|  | ||||
|         if (repeat == "") | ||||
|             return validationFailure(errorText); | ||||
| @@ -273,8 +334,6 @@ Page | ||||
|  | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|  | ||||
|     /* Input validation: fde_pass */ | ||||
|     function check_chars(input) { | ||||
|         for (var i = 0; i < input.length; i++) { | ||||
|             if (allowed_chars.indexOf(input[i]) == -1) | ||||
| @@ -297,18 +356,28 @@ Page | ||||
|         if (pass == "") | ||||
|             return validationFailure(errorText); | ||||
|  | ||||
|         /* This function gets called for the FDE password and for the user | ||||
|          * password. As of writing, all distributions shipping the mobile | ||||
|          * module are using osk-sdl to type in the FDE password after the | ||||
|          * installation, and another keyboard after booting up, to type in the | ||||
|          * user password. The osk-sdl password has the same keys as | ||||
|          * squeekboard's default layout, and other keyboards should be able to | ||||
|          * type these characters in as well. For now, verify that the password | ||||
|          * only contains characters that can be typed in by osk-sdl. If you | ||||
|          * need this to be more sophisticated, feel free to submit patches to | ||||
|          * make this more configurable. */ | ||||
|         if (!check_chars(pass)) | ||||
|             return validationFailure(errorText, | ||||
|                                      "The password must only contain" + | ||||
|                                      " these characters, others cannot be" + | ||||
|                                      " typed in at boot time:\n" + | ||||
|                                      " these characters, others can possibly" + | ||||
|                                      " not be typed in after installation:\n" + | ||||
|                                      "\n" + | ||||
|                                      allowed_chars_multiline()); | ||||
|  | ||||
|         if (pass.length < 8) | ||||
|         if (pass.length < 6) | ||||
|             return validationFailure(errorText, | ||||
|                                      "Too short: needs at least 8" + | ||||
|                                      " characters."); | ||||
|                                      "Too short: needs at least 6" + | ||||
|                                      " digits/characters."); | ||||
|  | ||||
|         if (repeat == "") | ||||
|             return validationFailure(errorText); | ||||
|   | ||||
| @@ -4,9 +4,13 @@ | ||||
|  | ||||
|   <file>welcome.qml</file> | ||||
|  | ||||
|   <file>default_pin.qml</file> <!-- default user: pin --> | ||||
|   <file>install_target.qml</file> <!-- install from external to internal? --> | ||||
|   <file>install_target_confirm.qml</file> <!-- overwrite internal storage? --> | ||||
|  | ||||
|   <file>user_pass.qml</file> <!-- default user: username, password --> | ||||
|   <file>ssh_confirm.qml</file> <!-- sshd: enable or not? --> | ||||
|   <file>ssh_credentials.qml</file> <!-- sshd user: username, password --> | ||||
|   <file>fs_selection.qml</file> <!-- filesystem selection --> | ||||
|  | ||||
|   <file>fde_confirm.qml</file> <!-- enable FDE or not? --> | ||||
|   <file>fde_pass.qml</file> <!-- FDE password (optional) --> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ Item { | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: welcomeText | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
| @@ -40,29 +40,29 @@ Item { | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: enableButton | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: welcomeText.bottom | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Enable") | ||||
|         onClicked: { | ||||
|             config.isSshEnabled = true; | ||||
|             navTo("ssh_credentials"); | ||||
|             navNext(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: enableButton.bottom | ||||
|         anchors.top: firstButton.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Disable") | ||||
|         onClicked: { | ||||
|             config.isSshEnabled = false; | ||||
|             navTo("fde_confirm"); | ||||
|             navNextFeature(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -100,7 +100,7 @@ Item { | ||||
|                 config.sshdUsername = username.text; | ||||
|                 config.sshdPassword = password.text; | ||||
|  | ||||
|                 navTo("fde_confirm"); | ||||
|                 navNext(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										143
									
								
								modules/mobile/user_pass.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,143 @@ | ||||
| /* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org> | ||||
|  * SPDX-License-Identifier: GPL-3.0-or-later */ | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.10 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import org.kde.kirigami 2.7 as Kirigami | ||||
| import QtGraphicalEffects 1.0 | ||||
| import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     property var passPlaceholder: (config.userPasswordNumeric | ||||
|                                ? "PIN" | ||||
|                                : "Password") | ||||
|     property var hints: (config.userPasswordNumeric | ||||
|                          ? Qt.ImhDigitsOnly | ||||
|                          : Qt.ImhPreferLowercase) | ||||
|     property var validatePassFunc: (config.userPasswordNumeric | ||||
|                                 ? validatePin | ||||
|                                 : validatePassword); | ||||
|  | ||||
|     property var validateNameFunc: validateUsername; | ||||
|  | ||||
|  | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
|     anchors.right: parent.right | ||||
|     width: parent.width | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: usernameDescription | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: (function() { | ||||
|             return "Set the username of your user. The default" + | ||||
|                    " username is \"" + config.username + "\"."; | ||||
|         }()) | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: username | ||||
|         anchors.top: usernameDescription.bottom | ||||
|         placeholderText: qsTr("Username") | ||||
|         onTextChanged: validateNameFunc(username, errorText) | ||||
|         text: config.username | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Text { | ||||
|         id: userPassDescription | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: username.bottom | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: (function() { | ||||
|             if (config.userPasswordNumeric) { | ||||
|                 return "Set the numeric password of your user. The" + | ||||
|                        " lockscreen will ask for this PIN. This is" + | ||||
|                        " <i>not</i> the PIN of your SIM card. Make sure to" + | ||||
|                        " remember it."; | ||||
|             } else { | ||||
|                 return "Set the password of your user. The lockscreen will" + | ||||
|                       " ask for this password. Make sure to remember it."; | ||||
|             } | ||||
|         }()) | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: userPass | ||||
|         anchors.top: userPassDescription.bottom | ||||
|         placeholderText: qsTr(passPlaceholder) | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         /* Let the virtual keyboard change to digits only */ | ||||
|         inputMethodHints: hints | ||||
|         onActiveFocusChanged: { | ||||
|             if(activeFocus) { | ||||
|                 Qt.inputMethod.update(Qt.ImQueryInput) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: userPassRepeat | ||||
|         anchors.top: userPass.bottom | ||||
|         placeholderText: qsTr(passPlaceholder + " (repeat)") | ||||
|         inputMethodHints: hints | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Text { | ||||
|         anchors.top: userPassRepeat.bottom | ||||
|         id: errorText | ||||
|         visible: false | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: errorText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Continue") | ||||
|         onClicked: { | ||||
|             if (validatePassFunc(userPass, userPassRepeat, errorText) && validateNameFunc(username, errorText)) { | ||||
|                 config.userPassword = userPass.text; | ||||
|                 config.username = username.text; | ||||
|                 navNext(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -38,7 +38,7 @@ Page | ||||
|             anchors.topMargin: 150 | ||||
|             wrapMode: Text.WordWrap | ||||
|             text: "Formatting and mounting target partition. This may" + | ||||
|                   " take up to 20 seconds, please be patient." | ||||
|                   " take up to ten minutes, please be patient." | ||||
|             width: 500 | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -34,7 +34,7 @@ Page | ||||
|                 source: "file:///usr/share/calamares/branding/default-mobile/logo.png" | ||||
|             } | ||||
|             Text { | ||||
|                 id: welcomeText | ||||
|                 id: mainText | ||||
|                 anchors.horizontalCenter: parent.horizontalCenter | ||||
|                 anchors.top: logo.bottom | ||||
|                 anchors.topMargin: 50 | ||||
| @@ -53,12 +53,12 @@ Page | ||||
|  | ||||
|             Button { | ||||
|                 anchors.horizontalCenter: parent.horizontalCenter | ||||
|                 anchors.top: welcomeText.bottom | ||||
|                 anchors.top: mainText.bottom | ||||
|                 anchors.topMargin: 50 | ||||
|                 width: 500 | ||||
|  | ||||
|                 text: qsTr("Continue") | ||||
|                 onClicked: navTo("default_pin") | ||||
|                 onClicked: navNext() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										20
									
								
								modules/os-freebsd/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| # The OS-FreeBSD module does "all the things" in a FreeBSD installation. | ||||
| # Since the other modules -- users, fstab, grub, pretty much all of them | ||||
| # -- are Linux-specific, it doesn't make much sense to fork each of them | ||||
| # or provide alternatives, so instead we have one module that completes | ||||
| # a FreeBSD installation based on the GlobalStorage values set by | ||||
| # Calamares viewmodules. | ||||
| # | ||||
| #   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: GPL-3.0-or-later | ||||
| #   License-Filename: LICENSE | ||||
| # | ||||
|  | ||||
| calamares_add_plugin( os-freebsd | ||||
|     TYPE job | ||||
|     EXPORT_MACRO PLUGINDLLEXPORT_PRO | ||||
|     SOURCES | ||||
|         FreeBSDJob.cpp | ||||
|     SHARED_LIB | ||||
|     NO_CONFIG | ||||
| ) | ||||
							
								
								
									
										58
									
								
								modules/os-freebsd/FreeBSDJob.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,58 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  *   License-Filename: LICENSE | ||||
|  */ | ||||
|  | ||||
| #include "FreeBSDJob.h" | ||||
|  | ||||
| #include "CalamaresVersion.h" | ||||
| #include "GlobalStorage.h" | ||||
| #include "JobQueue.h" | ||||
| #include "utils/Logger.h" | ||||
|  | ||||
| #include <QDateTime> | ||||
| #include <QProcess> | ||||
| #include <QThread> | ||||
|  | ||||
|  | ||||
| FreeBSDJob::FreeBSDJob( QObject* parent ) | ||||
|     : Calamares::CppJob( parent ) | ||||
| { | ||||
| } | ||||
|  | ||||
|  | ||||
| FreeBSDJob::~FreeBSDJob() {} | ||||
|  | ||||
|  | ||||
| QString | ||||
| FreeBSDJob::prettyName() const | ||||
| { | ||||
|     return tr( "FreeBSD Installation Job" ); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FreeBSDJob::exec() | ||||
| { | ||||
|     emit progress( 0.1 ); | ||||
|     cDebug() << "[FREEBSD]"; | ||||
|  | ||||
|     Calamares::JobQueue::instance()->globalStorage()->debugDump(); | ||||
|     emit progress( 0.5 ); | ||||
|  | ||||
|     QThread::sleep( 3 ); | ||||
|     emit progress( 1.0 ); | ||||
|  | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void | ||||
| FreeBSDJob::setConfigurationMap( const QVariantMap& configurationMap ) | ||||
| { | ||||
|     // TODO: actually fetch something from that configuration | ||||
|     m_configurationMap = configurationMap; | ||||
| } | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DEFINITION( FreeBSDJobFactory, registerPlugin< FreeBSDJob >(); ) | ||||
							
								
								
									
										39
									
								
								modules/os-freebsd/FreeBSDJob.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  *   License-Filename: LICENSE | ||||
|  */ | ||||
|  | ||||
| #ifndef FREEBSDJOB_H | ||||
| #define FREEBSDJOB_H | ||||
|  | ||||
| #include "CppJob.h" | ||||
| #include "DllMacro.h" | ||||
| #include "utils/PluginFactory.h" | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QVariantMap> | ||||
|  | ||||
|  | ||||
| class PLUGINDLLEXPORT FreeBSDJob : public Calamares::CppJob | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit FreeBSDJob( QObject* parent = nullptr ); | ||||
|     virtual ~FreeBSDJob() override; | ||||
|  | ||||
|     QString prettyName() const override; | ||||
|  | ||||
|     Calamares::JobResult exec() override; | ||||
|  | ||||
|     void setConfigurationMap( const QVariantMap& configurationMap ) override; | ||||
|  | ||||
| private: | ||||
|     QVariantMap m_configurationMap; | ||||
| }; | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DECLARATION( FreeBSDJobFactory ) | ||||
|  | ||||
| #endif  // FREEBSDJOB_H | ||||
							
								
								
									
										276
									
								
								modules/os-nixos/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,276 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # === This file is part of Calamares - <https://github.com/calamares> === | ||||
| # | ||||
| #   Calamares is free software: you can redistribute it and/or modify | ||||
| #   it under the terms of the GNU General Public License as published by | ||||
| #   the Free Software Foundation, either version 3 of the License, or | ||||
| #   (at your option) any later version. | ||||
| # | ||||
| #   Calamares is distributed in the hope that it will be useful, | ||||
| #   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| #   GNU General Public License for more details. | ||||
| # | ||||
| #   You should have received a copy of the GNU General Public License | ||||
| #   along with Calamares. If not, see <http://www.gnu.org/licenses/>. | ||||
| # | ||||
| #   SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org> | ||||
| #   SPDX-License-Identifier: GPL-3.0-or-later | ||||
| # | ||||
|  | ||||
| """ | ||||
| === NixOS Configuration | ||||
|  | ||||
| NixOS has its own "do all the things" configuration file which | ||||
| declaratively handles what things need to be done in the target | ||||
| system, and it has an existing tool to "execute" that declarative | ||||
| specification. This module takes configuration values set by | ||||
| Calamares viewmodules (e.g. the users module) and puts | ||||
| them into the configuration file in the target system, | ||||
| and then runs the necessary NixOS specific tools. | ||||
| """ | ||||
|  | ||||
| import libcalamares | ||||
| import os | ||||
| from time import gmtime, strftime, sleep | ||||
|  | ||||
| import gettext | ||||
| _ = gettext.translation("calamares-python", | ||||
|                         localedir=libcalamares.utils.gettext_path(), | ||||
|                         languages=libcalamares.utils.gettext_languages(), | ||||
|                         fallback=True).gettext | ||||
|  | ||||
|  | ||||
| # The following long **long** string is the entire text of | ||||
| # a nix-configuration file. It is cribbed from, and adapted from, | ||||
| # the sample file in https://github.com/itamar567/dotnix . | ||||
| # | ||||
| # We are going to substitute values into this text. However, | ||||
| # Python's .format() function wants parens { } around variable | ||||
| # names, and Nix's config file wants to use parens { } for block | ||||
| # structure. So we have a compromise format here: | ||||
| # | ||||
| # - Write the config file as you would normally, | ||||
| # - Write @@variable@@ instead of {variable} | ||||
| # | ||||
| # Some minor trickery later will massage this and substitute variables. | ||||
| # | ||||
| configuration_nix_sample = """# Nix configuration file | ||||
| { config, pkgs, ... }: | ||||
|  | ||||
| { | ||||
|   imports = | ||||
|     [ # Include the results of the hardware scan. | ||||
|       ./hardware-configuration.nix | ||||
|       ./command-not-found/command-not-found.nix | ||||
|     ]; | ||||
|  | ||||
|   # Use the systemd-boot EFI boot loader. | ||||
|   boot.loader.systemd-boot.enable = true; | ||||
|   boot.loader.efi.canTouchEfiVariables = true; | ||||
|  | ||||
|   # Use Zen Kernel | ||||
|   boot.kernelPackages = pkgs.linuxPackages_zen; | ||||
|  | ||||
|   networking.hostName = "@@hostname@@"; # Define your hostname. | ||||
|   # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant. | ||||
|  | ||||
|   # Set your time zone. | ||||
|   time.timeZone = "@@timezone@@"; | ||||
|  | ||||
|   # The global useDHCP flag is deprecated, therefore explicitly set to false here. | ||||
|   networking.useDHCP = false; | ||||
|   networking.interfaces.enp42s0.useDHCP = true; | ||||
|  | ||||
|   # Select internationalisation properties. | ||||
|   i18n.defaultLocale = "en_US.UTF-8"; | ||||
|  | ||||
|   # Configure X11 | ||||
|   services.xserver = { | ||||
|     enable = true; | ||||
|     windowManager.i3 = { | ||||
|       enable = true; | ||||
|       package = pkgs.i3-gaps; | ||||
|     }; | ||||
|  | ||||
|     # Set i3 to the default session in the display manager | ||||
|     displayManager.defaultSession = "none+i3"; | ||||
|   }; | ||||
|  | ||||
|   # SSH fix | ||||
|   programs.ssh.askPassword = pkgs.lib.mkForce ""; | ||||
|  | ||||
|   # Enable CUPS to print documents. | ||||
|   services.printing.enable = true; | ||||
|  | ||||
|   # Enable sound. | ||||
|   sound.enable = true; | ||||
|   hardware.pulseaudio.enable = true; | ||||
|  | ||||
|   # Define a user account. Don't forget to set a password with ‘passwd’. | ||||
|   users.users.username = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" "libvirtd" ]; | ||||
|   }; | ||||
|  | ||||
|   # Disable password for sudo | ||||
|   security.sudo.extraRules= [{ | ||||
|     groups = [ "wheel" ]; | ||||
|     commands = [{ | ||||
|         command = "ALL" ; | ||||
|         options= [ "NOPASSWD" ]; | ||||
|     }]; | ||||
|   }]; | ||||
|  | ||||
|   # Set ZSH as the default shell | ||||
|   users.defaultUserShell = pkgs.zsh; | ||||
|  | ||||
|   # clean /tmp on boot | ||||
|   boot.cleanTmpDir=true; | ||||
|  | ||||
|   # Config packages | ||||
|   nixpkgs.config = { | ||||
|     allowUnfree = true; | ||||
|  | ||||
|     chromium = { | ||||
|       enableWideVine = true; | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|    # Automatically upgrade the system | ||||
|    # This service is a modified version of https://github.com/NixOS/nixpkgs/blob/nixos-21.05/nixos/modules/tasks/auto-upgrade.nix#L122 | ||||
|    systemd = { | ||||
|      services.nixos-upgrade = { | ||||
|        description = "NixOS Upgrade"; | ||||
|  | ||||
|        # We use --upgrade, so we need internet access | ||||
|        wants = [ "network-online.target" ]; | ||||
|  | ||||
|        restartIfChanged = false; | ||||
|        unitConfig.X-StopOnRemoval = false; | ||||
|  | ||||
|        serviceConfig.Type = "oneshot"; | ||||
|  | ||||
|        environment = config.nix.envVars // { | ||||
|          inherit (config.environment.sessionVariables) NIX_PATH; | ||||
|          HOME = "/root"; | ||||
|        } // config.networking.proxy.envVars; | ||||
|  | ||||
|        path = with pkgs; [ | ||||
|          coreutils | ||||
|          gnutar | ||||
|          xz.bin | ||||
|          gzip | ||||
|          gitMinimal | ||||
|          config.nix.package.out | ||||
|        ]; | ||||
|  | ||||
|        script = let | ||||
|          nixos-rebuild = | ||||
|            "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; | ||||
|        in '' | ||||
|          ${nixos-rebuild} boot --upgrade | ||||
|          booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})" | ||||
|          built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" | ||||
|          if [ "$booted" = "$built" ]; then | ||||
|            ${nixos-rebuild} switch | ||||
|          fi | ||||
|        ''; | ||||
|      }; | ||||
|  | ||||
|      # To start the service at boot, we will use a systemd timer | ||||
|      timers.nixos-upgrade = { | ||||
|        wantedBy = [ "timers.target" ]; | ||||
|        partOf = [ "nixos-upgrade.service" ]; | ||||
|        timerConfig.OnBootSec = "5s"; | ||||
|      }; | ||||
|    }; | ||||
|  | ||||
|   # Some programs need SUID wrappers, can be configured further or are | ||||
|   # started in user sessions. | ||||
|   programs.mtr.enable = true; | ||||
|   programs.gnupg.agent = { | ||||
|     enable = true; | ||||
|     enableSSHSupport = true; | ||||
|   }; | ||||
|  | ||||
|   # Enable the OpenSSH daemon. | ||||
|   services.openssh.enable = true; | ||||
|  | ||||
|   # Open ports in the firewall. | ||||
|   networking.firewall.enable = false; | ||||
|  | ||||
|   # This value determines the NixOS release from which the default | ||||
|   # settings for stateful data, like file locations and database versions | ||||
|   # on your system were taken. It‘s perfectly fine and recommended to leave | ||||
|   # this value at the release version of the first install of this system. | ||||
|   # Before changing this value read the documentation for this option | ||||
|   # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). | ||||
|   system.stateVersion = "20.09"; # Did you read the comment? | ||||
| } | ||||
| """ | ||||
|  | ||||
|  | ||||
| def pretty_name(): | ||||
|     return _("NixOS Configuration.") | ||||
|  | ||||
|  | ||||
| def catenate(d, key, *values): | ||||
|     """ | ||||
|     Sets @p d[key] to the string-concatenation of @p values | ||||
|     if none of the values are None. | ||||
|  | ||||
|     This can be used to set keys conditionally based on | ||||
|     the values being found. | ||||
|     """ | ||||
|     if [v for v in values if v is None]: | ||||
|         return | ||||
|  | ||||
|     d[key] = "".join(values) | ||||
|  | ||||
|  | ||||
| def run(): | ||||
|     """NixOS Configuration.""" | ||||
|  | ||||
|     gs = libcalamares.globalstorage | ||||
|     text = configuration_nix_sample | ||||
|  | ||||
|     # Collect variables to substitute into the main text | ||||
|     variables = dict() | ||||
|     catenate(variables, "hostname", gs.value("hostname")) | ||||
|     catenate(variables, "timezone", gs.value("locationRegion"), "/", gs.value("locationZone")) | ||||
|  | ||||
|     # Check that all variables are used | ||||
|     for key in variables.keys(): | ||||
|         pattern = "@@{key}@@".format(key=key) | ||||
|         if not pattern in text: | ||||
|             libcalamares.utils.warning("Variable '{key}' is not used.".format(key=key)) | ||||
|  | ||||
|     # Check that all patterns exist | ||||
|     import re | ||||
|     variable_pattern = re.compile("@@\w+@@") | ||||
|     for match in variable_pattern.finditer(text): | ||||
|         variable_name = text[match.start()+2:match.end()-2] | ||||
|         if not variable_name in variables: | ||||
|             libcalamares.utils.warning("Variable '{key}' is used but not defined.".format(key=variable_name)) | ||||
|  | ||||
|     # Do the substitutions | ||||
|     for key in variables.keys(): | ||||
|         pattern = "@@{key}@@".format(key=key) | ||||
|         text = text.replace(pattern, str(variables[key])) | ||||
|  | ||||
|     # Write the result to a temp-file, then run the main tool. | ||||
|     # There is no progress reporting from the tool, so it's going | ||||
|     # to seem like the module is hanging (see issue #1740). | ||||
|     configuration_filename = "/tmp/configuration.nix" | ||||
|     with open(configuration_filename, "w") as f: | ||||
|         f.write(text) | ||||
|  | ||||
|     libcalamares.job.setprogress(0.1) | ||||
|     libcalamares.utils.check_target_env_call(["nix", configuration_filename]) | ||||
|  | ||||
|     # To indicate an error, return a tuple of: | ||||
|     # (message, detailed-error-message) | ||||
|     return None | ||||
							
								
								
									
										11
									
								
								modules/os-nixos/module.desc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # The NixOS module writes a nix-configuration file and then calls | ||||
| # the Nix configuration tool to do the actual work of building | ||||
| # the target system. | ||||
| --- | ||||
| type:       "job" | ||||
| name:       "os-nixos" | ||||
| interface:  "python" | ||||
| script:     "main.py" | ||||
							
								
								
									
										6
									
								
								modules/os-nixos/tests/1.global
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| --- | ||||
| hostname: my-nix-host | ||||
| locationRegion: Asia | ||||
| locationZone: Kolkata | ||||
							
								
								
									
										130
									
								
								modules/refind/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,130 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # === This file is part of Calamares - <https://calamares.io> === | ||||
| # | ||||
| #   SPDX-FileCopyrightText: 2021 Anke Boersma <demm@kaosx.us> | ||||
| #   SPDX-License-Identifier: GPL-3.0-or-later | ||||
| # | ||||
| #   Calamares is Free Software: see the License-Identifier above. | ||||
| # | ||||
|  | ||||
| import libcalamares | ||||
|  | ||||
| import os | ||||
| import subprocess | ||||
|  | ||||
| from libcalamares.utils import check_target_env_call | ||||
|  | ||||
| import gettext | ||||
| _ = gettext.translation("calamares-python", | ||||
|                         localedir=libcalamares.utils.gettext_path(), | ||||
|                         languages=libcalamares.utils.gettext_languages(), | ||||
|                         fallback=True).gettext | ||||
|  | ||||
|  | ||||
| def pretty_name(): | ||||
|     return _("Install rEFInd.") | ||||
|  | ||||
|  | ||||
| def get_uuid(): | ||||
|     partitions = libcalamares.globalstorage.value("partitions") | ||||
|     for partition in partitions: | ||||
|         if partition["mountPoint"] == "/": | ||||
|             libcalamares.utils.debug(partition["uuid"]) | ||||
|             return partition["uuid"] | ||||
|     return None | ||||
|  | ||||
|  | ||||
| def update_conf(uuid, conf_path): | ||||
|     """ | ||||
|     Updates the created rEFInd configuration file based on given parameters. | ||||
|     """ | ||||
|     partitions = libcalamares.globalstorage.value("partitions") | ||||
|  | ||||
|     kernel_params = ["quiet", "systemd.show_status=0"] | ||||
|     swap = None  # Partition UUID | ||||
|     swap_luks = None  # LUKS name | ||||
|     cryptdevice_params = [] | ||||
|     btrfs_params = "" | ||||
|  | ||||
|     for partition in partitions: | ||||
|         if partition["fs"] == "linuxswap" and not "luksMapperName" in partition: | ||||
|             swap = partition["uuid"] | ||||
|  | ||||
|         if partition["fs"] == "linuxswap" and "luksMapperName" in partition: | ||||
|             swap_luks = partition["luksMapperName"] | ||||
|  | ||||
|         if partition["mountPoint"] == "/" and "luksMapperName" in partition: | ||||
|             cryptdevice_params = [ | ||||
|                 "cryptdevice=UUID={!s}:{!s}".format(partition["luksUuid"], | ||||
|                                                     partition["luksMapperName"]), | ||||
|                 "root=/dev/mapper/{!s}".format(partition["luksMapperName"]), | ||||
|                 "resume=/dev/mapper/{!s}".format(partition["luksMapperName"]) | ||||
|             ] | ||||
|  | ||||
|         # rEFInd with a BTRFS root filesystem needs to be told | ||||
|         # about the root subvolume. | ||||
|         if partition["mountPoint"] == "/" and partition["fs"] == "btrfs": | ||||
|             btrfs_params = "rootflags=subvol=@" | ||||
|  | ||||
|     if cryptdevice_params: | ||||
|         kernel_params.extend(cryptdevice_params) | ||||
|     else: | ||||
|         kernel_params.append("root=UUID={!s}".format(uuid)) | ||||
|  | ||||
|     if swap: | ||||
|         kernel_params.append("resume=UUID={!s}".format(swap)) | ||||
|     if swap_luks: | ||||
|         kernel_params.append("resume=/dev/mapper/{!s}".format(swap_luks)) | ||||
|     if btrfs_params: | ||||
|         kernel_params.append(btrfs_params) | ||||
|  | ||||
|     with open(conf_path, "r") as refind_file: | ||||
|         filedata = [x.strip() for x in refind_file.readlines()] | ||||
|  | ||||
|     with open(conf_path, 'w') as refind_file: | ||||
|         for line in filedata: | ||||
|             if line.startswith('"Boot with standard options"'): | ||||
|                 line = '"Boot with standard options"    "rw {!s}"'.format(" ".join(kernel_params)) | ||||
|             refind_file.write(line + "\n") | ||||
|  | ||||
|  | ||||
| def efi_partitions(efi_boot_path): | ||||
|     """ | ||||
|     The (one) partition mounted on @p efi_boot_path, or an empty list. | ||||
|     """ | ||||
|     return [p for p in libcalamares.globalstorage.value("partitions") if p["mountPoint"] == efi_boot_path] | ||||
|  | ||||
|  | ||||
| def install_refind(): | ||||
|     install_path = libcalamares.globalstorage.value("rootMountPoint") | ||||
|     uuid = get_uuid() | ||||
|     conf_path = os.path.join(install_path, "boot/refind_linux.conf") | ||||
|  | ||||
|     # TODO: some distro's use /boot/efi , so maybe this needs to | ||||
|     #       become configurable (that depends on what rEFInd likes). | ||||
|     efi_boot_path = "/boot" | ||||
|  | ||||
|     # Might not have a /boot configured in the system at all; warn and don't operate | ||||
|     if not efi_partitions(efi_boot_path): | ||||
|         libcalamares.utils.warning("No partition mounted on {!s}".format(efi_boot_path)) | ||||
|         # This isn't returned as an error, but the installation | ||||
|         # probably won't boot because no bootloader was installed. | ||||
|         return None | ||||
|  | ||||
|     subprocess.call( | ||||
|         ["refind-install", "--root", "{!s}".format(install_path)]) | ||||
|     update_conf(uuid, conf_path) | ||||
|  | ||||
|  | ||||
| def run(): | ||||
|     """ | ||||
|     Optional entry for when providing bootloader choices. | ||||
|     Values taken from a packagechooser instance. | ||||
|     Module won't run, if value not present. | ||||
|     """ | ||||
|     bootchoice = libcalamares.globalstorage.value("packagechooser_bootchoice") | ||||
|  | ||||
|     if bootchoice == "refind": | ||||
|         return install_refind() | ||||
							
								
								
									
										11
									
								
								modules/refind/module.desc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| --- | ||||
| type:       "job" | ||||
| name:       "refind" | ||||
| interface:  "python" | ||||
| script:     "main.py" | ||||
| noconfig:   true | ||||
| # The partition module sets up the needed paths in | ||||
| # global storage, which is used to decide how to install. | ||||
| requiredModules: [ "partition" ] | ||||
							
								
								
									
										12
									
								
								modules/refind/refind.conf.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| --- | ||||
| ## This file should be present in the same directory as the EFISTUB kernel and initramfs files | ||||
| ## More info at http://www.rodsbooks.com/refind/linux.html , http://www.rodsbooks.com/efi-bootloaders/efistub.html | ||||
| ## File is not needed when rEFInd is installed with the `refind-install` option, it will be created automatically. | ||||
|  | ||||
| #"Boot with defaults"    "root=PARTUUID=XXXXXXXX rootfstype=XXXX rw add_efi_memmap" | ||||
| #"Boot to terminal"      "root=PARTUUID=XXXXXXXX rootfstype=XXXX rw add_efi_memmap systemd.unit=multi-user.target" | ||||
|  | ||||
|  | ||||
| @@ -1,3 +1,6 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # The slowpython module is .. just slow. It can be used | ||||
| # in testing to allow the slideshow time to run. | ||||
| --- | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # This is an example module for Python Job Modules. | ||||
| # | ||||
| # The slowpython module is just slow. It does produce | ||||
|   | ||||
							
								
								
									
										15
									
								
								modules/unpackfsc/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| # SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| calamares_add_plugin( unpackfsc | ||||
|     TYPE job | ||||
|     EXPORT_MACRO PLUGINDLLEXPORT_PRO | ||||
|     SOURCES | ||||
|         UnpackFSCJob.cpp | ||||
|         # The workers for differently-packed filesystems | ||||
|         Runners.cpp | ||||
|         FSArchiverRunner.cpp | ||||
|         TarballRunner.cpp | ||||
|         UnsquashRunner.cpp | ||||
|     SHARED_LIB | ||||
| ) | ||||
							
								
								
									
										117
									
								
								modules/unpackfsc/FSArchiverRunner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,117 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "FSArchiverRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| #include <utils/Runner.h> | ||||
|  | ||||
| #include <QProcess> | ||||
|  | ||||
| static constexpr const int chunk_size = 137; | ||||
| static const QString& | ||||
| toolName() | ||||
| { | ||||
|     static const QString name = QStringLiteral( "fsarchiver" ); | ||||
|     return name; | ||||
| } | ||||
|  | ||||
| void | ||||
| FSArchiverRunner::fsarchiverProgress( QString line ) | ||||
| { | ||||
|     m_since++; | ||||
|     // Typical line of output is this: | ||||
|     // -[00][ 99%][REGFILEM] /boot/thing | ||||
|     //      5   9           ^21 | ||||
|     if ( m_since >= chunk_size && line.length() > 21 && line[ 5 ] == '[' && line[ 9 ] == '%' ) | ||||
|     { | ||||
|         m_since = 0; | ||||
|         double p = double( line.mid( 6, 3 ).toInt() ) / 100.0; | ||||
|         const QString filename = line.mid( 22 ); | ||||
|         Q_EMIT progress( p, filename ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverRunner::checkPrerequisites( QString& fsarchiverExecutable ) const | ||||
| { | ||||
|     if ( !checkToolExists( toolName(), fsarchiverExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName() ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverRunner::checkDestination( QString& destinationPath ) const | ||||
| { | ||||
|     destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverDirRunner::run() | ||||
| { | ||||
|     QString fsarchiverExecutable; | ||||
|     if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|     QString destinationPath; | ||||
|     if ( auto res = checkDestination( destinationPath ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     Calamares::Utils::Runner r( | ||||
|         { fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restdir" ), m_source, destinationPath } ); | ||||
|     r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|     connect( &r, &decltype( r )::output, this, &FSArchiverDirRunner::fsarchiverProgress ); | ||||
|     return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) ); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverFSRunner::run() | ||||
| { | ||||
|     QString fsarchiverExecutable; | ||||
|     if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|     QString destinationPath; | ||||
|     if ( auto res = checkDestination( destinationPath ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     Calamares::Utils::Runner r( | ||||
|         { fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restfs" ), m_source, destinationPath } ); | ||||
|     r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|     connect( &r, &decltype( r )::output, this, &FSArchiverFSRunner::fsarchiverProgress ); | ||||
|     return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) ); | ||||
| } | ||||
							
								
								
									
										59
									
								
								modules/unpackfsc/FSArchiverRunner.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_FSARCHIVERRUNNER_H | ||||
| #define UNPACKFSC_FSARCHIVERRUNNER_H | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| /** @brief Base class for runners of FSArchiver | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverRunner : public Runner | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     using Runner::Runner; | ||||
|  | ||||
| protected Q_SLOTS: | ||||
|     void fsarchiverProgress( QString line ); | ||||
|  | ||||
| protected: | ||||
|     /** @brief Checks prerequisites, sets full path of fsarchiver in @p executable | ||||
|      */ | ||||
|     Calamares::JobResult checkPrerequisites( QString& executable ) const; | ||||
|     Calamares::JobResult checkDestination( QString& destinationPath ) const; | ||||
|  | ||||
|     int m_since = 0; | ||||
| }; | ||||
|  | ||||
| /** @brief Running FSArchiver in **dir** mode | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverDirRunner : public FSArchiverRunner | ||||
| { | ||||
| public: | ||||
|     using FSArchiverRunner::FSArchiverRunner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
| }; | ||||
|  | ||||
| /** @brief Running FSArchiver in **dir** mode | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverFSRunner : public FSArchiverRunner | ||||
| { | ||||
| public: | ||||
|     using FSArchiverRunner::FSArchiverRunner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										38
									
								
								modules/unpackfsc/Runners.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,38 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| #include <utils/CalamaresUtilsSystem.h> | ||||
| #include <utils/Logger.h> | ||||
|  | ||||
| #include <QFileInfo> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| Runner::Runner( const QString& source, const QString& destination ) | ||||
|     : m_source( source ) | ||||
|     , m_destination( destination ) | ||||
| { | ||||
| } | ||||
|  | ||||
| Runner::~Runner() { } | ||||
|  | ||||
| bool | ||||
| Runner::checkSourceExists() const | ||||
| { | ||||
|     QFileInfo fi( m_source ); | ||||
|     return fi.exists() && fi.isReadable(); | ||||
| } | ||||
|  | ||||
| bool | ||||
| Runner::checkToolExists( const QString& toolName, QString& fullPath ) | ||||
| { | ||||
|     fullPath = QStandardPaths::findExecutable( toolName ); | ||||
|     return !fullPath.isEmpty(); | ||||
| } | ||||
							
								
								
									
										48
									
								
								modules/unpackfsc/Runners.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,48 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_RUNNERS_H | ||||
| #define UNPACKFSC_RUNNERS_H | ||||
|  | ||||
| #include <Job.h> | ||||
|  | ||||
| class Runner : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     Runner( const QString& source, const QString& destination ); | ||||
|     ~Runner() override; | ||||
|  | ||||
|     virtual Calamares::JobResult run() = 0; | ||||
|  | ||||
|     /** @brief Check that the (configured) source file exists. | ||||
|      * | ||||
|      * Returns @c true if it's a file and readable. | ||||
|      */ | ||||
|     bool checkSourceExists() const; | ||||
|  | ||||
|     /** @brief Check that a named tool (executable) exists in the search path. | ||||
|      * | ||||
|      * Returns @c true if the tool is found and sets @p fullPath | ||||
|      * to the full path of that tool; returns @c false and clears | ||||
|      * @p fullPath otherwise. | ||||
|      */ | ||||
|     static bool checkToolExists( const QString& toolName, QString& fullPath ); | ||||
|  | ||||
| Q_SIGNALS: | ||||
|     // See Calamares Job::progress | ||||
|     void progress( qreal percent, const QString& message ); | ||||
|  | ||||
| protected: | ||||
|     QString m_source; | ||||
|     QString m_destination; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										86
									
								
								modules/unpackfsc/TarballRunner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,86 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "TarballRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| #include <utils/Runner.h> | ||||
| #include <utils/String.h> | ||||
|  | ||||
| #include <QString> | ||||
|  | ||||
| static constexpr const int chunk_size = 107; | ||||
|  | ||||
| Calamares::JobResult | ||||
| TarballRunner::run() | ||||
| { | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid tarball configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     const QString toolName = QStringLiteral( "tar" ); | ||||
|     QString tarExecutable; | ||||
|     if ( !checkToolExists( toolName, tarExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid tarball configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     // Get the stats (number of inodes) from the FS | ||||
|     { | ||||
|         m_total = 0; | ||||
|         Calamares::Utils::Runner r( { tarExecutable, QStringLiteral( "-tf" ), m_source } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         QObject::connect( &r, &decltype( r )::output, [ & ]( QString line ) { m_total++; } ); | ||||
|         /* ignored */ r.run(); | ||||
|     } | ||||
|     if ( m_total <= 0 ) | ||||
|     { | ||||
|         cWarning() << "No stats could be obtained from" << tarExecutable << "-tf" << m_source; | ||||
|     } | ||||
|  | ||||
|     // Now do the actual unpack | ||||
|     { | ||||
|         m_processed = 0; | ||||
|         m_since = 0; | ||||
|         Calamares::Utils::Runner r( | ||||
|             { tarExecutable, QStringLiteral( "-xpvf" ), m_source, QStringLiteral( "-C" ), destinationPath } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         connect( &r, &decltype( r )::output, this, &TarballRunner::tarballProgress ); | ||||
|         return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| TarballRunner::tarballProgress( QString line ) | ||||
| { | ||||
|     m_processed++; | ||||
|     m_since++; | ||||
|     if ( m_since > chunk_size ) | ||||
|     { | ||||
|         m_since = 0; | ||||
|         double p = m_total > 0 ? ( double( m_processed ) / double( m_total ) ) : 0.5; | ||||
|         Q_EMIT progress( p, tr( "Tarball extract file %1" ).arg( line ) ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								modules/unpackfsc/TarballRunner.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_TARBALLRUNNER_H | ||||
| #define UNPACKFSC_TARBALLRUNNER_H | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| /** @brief Use (GNU) tar for extracting a filesystem | ||||
|  * | ||||
|  */ | ||||
| class TarballRunner : public Runner | ||||
| { | ||||
| public: | ||||
|     using Runner::Runner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
|  | ||||
| protected Q_SLOTS: | ||||
|     void tarballProgress( QString line ); | ||||
|  | ||||
| private: | ||||
|     // Progress reporting | ||||
|     int m_total = 0; | ||||
|     int m_processed = 0; | ||||
|     int m_since = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										130
									
								
								modules/unpackfsc/UnpackFSCJob.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,130 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "UnpackFSCJob.h" | ||||
|  | ||||
| #include "FSArchiverRunner.h" | ||||
| #include "TarballRunner.h" | ||||
| #include "UnsquashRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| #include <utils/NamedEnum.h> | ||||
| #include <utils/RAII.h> | ||||
| #include <utils/Variant.h> | ||||
|  | ||||
| #include <memory> | ||||
|  | ||||
| static const NamedEnumTable< UnpackFSCJob::Type > | ||||
| typeNames() | ||||
| { | ||||
|     using T = UnpackFSCJob::Type; | ||||
|     // clang-format off | ||||
|     static const NamedEnumTable< T > names | ||||
|     { | ||||
|         { "none", T::None }, | ||||
|         { "fsarchiver", T::FSArchive }, | ||||
|         { "fsarchive", T::FSArchive }, | ||||
|         { "fsa", T::FSArchive }, | ||||
|         { "fsa-dir", T::FSArchive }, | ||||
|         { "fsa-block", T::FSArchiveFS }, | ||||
|         { "fsa-fs", T::FSArchiveFS }, | ||||
|         { "squashfs", T::Squashfs }, | ||||
|         { "squash", T::Squashfs }, | ||||
|         { "unsquash", T::Squashfs }, | ||||
|         { "tar", T::Tarball }, | ||||
|         { "tarball", T::Tarball }, | ||||
|         { "tgz", T::Tarball }, | ||||
|     }; | ||||
|     // clang-format on | ||||
|     return names; | ||||
| } | ||||
|  | ||||
| UnpackFSCJob::UnpackFSCJob( QObject* parent ) | ||||
|     : Calamares::CppJob( parent ) | ||||
| { | ||||
| } | ||||
|  | ||||
| UnpackFSCJob::~UnpackFSCJob() { } | ||||
|  | ||||
| QString | ||||
| UnpackFSCJob::prettyName() const | ||||
| { | ||||
|     return tr( "Unpack filesystems" ); | ||||
| } | ||||
|  | ||||
| QString | ||||
| UnpackFSCJob::prettyStatusMessage() const | ||||
| { | ||||
|     return m_progressMessage; | ||||
| } | ||||
| Calamares::JobResult | ||||
| UnpackFSCJob::exec() | ||||
| { | ||||
|     cScopedAssignment messageClearer( &m_progressMessage, QString() ); | ||||
|     std::unique_ptr< Runner > r; | ||||
|     switch ( m_type ) | ||||
|     { | ||||
|     case Type::FSArchive: | ||||
|         r = std::make_unique< FSArchiverDirRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::FSArchiveFS: | ||||
|         r = std::make_unique< FSArchiverFSRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::Squashfs: | ||||
|         r = std::make_unique< UnsquashRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::Tarball: | ||||
|         r = std::make_unique< TarballRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::None: | ||||
|     default: | ||||
|         cDebug() << "Nothing to do."; | ||||
|         return Calamares::JobResult::ok(); | ||||
|     } | ||||
|  | ||||
|     connect( r.get(), | ||||
|              &Runner::progress, | ||||
|              [ = ]( qreal percent, const QString& message ) | ||||
|              { | ||||
|                  m_progressMessage = message; | ||||
|                  Q_EMIT progress( percent ); | ||||
|              } ); | ||||
|     return r->run(); | ||||
| } | ||||
|  | ||||
| void | ||||
| UnpackFSCJob::setConfigurationMap( const QVariantMap& map ) | ||||
| { | ||||
|     QString source = CalamaresUtils::getString( map, "source" ); | ||||
|     QString sourceTypeName = CalamaresUtils::getString( map, "sourcefs" ); | ||||
|     if ( source.isEmpty() || sourceTypeName.isEmpty() ) | ||||
|     { | ||||
|         cWarning() << "Skipping item with bad source data:" << map; | ||||
|         return; | ||||
|     } | ||||
|     bool bogus = false; | ||||
|     Type sourceType = typeNames().find( sourceTypeName, bogus ); | ||||
|     if ( sourceType == Type::None ) | ||||
|     { | ||||
|         cWarning() << "Skipping item with source type None"; | ||||
|         return; | ||||
|     } | ||||
|     QString destination = CalamaresUtils::getString( map, "destination" ); | ||||
|     if ( destination.isEmpty() ) | ||||
|     { | ||||
|         cWarning() << "Skipping item with empty destination"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     m_source = source; | ||||
|     m_destination = destination; | ||||
|     m_type = sourceType; | ||||
| } | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DEFINITION( UnpackFSCFactory, registerPlugin< UnpackFSCJob >(); ) | ||||
							
								
								
									
										50
									
								
								modules/unpackfsc/UnpackFSCJob.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,50 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_UNPACKFSCJOB_H | ||||
| #define UNPACKFSC_UNPACKFSCJOB_H | ||||
|  | ||||
| #include <CppJob.h> | ||||
| #include <DllMacro.h> | ||||
| #include <utils/PluginFactory.h> | ||||
|  | ||||
| class PLUGINDLLEXPORT UnpackFSCJob : public Calamares::CppJob | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     enum class Type | ||||
|     { | ||||
|         None,  /// << Invalid | ||||
|         FSArchive, | ||||
|         FSArchiveFS, | ||||
|         Squashfs, | ||||
|         Tarball, | ||||
|     }; | ||||
|  | ||||
|     explicit UnpackFSCJob( QObject* parent = nullptr ); | ||||
|     ~UnpackFSCJob() override; | ||||
|  | ||||
|     QString prettyName() const override; | ||||
|     QString prettyStatusMessage() const override; | ||||
|  | ||||
|     Calamares::JobResult exec() override; | ||||
|  | ||||
|     void setConfigurationMap( const QVariantMap& configurationMap ) override; | ||||
|  | ||||
| private: | ||||
|     QString m_source; | ||||
|     QString m_destination; | ||||
|     Type m_type = Type::None; | ||||
|     QString m_progressMessage; | ||||
| }; | ||||
|  | ||||
| CALAMARES_PLUGIN_FACTORY_DECLARATION( UnpackFSCFactory ) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										101
									
								
								modules/unpackfsc/UnsquashRunner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,101 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "UnsquashRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| #include <utils/Runner.h> | ||||
| #include <utils/String.h> | ||||
|  | ||||
| #include <QString> | ||||
|  | ||||
| static constexpr const int chunk_size = 107; | ||||
|  | ||||
| Calamares::JobResult | ||||
| UnsquashRunner::run() | ||||
| { | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid unsquash configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     const QString toolName = QStringLiteral( "unsquashfs" ); | ||||
|     QString unsquashExecutable; | ||||
|     if ( !checkToolExists( toolName, unsquashExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid unsquash configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     // Get the stats (number of inodes) from the FS | ||||
|     { | ||||
|         m_inodes = -1; | ||||
|         Calamares::Utils::Runner r( { unsquashExecutable, QStringLiteral( "-s" ), m_source } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         QObject::connect( &r, | ||||
|                           &decltype( r )::output, | ||||
|                           [ & ]( QString line ) | ||||
|                           { | ||||
|                               if ( line.startsWith( "Number of inodes " ) ) | ||||
|                               { | ||||
|                                   m_inodes = line.split( ' ', SplitSkipEmptyParts ).last().toInt(); | ||||
|                               } | ||||
|                           } ); | ||||
|         /* ignored */ r.run(); | ||||
|     } | ||||
|     if ( m_inodes <= 0 ) | ||||
|     { | ||||
|         cWarning() << "No stats could be obtained from" << unsquashExecutable << "-s"; | ||||
|     } | ||||
|  | ||||
|     // Now do the actual unpack | ||||
|     { | ||||
|         m_processed = 0; | ||||
|         Calamares::Utils::Runner r( { unsquashExecutable, | ||||
|                                       QStringLiteral( "-i" ),  // List files | ||||
|                                       QStringLiteral( "-f" ),  // Force-overwrite | ||||
|                                       QStringLiteral( "-d" ), | ||||
|                                       destinationPath, | ||||
|                                       m_source } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         connect( &r, &decltype( r )::output, this, &UnsquashRunner::unsquashProgress ); | ||||
|         return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| UnsquashRunner::unsquashProgress( QString line ) | ||||
| { | ||||
|     m_processed++; | ||||
|     m_since++; | ||||
|     if ( m_since > chunk_size && line.contains( '/' ) ) | ||||
|     { | ||||
|         const QString filename = line.split( '/', SplitSkipEmptyParts ).last().trimmed(); | ||||
|         if ( !filename.isEmpty() ) | ||||
|         { | ||||
|             m_since = 0; | ||||
|             double p = m_inodes > 0 ? ( double( m_processed ) / double( m_inodes ) ) : 0.5; | ||||
|             Q_EMIT progress( p, tr( "Unsquash file %1" ).arg( filename ) ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								modules/unpackfsc/UnsquashRunner.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_UNSQUASHRUNNER_H | ||||
| #define UNPACKFSC_UNSQUASHRUNNER_H | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| /** @brief Use Unsquash for extracting a filesystem | ||||
|  * | ||||
|  */ | ||||
| class UnsquashRunner : public Runner | ||||
| { | ||||
| public: | ||||
|     using Runner::Runner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
|  | ||||
| protected Q_SLOTS: | ||||
|     void unsquashProgress( QString line ); | ||||
|  | ||||
| private: | ||||
|     int m_inodes = 0;  // Total in the FS | ||||
|  | ||||
|     // Progress reporting | ||||
|     int m_processed = 0; | ||||
|     int m_since = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										2
									
								
								modules/unpackfsc/tests/1.global
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,2 @@ | ||||
| --- | ||||
| rootMountPoint: /tmp/fstest | ||||
							
								
								
									
										4
									
								
								modules/unpackfsc/tests/1.job
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | ||||
| --- | ||||
| source: /tmp/src.fsa | ||||
| sourcefs: fsarchive | ||||
| destination: "/calasrc" | ||||
							
								
								
									
										39
									
								
								modules/unpackfsc/unpackfsc.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | ||||
| # SPDX-FileCopyrightText: no | ||||
| # SPDX-License-Identifier: CC0-1.0 | ||||
| # | ||||
| # Unpack a filesystem. Supported ways to "pack" the filesystem are: | ||||
| #   - fsarchiver in *savedir/restdir* mode (directories, not block devices) | ||||
| #   - squashfs | ||||
| # | ||||
| # Configuration: | ||||
| # | ||||
| #   from globalstorage: rootMountPoint | ||||
| #   from job configuration: the item to unpack | ||||
| # | ||||
|  | ||||
| --- | ||||
| # This module is configured a lot like the items in the *unpackfs* | ||||
| # module, but with only **one** item. Use multiple instances for | ||||
| # unpacking more than one filesystem. | ||||
| # | ||||
| # There are the following **mandatory** keys: | ||||
| #   - *source* path relative to the live / intstalling system to the image | ||||
| #   - *sourcefs* the type of the source files; valid entries are | ||||
| #       - `none` (this entry is ignored; kind of useless) | ||||
| #       - `fsarchiver` | ||||
| #         Aliases of this are `fsarchive`, `fsa` and `fsa-dir`. Uses | ||||
| #         fsarchiver in "restdir" mode. | ||||
| #       - `fsarchiver-block` | ||||
| #         Aliases of this are `fsa-block` and `fsa-fs`. Uses fsarchiver | ||||
| #         in "restfs" mode. | ||||
| #       - `squashfs` | ||||
| #         Aliases of this are `squash` and `unsquash`. | ||||
| #       - `tar` | ||||
| #   - *destination* path relative to rootMountPoint (so in the target | ||||
| #       system) where this filesystem is unpacked. It may be an | ||||
| #       empty string, which effectively is / (the root) of the target | ||||
| #       system. | ||||
| # | ||||
| source: /data/rootfs.fsa | ||||
| sourcefs: fsarchiver | ||||
| destination: "/" | ||||
							
								
								
									
										19
									
								
								modules/unpackfsc/unpackfsc.schema.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| # SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org> | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
| --- | ||||
| $schema: https://json-schema.org/schema# | ||||
| $id: https://calamares.io/schemas/unpackfsc | ||||
| additionalProperties: false | ||||
| type: object | ||||
| properties: | ||||
|     unpack: | ||||
|         type: array | ||||
|         items: | ||||
|             type: object | ||||
|             additionalProperties: false | ||||
|             properties: | ||||
|                 source: { type: string } | ||||
|                 sourcefs: { type: string } | ||||
|                 destination: { type: string } | ||||
|                 weight: { type: integer, exclusiveMinimum: 0 } | ||||
|             required: [ source , sourcefs, destination ] | ||||