54 Commits

Author SHA1 Message Date
Adriaan de Groot
ff3391f67b Docs: add release announcement 2021-05-10 13:50:13 +02:00
Adriaan de Groot
b60b21b680 CMake: bump version 2021-05-10 13:45:31 +02:00
Adriaan de Groot
8a533d22be [mobile] Consistent initialization-expressions in declaration of Config 2021-05-11 11:49:06 +02:00
Adriaan de Groot
6f32c18ef9 Merge pull request #14 from ollieparanoid/non-numeric-pass
[mobile] support non-numeric passwords
2021-05-11 11:42:01 +02:00
Oliver Smith
f36f21c55c mobile.qml: refactor navNextFeature()
Make it more readable as for-loop.
2021-05-09 19:01:09 +02:00
Oliver Smith
bcacab531f [mobile] navNextFeature: fix skipping > 1 feature
Fix the condition in the while loop, so that it can actually continue
with the "continue" keyword. Without this patch, having the sshd
feature disabled would result in the fsType feature getting displayed,
even if it was disabled.
2021-05-02 17:54:18 +02:00
Oliver Smith
85586293c8 [mobile] tweak invalid chars msg/related comments
Change "cannot be typed in at boot time" to "can possibly not be typed
in after installation" and explain that the same check is now used for
the user password too.
2021-05-02 17:54:17 +02:00
Oliver Smith
e71eb01feb [mobile] add option userPasswordNumeric
Related: https://gitlab.com/postmarketOS/postmarketos-ondev/-/issues/46
2021-05-02 17:54:15 +02:00
Oliver Smith
3eb3e9c98d [mobile] rename default_pin -> user_pass
Prepare to add a config option to allow non-numeric passwords, by giving
the existing default_pin screen the more generic name user_pass.
Adjust the title of the screen too.

"default" in the file name was referring to configuring the default
user's PIN/password as opposed to the SSH user. However, I think
replacing it with "user" makes it more intuitive.
2021-05-02 17:54:13 +02:00
Oliver Smith
2bf5706f73 [mobile] add option builtinVirtualKeyboard
Allow to always hide the built-in qtvirtualkeyboard to support using a
different keyboard.

Related: https://gitlab.com/postmarketOS/postmarketos-ondev/-/issues/47
2021-05-02 17:54:05 +02:00
Adriaan de Groot
76885c7fe1 [mobile] Don't need to list headers as source 2021-04-06 12:00:21 +02:00
Adriaan de Groot
fad0575e4d Merge pull request #13 from ollieparanoid/readme-update
Docs: README: update mobile description
2021-04-03 00:01:12 +02:00
Adriaan de Groot
550f7d40ef CMake: collect and report the skipped modules
Use the newly-added methods for reporting skipped modules.
This requires a post-3.2.39 Calamares, which the CMakeLists.txt
does not yet enforce.
2021-03-23 01:50:59 +01:00
Adriaan de Groot
6c07d39374 [os-freebsd] Remove superfluous linking
For external modules, calamares_add_plugin() does the right thing,
and links to Calamares::calamares; don't use the internal name
from the Calamares repository, and don't link redundantly
to it anyway.
2021-03-22 14:09:28 +01:00
Adriaan de Groot
4285ccebd7 [os-freebsd] Until there's a config file, mark it explicitly without 2021-03-22 13:38:39 +01:00
Adriaan de Groot
320d67a5ba CMake: bail out on broken CMake folders
On a developer's system, the CMake configuration from the **build**
can be found in cache, and that means that <srcdir>/build/CalamaresConfig.cmake
is read instead of an installed version; that doesn't work, so
bail out early (after a half-dozen errors from CalamaresConfig internals).
2021-03-22 13:04:08 +01:00
Adriaan de Groot
6a80ce6dab Add os-* modules to the build
Document SKIP_MODULES and USE_os, although they don't **work**
yet; this should be the same machinery as in the core repo.
2021-03-22 12:33:54 +01:00
Adriaan de Groot
33678a6a16 Import os-* modules from the main repo
The os-* branch was started to add some os-specific modules
to the main Calamares repo. Now that calamares-extensions
has its own release cycle and a reason-to-be beyond examples,
those modules are more suitable here than in the main repo.

