commit 3a783587af62b340d0e027459d864586388c7237 Author: Kevin Munoz Date: Sun Oct 13 11:11:58 2024 -0500 initial commit diff --git a/etc/calamares/branding/default/banner.png b/etc/calamares/branding/default/banner.png new file mode 100644 index 0000000..d1baeee Binary files /dev/null and b/etc/calamares/branding/default/banner.png differ diff --git a/etc/calamares/branding/default/banner.png.license b/etc/calamares/branding/default/banner.png.license new file mode 100644 index 0000000..38aa361 --- /dev/null +++ b/etc/calamares/branding/default/banner.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2020 Adriaan de Groot +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/etc/calamares/branding/default/branding.desc b/etc/calamares/branding/default/branding.desc new file mode 100644 index 0000000..67905a0 --- /dev/null +++ b/etc/calamares/branding/default/branding.desc @@ -0,0 +1,239 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +# Product branding information. This influences some global +# user-visible aspects of Calamares, such as the product +# name, window behavior, and the slideshow during installation. +# +# Additional styling can be done using the stylesheet.qss +# file, also in the branding directory. +--- +componentName: default + + +### WELCOME / OVERALL WORDING +# +# These settings affect some overall phrasing and looks, +# which are most visible in the welcome page. + +# This selects between different welcome texts. When false, uses +# the traditional "Welcome to the %1 installer.", and when true, +# uses "Welcome to the Calamares installer for %1." This allows +# to distinguish this installer from other installers for the +# same distribution. +welcomeStyleCalamares: false + +# Should the welcome image (productWelcome, below) be scaled +# up beyond its natural size? If false, the image does not grow +# with the window but remains the same size throughout (this +# may have surprising effects on HiDPI monitors). +welcomeExpandingLogo: true + +### WINDOW CONFIGURATION +# +# The settings here affect the placement of the Calamares +# window through hints to the window manager and initial +# sizing of the Calamares window. + +# Size and expansion policy for Calamares. +# - "normal" or unset, expand as needed, use *windowSize* +# - "fullscreen", start as large as possible, ignore *windowSize* +# - "noexpand", don't expand automatically, use *windowSize* +windowExpanding: normal + +# Size of Calamares window, expressed as w,h. Both w and h +# may be either pixels (suffix px) or font-units (suffix em). +# e.g. "800px,600px" +# "60em,480px" +# This setting is ignored if "fullscreen" is selected for +# *windowExpanding*, above. If not set, use constants defined +# in CalamaresUtilsGui, 800x520. +windowSize: 800px,520px + +# Placement of Calamares window. Either "center" or "free". +# Whether "center" actually works does depend on the window +# manager in use (and only makes sense if you're not using +# *windowExpanding* set to "fullscreen"). +windowPlacement: center + +### PANELS CONFIGURATION +# +# Calamares has a main content area, and two panels (navigation +# and progress / sidebar). The panels can be controlled individually, +# or switched off. If both panels are switched off, the layout of +# the main content area loses its margins, on the assumption that +# you're doing something special. + +# Kind of sidebar (panel on the left, showing progress). +# - "widget" or unset, use traditional sidebar (logo, items) +# - "none", hide it entirely +# - "qml", use calamares-sidebar.qml from branding folder +# In addition, you **may** specify a side, separated by a comma, +# from the kind. Valid sides are: +# - "left" (if not specified, uses this) +# - "right" +# - "top" +# - "bottom" +# For instance, "widget,right" is valid; so is "qml", which defaults +# to putting the sidebar on the left. Also valid is "qml,top". +# While "widget,top" is valid, the widgets code is **not** flexible +# and results will be terrible. +sidebar: widget + +# Kind of navigation (button panel on the bottom). +# - "widget" or unset, use traditional navigation +# - "none", hide it entirely +# - "qml", use calamares-navigation.qml from branding folder +# In addition, you **may** specify a side, separated by a comma, +# from the kind. The same sides are valid as for *sidebar*, +# except the default is *bottom*. +navigation: widget + + +### STRINGS, IMAGES AND COLORS +# +# This section contains the "branding proper" of names +# and images, rather than global-look settings. + +# These are strings shown to the user in the user interface. +# There is no provision for translating them -- since they +# are names, the string is included as-is. +# +# The four Url strings are the Urls used by the buttons in +# the welcome screen, and are not shown to the user. Clicking +# on the "Support" button, for instance, opens the link supportUrl. +# If a Url is empty, the corresponding button is not shown. +# +# bootloaderEntryName is how this installation / distro is named +# in the boot loader (e.g. in the GRUB menu). +# +# These strings support substitution from /etc/os-release +# if KDE Frameworks 5.58 are available at build-time. When +# enabled, ${varname} is replaced by the equivalent value +# from os-release. All the supported var-names are in all-caps, +# and are listed on the FreeDesktop.org site, +# https://www.freedesktop.org/software/systemd/man/os-release.html +# Note that ANSI_COLOR and CPE_NAME don't make sense here, and +# are not supported (the rest are). Remember to quote the string +# if it contains substitutions, or you'll get YAML exceptions. +# +# The *Url* entries are used on the welcome page, and they +# are visible as buttons there if the corresponding *show* keys +# are set to "true" (they can also be overridden). +strings: + productName: Condor Linux + #shortProductName: Generic + version: 2024.10.13 + shortVersion: 2023.10.13 + versionedName: Condor Linux "Uchiha" + #shortVersionedName: Condor Linux + bootloaderEntryName: Condor Linux + productUrl: https://condorcs.net/CondorLinux + supportUrl: https://condorcs.net/CondorLinux + knownIssuesUrl: https://condorcs.net/CondorLinux + releaseNotesUrl: https://condorcs.net/CondorLinux + #donateUrl: + +# These images are loaded from the branding module directory. +# +# productBanner is an optional image, which if present, will be shown +# on the welcome page of the application, above the welcome text. +# It is intended to have a width much greater than height. +# It is displayed at 64px height (also on HiDPI). +# Recommended size is 64px tall, and up to 460px wide. +# productIcon is used as the window icon, and will (usually) be used +# by the window manager to represent the application. This image +# should be square, and may be displayed by the window manager +# as small as 16x16 (but possibly larger). +# productLogo is used as the logo at the top of the left-hand column +# which shows the steps to be taken. The image should be square, +# and is displayed at 80x80 pixels (also on HiDPI). +# productWallpaper is an optional image, which if present, will replace +# the normal solid background on every page of the application. +# It can be any size and proportion, +# and will be tiled to fit the entire window. +# For a non-tiled wallpaper, the size should be the same as +# the overall window, see *windowSize* above (800x520). +# productWelcome is shown on the welcome page of the application in +# the middle of the window, below the welcome text. It can be +# any size and proportion, and will be scaled to fit inside +# the window. Use `welcomeExpandingLogo` to make it non-scaled. +# Recommended size is 320x150. +# +# These filenames can also use substitutions from os-release (see above). +images: + # productBanner: "banner.png" + productIcon: "squid.png" + productLogo: "squid.png" + # productWallpaper: "wallpaper.png" + productWelcome: "languages.png" + +# Colors for text and background components. +# +# - SidebarBackground is the background of the sidebar +# - SidebarText is the (foreground) text color +# - SidebarBackgroundCurrent sets the background of the current step. +# Optional, and defaults to the application palette. +# - SidebarTextCurrent is the text color of the current step. +# +# These colors can **also** be set through the stylesheet, if the +# branding component also ships a stylesheet.qss. Then they are +# the corresponding CSS attributes of #sidebarApp. +style: + SidebarBackground: "#292F34" + SidebarText: "#FFFFFF" + SidebarTextCurrent: "#292F34" + SidebarBackgroundCurrent: "#D35400" + +### SLIDESHOW +# +# The slideshow is displayed during execution steps (e.g. when the +# installer is actually writing to disk and doing other slow things). + +# The slideshow can be a QML file (recommended) which can display +# arbitrary things -- text, images, animations, or even play a game -- +# during the execution step. The QML **is** abruptly stopped when the +# execution step is done, though, so maybe a game isn't a great idea. +# +# The slideshow can also be a sequence of images (not recommended unless +# you don't want QML at all in your Calamares). The images are displayed +# at a rate of 1 every 2 seconds during the execution step. +# +# To configure a QML file, list a single filename: +# slideshow: "show.qml" +# To configure images, like the filenames (here, as an inline list): +# slideshow: [ "/etc/calamares/slideshow/0.png", "/etc/logo.png" ] +slideshow: "show.qml" + +# There are two available APIs for a QML slideshow: +# - 1 (the default) loads the entire slideshow when the installation- +# slideshow page is shown and starts the QML then. The QML +# is never stopped (after installation is done, times etc. +# continue to fire). +# - 2 loads the slideshow on startup and calls onActivate() and +# onLeave() in the root object. After the installation is done, +# the show is stopped (first by calling onLeave(), then destroying +# the QML components). +# +# An image slideshow does not need to have the API defined. +slideshowAPI: 2 + + +# These options are to customize online uploading of logs to pastebins: +# - type : Defines the kind of pastebin service to be used. Currently +# it accepts two values: +# - none : disables the pastebin functionality +# - fiche : use fiche pastebin server +# - url : Defines the address of pastebin service to be used. +# Takes string as input. Important bits are the host and port, +# the scheme is not used. +# - sizeLimit : Defines maximum size limit (in KiB) of log file to be pasted. +# The option must be set, to have the log option work. +# Takes integer as input. If < 0, no limit will be forced, +# else only last (approximately) 'n' KiB of log file will be pasted. +# Please note that upload size may be slightly over the limit (due +# to last minute logging), so provide a suitable value. +uploadServer : + type : "fiche" + url : "http://termbin.com:9999" + sizeLimit : -1 diff --git a/etc/calamares/branding/default/lang/calamares-default_ar.ts b/etc/calamares/branding/default/lang/calamares-default_ar.ts new file mode 100644 index 0000000..3c4fe09 --- /dev/null +++ b/etc/calamares/branding/default/lang/calamares-default_ar.ts @@ -0,0 +1,17 @@ + + + + + show + + + This is a second Slide element. + عرض الثاني + + + + This is a third Slide element. + عرض الثالث + + + diff --git a/etc/calamares/branding/default/lang/calamares-default_en.ts b/etc/calamares/branding/default/lang/calamares-default_en.ts new file mode 100644 index 0000000..b02dbd5 --- /dev/null +++ b/etc/calamares/branding/default/lang/calamares-default_en.ts @@ -0,0 +1,17 @@ + + + + + show + + + This is a second Slide element. + + + + + This is a third Slide element. + + + + diff --git a/etc/calamares/branding/default/lang/calamares-default_eo.ts b/etc/calamares/branding/default/lang/calamares-default_eo.ts new file mode 100644 index 0000000..7d1ef4e --- /dev/null +++ b/etc/calamares/branding/default/lang/calamares-default_eo.ts @@ -0,0 +1,17 @@ + + + + + show + + + This is a second Slide element. + Ĉi tio estas la dua gliteja. + + + + This is a third Slide element. + Ĉi tio estas la tria gliteja. + + + diff --git a/etc/calamares/branding/default/lang/calamares-default_fr.ts b/etc/calamares/branding/default/lang/calamares-default_fr.ts new file mode 100644 index 0000000..ec5e041 --- /dev/null +++ b/etc/calamares/branding/default/lang/calamares-default_fr.ts @@ -0,0 +1,17 @@ + + + + + show + + + This is a second Slide element. + Ceci est la deuxieme affiche. + + + + This is a third Slide element. + La troisième affice ce trouve ici. + + + diff --git a/etc/calamares/branding/default/lang/calamares-default_nl.ts b/etc/calamares/branding/default/lang/calamares-default_nl.ts new file mode 100644 index 0000000..19fd583 --- /dev/null +++ b/etc/calamares/branding/default/lang/calamares-default_nl.ts @@ -0,0 +1,17 @@ + + + + + show + + + This is a second Slide element. + Dit is het tweede Dia element. + + + + This is a third Slide element. + Dit is het derde Dia element. + + + diff --git a/etc/calamares/branding/default/languages.png b/etc/calamares/branding/default/languages.png new file mode 100644 index 0000000..5331652 Binary files /dev/null and b/etc/calamares/branding/default/languages.png differ diff --git a/etc/calamares/branding/default/languages.png.license b/etc/calamares/branding/default/languages.png.license new file mode 100644 index 0000000..ea82645 --- /dev/null +++ b/etc/calamares/branding/default/languages.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2015 Teo Mrnjavac +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/etc/calamares/branding/default/show.qml b/etc/calamares/branding/default/show.qml new file mode 100644 index 0000000..f4c50e6 --- /dev/null +++ b/etc/calamares/branding/default/show.qml @@ -0,0 +1,77 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2015 Teo Mrnjavac + * SPDX-FileCopyrightText: 2018 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +import QtQuick 2.0; +import calamares.slideshow 1.0; + +Presentation +{ + id: presentation + + function nextSlide() { + console.log("QML Component (default slideshow) Next slide"); + presentation.goToNextSlide(); + } + + Timer { + id: advanceTimer + interval: 1000 + running: presentation.activatedInCalamares + repeat: true + onTriggered: nextSlide() + } + + Slide { + + Image { + id: background + source: "squid.png" + width: 200; height: 200 + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } + Text { + anchors.horizontalCenter: background.horizontalCenter + anchors.top: background.bottom + text: "This is a customizable QML slideshow.
"+ + "Distributions should provide their own slideshow and list it in
"+ + "their custom branding.desc file.
"+ + "To create a Calamares presentation in QML, import calamares.slideshow,
"+ + "define a Presentation element with as many Slide elements as needed." + wrapMode: Text.WordWrap + width: presentation.width + horizontalAlignment: Text.Center + } + } + + Slide { + centeredText: qsTr("This is a second Slide element.") + } + + Slide { + centeredText: qsTr("This is a third Slide element.") + } + + // When this slideshow is loaded as a V1 slideshow, only + // activatedInCalamares is set, which starts the timer (see above). + // + // In V2, also the onActivate() and onLeave() methods are called. + // These example functions log a message (and re-start the slides + // from the first). + function onActivate() { + console.log("QML Component (default slideshow) activated"); + presentation.currentSlide = 0; + } + + function onLeave() { + console.log("QML Component (default slideshow) deactivated"); + } + +} diff --git a/etc/calamares/branding/default/squid.png b/etc/calamares/branding/default/squid.png new file mode 100644 index 0000000..452e445 Binary files /dev/null and b/etc/calamares/branding/default/squid.png differ diff --git a/etc/calamares/branding/default/squid.png.license b/etc/calamares/branding/default/squid.png.license new file mode 100644 index 0000000..cc08e1f --- /dev/null +++ b/etc/calamares/branding/default/squid.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2014 Teo Mrnjavac +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/etc/calamares/branding/default/stylesheet.qss b/etc/calamares/branding/default/stylesheet.qss new file mode 100644 index 0000000..5c36738 --- /dev/null +++ b/etc/calamares/branding/default/stylesheet.qss @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: no + * SPDX-License-Identifier: CC0-1.0 + */ + +/* +A branding component can ship a stylesheet (like this one) +which is applied to parts of the Calamares user-interface. +In principle, all parts can be styled through CSS. +Missing parts should be filed as issues. + +The IDs are based on the object names in the C++ code. +You can use the Debug Dialog to find out object names: + - Open the debug dialog + - Choose tab *Tools* + - Click *Widget Tree* button +The list of object names is printed in the log. + +Documentation for styling Qt Widgets through a stylesheet +can be found at + https://doc.qt.io/qt-5/stylesheet-examples.html + https://doc.qt.io/qt-5/stylesheet-reference.html +In Calamares, styling widget classes is supported (e.g. +using `QComboBox` as a selector). + +This example stylesheet has all the actual styling commented out. +The examples are not exhaustive. + +*/ + +/*** Generic Widgets. + * + * You can style **all** widgets of a given class by selecting + * the class name. Some widgets have specialized sub-selectors. + */ + +/* +QPushButton { background-color: green; } +*/ + +/*** Main application window. + * + * The main application window has the sidebar, which in turn + * contains a logo and a list of items -- note that the list + * can **not** be styled, since it has its own custom C++ + * delegate code. + */ + +/* +#mainApp { } +#sidebarApp { } +#logoApp { } +*/ + +/*** Welcome module. + * + * There are plenty of parts, but the buttons are the most interesting + * ones (donate, release notes, ...). The little icon image can be + * styled through *qproperty-icon*, which is a little obscure. + * URLs can reference the QRC paths of the Calamares application + * or loaded via plugins or within the filesystem. There is no + * comprehensive list of available icons, though. + */ + +/* +QPushButton#aboutButton { qproperty-icon: url(:/data/images/release.svg); } +#donateButton, +#supportButton, +#releaseNotesButton, +#knownIssuesButton { qproperty-icon: url(:/data/images/help.svg); } +*/ + +/*** Partitioning module. + * + * Many moving parts, which you will need to experiment with. + */ + +/* +#bootInfoIcon { } +#bootInfoLable { } +#deviceInfoIcon { } +#defineInfoLabel { } +#scrollAreaWidgetContents { } +#partitionBarView { } +*/ + +/*** Licensing module. + * + * The licensing module paints individual widgets for each of + * the licenses. The item can be collapsed or expanded. + */ + +/* +#licenseItem { } +#licenseItemFullText { } +*/ diff --git a/etc/calamares/modules/unpackfs/main.py b/etc/calamares/modules/unpackfs/main.py new file mode 100644 index 0000000..814556f --- /dev/null +++ b/etc/calamares/modules/unpackfs/main.py @@ -0,0 +1,500 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# === This file is part of Calamares - === +# +# SPDX-FileCopyrightText: 2014 Teo Mrnjavac +# SPDX-FileCopyrightText: 2014 Daniel Hillenbrand +# SPDX-FileCopyrightText: 2014 Philip Müller +# SPDX-FileCopyrightText: 2017 Alf Gaida +# SPDX-FileCopyrightText: 2019 Kevin Kofler +# SPDX-FileCopyrightText: 2020 Adriaan de Groot +# SPDX-FileCopyrightText: 2020 Gabriel Craciunescu +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Calamares is Free Software: see the License-Identifier above. +# + +import os +import re +import shutil +import subprocess +import sys +import tempfile + +import libcalamares + +import gettext +_ = gettext.translation("calamares-python", + localedir=libcalamares.utils.gettext_path(), + languages=libcalamares.utils.gettext_languages(), + fallback=True).gettext + +def pretty_name(): + return _("Filling up filesystems.") + +# This is going to be changed from various methods +status = pretty_name() + +def pretty_status_message(): + return status + +class UnpackEntry: + """ + Extraction routine using rsync. + + :param source: + :param sourcefs: + :param destination: + """ + __slots__ = ('source', 'sourcefs', 'destination', 'copied', 'total', 'exclude', 'excludeFile', + 'mountPoint', 'weight') + + def __init__(self, source, sourcefs, destination): + """ + @p source is the source file name (might be an image file, or + a directory, too) + @p sourcefs is a type indication; "file" is special, as is + "squashfs". + @p destination is where the files from the source go. This is + **already** prefixed by rootMountPoint, so should be a + valid absolute path within the host system. + + The members copied and total are filled in by the copying process. + """ + self.source = source + self.sourcefs = sourcefs + self.destination = destination + self.exclude = None + self.excludeFile = None + self.copied = 0 + self.total = 0 + self.mountPoint = None + self.weight = 1 + + def is_file(self): + return self.sourcefs == "file" + + def do_count(self): + """ + Counts the number of files this entry has. + """ + # Need a name we can use like a global + class counter(object): + count = 0 + def cb_count(s): + counter.count += 1 + + if self.sourcefs == "squashfs": + libcalamares.utils.host_env_process_output(["unsquashfs", "-l", self.source], cb_count) + + elif self.sourcefs == "ext4": + libcalamares.utils.host_env_process_output(["find", self.mountPoint, "-type", "f"], cb_count) + + elif self.is_file(): + # Hasn't been mounted, copy directly; find handles both + # files and directories. + libcalamares.utils.host_env_process_output(["find", self.source, "-type", "f"], cb_count) + + self.total = counter.count + return self.total + + def do_mount(self, base): + """ + Mount given @p entry as loop device underneath @p base + + A *file* entry (e.g. one with *sourcefs* set to *file*) + is not mounted and just ignored. + + :param base: directory to place all the mounts in. + + :returns: None, but throws if the mount failed + """ + imgbasename = os.path.splitext( + os.path.basename(self.source))[0] + imgmountdir = os.path.join(base, imgbasename) + os.makedirs(imgmountdir, exist_ok=True) + + # This is where it *would* go (files bail out before actually mounting) + self.mountPoint = imgmountdir + + if self.is_file(): + return + + if os.path.isdir(self.source): + r = libcalamares.utils.mount(self.source, imgmountdir, "", "--bind") + elif os.path.isfile(self.source): + r = libcalamares.utils.mount(self.source, imgmountdir, self.sourcefs, "loop") + else: # self.source is a device + r = libcalamares.utils.mount(self.source, imgmountdir, self.sourcefs, "") + + if r != 0: + libcalamares.utils.debug("Failed to mount '{}' (fs={}) (target={})".format(self.source, self.sourcefs, imgmountdir)) + raise subprocess.CalledProcessError(r, "mount") + + +ON_POSIX = 'posix' in sys.builtin_module_names + + +def global_excludes(): + """ + List excludes for rsync. + """ + lst = [] + extra_mounts = libcalamares.globalstorage.value("extraMounts") + if extra_mounts is None: + extra_mounts = [] + + for extra_mount in extra_mounts: + mount_point = extra_mount["mountPoint"] + + if mount_point: + lst.extend(['--exclude', mount_point + '/']) + + return lst + +def file_copy(source, entry, progress_cb): + """ + Extract given image using rsync. + + :param source: Source file. This may be the place the entry's + image is mounted, or if it's a single file, the entry's source value. + :param entry: The UnpackEntry being copied. + :param progress_cb: A callback function for progress reporting. + Takes a number and a total-number. + """ + import time + + dest = entry.destination + + # `source` *must* end with '/' otherwise a directory named after the source + # will be created in `dest`: ie if `source` is "/foo/bar" and `dest` is + # "/dest", then files will be copied in "/dest/bar". + if not source.endswith("/") and not os.path.isfile(source): + source += "/" + + num_files_total_local = 0 + num_files_copied = 0 # Gets updated through rsync output + + args = ['rsync', '-aHAXSr', '--filter=-x trusted.overlay.*'] + args.extend(global_excludes()) + if entry.excludeFile: + args.extend(["--exclude-from=" + entry.excludeFile]) + if entry.exclude: + for f in entry.exclude: + args.extend(["--exclude", f]) + args.extend(['--progress', source, dest]) + + # last_num_files_copied trails num_files_copied, and whenever at least 107 more + # files (file_count_chunk) have been copied, progress is reported and + # last_num_files_copied is updated. The chunk size isn't "tidy" + # so that all the digits of the progress-reported number change. + # + file_count_chunk = 107 + + class counter(object): + last_num_files_copied = 0 + last_timestamp_reported = time.time() + last_total_reported = 0 + + def output_cb(line): + # rsync outputs progress in parentheses. Each line will have an + # xfer and a chk item (either ir-chk or to-chk) as follows: + # + # - xfer#x => Interpret it as 'file copy try no. x' + # - ir-chk=x/y, where: + # - x = number of files yet to be checked + # - y = currently calculated total number of files. + # - to-chk=x/y, which is similar and happens once the ir-chk + # phase (collecting total files) is over. + # + # If you're copying directory with some links in it, the xfer# + # might not be a reliable counter (for one increase of xfer, many + # files may be created). + m = re.findall(r'xfr#(\d+), ..-chk=(\d+)/(\d+)', line) + + if m: + # we've got a percentage update + num_files_remaining = int(m[0][1]) + num_files_total_local = int(m[0][2]) + # adjusting the offset so that progressbar can be continuesly drawn + num_files_copied = num_files_total_local - num_files_remaining + + now = time.time() + if (num_files_copied - counter.last_num_files_copied >= file_count_chunk) or (now - counter.last_timestamp_reported > 0.5): + counter.last_num_files_copied = num_files_copied + counter.last_timestamp_reported = now + counter.last_total_reported = num_files_total_local + progress_cb(num_files_copied, num_files_total_local) + + try: + returncode = libcalamares.utils.host_env_process_output(args, output_cb) + except subprocess.CalledProcessError as e: + returncode = e.returncode + + progress_cb(counter.last_num_files_copied, counter.last_total_reported) # Push towards 100% + + # Mark this entry as really done + entry.copied = entry.total + + # 23 is the return code rsync returns if it cannot write extended + # attributes (with -X) because the target file system does not support it, + # e.g., the FAT EFI system partition. We need -X because distributions + # using file system capabilities and/or SELinux require the extended + # attributes. But distributions using SELinux may also have SELinux labels + # set on files under /boot/efi, and rsync complains about those. The only + # clean way would be to split the rsync into one with -X and + # --exclude /boot/efi and a separate one without -X for /boot/efi, but only + # if /boot/efi is actually an EFI system partition. For now, this hack will + # have to do. See also: + # https://bugzilla.redhat.com/show_bug.cgi?id=868755#c50 + # for the same issue in Anaconda, which uses a similar workaround. + if returncode != 0 and returncode != 23: + libcalamares.utils.warning("rsync failed with error code {}.".format(returncode)) + return _("rsync failed with error code {}.").format(returncode) + + return None + + +class UnpackOperation: + """ + Extraction routine using unsquashfs. + + :param entries: + """ + + def __init__(self, entries): + self.entries = entries + self.entry_for_source = dict((x.source, x) for x in self.entries) + self.total_weight = sum([e.weight for e in entries]) + + def report_progress(self): + """ + Pass progress to user interface + """ + progress = float(0) + + current_total = 0 + current_done = 0 # Files count in the current entry + complete_count = 0 + complete_weight = 0 # This much weight already finished + for entry in self.entries: + if entry.total == 0: + # Total 0 hasn't counted yet + continue + if entry.total == entry.copied: + complete_weight += entry.weight + complete_count += 1 + else: + # There is at most *one* entry in-progress + current_total = entry.total + current_done = entry.copied + complete_weight += entry.weight * ( 1.0 * current_done ) / current_total + break + + if current_total > 0: + progress = ( 1.0 * complete_weight ) / self.total_weight + + global status + status = _("Unpacking image {}/{}, file {}/{}").format((complete_count+1), len(self.entries), current_done, current_total) + libcalamares.job.setprogress(progress) + + def run(self): + """ + Extract given image using unsquashfs. + + :return: + """ + global status + source_mount_path = tempfile.mkdtemp() + + try: + complete = 0 + for entry in self.entries: + status = _("Starting to unpack {}").format(entry.source) + libcalamares.job.setprogress( ( 1.0 * complete ) / len(self.entries) ) + entry.do_mount(source_mount_path) + entry.do_count() # Fill in the entry.total + + self.report_progress() + error_msg = self.unpack_image(entry, entry.mountPoint) + + if error_msg: + return (_("Failed to unpack image \"{}\"").format(entry.source), + error_msg) + complete += 1 + + return None + finally: + shutil.rmtree(source_mount_path, ignore_errors=True, onerror=None) + + + def unpack_image(self, entry, imgmountdir): + """ + Unpacks image. + + :param entry: + :param imgmountdir: + :return: + """ + def progress_cb(copied, total): + """ Copies file to given destination target. + + :param copied: + """ + entry.copied = copied + if total > entry.total: + entry.total = total + self.report_progress() + + try: + if entry.is_file(): + source = entry.source + else: + source = imgmountdir + + return file_copy(source, entry, progress_cb) + finally: + if not entry.is_file(): + subprocess.check_call(["umount", "-l", imgmountdir]) + + +def get_supported_filesystems_kernel(): + """ + Reads /proc/filesystems (the list of supported filesystems + for the current kernel) and returns a list of (names of) + those filesystems. + """ + PATH_PROCFS = '/proc/filesystems' + + if os.path.isfile(PATH_PROCFS) and os.access(PATH_PROCFS, os.R_OK): + with open(PATH_PROCFS, 'r') as procfile: + filesystems = procfile.read() + filesystems = filesystems.replace( + "nodev", "").replace("\t", "").splitlines() + return filesystems + + return [] + + +def get_supported_filesystems(): + """ + Returns a list of all the supported filesystems + (valid values for the *sourcefs* key in an item. + """ + return ["file"] + get_supported_filesystems_kernel() + + +def repair_root_permissions(root_mount_point): + """ + If the / of the system gets permission 777, change it down + to 755. Any other permission is left alone. This + works around standard behavior from squashfs where + permissions are (easily, accidentally) set to 777. + """ + existing_root_mode = os.stat(root_mount_point).st_mode & 0o777 + if existing_root_mode == 0o777: + try: + os.chmod(root_mount_point, 0o755) # Want / to be rwxr-xr-x + except OSError as e: + libcalamares.utils.warning("Could not set / to safe permissions: {}".format(e)) + # But ignore it + + +def extract_weight(entry): + """ + Given @p entry, a dict representing a single entry in + the *unpack* list, returns its weight (1, or whatever is + set if it is sensible). + """ + w = entry.get("weight", None) + if w: + try: + wi = int(w) + return wi if wi > 0 else 1 + except ValueError: + libcalamares.utils.warning("*weight* setting {!r} is not valid.".format(w)) + except TypeError: + libcalamares.utils.warning("*weight* setting {!r} must be number.".format(w)) + return 1 + + +def run(): + """ + Unsquash filesystem. + """ + root_mount_point = libcalamares.globalstorage.value("rootMountPoint") + + if not root_mount_point: + libcalamares.utils.warning("No mount point for root partition") + return (_("No mount point for root partition"), + _("globalstorage does not contain a \"rootMountPoint\" key.")) + if not os.path.exists(root_mount_point): + libcalamares.utils.warning("Bad root mount point \"{}\"".format(root_mount_point)) + return (_("Bad mount point for root partition"), + _("rootMountPoint is \"{}\", which does not exist.".format(root_mount_point))) + + if libcalamares.job.configuration.get("unpack", None) is None: + libcalamares.utils.warning("No *unpack* key in job configuration.") + return (_("Bad unpackfs configuration"), + _("There is no configuration information.")) + + supported_filesystems = get_supported_filesystems() + + # Bail out before we start when there are obvious problems + # - unsupported filesystems + # - non-existent sources + # - missing tools for specific FS + for entry in libcalamares.job.configuration["unpack"]: + source = os.path.abspath(entry["source"]) + sourcefs = entry["sourcefs"] + + if sourcefs not in supported_filesystems: + libcalamares.utils.warning("The filesystem for \"{}\" ({}) is not supported by your current kernel".format(source, sourcefs)) + libcalamares.utils.warning(" ... modprobe {} may solve the problem".format(sourcefs)) + return (_("Bad unpackfs configuration"), + _("The filesystem for \"{}\" ({}) is not supported by your current kernel").format(source, sourcefs)) + if not os.path.exists(source): + libcalamares.utils.warning("The source filesystem \"{}\" does not exist".format(source)) + return (_("Bad unpackfs configuration"), + _("The source filesystem \"{}\" does not exist").format(source)) + if sourcefs == "squashfs": + if shutil.which("unsquashfs") is None: + libcalamares.utils.warning("Failed to find unsquashfs") + + return (_("Bad unpackfs configuration"), + _("Failed to find unsquashfs, make sure you have the squashfs-tools package installed.") + + " " + _("Failed to unpack image \"{}\"").format(source)) + + unpack = list() + + is_first = True + for entry in libcalamares.job.configuration["unpack"]: + source = os.path.abspath(entry["source"]) + sourcefs = entry["sourcefs"] + destination = os.path.abspath(root_mount_point + entry["destination"]) + + if not os.path.isdir(destination) and sourcefs != "file": + libcalamares.utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination)) + if is_first: + return (_("Bad unpackfs configuration"), + _("The destination \"{}\" in the target system is not a directory").format(destination)) + else: + libcalamares.utils.debug(".. assuming that the previous targets will create that directory.") + + unpack.append(UnpackEntry(source, sourcefs, destination)) + # Optional settings + if entry.get("exclude", None): + unpack[-1].exclude = entry["exclude"] + if entry.get("excludeFile", None): + unpack[-1].excludeFile = entry["excludeFile"] + unpack[-1].weight = extract_weight(entry) + + is_first = False + + repair_root_permissions(root_mount_point) + try: + unpackop = UnpackOperation(unpack) + return unpackop.run() + finally: + repair_root_permissions(root_mount_point) diff --git a/etc/calamares/modules/unpackfs/module.desc b/etc/calamares/modules/unpackfs/module.desc new file mode 100644 index 0000000..2723c3c --- /dev/null +++ b/etc/calamares/modules/unpackfs/module.desc @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# Syntax is YAML 1.2 +--- +type: "job" +name: "unpackfs" +interface: "python" +script: "main.py" +requiredModules: [ mount ] +weight: 12 diff --git a/etc/calamares/modules/unpackfs/runtests.sh b/etc/calamares/modules/unpackfs/runtests.sh new file mode 100644 index 0000000..2269b07 --- /dev/null +++ b/etc/calamares/modules/unpackfs/runtests.sh @@ -0,0 +1,37 @@ +#! /bin/sh +# +# SPDX-FileCopyrightText: 2019 Adriaan de Groot +# SPDX-License-Identifier: BSD-2-Clause +# +# Test preparation for unpackfs; since there's a bunch +# of fiddly bits than need to be present for the tests, +# do that in a script rather than entirely in CTest. +# +SRCDIR=$( dirname "$0" ) + +# For test 3 +mkdir /tmp/unpackfs-test-run-rootdir3 + +# For test 7 +mkdir /tmp/unpackfs-test-run-rootdir3/realdest + +# For test 9 +mkdir /tmp/unpackfs-test-run-rootdir3/smalldest +if test 0 = $( id -u ) ; then + mount -t tmpfs -o size=32M tmpfs /tmp/unpackfs-test-run-rootdir3/smalldest + dd if=/dev/zero of=/tmp/unpackfs-test-run-rootdir3/smalldest/bogus.zero bs=1M count=1 +fi + +# Run tests +sh "$SRCDIR/../testpythonrun.sh" unpackfs + +# Cleanup test 9 +if test 0 = $( id -u ) ; then + umount /tmp/unpackfs-test-run-rootdir3/smalldest +fi + +# Cleanup test 7 +rm -rf /tmp/unpackfs-test-run-rootdir3/realdest + +# Cleanup test 3 +rmdir /tmp/unpackfs-test-run-rootdir3 diff --git a/etc/calamares/modules/unpackfs/tests/1.global b/etc/calamares/modules/unpackfs/tests/1.global new file mode 100644 index 0000000..7dedc15 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/1.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +bogus: true diff --git a/etc/calamares/modules/unpackfs/tests/2.global b/etc/calamares/modules/unpackfs/tests/2.global new file mode 100644 index 0000000..d1e61ca --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/2.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir/ diff --git a/etc/calamares/modules/unpackfs/tests/3.global b/etc/calamares/modules/unpackfs/tests/3.global new file mode 100644 index 0000000..1c25cbe --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/3.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/3.job b/etc/calamares/modules/unpackfs/tests/3.job new file mode 100644 index 0000000..82d3531 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/3.job @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +unpack: [] diff --git a/etc/calamares/modules/unpackfs/tests/4.global b/etc/calamares/modules/unpackfs/tests/4.global new file mode 100644 index 0000000..1c25cbe --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/4.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/4.job b/etc/calamares/modules/unpackfs/tests/4.job new file mode 100644 index 0000000..e6b067d --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/4.job @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +# Test that a "bogus" sourcefs (a filesystem kind that does not +# exist) fails gracefully. +--- +unpack: + - source: . + sourcefs: bogus + destination: / diff --git a/etc/calamares/modules/unpackfs/tests/5.global b/etc/calamares/modules/unpackfs/tests/5.global new file mode 100644 index 0000000..1c25cbe --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/5.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/5.job b/etc/calamares/modules/unpackfs/tests/5.job new file mode 100644 index 0000000..268ee7c --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/5.job @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +unpack: + - source: ./fakesource + sourcefs: ext4 + destination: fakedest diff --git a/etc/calamares/modules/unpackfs/tests/6.global b/etc/calamares/modules/unpackfs/tests/6.global new file mode 100644 index 0000000..1c25cbe --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/6.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/6.job b/etc/calamares/modules/unpackfs/tests/6.job new file mode 100644 index 0000000..1ec0840 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/6.job @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +unpack: + - source: . + sourcefs: ext4 + destination: fakedest diff --git a/etc/calamares/modules/unpackfs/tests/7.global b/etc/calamares/modules/unpackfs/tests/7.global new file mode 100644 index 0000000..1c25cbe --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/7.global @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/7.job b/etc/calamares/modules/unpackfs/tests/7.job new file mode 100644 index 0000000..ffd898f --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/7.job @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +unpack: + - source: . + sourcefs: ext4 + destination: realdest diff --git a/etc/calamares/modules/unpackfs/tests/8.global b/etc/calamares/modules/unpackfs/tests/8.global new file mode 100644 index 0000000..15c3085 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/8.global @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir/ +localeConf: + - LANG: nl diff --git a/etc/calamares/modules/unpackfs/tests/8.job b/etc/calamares/modules/unpackfs/tests/8.job new file mode 100644 index 0000000..ffd898f --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/8.job @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +--- +unpack: + - source: . + sourcefs: ext4 + destination: realdest diff --git a/etc/calamares/modules/unpackfs/tests/9.global b/etc/calamares/modules/unpackfs/tests/9.global new file mode 100644 index 0000000..e7a2cd9 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/9.global @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# This test uses a small destination FS, to make rsync fail +--- +rootMountPoint: /tmp/unpackfs-test-run-rootdir3/ diff --git a/etc/calamares/modules/unpackfs/tests/9.job b/etc/calamares/modules/unpackfs/tests/9.job new file mode 100644 index 0000000..b896334 --- /dev/null +++ b/etc/calamares/modules/unpackfs/tests/9.job @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# This test uses a small destination FS, to make rsync fail +--- +unpack: + - source: . + sourcefs: ext4 + destination: smalldest diff --git a/etc/calamares/modules/unpackfs/unpackfs.conf b/etc/calamares/modules/unpackfs/unpackfs.conf new file mode 100644 index 0000000..d12110b --- /dev/null +++ b/etc/calamares/modules/unpackfs/unpackfs.conf @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +# Unsquash / unpack a filesystem. Multiple sources are supported, and +# they may be squashed or plain filesystems. +# +# Configuration: +# +# from globalstorage: rootMountPoint +# from job.configuration: the path to where to mount the source image(s) +# for copying an ordered list of unpack mappings for image file <-> +# target dir relative to rootMountPoint. + +--- +# Each list item is unpacked, in order, to the target system. +# +# Each list item has the following **mandatory** attributes: +# - *source* path relative to the live / intstalling system to the image +# - *sourcefs* the type of the source files; valid entries are +# - `ext4` (copies the filesystem contents) +# - `squashfs` (unsquashes) +# - `file` (copies a file or directory) +# - (may be others if mount supports it) +# - *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. +# +# Each list item **optionally** can include the following attributes: +# - *exclude* is a list of values that is expanded into --exclude +# arguments for rsync (each entry in exclude gets its own --exclude). +# - *excludeFile* is a single file that is passed to rsync as an +# --exclude-file argument. This should be a full pathname +# inside the **host** filesystem. +# - *weight* is useful when the entries take wildly different +# times to unpack (e.g. with a squashfs, and one single file) +# and the total weight of this module should be distributed +# differently between the entries. (This is only relevant when +# there is more than one entry; by default all the entries +# have the same weight, 1) +# +# EXAMPLES +# +# Usually you list a filesystem image to unpack; you can use +# squashfs or an ext4 image. An empty destination is equivalent to "/", +# the root of the target system. The destination directory must exist +# in the target system. +# +# - source: "/path/to/filesystem.sqfs" +# sourcefs: "squashfs" +# destination: "" +# +# Multiple entries are unpacked in-order; if there is more than one +# item then only the first must exist beforehand -- it's ok to +# create directories with one unsquash and then to use those +# directories as a target from a second unsquash. +# +# - source: "/path/to/another/filesystem.img" +# sourcefs: "ext4" +# destination: "" +# - source: "/path/to/another/filesystem2.img" +# sourcefs: "ext4" +# destination: "/usr/lib/extra" +# +# You can list filesystem source paths relative to the Calamares run +# directory, if you use -d (this is only useful for testing, though). +# +# - source: ./example.sqfs +# sourcefs: squashfs +# destination: "" +# +# You can list individual files (copied one-by-one), or directories +# (the files inside this directory are copied directly to the destination, +# so no "dummycpp/" subdirectory is created in this example). +# Do note that the target directory must exist already (e.g. from +# extracting some other filesystem). +# +# - source: ../CHANGES +# sourcefs: file +# destination: "/tmp/derp" +# - source: ../src/modules/dummycpp +# sourcefs: file +# destination: "/tmp/derp" +# +# The *destination* and *source* are handed off to rsync, so the semantics +# of trailing slashes apply. In order to *rename* a file as it is +# copied, specify one single file (e.g. CHANGES) and a full pathname +# for its destination name, as in the example below. + +unpack: + - source: ../CHANGES + sourcefs: file + destination: "/tmp/changes.txt" + weight: 1 # Single file + - source: src/qml/calamares/slideshow + sourcefs: file + destination: "/tmp/slideshow/" + exclude: [ "*.qmlc", "qmldir" ] + weight: 5 # Lots of files + # excludeFile: /etc/calamares/modules/unpackfs/exclude-list.txt diff --git a/etc/calamares/modules/unpackfs/unpackfs.schema.yaml b/etc/calamares/modules/unpackfs/unpackfs.schema.yaml new file mode 100644 index 0000000..0d96fe9 --- /dev/null +++ b/etc/calamares/modules/unpackfs/unpackfs.schema.yaml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2020 Adriaan de Groot +# SPDX-License-Identifier: GPL-3.0-or-later +--- +$schema: https://json-schema.org/schema# +$id: https://calamares.io/schemas/unpackfs +additionalProperties: false +type: object +properties: + unpack: + type: array + items: + type: object + additionalProperties: false + properties: + source: { type: string } + sourcefs: { type: string } + destination: { type: string } + excludeFile: { type: string } + exclude: { type: array, items: { type: string } } + weight: { type: integer, exclusiveMinimum: 0 } + required: [ source , sourcefs, destination ] diff --git a/etc/calamares/settings.conf b/etc/calamares/settings.conf new file mode 100644 index 0000000..d0e0860 --- /dev/null +++ b/etc/calamares/settings.conf @@ -0,0 +1,236 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +# +# Configuration file for Calamares +# +# This is the top-level configuration file for Calamares. +# It specifies what modules will be used, as well as some +# overall characteristics -- is this a setup program, or +# an installer. More specific configuration is devolved +# to the branding file (for the UI) and the individual +# module configuration files (for functionality). +--- +# Modules can be job modules (with different interfaces) and QtWidgets view +# modules. They could all be placed in a number of different paths. +# "modules-search" is a list of strings, each of these can either be a full +# path to a directory or the keyword "local". +# +# "local" means: +# - modules in $LIBDIR/calamares/modules, with +# - settings in SHARE/calamares/modules or /etc/calamares/modules. +# In debug-mode (e.g. calamares -d) "local" also adds some paths +# that make sense from inside the build-directory, so that you +# can build-and-run with the latest modules immediately. +# +# Strings other than "local" are taken as paths and interpreted +# relative to wherever Calamares is started. It is therefore **strongly** +# recommended to use only absolute paths here. This is mostly useful +# if your distro has forks of standard Calamares modules, but also +# uses some form of upstream packaging which might overwrite those +# forked modules -- then you can keep modules somewhere outside of +# the "regular" module tree. +# +# +# YAML: list of strings. +modules-search: [ local ] + +# Instances section. This section is optional, and it defines custom instances +# for modules of any kind. An instance entry has these keys: +# - *module* name, which matches the module name from the module descriptor +# (usually the name of the directory under `src/modules/`, but third- +# party modules may diverge. +# - *id* (optional) an identifier to distinguish this instance from +# all the others. If none is given, the name of the module is used. +# Together, the module and id form an instance key (see below). +# - *config* (optional) a filename for the configuration. If none is +# given, *module*`.conf` is used (e.g. `welcome.conf` for the welcome +# module) +# - *weight* (optional) In the *exec* phase of the sequence, progress +# is reported as jobs are completed. The jobs from a single module +# together contribute the full weight of that module. The overall +# progress (0 .. 100%) is divided up according to the weight of each +# module. Give modules that take a lot of time to complete, a larger +# weight to keep the overall progress moving along steadily. This +# weight overrides a weight given in the module descriptor. If no weight +# is given, uses the value from the module descriptor, or 1 if there +# isn't one there either. +# +# The primary goal of this mechanism is to allow loading multiple instances +# of the same module, with different configuration. If you don't need this, +# the instances section can safely be left empty. +# +# Module name plus instance name makes an instance key, e.g. +# "packagechooserq@licenseq", where "packagechooserq" is the module name (for the packagechooserq +# viewmodule) and "licenseq" is the instance name. In the *sequence* +# section below, use instance-keys to name instances (instead of just +# a module name, for modules which have only a single instance). +# +# Every module implicitly has an instance with the instance name equal +# to its module name, e.g. "welcome@welcome". In the *sequence* section, +# mentioning a module without a full instance key (e.g. "welcome") +# means that implicit module. +# +# An instance may specify its configuration file (e.g. `webview-home.conf`). +# The implicit instances all have configuration files named `.conf`. +# This (implict) way matches the source examples, where the welcome +# module contains an example `welcome.conf`. Specify a *config* for +# any module (also implicit instances) to change which file is used. +# +# For more information on running module instances, run Calamares in debug +# mode and check the Modules page in the Debug information interface. +# +# A module that is often used with instances is shellprocess, which will +# run shell commands specified in the configuration file. By configuring +# more than one instance of the module, multiple shell sessions can be run +# during install. +# +# YAML: list of maps of string:string key-value pairs. +#instances: +#- id: licenseq +# module: packagechooserq +# config: licenseq.conf + +# Sequence section. This section describes the sequence of modules, both +# viewmodules and jobmodules, as they should appear and/or run. +# +# A jobmodule instance key (or name) can only appear in an exec phase, whereas +# a viewmodule instance key (or name) can appear in both exec and show phases. +# There is no limit to the number of show or exec phases. However, the same +# module instance key should not appear more than once per phase, and +# deployers should take notice that the global storage structure is persistent +# throughout the application lifetime, possibly influencing behavior across +# phases. A show phase defines a sequence of viewmodules (and therefore +# pages). These viewmodules can offer up jobs for the execution queue. +# +# An exec phase displays a progress page (with brandable slideshow). This +# progress page iterates over the modules listed in the *immediately +# preceding* show phase, and enqueues their jobs, as well as any other jobs +# from jobmodules, in the order defined in the current exec phase. +# +# It then executes the job queue and clears it. If a viewmodule offers up a +# job for execution, but the module name (or instance key) isn't listed in the +# immediately following exec phase, this job will not be executed. +# +# YAML: list of lists of strings. +sequence: +- show: + - welcome +# - notesqml +# - packagechooserq@licenseq + - locale + - keyboard + - partition + - users +# - tracking + - summary +- exec: +# - dummycpp +# - dummyprocess +# - dummypython + - partition +# - zfs + - mount + - unpackfs + - machineid + - locale + - keyboard + - localecfg +# - luksbootkeyfile +# - luksopenswaphookcfg +# - dracutlukscfg + - fstab +# - plymouthcfg +# - zfshostid + - initcpiocfg + - initcpio + - users + - displaymanager + - networkcfg + - hwclock + - services-systemd +# - dracut + - initramfs +# - grubcfg + - bootloader + - umount +- show: + - finished + +# A branding component is a directory, either in SHARE/calamares/branding or +# in /etc/calamares/branding (the latter takes precedence). The directory must +# contain a YAML file branding.desc which may reference additional resources +# (such as images) as paths relative to the current directory. +# +# A branding component can also ship a QML slideshow for execution pages, +# along with translation files. +# +# Only the name of the branding component (directory) should be specified +# here, Calamares then takes care of finding it and loading the contents. +# +# YAML: string. +branding: default + +# If this is set to true, Calamares will show an "Are you sure?" prompt right +# before each execution phase, i.e. at points of no return. If this is set to +# false, no prompt is shown. Default is false, but Calamares will complain if +# this is not explicitly set. +# +# YAML: boolean. +prompt-install: false + +# If this is set to true, Calamares will execute all target environment +# commands in the current environment, without chroot. This setting should +# only be used when setting up Calamares as a post-install configuration tool, +# as opposed to a full operating system installer. +# +# Some official Calamares modules are not expected to function with this +# setting. (e.g. partitioning seems like a bad idea, since that is expected to +# have been done already) +# +# Default is false (for a normal installer), but Calamares will complain if +# this is not explicitly set. +# +# YAML: boolean. +dont-chroot: false + +# If this is set to true, Calamares refers to itself as a "setup program" +# rather than an "installer". Defaults to the value of dont-chroot, but +# Calamares will complain if this is not explicitly set. +oem-setup: false + +# If this is set to true, the "Cancel" button will be disabled entirely. +# The button is also hidden from view. +# +# This can be useful if when e.g. Calamares is used as a post-install +# configuration tool and you require the user to go through all the +# configuration steps. +# +# Default is false, but Calamares will complain if this is not explicitly set. +# +# YAML: boolean. +disable-cancel: false + +# If this is set to true, the "Cancel" button will be disabled once +# you start the 'Installation', meaning there won't be a way to cancel +# the Installation until it has finished or installation has failed. +# +# Default is false, but Calamares will complain if this is not explicitly set. +# +# YAML: boolean. +disable-cancel-during-exec: false + +# If this is set to true, the "Next" and "Back" button will be hidden once +# you start the 'Installation'. +# +# Default is false, but Calamares will complain if this is not explicitly set. +# +# YAML: boolean. +hide-back-and-next-during-exec: false + +# If this is set to true, then once the end of the sequence has +# been reached, the quit (done) button is clicked automatically +# and Calamares will close. Default is false: the user will see +# that the end of installation has been reached, and that things are ok. +# +# +quit-at-end: false