Compare commits
	
		
			24 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | f01b4ed2f8 | ||
|   | ea762b0945 | ||
|   | cae8acb4a4 | ||
|   | ae204d0108 | ||
|   | a2fae600c4 | ||
|   | 349acad491 | ||
|   | 9b4c4876bc | ||
|   | cc02baed9a | ||
|   | dfab089938 | ||
|   | 2dd9a7ba8a | ||
|   | 82f31f3cd9 | ||
|   | c5b01a574d | ||
|   | bc4789d57f | ||
|   | 0962b98494 | ||
|   | 108476c025 | ||
|   | 04a1bc9e2c | ||
|   | bff5e485f4 | ||
|   | 3c838436c2 | ||
|   | 644c9cf4f3 | ||
|   | dcaa378ddd | ||
|   | 14fd23dcef | ||
|   | f4bc7052e0 | ||
|   | 4f0f48d99d | ||
|   | 1344880f2e | 
| @@ -29,15 +29,12 @@ rules of decent behavior in both communities are pretty much the same). | ||||
|  | ||||
| GitHub Issues are **one** place for discussing Calamares and its extensions if there are concrete | ||||
| problems or a new feature to discuss. | ||||
| Issues are not a help channel. | ||||
| Visit Matrix for help with configuration or compilation. | ||||
|  | ||||
| Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/) | ||||
| room, `#calamares:kde.org`. The conversation is bridged with IRC | ||||
| on [Libera.Chat](https://libera.chat/). | ||||
| Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. If you use IRC, **DO NOT** ask-and-leave. Keep | ||||
| that chat window open because it can easily take a few hours for | ||||
| someone to notice a message. | ||||
| room, `#calamares:kde.org`. Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. | ||||
| Matrix is persistent, and we'll see your message eventually. | ||||
|  | ||||
| * [](https://webchat.kde.org/#/room/%23calamares:kde.org) | ||||
| * [](https://kiwiirc.com/client/irc.libera.chat/#calamares) | ||||
|   | ||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							| @@ -40,7 +40,10 @@ and documentation for the framework that Calamares ships with. | ||||
|    (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. | ||||
|    has translations and a bunch of fancy graphics for the | ||||
|    slideshow. Plus it includes examples of using different | ||||
|    QML options for a vertical navigation bar and horizontal | ||||
|    sidebar. | ||||
|  - [`samegame/` ](branding/default/branding.desc) | ||||
|    is a copy of the Qt Company "Same Game" QML demo. It | ||||
|    shows that **any** QML can be used for branding purposes. | ||||
| @@ -217,15 +220,12 @@ The API is loosely documented in the | ||||
| GitHub Issues are **one** place for discussing Calamares (and Calamares Extensions) | ||||
| if there are concrete | ||||
| problems or a new feature to discuss. | ||||
| Issues are not a help channel. | ||||
| Visit Matrix for help with configuration or compilation. | ||||
|  | ||||
| Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/) | ||||
| room, `#calamares:kde.org`. The conversation is bridged with IRC | ||||
| on [Libera.Chat](https://libera.chat/). | ||||
| Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. If you use IRC, **DO NOT** ask-and-leave. Keep | ||||
| that chat window open because it can easily take a few hours for | ||||
| someone to notice a message. | ||||
| room, `#calamares:kde.org`. Responsiveness is best during the day | ||||
| in Europe, but feel free to idle. | ||||
| Matrix is persistent, and we'll see your message eventually. | ||||
|  | ||||
| * [](https://webchat.kde.org/#/room/%23calamares:kde.org) | ||||
| * [](https://kiwiirc.com/client/irc.libera.chat/#calamares) | ||||
|   | ||||
							
								
								
									
										101
									
								
								branding/kaos_branding/about.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								branding/kaos_branding/about.qml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2020 2022 Anke Boersma <demm@kaosx.us> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| import io.calamares.core 1.0 | ||||
| import io.calamares.ui 1.0 | ||||
|  | ||||
| import QtQuick 2.7 | ||||
| import QtQuick.Controls 2.0 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import QtQuick.Window 2.3 | ||||
|  | ||||
| ApplicationWindow { | ||||
|     id: about | ||||
|     visible: true | ||||
|     width: 760 | ||||
|     height: 400 | ||||
|     title: qsTr("About Calamares") | ||||
|  | ||||
|     property var appName: "Calamares" | ||||
|     property var appVersion: "3.3 RC" | ||||
|  | ||||
|     Rectangle { | ||||
|         id: textArea | ||||
|         anchors.fill: parent | ||||
|         color: "#f2f2f2" | ||||
|  | ||||
|         Column { | ||||
|             id: column | ||||
|             anchors.centerIn: parent | ||||
|  | ||||
|  | ||||
|             Rectangle { | ||||
|                 width: 560 | ||||
|                 height: 250 | ||||
|                 radius: 10 | ||||
|                 border.width: 0 | ||||
|  | ||||
|                 Text { | ||||
|                     width: 400 | ||||
|                     height: 250 | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("<h1>%1</h1><br/> | ||||
|                         <strong>%2<br/> | ||||
|                         for %3</strong><br/><br/> | ||||
|                         Copyright 2014-2017 Teo Mrnjavac <teo@kde.org><br/> | ||||
|                         Copyright 2017-2022 Adriaan de Groot <groot@kde.org><br/> | ||||
|                         Thanks to <a href='https://calamares.io/team/'>the Calamares team</a> | ||||
|                         and the <a href=\"https://www.transifex.com/kaos/kaos/\">KaOS | ||||
|                         translators team</a>.<br/><br/> | ||||
|                         <a href='https://calamares.io/'>Calamares</a> | ||||
|                         development is sponsored by <br/> | ||||
|                         <a href='http://www.blue-systems.com/'>Blue Systems</a> - | ||||
|                         Liberating Software." ) | ||||
|                         .arg(appName) | ||||
|                         .arg(appVersion) | ||||
|                         .arg(Branding.string(Branding.VersionedName)) | ||||
|  | ||||
|                         onLinkActivated: Qt.openUrlExternally(link) | ||||
|  | ||||
|                         MouseArea { | ||||
|                             anchors.fill: parent | ||||
|                             acceptedButtons: Qt.NoButton | ||||
|                             cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor | ||||
|                         } | ||||
|  | ||||
|                     font.pointSize: 10 | ||||
|                     anchors.verticalCenterOffset: 10 | ||||
|                     anchors.horizontalCenterOffset: 40 | ||||
|                     wrapMode: Text.WordWrap | ||||
|                 } | ||||
|  | ||||
|                 Image { | ||||
|                     id: image | ||||
|                     x: 8 | ||||
|                     y: 12 | ||||
|                     height: 100 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     source: "squid.png" | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         Button { | ||||
|             anchors.horizontalCenter: parent.horizontalCenter | ||||
|             anchors.bottom: parent.bottom | ||||
|             icon.name: "window-close" | ||||
|             text: qsTr("Close") | ||||
|             hoverEnabled: true | ||||
|             onClicked: about.close(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,22 +1,32 @@ | ||||
| --- | ||||
| componentName:  kaos | ||||
|  | ||||
| welcomeStyleCalamares:   false | ||||
|  | ||||
| # Should the welcome image (productWelcome, below) be scaled | ||||
| # up beyond its natural size? | ||||
| welcomeExpandingLogo:   true | ||||
|  | ||||
| windowExpanding:    normal | ||||
| windowSize: 920px,630px | ||||
| windowPlacement: center | ||||
|  | ||||
| sidebar: qml,bottom | ||||
| navigation: qml,right | ||||
|  | ||||
| strings: | ||||
|     productName:         KaOS | ||||
|     shortProductName:    KaOS | ||||
|     version:             2018.03 | ||||
|     version:             2022.08 | ||||
|     shortVersion:        KaOS | ||||
|     versionedName:       KaOS 2018.03 | ||||
|     versionedName:       KaOS 2022.08 | ||||
|     shortVersionedName:  KaOS 2018.03 | ||||
|     bootloaderEntryName: KaOS | ||||
|     productUrl:          https://kaosx.us/ | ||||
|     supportUrl:          https://kaosx.us/docs/ | ||||
|     knownIssuesUrl:      https://kaosx.us/pages/download/#known-issues | ||||
|     releaseNotesUrl:     https://kaosx.us/pages/release_notes | ||||
|     donateUrl:           https://kaosx.us/about/donors | ||||
|  | ||||
| images: | ||||
|     productLogo:         "kaos.png" | ||||
| @@ -27,6 +37,7 @@ slideshow:               "show.qml" | ||||
| slideshowAPI:            1 | ||||
|  | ||||
| style: | ||||
|    sidebarBackground:    "#bdc3c7" | ||||
|    sidebarText:          "#1F1F1F" | ||||
|    sidebarTextSelect:    "#3498DB" | ||||
|    SidebarBackground:    "#bdc3c7" | ||||
|    SidebarText:          "#1F1F1F" | ||||
|    SidebarTextCurrent:    "#3498DB" | ||||
|    SidebarBackgroundCurrent: "#eff0f1" | ||||
|   | ||||
							
								
								
									
										224
									
								
								branding/kaos_branding/calamares-navigation.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								branding/kaos_branding/calamares-navigation.qml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| /* Sample of QML navigation. | ||||
|  | ||||
|    SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org> | ||||
|    SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us> | ||||
|    SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
|  | ||||
|    This navigation panel is for a "vertical" layout, with | ||||
|    mouse areas for next and previous and it includes the logo | ||||
|    plus About & Debug buttons. | ||||
| */ | ||||
| import io.calamares.ui 1.0 | ||||
| import io.calamares.core 1.0 | ||||
|  | ||||
| import QtQuick 2.3 | ||||
| import QtQuick.Controls 2.10 | ||||
| import QtQuick.Layouts 1.3 | ||||
|  | ||||
| Rectangle { | ||||
|     id: navigationBar; | ||||
|     color: Branding.styleString( Branding.SidebarBackground ); | ||||
|     height: parent.height; | ||||
|     width:64; | ||||
|  | ||||
|     ColumnLayout { | ||||
|         id: buttonBar | ||||
|         anchors.fill: parent; | ||||
|         spacing: 1 | ||||
|  | ||||
|         Image { | ||||
|             Layout.topMargin: 1; | ||||
|             Layout.bottomMargin:parent.height / 7; | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignTop | ||||
|             id: logo; | ||||
|             width: 62; | ||||
|             height: width;  // square | ||||
|             source: "file:/" + Branding.imagePath(Branding.ProductLogo); | ||||
|             sourceSize.width: width; | ||||
|             sourceSize.height: height; | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: backArea | ||||
|             Layout.fillWidth: true; | ||||
|             Layout.preferredHeight: parent.height / 7; | ||||
|             color: mouseBack.containsMouse ? "#e6e9ea" : "#d9dcde"; | ||||
|             enabled: ViewManager.backEnabled; | ||||
|             visible: ViewManager.backAndNextVisible; | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseBack | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|  | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Back") | ||||
|                     color: Branding.styleString( !backArea.enabled ? Branding.SidebarBackground : (mouseBack.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "pan-start-symbolic.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 32 | ||||
|                     opacity: backArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.back(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: nextArea | ||||
|             Layout.preferredHeight: parent.height / 7; | ||||
|             Layout.fillWidth: true | ||||
|             color: mouseNext.containsMouse ? "#f4f5f6" : "#e6e9ea"; | ||||
|             enabled: ViewManager.nextEnabled; | ||||
|             visible: ViewManager.backAndNextVisible; | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseNext | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Next") | ||||
|                     color: Branding.styleString( !nextArea.enabled ? Branding.SidebarBackground : (mouseNext.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "pan-end-symbolic.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 32 | ||||
|                     opacity: nextArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.next(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: cancelArea | ||||
|             height: parent.height / 7; | ||||
|             Layout.fillWidth: true | ||||
|             color: mouseCancel.containsMouse ? "#e6e9ea" : "#d9dcde"; | ||||
|  | ||||
|              /* | ||||
|              * The ViewManager has settings -- user-controlled via the | ||||
|              * branding component, and party based on program state -- | ||||
|              * whether the quit button should be enabled and visible. | ||||
|              * | ||||
|              * QML navigation *should* follow this pattern, but can also | ||||
|              * add other qualifications. For instance, you may have a | ||||
|              * "finished" module that handles quit in its own way, and | ||||
|              * want to hide the quit button then. The ViewManager has a | ||||
|              * current step and a total count, so compare them: | ||||
|              * | ||||
|              * visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); | ||||
|              */ | ||||
|  | ||||
|              enabled: ViewManager.quitEnabled; | ||||
|              visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); | ||||
|  | ||||
|             ToolTip { | ||||
|                 width: 59 | ||||
|                 visible: mouseCancel.containsMouse | ||||
|                 timeout: 5000 | ||||
|                 delay: 1000 | ||||
|                 text: ViewManager.quitTooltip; | ||||
|             } | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseCancel | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Cancel") | ||||
|                     color: Branding.styleString( !cancelArea.enabled ? Branding.SidebarBackground : (mouseCancel.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText )); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|                 Image { | ||||
|                     source: "draw-rectangle.svg" | ||||
|                     anchors.centerIn: parent | ||||
|                     anchors.verticalCenterOffset : 18 | ||||
|                     fillMode: Image.PreserveAspectFit | ||||
|                     height: 9 | ||||
|                     opacity: cancelArea.enabled ? 1 : 0.2 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: { ViewManager.quit(); } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Item { | ||||
|             Layout.fillHeight: true; | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: debugArea | ||||
|             Layout.fillWidth: true; | ||||
|             height: 35 | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom | ||||
|             color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground); | ||||
|             visible: debug.enabled | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseAreaDebug | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("Debug") | ||||
|                     color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackground ); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|  | ||||
|                 onClicked: debug.toggle() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Rectangle { | ||||
|             id: aboutArea | ||||
|             Layout.fillWidth: true; | ||||
|             height: 35 | ||||
|             Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom | ||||
|             color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground); | ||||
|             visible: true | ||||
|  | ||||
|             MouseArea { | ||||
|                 id: mouseAreaAbout | ||||
|                 anchors.fill: parent; | ||||
|                 cursorShape: Qt.PointingHandCursor | ||||
|                 hoverEnabled: true | ||||
|                 Text { | ||||
|                     anchors.centerIn: parent | ||||
|                     text: qsTr("About") | ||||
|                     ToolTip { | ||||
|                         visible: mouseAreaAbout.containsMouse | ||||
|                         delay: 1000 | ||||
|                         text: qsTr("Info about Calamares") | ||||
|                     } | ||||
|                     color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent ); | ||||
|                     font.pointSize : 8 | ||||
|                 } | ||||
|  | ||||
|                 property variant window; | ||||
|                 onClicked: { | ||||
|                     var component = Qt.createComponent("about.qml"); | ||||
|                     window = component.createObject(); | ||||
|                     window.show(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										72
									
								
								branding/kaos_branding/calamares-sidebar.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								branding/kaos_branding/calamares-sidebar.qml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| /* Sample of QML progress tree. | ||||
|  | ||||
|    SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org> | ||||
|    SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us> | ||||
|    SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
|  | ||||
|    The progress tree (actually a list) is "horizontal" in this example, | ||||
|    with the steps going to the right. | ||||
| */ | ||||
| import io.calamares.ui 1.0 | ||||
| import io.calamares.core 1.0 | ||||
|  | ||||
| import QtQuick 2.3 | ||||
| import QtQuick.Layouts 1.3 | ||||
| import QtQuick.Controls 2.15 | ||||
|  | ||||
| Rectangle { | ||||
|     id: sideBar; | ||||
|     color: Branding.styleString( Branding.SidebarBackground ); | ||||
|     height: 48; | ||||
|     width: parent.width | ||||
|  | ||||
|     RowLayout { | ||||
|         anchors.fill: parent; | ||||
|         spacing: 2; | ||||
|  | ||||
|         Item { | ||||
|             Layout.fillHeight: true; | ||||
|         } | ||||
|  | ||||
|         Repeater { | ||||
|             model: ViewManager | ||||
|             Rectangle { | ||||
|                 Layout.leftMargin: 0; | ||||
|                 Layout.fillWidth: true; | ||||
|                 Layout.alignment: Qt.AlignTop; | ||||
|                 height: 42; | ||||
|                 radius: 0; | ||||
|                 color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground ); | ||||
|  | ||||
|                 Text { | ||||
|                     anchors.verticalCenter: parent.verticalCenter; | ||||
|                     anchors.horizontalCenter: parent.horizontalCenter | ||||
|                     x: parent.x + 12; | ||||
|                     color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText ); | ||||
|                     text: display; | ||||
|                     font.pointSize : index == ViewManager.currentStepIndex ? 10 : 9 | ||||
|                 } | ||||
|  | ||||
|                 Rectangle { | ||||
|                     height: 2 | ||||
|                     width: 800 | ||||
|                     anchors.bottom: parent.bottom; | ||||
|                     border.color: Branding.styleString(ViewManager.currentStepIndex === index ? Branding.SidebarTextCurrent : (ViewManager.currentStepIndex >= index ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent)) | ||||
|                     border.width: 3 | ||||
|  | ||||
|                     Image { | ||||
|                         source: "pan-up-symbolic.svg" | ||||
|                         id: image | ||||
|                         anchors.verticalCenter: parent.verticalCenter; | ||||
|                         anchors.verticalCenterOffset : -3 | ||||
|                         x: parent.x + 35; | ||||
|                         fillMode: Image.PreserveAspectFit | ||||
|                         height: 32 | ||||
|                         visible: index == ViewManager.currentStepIndex ? true : false | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								branding/kaos_branding/draw-rectangle.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								branding/kaos_branding/draw-rectangle.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><path d="m2 1034.36v16h16v-16z" fill="#566060" transform="translate(1-1031.36)"/></svg> | ||||
| After Width: | Height: | Size: 147 B | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 106 KiB | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-end-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								branding/kaos_branding/pan-end-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-445.0002,-129)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 451.0002,142 5,-5 -5,-5 z" id="path6412" sodipodi:nodetypes="cccc" fill="#555555"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 896 B | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-start-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								branding/kaos_branding/pan-start-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-425.0002,-129)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 435.0002,142 -5,-5 5,-5 z" id="path6400-8" sodipodi:nodetypes="cccc" fill="#555555"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 898 B | 
							
								
								
									
										15
									
								
								branding/kaos_branding/pan-up-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								branding/kaos_branding/pan-up-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||||
| <svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new"> | ||||
|  <metadata id="metadata90"/> | ||||
|  <defs id="defs7386"> | ||||
|   <linearGradient id="linearGradient5606" osb:paint="solid"> | ||||
|    <stop id="stop5608"/> | ||||
|   </linearGradient> | ||||
|   <filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554"> | ||||
|    <feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/> | ||||
|   </filter> | ||||
|  </defs> | ||||
|  <g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-465.0002,-129.00001)"> | ||||
|   <path inkscape:connector-curvature="0" d="m 478.0002,139 -5,-5 -5,5 z" id="path6418" sodipodi:nodetypes="cccc" fill="#3498DB"/> | ||||
|  </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 902 B | 
| @@ -1,6 +1,7 @@ | ||||
| /* === This file is part of Calamares - <https://github.com/calamares> === | ||||
|  * | ||||
|  *   Copyright 2015, Teo Mrnjavac <teo@kde.org> | ||||
|  *   Copyright 2015-2018, Anke Boersma <demm@kaosx.us> | ||||
|  * | ||||
|  *   Calamares is free software: you can redistribute it and/or modify | ||||
|  *   it under the terms of the GNU General Public License as published by | ||||
| @@ -24,13 +25,12 @@ Presentation | ||||
|     id: presentation | ||||
|  | ||||
|     Timer { | ||||
|         id: advanceTimer | ||||
|         interval: 5000 | ||||
|         running: false | ||||
|         repeat: true | ||||
|         onTriggered: presentation.goToNextSlide() | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Slide { | ||||
|         anchors.fill: parent | ||||
|  | ||||
| @@ -38,7 +38,7 @@ Presentation | ||||
|             id: background | ||||
|             source: "1.svg" | ||||
|             anchors.fill: parent | ||||
|          | ||||
|  | ||||
|             Text { | ||||
|                 anchors.centerIn: parent | ||||
|                 anchors.verticalCenterOffset: 0 | ||||
| @@ -96,15 +96,15 @@ Presentation | ||||
|                 anchors.horizontalCenterOffset: -100 | ||||
|                 font.pixelSize: parent.width *.015 | ||||
|                 color: 'white' | ||||
|                 text: qsTr("The default Office Suite is Calligra.<br/>"+ | ||||
|                     "LibreOffice is available in the repositories. <br/>") | ||||
|                 text: qsTr("The default Office Suite is LibreOffice.<br/>"+ | ||||
|                     "Calligra is available in the repositories. <br/>") | ||||
|                 wrapMode: Text.WordWrap | ||||
|                 width: 450 | ||||
|                 horizontalAlignment: Text.AlignLeft | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Slide { | ||||
|         anchors.fill: parent | ||||
|  | ||||
| @@ -120,7 +120,7 @@ Presentation | ||||
|                 font.pixelSize: parent.width *.015 | ||||
|                 color: 'white' | ||||
|                 text: qsTr("Qt/KDE specific internet applications include the <br/>"+ | ||||
|                     "Qupzilla web-browser and kde-telepathy for <br/>"+ | ||||
|                     "Falkon web-browser and kde-telepathy for <br/>"+ | ||||
|                     "chat and Instant Messaging. <br/>") | ||||
|                 wrapMode: Text.WordWrap | ||||
|                 width: 450 | ||||
| @@ -128,7 +128,7 @@ Presentation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Slide { | ||||
|         anchors.fill: parent | ||||
|  | ||||
| @@ -150,7 +150,7 @@ Presentation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Slide { | ||||
|         anchors.fill: parent | ||||
|  | ||||
| @@ -172,6 +172,4 @@ Presentation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Component.onCompleted: advanceTimer.running = true | ||||
| } | ||||
|   | ||||
| @@ -30,6 +30,13 @@ Config::setConfigurationMap( const QVariantMap& cfgMap ) | ||||
|     m_device = getString( cfgMap, "device", "(unknown)" ); | ||||
|     m_userInterface = getString( cfgMap, "userInterface", "(unknown)" ); | ||||
|     m_version = getString( cfgMap, "version", "(unknown)" ); | ||||
|  | ||||
|     m_reservedUsernames = getStringList( cfgMap, "reservedUsernames", QStringList { "adm", "at ", "bin", "colord", | ||||
|             "cron", "cyrus", "daemon", "ftp", "games", "geoclue", "guest", "halt", "lightdm", "lp", "mail", "man", | ||||
|             "messagebus", "news", "nobody", "ntp", "operator", "polkitd", "postmaster", "pulse", "root", "shutdown", | ||||
|             "smmsp", "squid", "sshd", "sync", "uucp", "vpopmail", "xfs" } ); | ||||
|  | ||||
|     // ensure m_cmdUsermod matches m_username | ||||
|     m_username = getString( cfgMap, "username", "user" ); | ||||
|     m_userPasswordNumeric = getBool( cfgMap, "userPasswordNumeric", true ); | ||||
|  | ||||
| @@ -54,6 +61,8 @@ Config::setConfigurationMap( const QVariantMap& cfgMap ) | ||||
|  | ||||
|     m_cmdInternalStoragePrepare = getString( cfgMap, "cmdInternalStoragePrepare", "ondev-internal-storage-prepare" ); | ||||
|     m_cmdPasswd = getString( cfgMap, "cmdPasswd", "passwd" ); | ||||
|     m_cmdUsermod = getString( cfgMap, "cmdUsermod", "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user"); | ||||
|  | ||||
|     m_cmdSshdEnable = getString( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" ); | ||||
|     m_cmdSshdDisable = getString( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" ); | ||||
|     m_cmdSshdUseradd = getString( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" ); | ||||
| @@ -68,6 +77,7 @@ Config::createJobs() | ||||
|     /* Put users job in queue (should run after unpackfs) */ | ||||
|     Calamares::Job* j = new UsersJob( m_featureSshd, | ||||
|                                       m_cmdPasswd, | ||||
|                                       m_cmdUsermod, | ||||
|                                       cmdSshd, | ||||
|                                       m_cmdSshdUseradd, | ||||
|                                       m_isSshEnabled, | ||||
| @@ -132,6 +142,13 @@ Config::runPartitionJobThenLeave( bool b ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setUsername( const QString& username ) | ||||
| { | ||||
|     m_username = username; | ||||
|     emit usernameChanged( m_username ); | ||||
| } | ||||
|  | ||||
| void | ||||
| Config::setUserPassword( const QString& userPassword ) | ||||
| { | ||||
|   | ||||
| @@ -20,8 +20,11 @@ class Config : public QObject | ||||
|     Q_PROPERTY( QString userInterface READ userInterface CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString version READ version CONSTANT FINAL ) | ||||
|  | ||||
|     /* reserved usernames (user_pass, ssh_credentials )*/ | ||||
|     Q_PROPERTY( QStringList reservedUsernames READ reservedUsernames CONSTANT FINAL ) | ||||
|  | ||||
|     /* default user */ | ||||
|     Q_PROPERTY( QString username READ username CONSTANT FINAL ) | ||||
|     Q_PROPERTY( QString username READ username WRITE setUsername NOTIFY usernameChanged ) | ||||
|     Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged ) | ||||
|     Q_PROPERTY( bool userPasswordNumeric READ userPasswordNumeric CONSTANT FINAL ) | ||||
|  | ||||
| @@ -72,13 +75,17 @@ public: | ||||
|     QString userInterface() const { return m_userInterface; } | ||||
|     QString version() const { return m_version; } | ||||
|  | ||||
|     /* default user */ | ||||
|     /* reserved usernames (user_pass, ssh_credentials) */ | ||||
|     QStringList reservedUsernames() const { return m_reservedUsernames; }; | ||||
|  | ||||
|     /* user */ | ||||
|     QString username() const { return m_username; } | ||||
|     QString userPassword() const { return m_userPassword; } | ||||
|     void setUsername( const QString& username ); | ||||
|     void setUserPassword( const QString& userPassword ); | ||||
|     bool userPasswordNumeric() const { return m_userPasswordNumeric; } | ||||
|  | ||||
|     /* ssh server + credetials */ | ||||
|     /* ssh server + credentials */ | ||||
|     bool featureSshd() { return m_featureSshd; } | ||||
|     QString sshdUsername() const { return m_sshdUsername; } | ||||
|     QString sshdPassword() const { return m_sshdPassword; } | ||||
| @@ -120,6 +127,7 @@ public: | ||||
|  | ||||
|     /* users job */ | ||||
|     QString cmdPasswd() const { return m_cmdPasswd; } | ||||
|     QString cmdUsermod() const { return m_cmdUsermod; } | ||||
|     QString cmdSshdEnable() const { return m_cmdSshdEnable; } | ||||
|     QString cmdSshdDisable() const { return m_cmdSshdDisable; } | ||||
|     QString cmdSshdUseradd() const { return m_cmdSshdUseradd; } | ||||
| @@ -135,6 +143,9 @@ private: | ||||
|     QString m_userInterface; | ||||
|     QString m_version; | ||||
|  | ||||
|     /* reserved usernames (user_pass, ssh_credentials) */ | ||||
|     QStringList m_reservedUsernames; | ||||
|  | ||||
|     /* default user */ | ||||
|     QString m_username; | ||||
|     QString m_userPassword; | ||||
| @@ -172,6 +183,7 @@ private: | ||||
|  | ||||
|     /* users job */ | ||||
|     QString m_cmdPasswd; | ||||
|     QString m_cmdUsermod; | ||||
|     QString m_cmdSshdEnable; | ||||
|     QString m_cmdSshdDisable; | ||||
|     QString m_cmdSshdUseradd; | ||||
| @@ -181,6 +193,7 @@ signals: | ||||
|  | ||||
|     /* default user */ | ||||
|     void userPasswordChanged( QString userPassword ); | ||||
|     void usernameChanged( QString username ); | ||||
|  | ||||
|     /* ssh server + credentials */ | ||||
|     void sshdUsernameChanged( QString sshdUsername ); | ||||
|   | ||||
| @@ -118,7 +118,7 @@ PartitionJob::exec() | ||||
|         const QString pathRoot = "/"; | ||||
|  | ||||
|         ProcessResult res | ||||
|             = System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 120 ) ); | ||||
|             = System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 600 ) ); | ||||
|         if ( res.getExitCode() ) | ||||
|         { | ||||
|             return JobResult::error( "Command failed:<br><br>" | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
|  | ||||
| UsersJob::UsersJob( bool featureSshd, | ||||
|                     const QString& cmdPasswd, | ||||
|                     const QString& cmdUsermod, | ||||
|                     const QString& cmdSshd, | ||||
|                     const QString& cmdSshdUseradd, | ||||
|                     bool isSshEnabled, | ||||
| @@ -24,6 +25,7 @@ UsersJob::UsersJob( bool featureSshd, | ||||
|     : Calamares::Job() | ||||
|     , m_featureSshd( featureSshd ) | ||||
|     , m_cmdPasswd( cmdPasswd ) | ||||
|     , m_cmdUsermod( cmdUsermod ) | ||||
|     , m_cmdSshd( cmdSshd ) | ||||
|     , m_cmdSshdUseradd( cmdSshdUseradd ) | ||||
|     , m_isSshEnabled( isSshEnabled ) | ||||
| @@ -49,9 +51,11 @@ UsersJob::exec() | ||||
|     using namespace std; | ||||
|  | ||||
|     QList< QPair< QStringList, QString > > commands = { | ||||
|         { { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" }, | ||||
|         { { "sh", "-c", m_cmdUsermod }, m_username + "\n" } | ||||
|     }; | ||||
|  | ||||
|     commands.append( { { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" } ); | ||||
|  | ||||
|     if ( m_featureSshd ) | ||||
|     { | ||||
|         commands.append( { { "sh", "-c", m_cmdSshd }, QString() } ); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ class UsersJob : public Calamares::Job | ||||
| public: | ||||
|     UsersJob( bool featureSshd, | ||||
|               const QString& cmdPasswd, | ||||
|               const QString& cmdUsermod, | ||||
|               const QString& cmdSshd, | ||||
|               const QString& cmdSshdUseradd, | ||||
|               bool isSshEnabled, | ||||
| @@ -26,6 +27,7 @@ public: | ||||
| private: | ||||
|     bool m_featureSshd; | ||||
|     QString m_cmdPasswd; | ||||
|     QString m_cmdUsermod; | ||||
|     QString m_cmdSshd; | ||||
|     QString m_cmdSshdUseradd; | ||||
|     bool m_isSshEnabled; | ||||
|   | ||||
| @@ -22,13 +22,13 @@ Item { | ||||
|         id: mainText | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         anchors.topMargin: 25 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         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>"; | ||||
|                 " device until it is done.<br>"; | ||||
|  | ||||
|             if (config.installFromExternalToInternal) { | ||||
|                 ret += "<b>After the installation, your device will shutdown" + | ||||
| @@ -44,14 +44,14 @@ Item { | ||||
|             return ret; | ||||
|         }()) | ||||
|  | ||||
|         width: 500 | ||||
|         width: 550 | ||||
|     } | ||||
|  | ||||
|     Button { | ||||
|         id: firstButton | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: mainText.bottom | ||||
|         anchors.topMargin: 40 | ||||
|         anchors.topMargin: 20 | ||||
|         width: 500 | ||||
|  | ||||
|         text: qsTr("Install") | ||||
|   | ||||
| @@ -26,8 +26,45 @@ bogus: true | ||||
| # version: "(unknown)" | ||||
|  | ||||
| ## Default username (for which the password will be set) | ||||
| ## Ensure also cmdUsermod command matches the default user, so it can be changed if desired. | ||||
| # username: "user" | ||||
|  | ||||
| ## reserved usernames (for user_pass username prompt and ssh_credentials) | ||||
| # reservedUsernames: | ||||
| #        - adm | ||||
| #        - at | ||||
| #        - bin | ||||
| #        - colord | ||||
| #        - cron | ||||
| #        - cyrus | ||||
| #        - daemon | ||||
| #        - ftp | ||||
| #        - games | ||||
| #        - geoclue | ||||
| #        - guest | ||||
| #        - halt | ||||
| #        - lightdm | ||||
| #        - lp | ||||
| #        - mail | ||||
| #        - man | ||||
| #        - messagebus | ||||
| #        - news | ||||
| #        - nobody | ||||
| #        - ntp | ||||
| #        - operator | ||||
| #        - polkitd | ||||
| #        - postmaster | ||||
| #        - pulse | ||||
| #        - root | ||||
| #        - shutdown | ||||
| #        - smmsp | ||||
| #        - squid | ||||
| #        - sshd | ||||
| #        - sync | ||||
| #        - uucp | ||||
| #        - vpopmail | ||||
| #        - xfs | ||||
|  | ||||
| ####### | ||||
| ### Target device information | ||||
| ####### | ||||
| @@ -118,6 +155,10 @@ bogus: true | ||||
| ### Commands running in the target OS (chroot) | ||||
| ####### | ||||
|  | ||||
| ## Change the username for the default user | ||||
| ## Stdin: username with \n | ||||
| # cmdUsermod: "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user" | ||||
|  | ||||
| ## Set the password for default user and sshd user | ||||
| ## Arguments: <username> | ||||
| ## Stdin: password twice, each time with \n | ||||
|   | ||||
| @@ -253,7 +253,7 @@ Page | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /* Input validation: user-screens (user_pass, ssh_credentials) */ | ||||
|     /* Input validation: user-screens (fde_pass, user_pass, ssh_credentials) */ | ||||
|     function validatePin(userPin, userPinRepeat, errorText) { | ||||
|         var pin = userPin.text; | ||||
|         var repeat = userPinRepeat.text; | ||||
| @@ -278,47 +278,12 @@ Page | ||||
|  | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|     function validateSshdUsername(username, errorText) { | ||||
|     function validateUsername(username, errorText, extraReservedUsernames = []) { | ||||
|         var name = username.text; | ||||
|         var reserved = [ /* FIXME: make configurable */ | ||||
|             config.username, | ||||
|             "adm", | ||||
|             "at ", | ||||
|             "bin", | ||||
|             "colord", | ||||
|             "cron", | ||||
|             "cyrus", | ||||
|             "daemon", | ||||
|             "ftp", | ||||
|             "games", | ||||
|             "geoclue", | ||||
|             "guest", | ||||
|             "halt", | ||||
|             "lightdm", | ||||
|             "lp", | ||||
|             "mail", | ||||
|             "man", | ||||
|             "messagebus", | ||||
|             "news", | ||||
|             "nobody", | ||||
|             "ntp", | ||||
|             "operator", | ||||
|             "polkitd", | ||||
|             "postmaster", | ||||
|             "pulse", | ||||
|             "root", | ||||
|             "shutdown", | ||||
|             "smmsp", | ||||
|             "squid", | ||||
|             "sshd", | ||||
|             "sync", | ||||
|             "uucp", | ||||
|             "vpopmail", | ||||
|             "xfs", | ||||
|         ] | ||||
|         var reserved = config.reservedUsernames.concat(extraReservedUsernames); | ||||
|  | ||||
|         /* Validate characters */ | ||||
|         for (var i=0; i<name.length; i++) { | ||||
|         for (var i = 0; i < name.length; i++) { | ||||
|             if (i) { | ||||
|                 if (!name[i].match(/^[a-z0-9_-]$/)) | ||||
|                     return validationFailure(errorText, | ||||
| @@ -335,16 +300,20 @@ Page | ||||
|         } | ||||
|  | ||||
|         /* Validate against reserved usernames */ | ||||
|         for (var i=0;i<reserved.length;i++) { | ||||
|         for (var i = 0; i < reserved.length; i++) { | ||||
|             if (name == reserved[i]) | ||||
|                 return validationFailure(errorText, "Username '" + | ||||
|                                                     reserved[i] + | ||||
|                                                     "' is reserved.") | ||||
|                                                     "' is reserved."); | ||||
|         } | ||||
|  | ||||
|         /* Passed */ | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|  | ||||
|     function validateSshdUsername(username, errorText) { | ||||
|         return validateUsername(username, errorText, [config.username]); | ||||
|     } | ||||
|     function validateSshdPassword(password, passwordRepeat, errorText) { | ||||
|         var pass = password.text; | ||||
|         var repeat = passwordRepeat.text; | ||||
| @@ -352,10 +321,10 @@ Page | ||||
|         if (pass == "") | ||||
|             return validationFailure(errorText); | ||||
|  | ||||
|         if (pass.length < 8) | ||||
|         if (pass.length < 6) | ||||
|             return validationFailure(errorText, | ||||
|                                      "Too short: needs at least 8" + | ||||
|                                      " characters."); | ||||
|                                      "Too short: needs at least 6" + | ||||
|                                      " digits/characters."); | ||||
|  | ||||
|         if (repeat == "") | ||||
|             return validationFailure(errorText); | ||||
| @@ -365,8 +334,6 @@ Page | ||||
|  | ||||
|         return validationFailureClear(errorText); | ||||
|     } | ||||
|  | ||||
|     /* Input validation: fde_pass */ | ||||
|     function check_chars(input) { | ||||
|         for (var i = 0; i < input.length; i++) { | ||||
|             if (allowed_chars.indexOf(input[i]) == -1) | ||||
| @@ -407,10 +374,10 @@ Page | ||||
|                                      "\n" + | ||||
|                                      allowed_chars_multiline()); | ||||
|  | ||||
|         if (pass.length < 8) | ||||
|         if (pass.length < 6) | ||||
|             return validationFailure(errorText, | ||||
|                                      "Too short: needs at least 8" + | ||||
|                                      " characters."); | ||||
|                                      "Too short: needs at least 6" + | ||||
|                                      " digits/characters."); | ||||
|  | ||||
|         if (repeat == "") | ||||
|             return validationFailure(errorText); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|   <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>user_pass.qml</file> <!-- default user: username, password --> | ||||
|   <file>ssh_confirm.qml</file> <!-- sshd: enable or not? --> | ||||
|   <file>ssh_credentials.qml</file> <!-- sshd user: username, password --> | ||||
|   <file>fs_selection.qml</file> <!-- filesystem selection --> | ||||
|   | ||||
| @@ -12,16 +12,18 @@ import QtQuick.Window 2.3 | ||||
| import QtQuick.VirtualKeyboard 2.1 | ||||
|  | ||||
| Item { | ||||
|     property var placeholder: (config.userPasswordNumeric | ||||
|     property var passPlaceholder: (config.userPasswordNumeric | ||||
|                                ? "PIN" | ||||
|                                : "Password") | ||||
|     property var hints: (config.userPasswordNumeric | ||||
|                          ? Qt.ImhDigitsOnly | ||||
|                          : Qt.ImhPreferLowercase) | ||||
|     property var validateFunc: (config.userPasswordNumeric | ||||
|     property var validatePassFunc: (config.userPasswordNumeric | ||||
|                                 ? validatePin | ||||
|                                 : validatePassword); | ||||
|  | ||||
|     property var validateNameFunc: validateUsername; | ||||
|  | ||||
|  | ||||
|     anchors.left: parent.left | ||||
|     anchors.top: parent.top | ||||
| @@ -30,12 +32,38 @@ Item { | ||||
|     height: parent.height | ||||
|  | ||||
|     Text { | ||||
|         id: description | ||||
|         id: usernameDescription | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: parent.top | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: (function() { | ||||
|             return "Set the username of your user. The default" + | ||||
|                    " username is \"" + config.username + "\"."; | ||||
|         }()) | ||||
|  | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     TextField { | ||||
|         id: username | ||||
|         anchors.top: usernameDescription.bottom | ||||
|         placeholderText: qsTr("Username") | ||||
|         onTextChanged: validateNameFunc(username, errorText) | ||||
|         text: config.username | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.topMargin: 50 | ||||
|         width: 500 | ||||
|     } | ||||
|  | ||||
|     Text { | ||||
|         id: userPassDescription | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
|         anchors.top: username.bottom | ||||
|         anchors.topMargin: 30 | ||||
|         wrapMode: Text.WordWrap | ||||
|  | ||||
|         text: (function() { | ||||
|             if (config.userPasswordNumeric) { | ||||
|                 return "Set the numeric password of your user. The" + | ||||
| @@ -53,10 +81,10 @@ Item { | ||||
|  | ||||
|     TextField { | ||||
|         id: userPass | ||||
|         anchors.top: description.bottom | ||||
|         placeholderText: qsTr(placeholder) | ||||
|         anchors.top: userPassDescription.bottom | ||||
|         placeholderText: qsTr(passPlaceholder) | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validateFunc(userPass, userPassRepeat, errorText) | ||||
|         onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         /* Let the virtual keyboard change to digits only */ | ||||
| @@ -75,10 +103,10 @@ Item { | ||||
|     TextField { | ||||
|         id: userPassRepeat | ||||
|         anchors.top: userPass.bottom | ||||
|         placeholderText: qsTr(placeholder + " (repeat)") | ||||
|         placeholderText: qsTr(passPlaceholder + " (repeat)") | ||||
|         inputMethodHints: hints | ||||
|         echoMode: TextInput.Password | ||||
|         onTextChanged: validateFunc(userPass, userPassRepeat, errorText) | ||||
|         onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText) | ||||
|         text: config.userPassword | ||||
|  | ||||
|         anchors.horizontalCenter: parent.horizontalCenter | ||||
| @@ -105,8 +133,9 @@ Item { | ||||
|  | ||||
|         text: qsTr("Continue") | ||||
|         onClicked: { | ||||
|             if (validateFunc(userPass, userPassRepeat, errorText)) { | ||||
|             if (validatePassFunc(userPass, userPassRepeat, errorText) && validateNameFunc(username, errorText)) { | ||||
|                 config.userPassword = userPass.text; | ||||
|                 config.username = username.text; | ||||
|                 navNext(); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -38,7 +38,7 @@ Page | ||||
|             anchors.topMargin: 150 | ||||
|             wrapMode: Text.WordWrap | ||||
|             text: "Formatting and mounting target partition. This may" + | ||||
|                   " take up to two minutes, please be patient." | ||||
|                   " take up to ten minutes, please be patient." | ||||
|             width: 500 | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ calamares_add_plugin( unpackfsc | ||||
|         # The workers for differently-packed filesystems | ||||
|         Runners.cpp | ||||
|         FSArchiverRunner.cpp | ||||
|         TarballRunner.cpp | ||||
|         UnsquashRunner.cpp | ||||
|     SHARED_LIB | ||||
| ) | ||||
|   | ||||
| @@ -15,46 +15,11 @@ | ||||
| #include <QProcess> | ||||
|  | ||||
| static constexpr const int chunk_size = 137; | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverRunner::run() | ||||
| static const QString& | ||||
| toolName() | ||||
| { | ||||
|     const QString toolName = QStringLiteral( "fsarchiver" ); | ||||
|  | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     QString fsarchiverExecutable; | ||||
|     if ( !checkToolExists( toolName, fsarchiverExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     Calamares::Utils::Runner r( { fsarchiverExecutable, | ||||
|                                   QStringLiteral( "-v" ), | ||||
|                                   QStringLiteral( "restdir" ), | ||||
|                                   m_source, | ||||
|                                   destinationPath } ); | ||||
|     r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|     connect( &r, &decltype( r )::output, this, &FSArchiverRunner::fsarchiverProgress ); | ||||
|     return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) ); | ||||
|     static const QString name = QStringLiteral( "fsarchiver" ); | ||||
|     return name; | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -64,11 +29,89 @@ FSArchiverRunner::fsarchiverProgress( QString line ) | ||||
|     // Typical line of output is this: | ||||
|     // -[00][ 99%][REGFILEM] /boot/thing | ||||
|     //      5   9           ^21 | ||||
|     if (m_since >= chunk_size && line.length() > 21 && line[5] == '[' && line[9] == '%') | ||||
|     if ( m_since >= chunk_size && line.length() > 21 && line[ 5 ] == '[' && line[ 9 ] == '%' ) | ||||
|     { | ||||
|         m_since = 0; | ||||
|         double p = double(line.mid(6,3).toInt()) / 100.0; | ||||
|         const QString filename = line.mid(22); | ||||
|         Q_EMIT progress(p, filename); | ||||
|         double p = double( line.mid( 6, 3 ).toInt() ) / 100.0; | ||||
|         const QString filename = line.mid( 22 ); | ||||
|         Q_EMIT progress( p, filename ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverRunner::checkPrerequisites( QString& fsarchiverExecutable ) const | ||||
| { | ||||
|     if ( !checkToolExists( toolName(), fsarchiverExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName() ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverRunner::checkDestination( QString& destinationPath ) const | ||||
| { | ||||
|     destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid fsarchiver configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     return Calamares::JobResult::ok(); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverDirRunner::run() | ||||
| { | ||||
|     QString fsarchiverExecutable; | ||||
|     if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|     QString destinationPath; | ||||
|     if ( auto res = checkDestination( destinationPath ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     Calamares::Utils::Runner r( | ||||
|         { fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restdir" ), m_source, destinationPath } ); | ||||
|     r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|     connect( &r, &decltype( r )::output, this, &FSArchiverDirRunner::fsarchiverProgress ); | ||||
|     return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) ); | ||||
| } | ||||
|  | ||||
| Calamares::JobResult | ||||
| FSArchiverFSRunner::run() | ||||
| { | ||||
|     QString fsarchiverExecutable; | ||||
|     if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|     QString destinationPath; | ||||
|     if ( auto res = checkDestination( destinationPath ); !res ) | ||||
|     { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     Calamares::Utils::Runner r( | ||||
|         { fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restfs" ), m_source, destinationPath } ); | ||||
|     r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|     connect( &r, &decltype( r )::output, this, &FSArchiverFSRunner::fsarchiverProgress ); | ||||
|     return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) ); | ||||
| } | ||||
|   | ||||
| @@ -12,19 +12,48 @@ | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| /** @brief Base class for runners of FSArchiver | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverRunner : public Runner | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     using Runner::Runner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
|  | ||||
| protected Q_SLOTS: | ||||
|     void fsarchiverProgress( QString line ); | ||||
|  | ||||
| private: | ||||
| protected: | ||||
|     /** @brief Checks prerequisites, sets full path of fsarchiver in @p executable | ||||
|      */ | ||||
|     Calamares::JobResult checkPrerequisites( QString& executable ) const; | ||||
|     Calamares::JobResult checkDestination( QString& destinationPath ) const; | ||||
|  | ||||
|     int m_since = 0; | ||||
| }; | ||||
|  | ||||
| /** @brief Running FSArchiver in **dir** mode | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverDirRunner : public FSArchiverRunner | ||||
| { | ||||
| public: | ||||
|     using FSArchiverRunner::FSArchiverRunner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
| }; | ||||
|  | ||||
| /** @brief Running FSArchiver in **dir** mode | ||||
|  * | ||||
|  */ | ||||
| class FSArchiverFSRunner : public FSArchiverRunner | ||||
| { | ||||
| public: | ||||
|     using FSArchiverRunner::FSArchiverRunner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -21,7 +21,7 @@ Runner::Runner( const QString& source, const QString& destination ) | ||||
| { | ||||
| } | ||||
|  | ||||
| Runner::~Runner() {} | ||||
| Runner::~Runner() { } | ||||
|  | ||||
| bool | ||||
| Runner::checkSourceExists() const | ||||
|   | ||||
							
								
								
									
										86
									
								
								modules/unpackfsc/TarballRunner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								modules/unpackfsc/TarballRunner.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "TarballRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| #include <utils/Runner.h> | ||||
| #include <utils/String.h> | ||||
|  | ||||
| #include <QString> | ||||
|  | ||||
| static constexpr const int chunk_size = 107; | ||||
|  | ||||
| Calamares::JobResult | ||||
| TarballRunner::run() | ||||
| { | ||||
|     if ( !checkSourceExists() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid tarball configuration" ), | ||||
|             tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     const QString toolName = QStringLiteral( "tar" ); | ||||
|     QString tarExecutable; | ||||
|     if ( !checkToolExists( toolName, tarExecutable ) ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Missing tools" ), | ||||
|             tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ), | ||||
|             Calamares::JobResult::MissingRequirements ); | ||||
|     } | ||||
|  | ||||
|     const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination ); | ||||
|     if ( destinationPath.isEmpty() ) | ||||
|     { | ||||
|         return Calamares::JobResult::internalError( | ||||
|             tr( "Invalid tarball configuration" ), | ||||
|             tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ), | ||||
|             Calamares::JobResult::InvalidConfiguration ); | ||||
|     } | ||||
|  | ||||
|     // Get the stats (number of inodes) from the FS | ||||
|     { | ||||
|         m_total = 0; | ||||
|         Calamares::Utils::Runner r( { tarExecutable, QStringLiteral( "-tf" ), m_source } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         QObject::connect( &r, &decltype( r )::output, [ & ]( QString line ) { m_total++; } ); | ||||
|         /* ignored */ r.run(); | ||||
|     } | ||||
|     if ( m_total <= 0 ) | ||||
|     { | ||||
|         cWarning() << "No stats could be obtained from" << tarExecutable << "-tf" << m_source; | ||||
|     } | ||||
|  | ||||
|     // Now do the actual unpack | ||||
|     { | ||||
|         m_processed = 0; | ||||
|         m_since = 0; | ||||
|         Calamares::Utils::Runner r( | ||||
|             { tarExecutable, QStringLiteral( "-xpvf" ), m_source, QStringLiteral( "-C" ), destinationPath } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         connect( &r, &decltype( r )::output, this, &TarballRunner::tarballProgress ); | ||||
|         return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| TarballRunner::tarballProgress( QString line ) | ||||
| { | ||||
|     m_processed++; | ||||
|     m_since++; | ||||
|     if ( m_since > chunk_size ) | ||||
|     { | ||||
|         m_since = 0; | ||||
|         double p = m_total > 0 ? ( double( m_processed ) / double( m_total ) ) : 0.5; | ||||
|         Q_EMIT progress( p, tr( "Tarball extract file %1" ).arg( line ) ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								modules/unpackfsc/TarballRunner.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/unpackfsc/TarballRunner.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* === This file is part of Calamares - <https://calamares.io> === | ||||
|  * | ||||
|  *   SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org> | ||||
|  *   SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  * | ||||
|  *   Calamares is Free Software: see the License-Identifier above. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef UNPACKFSC_TARBALLRUNNER_H | ||||
| #define UNPACKFSC_TARBALLRUNNER_H | ||||
|  | ||||
| #include "Runners.h" | ||||
|  | ||||
| /** @brief Use (GNU) tar for extracting a filesystem | ||||
|  * | ||||
|  */ | ||||
| class TarballRunner : public Runner | ||||
| { | ||||
| public: | ||||
|     using Runner::Runner; | ||||
|  | ||||
|     Calamares::JobResult run() override; | ||||
|  | ||||
| protected Q_SLOTS: | ||||
|     void tarballProgress( QString line ); | ||||
|  | ||||
| private: | ||||
|     // Progress reporting | ||||
|     int m_total = 0; | ||||
|     int m_processed = 0; | ||||
|     int m_since = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include "UnpackFSCJob.h" | ||||
|  | ||||
| #include "FSArchiverRunner.h" | ||||
| #include "TarballRunner.h" | ||||
| #include "UnsquashRunner.h" | ||||
|  | ||||
| #include <utils/Logger.h> | ||||
| @@ -31,10 +32,14 @@ typeNames() | ||||
|         { "fsarchive", T::FSArchive }, | ||||
|         { "fsa", T::FSArchive }, | ||||
|         { "fsa-dir", T::FSArchive }, | ||||
|         // TODO: support fsa-block, savefs/restfs format | ||||
|         { "fsa-block", T::FSArchiveFS }, | ||||
|         { "fsa-fs", T::FSArchiveFS }, | ||||
|         { "squashfs", T::Squashfs }, | ||||
|         { "squash", T::Squashfs }, | ||||
|         { "unsquash", T::Squashfs }, | ||||
|         { "tar", T::Tarball }, | ||||
|         { "tarball", T::Tarball }, | ||||
|         { "tgz", T::Tarball }, | ||||
|     }; | ||||
|     // clang-format on | ||||
|     return names; | ||||
| @@ -45,7 +50,7 @@ UnpackFSCJob::UnpackFSCJob( QObject* parent ) | ||||
| { | ||||
| } | ||||
|  | ||||
| UnpackFSCJob::~UnpackFSCJob() {} | ||||
| UnpackFSCJob::~UnpackFSCJob() { } | ||||
|  | ||||
| QString | ||||
| UnpackFSCJob::prettyName() const | ||||
| @@ -66,21 +71,30 @@ UnpackFSCJob::exec() | ||||
|     switch ( m_type ) | ||||
|     { | ||||
|     case Type::FSArchive: | ||||
|         r = std::make_unique< FSArchiverRunner >( m_source, m_destination ); | ||||
|         r = std::make_unique< FSArchiverDirRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::FSArchiveFS: | ||||
|         r = std::make_unique< FSArchiverFSRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::Squashfs: | ||||
|         r = std::make_unique< UnsquashRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::Tarball: | ||||
|         r = std::make_unique< TarballRunner >( m_source, m_destination ); | ||||
|         break; | ||||
|     case Type::None: | ||||
|     default: | ||||
|         cDebug() << "Nothing to do."; | ||||
|         return Calamares::JobResult::ok(); | ||||
|     } | ||||
|  | ||||
|     connect( r.get(), &Runner::progress, [=]( qreal percent, const QString& message ) { | ||||
|         m_progressMessage = message; | ||||
|         Q_EMIT progress( percent ); | ||||
|     } ); | ||||
|     connect( r.get(), | ||||
|              &Runner::progress, | ||||
|              [ = ]( qreal percent, const QString& message ) | ||||
|              { | ||||
|                  m_progressMessage = message; | ||||
|                  Q_EMIT progress( percent ); | ||||
|              } ); | ||||
|     return r->run(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,9 @@ public: | ||||
|     { | ||||
|         None,  /// << Invalid | ||||
|         FSArchive, | ||||
|         FSArchiveFS, | ||||
|         Squashfs, | ||||
|         Tarball, | ||||
|     }; | ||||
|  | ||||
|     explicit UnpackFSCJob( QObject* parent = nullptr ); | ||||
|   | ||||
| @@ -52,12 +52,15 @@ UnsquashRunner::run() | ||||
|         m_inodes = -1; | ||||
|         Calamares::Utils::Runner r( { unsquashExecutable, QStringLiteral( "-s" ), m_source } ); | ||||
|         r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing(); | ||||
|         QObject::connect( &r, &decltype( r )::output, [&]( QString line ) { | ||||
|             if ( line.startsWith( "Number of inodes " ) ) | ||||
|             { | ||||
|                 m_inodes = line.split( ' ', SplitSkipEmptyParts ).last().toInt(); | ||||
|             } | ||||
|         } ); | ||||
|         QObject::connect( &r, | ||||
|                           &decltype( r )::output, | ||||
|                           [ & ]( QString line ) | ||||
|                           { | ||||
|                               if ( line.startsWith( "Number of inodes " ) ) | ||||
|                               { | ||||
|                                   m_inodes = line.split( ' ', SplitSkipEmptyParts ).last().toInt(); | ||||
|                               } | ||||
|                           } ); | ||||
|         /* ignored */ r.run(); | ||||
|     } | ||||
|     if ( m_inodes <= 0 ) | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
|  | ||||
| /** @brief Use Unsquash for extracting a filesystem | ||||
|  * | ||||
|  * NOTE: not implemented | ||||
|  */ | ||||
| class UnsquashRunner : public Runner | ||||
| { | ||||
|   | ||||
| @@ -21,15 +21,19 @@ | ||||
| #   - *sourcefs* the type of the source files; valid entries are | ||||
| #       - `none` (this entry is ignored; kind of useless) | ||||
| #       - `fsarchiver` | ||||
| #         Aliases of this are `fsarchive`, `fsa` and `fsa-dir`. | ||||
| #         Aliases of this are `fsarchive`, `fsa` and `fsa-dir`. Uses | ||||
| #         fsarchiver in "restdir" mode. | ||||
| #       - `fsarchiver-block` | ||||
| #         Aliases of this are `fsa-block` and `fsa-fs`. Uses fsarchiver | ||||
| #         in "restfs" mode. | ||||
| #       - `squashfs` | ||||
| #         Aliases of this are `squash` and `unsquash`. | ||||
| #       - `tar` | ||||
| #   - *destination* path relative to rootMountPoint (so in the target | ||||
| #       system) where this filesystem is unpacked. It may be an | ||||
| #       empty string, which effectively is / (the root) of the target | ||||
| #       system. | ||||
| # | ||||
| # TODO: add `fsa-block` and support for *savefs/restfs* mode. | ||||
| source: /data/rootfs.fsa | ||||
| sourcefs: fsarchiver | ||||
| destination: "/" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user