Both modules are stubs; development did not get very far.
2021-03-22 12:02:19 +01:00
Oliver Smith
2c91dc4664 Docs: README: update mobile description 2021-02-23 21:13:01 +01:00
Adriaan de Groot
b3cda8d7cb Docs: polish the README to match new additions 2021-02-23 12:20:55 +01:00
Adriaan de Groot
4611f2f9ea CI: note that the release-script is Linux-only 2021-02-23 12:20:28 +01:00
Adriaan de Groot
7acd4bb3d6 Changes: pre-release housekeeping 2021-02-23 11:41:06 +01:00
Adriaan de Groot
41b4b59a5e [mobile] Apply coding style 2021-02-23 11:37:55 +01:00
Adriaan de Groot
077320dc19 CI: add the style tool from calamares 2021-02-23 11:37:16 +01:00
Adriaan de Groot
c5eeeb7a50 Merge pull request #8 from Undef-a/upstream/fs_selection
[mobile] Allow user to configure filesystem type
2021-02-23 11:17:03 +01:00
undef
52882df5ee [mobile] bugfix: initialise externalToInternal
This variable was uninitialised, leading to an undefined action occurring
when the install target screen is skipped.
2021-02-21 21:13:30 +00:00
undef
616e51b3ee [mobile] Allow user to configure filesystem type
The user can now configure the target root filesystem type. Options
provided are ext4 (default), f2fs and btrfs.

OS Maintainers are required to provide their own BTRFS install script
which configures default submodules as required.

Allow disabling selection of fstype
This setting is disabled by default and defaults to ext4. Enabling it
will provide the user with a choice of ext4, f2fs and btrfs for the root
filesystem.

Add FS specific mkfs configuration options
This allows distribution maintainers to set the command/script used for
configuring the root filesystem on a per-fs level. Two examples of its
use are:
* F2FS: mkfs.f2fs uses -l for label, rather than -L like other filesystems.
* BTRFS: Distributions can provide a script which will configure submodules
         as requiref for snapshots to work correctly.

Use of QStringList rather than a Model:
We don't need the complexities of a full model here for a list of strings
and labelModel was the wrong one anyway. At least going down that path means
the back and forward buttons work.
2021-02-21 21:12:21 +00:00
Adriaan de Groot
f2e59e611f [image-slideshow] Add an example QML slideshow for images
The default slideshow is rather complicated for a "simple" slideshow
with images, so add an extensively-documented images-only slideshow
in QML. This can easily be extended with more images, or with
text and fanciness if the designer wants to flex more QML.
2021-02-17 21:53:44 +01:00
Adriaan de Groot
a532b309b7 CI: massage message a bit and adjust naming scheme 2021-02-17 10:43:38 +01:00
Adriaan de Groot
45ae6084d8 Docs: mention the *mobile* module 2021-02-16 23:38:52 +01:00
Adriaan de Groot
e0cd044e5b CI: extract the tarball from calamares first 2021-02-16 15:34:29 +01:00
Adriaan de Groot
2c1cbb7f85 CI: try to run CI for the extensions, too 2021-02-16 15:13:12 +01:00
Adriaan de Groot
bf5e3d857a Merge pull request #11 from ollieparanoid/wait-2min
[mobile] wait screen: reword 20s -> 2 min
2021-02-16 10:53:27 +01:00
Oliver Smith
e78bd936a3 [mobile] wait screen: reword 20s -> 2 min
Change the message in the wait screen from "This may take up to 20
seconds" to "This may take up to two minutes". That's what Mobian needs,
and with "up to" in the sentence, it's not wrong, even if the actual
time is much shorter.

