parent
1a835b2e1a
commit
cbf5c9a9d6
Binary file not shown.
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -1,5 +1,6 @@
|
|||||||
vanilla-first-setup (0.1.9) jammy; urgency=low
|
vanilla-first-setup (1.0.0) jammy; urgency=low
|
||||||
|
|
||||||
* First release
|
* Rewrite from scratch to support custom recipes and
|
||||||
|
to be more modular.
|
||||||
|
|
||||||
-- Mirko Brombin <send@mirko.pm> Mon, 05 Sep 2022 20:42:00 +0000
|
-- Mirko Brombin <send@mirko.pm> Thu, 20 Sep 2022 22:01:00 +0000
|
@ -0,0 +1,136 @@
|
|||||||
|
{
|
||||||
|
"log_file": "/etc/vanilla/first-setup.log",
|
||||||
|
"distro_name": "Vanilla OS",
|
||||||
|
"distro_logo": "io.github.vanilla-os.FirstSetup",
|
||||||
|
"steps": {
|
||||||
|
"welcome": {
|
||||||
|
"template": "welcome"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"template": "theme"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"template": "preferences",
|
||||||
|
"icon": "vanilla-package-symbolic",
|
||||||
|
"title": "Package Manager",
|
||||||
|
"description": "Choose one or more package managers to install",
|
||||||
|
"preferences": [
|
||||||
|
{
|
||||||
|
"id": "flatpak",
|
||||||
|
"title": "Flatpak",
|
||||||
|
"subtitle": "Will also configure the Flathub repository.",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "snap",
|
||||||
|
"title": "Snap",
|
||||||
|
"subtitle": "Uses the Snapcraft repository. Default in Ubuntu."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "appimage",
|
||||||
|
"title": "AppImage",
|
||||||
|
"subtitle": "Will install the necessary dependencies to run AppImages."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"final": [
|
||||||
|
{
|
||||||
|
"if": "flatpak",
|
||||||
|
"type": "command",
|
||||||
|
"commands": [
|
||||||
|
"sudo apt install -y flatpak",
|
||||||
|
"flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "snap",
|
||||||
|
"type": "command",
|
||||||
|
"commands": ["sudo apt install -y snapd"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "appimage",
|
||||||
|
"type": "command",
|
||||||
|
"commands": ["sudo apt install -y fuse2"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subsystem": {
|
||||||
|
"template": "yes-no",
|
||||||
|
"icon": "vanilla-container-terminal-symbolic",
|
||||||
|
"title": "Sub System",
|
||||||
|
"description": "Access a minimal mutable Ubuntu installation integrated with Vanilla OS.",
|
||||||
|
"buttons": {
|
||||||
|
"yes": "Enable",
|
||||||
|
"no": "Skip",
|
||||||
|
"info": {
|
||||||
|
"type": "text",
|
||||||
|
"title": "What is Sub System?",
|
||||||
|
"text": "The Sub-System is a container that allows you to install deb packages without altering the system. It is useful for installing software without having to enter in read-write mode.\n\nYou don't need to enter in the container to install packages, just use the apx command (wrapper around the apt inside the container) to install new programs and automatically make them available in your Vanilla OS installation.\n\nThis features uses distrobox as backend."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"final": [
|
||||||
|
{
|
||||||
|
"if": "subsystem",
|
||||||
|
"type": "command",
|
||||||
|
"commands": [
|
||||||
|
"sudo apt install -y apx",
|
||||||
|
"curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/install | sudo sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nvidia": {
|
||||||
|
"template": "yes-no",
|
||||||
|
"icon": "video-display-symbolic",
|
||||||
|
"title": "NVIDIA® Drivers",
|
||||||
|
"description": "Choose whether to install proprietary NVIDIA drivers for better compatibility and performance.",
|
||||||
|
"buttons": {
|
||||||
|
"yes": "Yes, install",
|
||||||
|
"no": "Skip",
|
||||||
|
"info": {
|
||||||
|
"type": "text",
|
||||||
|
"title": "About Proprietary Drivers",
|
||||||
|
"text": "A proprietary driver has private code that neither Vanilla OS nor Ubuntu developers can't review.\n\nSecurity and other updates are dependent on the driver vendor."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"final": [
|
||||||
|
{
|
||||||
|
"if": "nvidia",
|
||||||
|
"type": "command",
|
||||||
|
"commands": ["sudo ubuntu-drivers install --recommended"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"template": "preferences",
|
||||||
|
"icon": "vanilla-puzzle-piece-symbolic",
|
||||||
|
"title": "Extra Settings",
|
||||||
|
"description": "The following are optional settings, leave them as they are if you don't know what they do.",
|
||||||
|
"preferences": [
|
||||||
|
{
|
||||||
|
"id": "apport",
|
||||||
|
"title": "Apport",
|
||||||
|
"subtitle": "Apport is a crash reporting system that helps us improve the stability of the system."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"final": [
|
||||||
|
{
|
||||||
|
"if": "apport",
|
||||||
|
"type": "command",
|
||||||
|
"commands": [
|
||||||
|
"sudo apt install -y apport",
|
||||||
|
"systemctl enable apport.service || true"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "apport",
|
||||||
|
"condition": false,
|
||||||
|
"type": "command",
|
||||||
|
"commands": [
|
||||||
|
"sudo apt remove -y apport",
|
||||||
|
"systemctl disable apport.service || true"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
||||||
|
defaultsdir = join_paths(pkgdatadir, 'vanilla_first_setup/defaults')
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'__init__.py',
|
||||||
|
'welcome.py',
|
||||||
|
'theme.py',
|
||||||
|
]
|
||||||
|
|
||||||
|
install_data(sources, install_dir: defaultsdir)
|
@ -0,0 +1,54 @@
|
|||||||
|
# theme.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from gi.repository import Gtk, Gio, GLib, Adw
|
||||||
|
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/default-theme.ui')
|
||||||
|
class VanillaDefaultTheme(Gtk.Box):
|
||||||
|
__gtype_name__ = 'VanillaDefaultTheme'
|
||||||
|
|
||||||
|
btn_next = Gtk.Template.Child()
|
||||||
|
btn_default = Gtk.Template.Child()
|
||||||
|
btn_dark = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, window, distro_info, key, step, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.__window = window
|
||||||
|
self.__distro_info = distro_info
|
||||||
|
self.__key = key
|
||||||
|
self.__step = step
|
||||||
|
|
||||||
|
self.__build_ui()
|
||||||
|
|
||||||
|
self.btn_next.connect("clicked", self.__window.next)
|
||||||
|
self.btn_default.connect('toggled', self.__set_theme, "light")
|
||||||
|
self.btn_dark.connect('toggled', self.__set_theme, "dark")
|
||||||
|
|
||||||
|
def __build_ui(self):
|
||||||
|
self.btn_dark.set_group(self.btn_default)
|
||||||
|
|
||||||
|
def __set_theme(self, widget, theme: str):
|
||||||
|
pref = "prefer-dark" if theme == "dark" else "default"
|
||||||
|
gtk = "Adwaita-dark" if theme == "dark" else "Adwaita"
|
||||||
|
Gio.Settings.new("org.gnome.desktop.interface").set_string(
|
||||||
|
"color-scheme", pref)
|
||||||
|
Gio.Settings.new("org.gnome.desktop.interface").set_string(
|
||||||
|
"gtk-theme", gtk)
|
||||||
|
|
||||||
|
def get_finals(self):
|
||||||
|
return {}
|
@ -0,0 +1,93 @@
|
|||||||
|
# welcome.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from gi.repository import Gtk, Gio, GLib, Adw
|
||||||
|
|
||||||
|
from vanilla_first_setup.utils.run_async import RunAsync
|
||||||
|
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/default-welcome.ui')
|
||||||
|
class VanillaDefaultWelcome(Adw.Bin):
|
||||||
|
__gtype_name__ = 'VanillaDefaultWelcome'
|
||||||
|
|
||||||
|
btn_next = Gtk.Template.Child()
|
||||||
|
status_page = Gtk.Template.Child()
|
||||||
|
|
||||||
|
welcome = [
|
||||||
|
'Welcome',
|
||||||
|
'Benvenuto',
|
||||||
|
'Bienvenido',
|
||||||
|
'Bienvenue',
|
||||||
|
'Willkommen',
|
||||||
|
'Bem-vindo',
|
||||||
|
'Добро пожаловать',
|
||||||
|
'欢迎',
|
||||||
|
'ようこそ',
|
||||||
|
'환영합니다',
|
||||||
|
'أهلا بك',
|
||||||
|
'ברוך הבא',
|
||||||
|
'Καλώς ήρθατε',
|
||||||
|
'Hoşgeldiniz',
|
||||||
|
'Welkom',
|
||||||
|
'Witamy',
|
||||||
|
'Välkommen',
|
||||||
|
'Tervetuloa',
|
||||||
|
'Vítejte',
|
||||||
|
'Üdvözöljük',
|
||||||
|
'Bun venit',
|
||||||
|
'Vitajte',
|
||||||
|
'Tere tulemast',
|
||||||
|
'Sveiki atvykę',
|
||||||
|
'Dobrodošli',
|
||||||
|
'خوش آمدید',
|
||||||
|
'आपका स्वागत है',
|
||||||
|
'স্বাগতম',
|
||||||
|
'வரவேற்கிறோம்',
|
||||||
|
'స్వాగతం',
|
||||||
|
'मुबारक हो',
|
||||||
|
'સુસ્વાગત છે',
|
||||||
|
'ಸುಸ್ವಾಗತ',
|
||||||
|
'സ്വാഗതം'
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, window, distro_info, key, step, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.__window = window
|
||||||
|
self.__distro_info = distro_info
|
||||||
|
self.__key = key
|
||||||
|
self.__step = step
|
||||||
|
|
||||||
|
# animation start
|
||||||
|
self.__start_welcome_animation()
|
||||||
|
|
||||||
|
# signals
|
||||||
|
self.btn_next.connect("clicked", self.__window.next)
|
||||||
|
|
||||||
|
# set distro logo
|
||||||
|
self.status_page.set_icon_name(self.__distro_info["logo"])
|
||||||
|
|
||||||
|
def __start_welcome_animation(self):
|
||||||
|
def change_langs():
|
||||||
|
while True:
|
||||||
|
for lang in self.welcome:
|
||||||
|
GLib.idle_add(self.status_page.set_title, lang)
|
||||||
|
time.sleep(1.2)
|
||||||
|
|
||||||
|
RunAsync(change_langs, None)
|
||||||
|
|
||||||
|
def get_finals(self):
|
||||||
|
return {}
|
@ -1,10 +0,0 @@
|
|||||||
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
|
||||||
dialogsdir = join_paths(pkgdatadir, 'vanilla_first_setup/dialogs')
|
|
||||||
|
|
||||||
sources = [
|
|
||||||
'__init__.py',
|
|
||||||
'subsystem.py',
|
|
||||||
'prop_drivers.py',
|
|
||||||
]
|
|
||||||
|
|
||||||
install_data(sources, install_dir: dialogsdir)
|
|
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaDefaultTheme" parent="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="spacing">10</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="btn_default">
|
||||||
|
<property name="tooltip-text">Default</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="theme-selector" />
|
||||||
|
<class name="light" />
|
||||||
|
<class name="card" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="btn_dark">
|
||||||
|
<property name="tooltip-text">Dark</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="theme-selector" />
|
||||||
|
<class name="dark" />
|
||||||
|
<class name="card" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage">
|
||||||
|
<property name="title">Color Scheme</property>
|
||||||
|
<property name="description">Choose a color scheme for your system.</property>
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_next">
|
||||||
|
<property name="label">Next</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaDefaultWelcome" parent="AdwBin">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="icon-name">io.github.vanilla-os.FirstSetup</property>
|
||||||
|
<property name="title">Welcome!</property>
|
||||||
|
<property name="description">Make your choices, this wizard will take care of everything.</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_next">
|
||||||
|
<property name="label">Let's Start</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<interface>
|
|
||||||
<requires lib="gtk" version="4.0"/>
|
|
||||||
<requires lib="libadwaita" version="1.0"/>
|
|
||||||
<template class="SubSystemDialog" parent="AdwWindow">
|
|
||||||
<property name="title" translatable="yes">Info About Sub System</property>
|
|
||||||
<property name="default-width">500</property>
|
|
||||||
<property name="modal">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="AdwHeaderBar">
|
|
||||||
<style>
|
|
||||||
<class name="flat"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="margin-top">10</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<property name="margin-bottom">20</property>
|
|
||||||
<property name="wrap">True</property>
|
|
||||||
<property name="label">The Sub-System is a container that allows you to install deb packages without altering the system. It is useful for installing software without having to enter in read-write mode.
|
|
||||||
|
|
||||||
You don't need to enter in the container to install packages, just use the apx command (wrapper around the apt inside the container) to install new programs and automatically make them available in your Vanilla OS installation.
|
|
||||||
|
|
||||||
This features uses distrobox as backend.</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</template>
|
|
||||||
</interface>
|
|
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaDone" parent="AdwBin">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="icon-name">emblem-default-symbolic</property>
|
||||||
|
<property name="title">Done!</property>
|
||||||
|
<property name="description">Restart your PC to enjoy your Vanila OS experience.</property>
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_reboot">
|
||||||
|
<property name="label">Reboot Now</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_close">
|
||||||
|
<property name="label">Close</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaLayoutPreferences" parent="AdwBin">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesPage">
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="prefs_list"></object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_next">
|
||||||
|
<property name="label">Next</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaLayoutYesNo" parent="AdwBin">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="spacing">10</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_no">
|
||||||
|
<property name="label">No</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_yes">
|
||||||
|
<property name="label">Yes, enable it</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btn_info">
|
||||||
|
<property name="icon-name">dialog-information-symbolic</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<requires lib="libadwaita" version="1.0" />
|
||||||
|
<template class="VanillaProgress" parent="AdwBin">
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwStatusPage" id="status_page">
|
||||||
|
<property name="title">Please Wait…</property>
|
||||||
|
<property name="description">The changes are being applied.</property>
|
||||||
|
<property name="halign">fill</property>
|
||||||
|
<property name="valign">fill</property>
|
||||||
|
<property name="hexpand">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinner" id="spinner">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="spinning">true</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
@ -0,0 +1,10 @@
|
|||||||
|
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
||||||
|
layoutsdir = join_paths(pkgdatadir, 'vanilla_first_setup/layouts')
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'__init__.py',
|
||||||
|
'preferences.py',
|
||||||
|
'yes_no.py',
|
||||||
|
]
|
||||||
|
|
||||||
|
install_data(sources, install_dir: layoutsdir)
|
@ -0,0 +1,68 @@
|
|||||||
|
# preferences.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from gi.repository import Gtk, Gio, GLib, Adw
|
||||||
|
|
||||||
|
from vanilla_first_setup.utils.run_async import RunAsync
|
||||||
|
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/layout-preferences.ui')
|
||||||
|
class VanillaLayoutPreferences(Adw.Bin):
|
||||||
|
__gtype_name__ = 'VanillaLayoutPreferences'
|
||||||
|
|
||||||
|
status_page = Gtk.Template.Child()
|
||||||
|
prefs_list = Gtk.Template.Child()
|
||||||
|
btn_next = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, window, distro_info, key, step, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.__window = window
|
||||||
|
self.__distro_info = distro_info
|
||||||
|
self.__key = key
|
||||||
|
self.__step = step
|
||||||
|
self.__register_widgets = []
|
||||||
|
self.__build_ui()
|
||||||
|
|
||||||
|
# signals
|
||||||
|
self.btn_next.connect("clicked", self.__window.next)
|
||||||
|
|
||||||
|
def __build_ui(self):
|
||||||
|
self.status_page.set_icon_name(self.__step["icon"])
|
||||||
|
self.status_page.set_title(self.__step["title"])
|
||||||
|
self.status_page.set_description(self.__step["description"])
|
||||||
|
|
||||||
|
for item in self.__step["preferences"]:
|
||||||
|
_action_row = Adw.ActionRow(
|
||||||
|
title=item["title"],
|
||||||
|
subtitle=item.get("subtitle", "")
|
||||||
|
)
|
||||||
|
_switcher = Gtk.Switch()
|
||||||
|
_switcher.set_active(item.get("default", False))
|
||||||
|
_switcher.set_valign(Gtk.Align.CENTER)
|
||||||
|
_action_row.add_suffix(_switcher)
|
||||||
|
|
||||||
|
self.prefs_list.add(_action_row)
|
||||||
|
|
||||||
|
self.__register_widgets.append((item["id"], _switcher))
|
||||||
|
|
||||||
|
def get_finals(self):
|
||||||
|
finals = {"vars": {}, "funcs": [x for x in self.__step["final"]]}
|
||||||
|
|
||||||
|
for _id, switcher in self.__register_widgets:
|
||||||
|
finals["vars"][_id] = switcher.get_active()
|
||||||
|
|
||||||
|
return finals
|
@ -0,0 +1,79 @@
|
|||||||
|
# yes_no.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from gi.repository import Gtk, Gio, GLib, Adw
|
||||||
|
|
||||||
|
from vanilla_first_setup.utils.run_async import RunAsync
|
||||||
|
from vanilla_first_setup.dialog import VanillaDialog
|
||||||
|
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/layout-yes-no.ui')
|
||||||
|
class VanillaLayoutYesNo(Adw.Bin):
|
||||||
|
__gtype_name__ = 'VanillaLayoutYesNo'
|
||||||
|
|
||||||
|
status_page = Gtk.Template.Child()
|
||||||
|
btn_no = Gtk.Template.Child()
|
||||||
|
btn_yes = Gtk.Template.Child()
|
||||||
|
btn_info = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, window, distro_info, key, step, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.__window = window
|
||||||
|
self.__distro_info = distro_info
|
||||||
|
self.__key = key
|
||||||
|
self.__step = step
|
||||||
|
self.__response = False
|
||||||
|
self.__build_ui()
|
||||||
|
|
||||||
|
# signals
|
||||||
|
self.btn_yes.connect("clicked", self.__on_response, True)
|
||||||
|
self.btn_no.connect("clicked", self.__on_response, False)
|
||||||
|
self.btn_info.connect("clicked", self.__on_info)
|
||||||
|
|
||||||
|
def __build_ui(self):
|
||||||
|
self.status_page.set_icon_name(self.__step["icon"])
|
||||||
|
self.status_page.set_title(self.__step["title"])
|
||||||
|
self.status_page.set_description(self.__step["description"])
|
||||||
|
|
||||||
|
self.btn_yes.set_label(self.__step["buttons"]["yes"])
|
||||||
|
self.btn_no.set_label(self.__step["buttons"]["no"])
|
||||||
|
|
||||||
|
if "info" in self.__step["buttons"]:
|
||||||
|
self.btn_info.set_visible(True)
|
||||||
|
|
||||||
|
def __on_response(self, _, response):
|
||||||
|
self.__response = response
|
||||||
|
self.__window.next()
|
||||||
|
|
||||||
|
def __on_info(self, _):
|
||||||
|
if "info" not in self.__step["buttons"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
dialog = VanillaDialog(
|
||||||
|
self.__window,
|
||||||
|
self.__step["buttons"]["info"]["title"],
|
||||||
|
self.__step["buttons"]["info"]["text"]
|
||||||
|
)
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
def get_finals(self):
|
||||||
|
return {
|
||||||
|
"vars": {
|
||||||
|
self.__key: self.__response
|
||||||
|
},
|
||||||
|
"funcs": [x for x in self.__step["final"]]
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("FirstSetup::Config")
|
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
snap: bool,
|
|
||||||
flatpak: bool,
|
|
||||||
appimage: bool,
|
|
||||||
apport: bool,
|
|
||||||
apx: bool,
|
|
||||||
nvidia: bool,
|
|
||||||
):
|
|
||||||
self.snap = snap
|
|
||||||
self.flatpak = flatpak
|
|
||||||
self.appimage = appimage
|
|
||||||
self.apport = apport
|
|
||||||
self.apx = apx
|
|
||||||
self.nvidia = nvidia
|
|
||||||
|
|
||||||
def get_str(self) -> str:
|
|
||||||
keys = [
|
|
||||||
"snap", "flatpak", "appimage", "apport", "apx", "nvidia"
|
|
||||||
]
|
|
||||||
vals = [
|
|
||||||
self.snap, self.flatpak, self.appimage, self.apport, self.apx, self.nvidia
|
|
||||||
]
|
|
||||||
return "|".join([f"{key}::{val}" for key, val in zip(keys, vals)])
|
|
||||||
|
|
||||||
def set_val(self, key: str, val: bool):
|
|
||||||
if key == "snap":
|
|
||||||
self.snap = val
|
|
||||||
elif key == "flatpak":
|
|
||||||
self.flatpak = val
|
|
||||||
elif key == "appimage":
|
|
||||||
self.appimage = val
|
|
||||||
elif key == "apport":
|
|
||||||
self.apport = val
|
|
||||||
elif key == "apx":
|
|
||||||
self.apx = val
|
|
||||||
elif key == "nvidia":
|
|
||||||
self.nvidia = val
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info(f"Setting {key} to {val}")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_str(cls, config_str: str) -> 'Config':
|
|
||||||
def get_bool(value: str):
|
|
||||||
return "True" in value
|
|
||||||
|
|
||||||
items = config_str.split('|')
|
|
||||||
|
|
||||||
snap = items[0].split('::')[1]
|
|
||||||
flatpak = items[1].split('::')[1]
|
|
||||||
appimage = items[2].split('::')[1]
|
|
||||||
apport = items[3].split('::')[1]
|
|
||||||
apx = items[4].split('::')[1]
|
|
||||||
nvidia = items[5].split('::')[1]
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
snap=get_bool(snap),
|
|
||||||
flatpak=get_bool(flatpak),
|
|
||||||
appimage=get_bool(appimage),
|
|
||||||
apport=get_bool(apport),
|
|
||||||
apx=get_bool(apx),
|
|
||||||
nvidia=get_bool(nvidia),
|
|
||||||
)
|
|
@ -1,10 +0,0 @@
|
|||||||
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
|
||||||
modelsdir = join_paths(pkgdatadir, 'vanilla_first_setup/models')
|
|
||||||
|
|
||||||
sources = [
|
|
||||||
'__init__.py',
|
|
||||||
'config.py',
|
|
||||||
'preset.py',
|
|
||||||
]
|
|
||||||
|
|
||||||
install_data(sources, install_dir: modelsdir)
|
|
@ -1,8 +0,0 @@
|
|||||||
class Preset:
|
|
||||||
|
|
||||||
snap: bool = False
|
|
||||||
flatpak: bool = True
|
|
||||||
appimage: bool = False
|
|
||||||
apport: bool = False
|
|
||||||
apx: bool = True
|
|
||||||
nvidia: bool = False
|
|
@ -1,58 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
|
|
||||||
class Apt:
|
|
||||||
|
|
||||||
env = os.environ.copy()
|
|
||||||
env['DEBIAN_FRONTEND'] = 'noninteractive'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def install(packages: list):
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'apt', 'install'] + packages + ['-y'],
|
|
||||||
env=Apt.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def remove(packages: list):
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'apt', 'remove'] + packages + ['-y'],
|
|
||||||
env=Apt.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def purge(packages: list):
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'apt', 'purge'] + packages + ['-y'],
|
|
||||||
env=Apt.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def update():
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'apt', 'update'],
|
|
||||||
env=Apt.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def upgrade():
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'apt', 'upgrade', '-y'],
|
|
||||||
env=Apt.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
@ -0,0 +1,95 @@
|
|||||||
|
# builder.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
|
from vanilla_first_setup.utils.recipe import RecipeLoader
|
||||||
|
|
||||||
|
from vanilla_first_setup.defaults.welcome import VanillaDefaultWelcome
|
||||||
|
from vanilla_first_setup.defaults.theme import VanillaDefaultTheme
|
||||||
|
|
||||||
|
from vanilla_first_setup.layouts.preferences import VanillaLayoutPreferences
|
||||||
|
from vanilla_first_setup.layouts.yes_no import VanillaLayoutYesNo
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("FirstSetup::Builder")
|
||||||
|
|
||||||
|
|
||||||
|
templates = {
|
||||||
|
"welcome": VanillaDefaultWelcome,
|
||||||
|
"theme": VanillaDefaultTheme,
|
||||||
|
"preferences": VanillaLayoutPreferences,
|
||||||
|
"yes-no": VanillaLayoutYesNo
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Builder:
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
self.__window = window
|
||||||
|
self.__recipe = RecipeLoader()
|
||||||
|
self.__register_widgets = []
|
||||||
|
self.__register_finals = []
|
||||||
|
self.__load()
|
||||||
|
|
||||||
|
def __load(self):
|
||||||
|
# here we create a temporary file to store the output of the commands
|
||||||
|
# the log path is defined in the recipe
|
||||||
|
if "log_file" not in self.__recipe.raw:
|
||||||
|
logger.critical("Missing 'log_file' in the recipe.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
log_path = self.__recipe.raw["log_file"]
|
||||||
|
|
||||||
|
if not os.path.exists(log_path):
|
||||||
|
try:
|
||||||
|
open(log_path, 'a').close()
|
||||||
|
except OSError:
|
||||||
|
logger.critical("failed to create log file: %s" % log_path)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
for key, step in self.__recipe.raw["steps"].items():
|
||||||
|
if step["template"] in templates:
|
||||||
|
_widget = templates[step["template"]](self.__window, self.distro_info, key, step)
|
||||||
|
self.__register_widgets.append(_widget)
|
||||||
|
|
||||||
|
def get_finals(self):
|
||||||
|
self.__register_finals = []
|
||||||
|
|
||||||
|
for widget in self.__register_widgets:
|
||||||
|
self.__register_finals.append(widget.get_finals())
|
||||||
|
|
||||||
|
return self.__register_finals
|
||||||
|
|
||||||
|
@property
|
||||||
|
def widgets(self):
|
||||||
|
return self.__register_widgets
|
||||||
|
|
||||||
|
@property
|
||||||
|
def recipe(self):
|
||||||
|
return self.__recipe.raw
|
||||||
|
|
||||||
|
@property
|
||||||
|
def distro_info(self):
|
||||||
|
return {
|
||||||
|
"name": self.__recipe.raw["distro_name"],
|
||||||
|
"logo": self.__recipe.raw["distro_logo"]
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
|
|
||||||
def is_snap_installed():
|
|
||||||
return shutil.which('snap') is not None
|
|
||||||
|
|
||||||
|
|
||||||
def is_flatpak_installed():
|
|
||||||
return shutil.which('flatpak') is not None
|
|
||||||
|
|
||||||
|
|
||||||
def is_apport_installed():
|
|
||||||
return shutil.which('apport') is not None
|
|
||||||
|
|
||||||
|
|
||||||
def has_nvidia_gpu():
|
|
||||||
return subprocess.run(['lspci'], stdout=subprocess.PIPE).stdout.decode('utf-8').find('VGA compatible controller: NVIDIA Corporation') != -1
|
|
@ -1,128 +0,0 @@
|
|||||||
import os
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from gi.repository import Gio
|
|
||||||
|
|
||||||
from vanilla_first_setup.utils import checks
|
|
||||||
from vanilla_first_setup.utils.apt import Apt
|
|
||||||
from vanilla_first_setup.utils.flatpak import Flatpak
|
|
||||||
from vanilla_first_setup.utils.snap import Snap
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("FirstSetup::Configurator")
|
|
||||||
|
|
||||||
|
|
||||||
class Configurator:
|
|
||||||
|
|
||||||
def __init__(self, config: 'Config', fake: bool = False):
|
|
||||||
self.config = config
|
|
||||||
self.fake = fake
|
|
||||||
|
|
||||||
def apply(self):
|
|
||||||
logging.info(f"Applying config: {self.config.get_str()}")
|
|
||||||
self.__enable_snap() if self.config.snap else self.__disable_snap()
|
|
||||||
self.__enable_flatpak() if self.config.flatpak else self.__disable_flatpak()
|
|
||||||
self.__enable_appimage() if self.config.appimage else self.__disable_appimage()
|
|
||||||
self.__enable_apport() if self.config.apport else self.__disable_apport()
|
|
||||||
if self.config.apx:
|
|
||||||
self.__enable_apx()
|
|
||||||
if self.config.nvidia:
|
|
||||||
self.__enable_nvidia()
|
|
||||||
|
|
||||||
def __fake(self, msg: str):
|
|
||||||
time.sleep(1)
|
|
||||||
logger.info(f"Fake: {msg}")
|
|
||||||
|
|
||||||
def __enable_snap(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Snap enabled")
|
|
||||||
|
|
||||||
if not checks.is_snap_installed():
|
|
||||||
Apt.install(['snapd', 'gnome-software-plugin-snap'])
|
|
||||||
Apt.update()
|
|
||||||
|
|
||||||
if not self.config.flatpak:
|
|
||||||
Snap.install(['snap-store'])
|
|
||||||
|
|
||||||
def __disable_snap(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Snap disabled")
|
|
||||||
|
|
||||||
if checks.is_snap_installed():
|
|
||||||
Apt.purge(['snapd'])
|
|
||||||
|
|
||||||
def __enable_flatpak(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Flatpak enabled")
|
|
||||||
|
|
||||||
if not checks.is_flatpak_installed():
|
|
||||||
Apt.install(['flatpak'])
|
|
||||||
Apt.update()
|
|
||||||
Flatpak.add_repo("https://flathub.org/repo/flathub.flatpakrepo")
|
|
||||||
|
|
||||||
def __disable_flatpak(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Flatpak disabled")
|
|
||||||
|
|
||||||
if checks.is_flatpak_installed():
|
|
||||||
Apt.purge(['flatpak'])
|
|
||||||
|
|
||||||
def __enable_appimage(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: AppImage enabled")
|
|
||||||
|
|
||||||
Apt.install(['fuse2'])
|
|
||||||
Apt.update()
|
|
||||||
|
|
||||||
def __disable_appimage(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: AppImage disabled")
|
|
||||||
|
|
||||||
# Apt.purge(['libfuse2']) # NOTE: we should not remove libfuse2, it may be needed by other packages at this point
|
|
||||||
|
|
||||||
def __enable_apport(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Apport enabled")
|
|
||||||
|
|
||||||
if not checks.is_apport_installed():
|
|
||||||
Apt.install(['apport'])
|
|
||||||
Apt.update()
|
|
||||||
subprocess.run(['sudo', 'systemctl', 'start', 'apport.service'])
|
|
||||||
|
|
||||||
def __disable_apport(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Apport disabled")
|
|
||||||
|
|
||||||
if checks.is_apport_installed():
|
|
||||||
subprocess.run(['sudo', 'systemctl', 'stop', 'apport.service'])
|
|
||||||
Apt.purge(['apport'])
|
|
||||||
|
|
||||||
def __enable_apx(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: apx enabled")
|
|
||||||
|
|
||||||
Apt.install(['curl', 'podman', 'apx'])
|
|
||||||
Apt.update()
|
|
||||||
|
|
||||||
proc = subprocess.run(['curl', '-s', 'https://raw.githubusercontent.com/89luca89/distrobox/main/install'], stdout=subprocess.PIPE)
|
|
||||||
proc = subprocess.run(['sudo', 'sh'], input=proc.stdout, stdout=subprocess.PIPE)
|
|
||||||
|
|
||||||
def __enable_nvidia(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Nvidia enabled")
|
|
||||||
|
|
||||||
subprocess.run(['sudo', 'ubuntu-drivers', 'install', '--recommended'])
|
|
||||||
|
|
||||||
def __disable_on_startup(self):
|
|
||||||
if self.fake:
|
|
||||||
return self.__fake("Fake: Disable on startup")
|
|
||||||
|
|
||||||
autostart_file = os.path.expanduser("~/.config/autostart/io.github.vanilla-os.FirstSetup.desktop")
|
|
||||||
if os.path.exists(autostart_file):
|
|
||||||
os.remove(autostart_file)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def reboot():
|
|
||||||
subprocess.run(['gnome-session-quit', '--reboot'])
|
|
@ -1,38 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
|
|
||||||
class Flatpak:
|
|
||||||
env = os.environ.copy()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def install(packages: list):
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
['flatpak', 'install', '--user'] + packages,
|
|
||||||
env=Flatpak.env,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
proc.communicate(input=b'y\n')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def remove(packages: list):
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
['flatpak', 'remove', '--user'] + packages,
|
|
||||||
env=Flatpak.env,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
proc.communicate(input=b'y\n')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_repo(repo: str):
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
['flatpak', 'remote-add', 'test', '--user', '--if-not-exists', repo],
|
|
||||||
env=Flatpak.env,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
proc.communicate(input=b'y\n')
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
|||||||
|
# parser.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
logger = logging.getLogger("FirstSetup::Parser")
|
||||||
|
|
||||||
|
|
||||||
|
class Parser:
|
||||||
|
|
||||||
|
supported_types = ["command"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse(finals):
|
||||||
|
commands = []
|
||||||
|
|
||||||
|
for final in finals:
|
||||||
|
if len(final) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
_vars = final["vars"]
|
||||||
|
|
||||||
|
for _func in final["funcs"]:
|
||||||
|
|
||||||
|
if "if" not in _func:
|
||||||
|
logger.critical(f"Missing an 'if' operand in {_func}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if _func["if"] not in _vars:
|
||||||
|
logger.critical(
|
||||||
|
f"Missing a variable named '{_func['if']}' in the 'vars' section.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if _func.get("type") not in Parser.supported_types:
|
||||||
|
logger.critical(
|
||||||
|
f"Unsupported final type: {_func.get('type')}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# assume True if no condition is given
|
||||||
|
_condition = _func.get("condition", True)
|
||||||
|
|
||||||
|
# check if the condition is met
|
||||||
|
if _condition == _vars[_func["if"]]:
|
||||||
|
commands += _func["commands"]
|
||||||
|
|
||||||
|
return commands
|
@ -0,0 +1,74 @@
|
|||||||
|
# recipe.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("FirstSetup::RecipeLoader")
|
||||||
|
|
||||||
|
|
||||||
|
class RecipeLoader:
|
||||||
|
|
||||||
|
recipe_path = "/etc/vanilla-first-setup/recipe.json"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__recipe = {}
|
||||||
|
self.__load()
|
||||||
|
|
||||||
|
def __load(self):
|
||||||
|
if "VANILLA_CUSTOM_RECIPE" in os.environ:
|
||||||
|
self.recipe_path = os.environ["VANILLA_CUSTOM_RECIPE"]
|
||||||
|
|
||||||
|
if os.path.exists(self.recipe_path):
|
||||||
|
with open(self.recipe_path, "r") as f:
|
||||||
|
self.__recipe = json.load(f)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.__validate():
|
||||||
|
logger.error("Invalid recipe file")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logger.error(f"Recipe not found at {self.recipe_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def __validate(self):
|
||||||
|
essential_keys = ["log_file", "distro_name", "distro_logo", "steps"]
|
||||||
|
if not isinstance(self.__recipe, dict):
|
||||||
|
logger.error("Recipe is not a dictionary")
|
||||||
|
return False
|
||||||
|
|
||||||
|
for key in essential_keys:
|
||||||
|
if key not in self.__recipe:
|
||||||
|
logger.error(f"Recipe is missing the '{key}' key")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not isinstance(self.__recipe["steps"], list):
|
||||||
|
logger.error("Recipe steps is not a list")
|
||||||
|
return False
|
||||||
|
|
||||||
|
for step in self.__recipe["steps"]:
|
||||||
|
if not isinstance(step, dict):
|
||||||
|
logger.error(f"Step {step} is not a dictionary")
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raw(self):
|
||||||
|
return self.__recipe
|
@ -1,26 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
|
|
||||||
class Snap:
|
|
||||||
env = os.environ.copy()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def install(packages: list):
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'snap', 'install'] + packages,
|
|
||||||
env=Snap.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def remove(packages: list):
|
|
||||||
subprocess.run(
|
|
||||||
['sudo', 'snap', 'remove'] + packages,
|
|
||||||
env=Snap.env,
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE
|
|
||||||
)
|
|
@ -1,36 +0,0 @@
|
|||||||
welcome = [
|
|
||||||
'Welcome',
|
|
||||||
'Benvenuto',
|
|
||||||
'Bienvenido',
|
|
||||||
'Bienvenue',
|
|
||||||
'Willkommen',
|
|
||||||
'Bem-vindo',
|
|
||||||
'Добро пожаловать',
|
|
||||||
'欢迎',
|
|
||||||
'ようこそ',
|
|
||||||
'환영합니다',
|
|
||||||
'أهلا بك',
|
|
||||||
'ברוך הבא',
|
|
||||||
'Καλώς ήρθατε',
|
|
||||||
'Hoşgeldiniz',
|
|
||||||
'Welkom',
|
|
||||||
'Witamy',
|
|
||||||
'Välkommen',
|
|
||||||
'Tervetuloa',
|
|
||||||
'Vítejte',
|
|
||||||
'Üdvözöljük',
|
|
||||||
'Bun venit',
|
|
||||||
'Vitajte',
|
|
||||||
'Tere tulemast',
|
|
||||||
'Sveiki atvykę',
|
|
||||||
'Dobrodošli',
|
|
||||||
'خوش آمدید',
|
|
||||||
'आपका स्वागत है',
|
|
||||||
'স্বাগতম',
|
|
||||||
'வரவேற்கிறோம்',
|
|
||||||
'స్వాగతం',
|
|
||||||
'मुबारक हो',
|
|
||||||
'સુસ્વાગત છે',
|
|
||||||
'ಸುಸ್ವಾಗತ',
|
|
||||||
'സ്വാഗതം'
|
|
||||||
]
|
|
@ -0,0 +1,54 @@
|
|||||||
|
# done.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 mirkobrombin
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundationat version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from gi.repository import Gtk, Adw
|
||||||
|
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/done.ui')
|
||||||
|
class VanillaDone(Adw.Bin):
|
||||||
|
__gtype_name__ = 'VanillaDone'
|
||||||
|
|
||||||
|
status_page = Gtk.Template.Child()
|
||||||
|
btn_reboot = Gtk.Template.Child()
|
||||||
|
btn_close = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, window, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.__window = window
|
||||||
|
|
||||||
|
self.status_page.set_description(
|
||||||
|
"Restart your PC to enjoy your {} experience.".format(
|
||||||
|
self.__window.recipe["distro_name"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.btn_reboot.connect("clicked", self.__on_reboot_clicked)
|
||||||
|
self.btn_close.connect("clicked", self.__on_close_clicked)
|
||||||
|
|
||||||
|
def set_result(self, result):
|
||||||
|
if not result:
|
||||||
|
self.status_page.set_icon_name("dialog-error-symbolic")
|
||||||
|
self.status_page.set_title("Something went wrong")
|
||||||
|
self.status_page.set_description("Please contact the distribution developers.")
|
||||||
|
self.btn_reboot.set_visible(False)
|
||||||
|
self.btn_close.set_visible(True)
|
||||||
|
|
||||||
|
def __on_reboot_clicked(self, button):
|
||||||
|
subprocess.run(['gnome-session-quit', '--reboot'])
|
||||||
|
|
||||||
|
def __on_close_clicked(self, button):
|
||||||
|
self.__window.close()
|
@ -0,0 +1,10 @@
|
|||||||
|
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
||||||
|
viewsdir = join_paths(pkgdatadir, 'vanilla_first_setup/views')
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'__init__.py',
|
||||||
|
'done.py',
|
||||||
|
'progress.py',
|
||||||
|
]
|
||||||
|
|
||||||
|
install_data(sources, install_dir: viewsdir)
|
Loading…
Reference in New Issue