Creating a config option was considered (#10), but would only add
technical debt since the wait screen is already a hack (as described in
the big comment in runPartitionJobThenLeave()).
2021-02-08 22:34:16 +01:00
Adriaan de Groot
a53f9359f4 Changes: post-release housekeeping 2021-01-04 11:53:40 +01:00
Adriaan de Groot
3a525359a5 Changes: pre-release housekeeping 2021-01-04 11:35:51 +01:00
Adriaan de Groot
7716052fbb CMake: behave a little more modern
- This copies in some more settings from Calamares-proper
2021-01-04 11:29:12 +01:00
Adriaan de Groot
5e7c6ef005 Merge pull request #7 from ollieparanoid/sd-to-emmc
[mobile] Offer to install from SD to eMMC
2020-12-24 14:53:02 +01:00
Oliver Smith
83da9b2485 [mobile] Offer to install from SD to eMMC
Make it possible to install from external storage to internal storage,
if the installer was booted from the external storage medium.
2020-12-19 13:16:01 +01:00
Oliver Smith
ceea4db418 [mobile] skipDisabledFeatures: add skip by func
Make it possible to skip features by defining a skip function.
2020-12-19 13:15:59 +01:00
Oliver Smith
86823162c6 [mobile] Config: remove redundant get{Bool,Str}
Use getBool and getString from utils/Variant.h instead. I had
implemented my own versions earlier, because I didn't know about the
existing ones.
2020-12-19 13:15:58 +01:00
Oliver Smith
19ffdc47bb [mobile] *Job: 'const QString&' for args
Related: https://github.com/calamares/calamares-extensions/pull/6#discussion_r545049605
2020-12-19 13:15:57 +01:00
Oliver Smith
0bd415f83e [mobile] Don't ignore partition job errors
Stop the installation if the partition job does not finish successfully
instead of carrying on and failing later on. While at it, elaborate some
more on why it is necessary to call the partition job early.

Related: https://github.com/calamares/calamares/issues/1600
2020-12-19 13:15:55 +01:00
Oliver Smith
028042afe7 [mobile] MobileQmlViewStep: remove unused include 2020-12-19 13:15:54 +01:00
Oliver Smith
59556074cc [mobile] create Users job in jobs()
Don't create the user's job in MobileQmlViewStep::onLeave() anymore.
Instead, have Config::createJobs() and call that from
MobileQmlViewStep::jobs(), as suggested by Adriaan, and that's also how
it's done in the keyboard module in calamares.git. This allows getting
rid of m_jobs, and makes it less awkward to pass parameters to the job.

Related: https://github.com/calamares/calamares-extensions/pull/6#discussion_r545048454
2020-12-19 13:15:53 +01:00
Oliver Smith
a6a9dc6890 [mobile] qml: use generic names for id fields
Rename "enableButton" to "firstButton" and "welcomeText" to "mainText".
2020-12-19 13:15:51 +01:00
Oliver Smith
ed7d63d913 [mobile] mobile.conf: tweak line ending 2020-12-19 13:15:49 +01:00
Oliver Smith
9b1da6ff8c [mobile] Config.h: tweak signal related comments
Fix a typo and make the "booleans we don't read from QML don't need
a signal" message generic with one example, but not with a listing of
all these booleans. Then we won't need to adjust this comment with each
new one.
2020-12-19 13:15:41 +01:00
Oliver Smith
7d3c483b35 [mobile] mobile.qml: fix whitespace error 2020-12-19 13:15:33 +01:00
Adriaan de Groot
0d057478b0 Merge pull request #6 from ollieparanoid/sshd-optional
[mobile] make sshd feature optional and related navigation refactoring
2020-12-17 13:27:34 +01:00
Oliver Smith
7f750cb145 [mobile] Make sshd feature optional
Add featureSshd config key to hide related UI screens and skip related
logic in UsersJob.
2020-12-09 15:39:14 +01:00
Oliver Smith
86e77b975f [mobile] navNextFeature: support skipping features
Skip whole features if a featureSshd (example for feature "sshd") or
smilar config key exists and is set to false.
2020-12-09 15:39:10 +01:00
Oliver Smith
70fa9fa766 [mobile] Refactor screen navigation logic
Organize the screens into features and replace all navTo() calls with
hardcoded screen names with new navNext() and navNextFeature()
functions.
2020-12-09 15:39:05 +01:00
Oliver Smith
c43bd06860 [mobile] navTo: add log message for screen change 2020-12-09 15:39:01 +01:00
42 changed files with 1583 additions and 188 deletions

100
.github/workflows/nightly-neon.yml vendored Normal file
View File

@@ -0,0 +1,100 @@
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"
run: |
sudo apt-get update
sudo apt-get -y install git-core
sudo apt-get -y install \
build-essential \
cmake \
extra-cmake-modules \
gettext \
kio-dev \
libatasmart-dev \
libboost-python-dev \
libkf5config-dev \
libkf5coreaddons-dev \
libkf5i18n-dev \
libkf5iconthemes-dev \
libkf5parts-dev \
libkf5service-dev \
libkf5solid-dev \
libkpmcore-dev \
libparted-dev \
libpolkit-qt5-1-dev \
libqt5svg5-dev \
libqt5webkit5-dev \
libyaml-cpp-dev \
os-prober \
pkg-config \
python3-dev \
qtbase5-dev \
qtdeclarative5-dev \
qttools5-dev \
qttools5-dev-tools
- name: "prepare source"
uses: actions/checkout@v2
- name: "prepare artifacts"
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
- name: "prepare build"
id: pre_build
run: |
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
mkdir -p $BUILDDIR
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
echo "::set-output name=message::"`git log -1 --abbrev-commit --pretty=oneline --no-decorate ${{ github.event.head_commit.id }}`
- name: "Calamares-Extensions: cmake"
working-directory: ${{ env.BUILDDIR }}
run: cmake $CMAKE_ARGS $SRCDIR
- name: "Calamares-Extensions: make"
working-directory: ${{ env.BUILDDIR }}
run: make -j2 VERBOSE=1
- name: "Calamares-Extensions: install"
working-directory: ${{ env.BUILDDIR }}
run: make install VERBOSE=1
- name: "notify: ok"
uses: rectalogic/notify-irc@v1
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
with:
server: chat.freenode.net
nickname: cala-ci
channel: "#calamares"
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
- name: "notify: fail"
uses: rectalogic/notify-irc@v1
if: ${{ failure() && github.repository == 'calamares/calamares' }}
with:
server: chat.freenode.net
nickname: cala-ci
channel: "#calamares"
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"

106
.github/workflows/push.yml vendored Normal file
View File

@@ -0,0 +1,106 @@
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"
run: |
sudo apt-get update
sudo apt-get -y install git-core
sudo apt-get -y install \
build-essential \
cmake \
extra-cmake-modules \
gettext \
kio-dev \
libatasmart-dev \
libboost-python-dev \
libkf5config-dev \
libkf5coreaddons-dev \
libkf5i18n-dev \
libkf5iconthemes-dev \
libkf5parts-dev \
libkf5service-dev \
libkf5solid-dev \
libkpmcore-dev \
libparted-dev \
libpolkit-qt5-1-dev \
libqt5svg5-dev \
libqt5webkit5-dev \
libyaml-cpp-dev \
os-prober \
pkg-config \
python3-dev \
qtbase5-dev \
qtdeclarative5-dev \
qttools5-dev \
qttools5-dev-tools
- name: "prepare source"
uses: actions/checkout@v2
- name: "prepare artifacts"
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
- name: "prepare build"
id: pre_build
run: |
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
mkdir -p $BUILDDIR
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
echo "::set-output name=message::"`git log -1 --abbrev-commit --pretty=oneline --no-decorate ${{ github.event.head_commit.id }}`
- name: "Calamares-Extensions: cmake"
working-directory: ${{ env.BUILDDIR }}
run: cmake $CMAKE_ARGS $SRCDIR
- name: "Calamares-Extensions: make"
working-directory: ${{ env.BUILDDIR }}
run: make -j2 VERBOSE=1
- name: "Calamares-Extensions: install"
working-directory: ${{ env.BUILDDIR }}
run: make install VERBOSE=1
- name: "notify: ok"
uses: rectalogic/notify-irc@v1
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
with:
server: chat.freenode.net
nickname: cala-ci
channel: "#calamares"
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}"
- name: "notify: fail"
uses: rectalogic/notify-irc@v1
if: ${{ failure() && github.repository == 'calamares/calamares' }}
with:
server: chat.freenode.net
nickname: cala-ci
channel: "#calamares"
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}\n.. DIFF ${{ github.event.compare }}"

54
CHANGES Normal file
View File

@@ -0,0 +1,54 @@
<!-- 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.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

View File

@@ -24,15 +24,54 @@
# 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.
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(calamares-extensions
VERSION 1.0.0
VERSION 1.1.2
LANGUAGES CXX
)
find_package(Calamares 3.2.26 REQUIRED)
# 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).
find_package(Calamares 3.2.26 REQUIRED NO_CMAKE_PACKAGE_REGISTRY)
if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui)
message(FATAL_ERROR "Calamares found with missing CMake targets")
endif()
find_package(YAMLCPP REQUIRED) # Needed to untangle some dependencies before Calamares 3.2.36
### 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()
find_package(YAMLCPP REQUIRED)
### BRANDING
#
@@ -56,17 +95,22 @@ 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/filekeeper LIST_SKIPPED_MODULES ) # C++ 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/slowpython LIST_SKIPPED_MODULES ) # Python job
# 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} )
calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} )
### RELEASE SUPPORT
#
#
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 )

View File

@@ -1,10 +1,11 @@
# 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,13 +14,9 @@ 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
## Branding
- [Module](#modules) documentation
## Branding
> Branding shapes the **look** of Calamares to your distro
@@ -28,11 +25,20 @@ 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
- [`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.
- `samegame/` is a copy of the Qt Company "Same Game" QML demo. It
- [`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
@@ -62,7 +68,7 @@ and documentation for the framework that Calamares ships with.
parts of Calamares.
See the [styling paragraph](https://github.com/calamares/calamares/wiki/Deploy-Guide#styling-calamares) of the deployment guide for more details.
### Testing a Branding Component
If Calamares is installed, then the Calamares QML support files
@@ -72,7 +78,7 @@ branding component is free to do whatever is interesting in QML.
The tool for quickly viewing QML files is `qmlscene`, which is
included with the Qt development tools. It can be used to
preview a Calamares branding component (slideshow) without starting
preview a Calamares branding component (slideshow) without starting
Calamares. If the component uses translations, you will need to
build the translations first (using Qt Linguist `lrelease`, or by
using the normal build system for branding components).
@@ -87,7 +93,7 @@ qmlscene \
-translation build/calamares-fancy_nl.qm \
-I /usr/local/share/calamares/qml \
-geometry 600x400 \
fancy/show.qml
fancy/show.qml
```
This starts the viewer with the Dutch (nl) translation, using the
@@ -104,25 +110,39 @@ every time.
### Calamares Branding API
The slideshow which is configured in the branding files can have
one of two "API styles".
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
`onActivate()` and `onLeave()` then those functions
are called when the slideshow becomes visible and when the installation is finished.
These can be used to start and stop timers or sound effects or
whatever.
whatever.
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
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 +155,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 +168,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()`

View 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
}
}

View 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

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -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

17
ci/astylerc Normal file
View 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

77
ci/calamaresstyle Executable file
View File

@@ -0,0 +1,77 @@
#!/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-7 -8 or -9
#
# Clang-format-10 is **not** supported, since it changes a default
# that re-introduces a space into empty function bodies; this
# can be turned off with a style setting, but that breaks
# older format versions which don't recognize the setting.
#
# 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
AS=$( which astyle )
CF_VERSIONS="clang-format-7 clang-format-8 clang-format70 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 ; }
unmangle_clang_format=""
if expr `"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1` '<' 10 > /dev/null ; then
:
else
unmangle_clang_format=$( dirname $0 )/../.clang-format
echo "SpaceInEmptyBlock: false" >> "$unmangle_clang_format"
fi
set -e
any_dirs=no
for d in "$@"
do
test -d "$d" && any_dirs=yes
done
style_some()
{
if test -n "$*" ; then
$AS --options=$(dirname $0)/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
if test -n "$unmangle_clang_format" ; then
sed -i.bak '/^SpaceInEmptyBlock/d' "$unmangle_clang_format"
fi

View File

@@ -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

View File

@@ -1,6 +1,12 @@
/* 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/Variant.h"
#include <QVariant>
Config::Config( QObject* parent )
@@ -8,37 +14,116 @@ 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" );
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_username = getString( cfgMap, "username", "user" );
m_userPasswordNumeric = getBool( cfgMap, "userPasswordNumeric", true );
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_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_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,
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
@@ -80,3 +165,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 );
}

View File

@@ -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 )
@@ -17,8 +23,10 @@ class Config : public QObject
/* default user */
Q_PROPERTY( QString username READ username CONSTANT FINAL )
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 +35,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 +60,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; }
@@ -53,8 +76,10 @@ public:
QString username() const { return m_username; }
QString userPassword() const { return m_userPassword; }
void setUserPassword( const QString& userPassword );
bool userPasswordNumeric() const { return m_userPasswordNumeric; }
/* ssh server + credetials */
bool featureSshd() { return m_featureSshd; }
QString sshdUsername() const { return m_sshdUsername; }
QString sshdPassword() const { return m_sshdPassword; }
bool isSshEnabled() { return m_isSshEnabled; }
@@ -68,12 +93,30 @@ 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; }
@@ -82,6 +125,9 @@ public:
QString cmdSshdUseradd() const { return m_cmdSshdUseradd; }
private:
/* installer UI */
bool m_builtinVirtualKeyboard;
/* welcome */
QString m_osName;
QString m_arch;
@@ -92,22 +138,37 @@ private:
/* 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;
@@ -116,14 +177,18 @@ private:
QString m_cmdSshdUseradd;
signals:
/* booleans we don't read from QML (like isSshEnabled) don't need a signal */
/* default user */
void userPasswordChanged( QString userPassword );
/* 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 );
};

View File

@@ -1,11 +1,8 @@
/* 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 "GlobalStorage.h"
#include "JobQueue.h"
#include "locale/LabelModel.h"
#include "utils/Dirs.h"
@@ -35,34 +32,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 +65,7 @@ MobileQmlViewStep::isAtEnd() const
Calamares::JobList
MobileQmlViewStep::jobs() const
{
return m_jobs;
return m_config->createJobs();
}
QObject*

View File

@@ -32,7 +32,6 @@ public:
private:
Config* m_config;
QList< Calamares::job_ptr > m_jobs;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( MobileQmlViewStepFactory )

View File

@@ -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 )
{

View File

@@ -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;
};

View File

@@ -12,15 +12,17 @@
#include <QFileInfo>
UsersJob::UsersJob( QString cmdPasswd,
QString cmdSshd,
QString cmdSshdUseradd,
UsersJob::UsersJob( bool featureSshd,
const QString& cmdPasswd,
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_cmdSshd( cmdSshd )
, m_cmdSshdUseradd( cmdSshdUseradd )
@@ -48,14 +50,18 @@ UsersJob::exec()
QList< QPair< QStringList, QString > > commands = {
{ { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" },
{ { "sh", "-c", m_cmdSshd }, QString() },
};
if ( m_isSshEnabled )
if ( m_featureSshd )
{
commands.append( { { "sh", "-c", m_cmdSshdUseradd + " " + m_sshdUsername }, QString() } );
commands.append(
{ { "sh", "-c", m_cmdPasswd + " " + m_sshdUsername }, m_sshdPassword + "\n" + m_sshdPassword + "\n" } );
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 )

View File

@@ -8,14 +8,15 @@ class UsersJob : public Calamares::Job
{
Q_OBJECT
public:
UsersJob( QString cmdPasswd,
QString cmdSshd,
QString cmdSshdUseradd,
UsersJob( bool featureSshd,
const QString& cmdPasswd,
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,6 +24,7 @@ public:
Calamares::JobList createJobs();
private:
bool m_featureSshd;
QString m_cmdPasswd;
QString m_cmdSshd;
QString m_cmdSshdUseradd;

View File

@@ -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();
}
}
}

View File

@@ -73,7 +73,7 @@ Item {
onClicked: {
if (validatePassword(password, passwordRepeat, errorText)) {
config.fdePassword = password.text;
navTo("install_confirm");
navNext();
}
}
}

View 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();
}
}
}

View File

@@ -19,24 +19,38 @@ Item {
height: parent.height
Text {
id: welcomeText
id: mainText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 30
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><br>";
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: 500
}
Button {
id: enableButton
id: firstButton
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: welcomeText.bottom
anchors.top: mainText.bottom
anchors.topMargin: 40
width: 500

View 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();
}
}
}

View 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();
}
}
}

View File

@@ -11,6 +11,10 @@
## 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)"
@@ -27,9 +31,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,12 +88,25 @@
## 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)
#######

View File

@@ -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 (user_pass, ssh_credentials) */
function validatePin(userPin, userPinRepeat, errorText) {
var pin = userPin.text;
var repeat = userPinRepeat.text;
@@ -183,7 +275,7 @@ Page
if (repeat != pin)
return validationFailure(errorText,
"The PINs don't match.");
return validationFailureClear(errorText);
}
function validateSshdUsername(username, errorText) {
@@ -297,11 +389,21 @@ 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());

View File

@@ -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: 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) -->

View File

@@ -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();
}
}
}

View File

@@ -100,7 +100,7 @@ Item {
config.sshdUsername = username.text;
config.sshdPassword = password.text;
navTo("fde_confirm");
navNext();
}
}
}

View File

@@ -12,6 +12,17 @@ import QtQuick.Window 2.3
import QtQuick.VirtualKeyboard 2.1
Item {
property var placeholder: (config.userPasswordNumeric
? "PIN"
: "Password")
property var hints: (config.userPasswordNumeric
? Qt.ImhDigitsOnly
: Qt.ImhPreferLowercase)
property var validateFunc: (config.userPasswordNumeric
? validatePin
: validatePassword);
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right
@@ -25,23 +36,31 @@ Item {
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."
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: userPin
id: userPass
anchors.top: description.bottom
placeholderText: qsTr("PIN")
placeholderText: qsTr(placeholder)
echoMode: TextInput.Password
onTextChanged: validatePin(userPin, userPinRepeat, errorText)
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
text: config.userPassword
/* Let the virtual keyboard change to digits only */
inputMethodHints: Qt.ImhDigitsOnly
inputMethodHints: hints
onActiveFocusChanged: {
if(activeFocus) {
Qt.inputMethod.update(Qt.ImQueryInput)
@@ -54,12 +73,12 @@ Item {
}
TextField {
id: userPinRepeat
anchors.top: userPin.bottom
placeholderText: qsTr("PIN (repeat)")
inputMethodHints: Qt.ImhDigitsOnly
id: userPassRepeat
anchors.top: userPass.bottom
placeholderText: qsTr(placeholder + " (repeat)")
inputMethodHints: hints
echoMode: TextInput.Password
onTextChanged: validatePin(userPin, userPinRepeat, errorText)
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
text: config.userPassword
anchors.horizontalCenter: parent.horizontalCenter
@@ -68,7 +87,7 @@ Item {
}
Text {
anchors.top: userPinRepeat.bottom
anchors.top: userPassRepeat.bottom
id: errorText
visible: false
wrapMode: Text.WordWrap
@@ -86,9 +105,9 @@ Item {
text: qsTr("Continue")
onClicked: {
if (validatePin(userPin, userPinRepeat, errorText)) {
config.userPassword = userPin.text;
navTo("ssh_confirm");
if (validateFunc(userPass, userPassRepeat, errorText)) {
config.userPassword = userPass.text;
navNext();
}
}
}

View File

@@ -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 two minutes, please be patient."
width: 500
}
}

View File

@@ -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()
}
}
}

View 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
)

View 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 >(); )

View 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

83
modules/os-nixos/main.py Normal file
View File

@@ -0,0 +1,83 @@
#!/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
# License-Filename: LICENSE
#
"""
=== 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
def pretty_name():
return _("NixOS Configuration.")
def run():
"""NixOS Configuration."""
libcalamares.utils.debug("LocaleDir=" +
str(libcalamares.utils.gettext_path()))
libcalamares.utils.debug("Languages=" +
str(libcalamares.utils.gettext_languages()))
# TODO: probably want to use the job configuration
# with a key "stage" to distinguish generate-config
# from execute-config; maybe it wants an "all" as well
# to do both.
accumulator = "*** Job configuration\n"
accumulator += str(libcalamares.job.configuration)
libcalamares.utils.debug(accumulator)
accumulator = "*** GlobalStorage configuration\n"
accumulator += "count: " + str(libcalamares.globalstorage.count()) + "\n"
accumulator += "keys: {}\n".format(str(libcalamares.globalstorage.keys()))
libcalamares.utils.debug(accumulator)
libcalamares.utils.debug("Run NixOS tools.")
libcalamares.job.setprogress( 0.1 )
sleep(1)
libcalamares.job.setprogress( 0.5 )
sleep(1)
libcalamares.job.setprogress( 1.0 )
sleep(3)
# To indicate an error, return a tuple of:
# (message, detailed-error-message)
return None

View File

@@ -0,0 +1,5 @@
---
type: "job"
name: "os-nixos"
interface: "python"
script: "main.py"