diff --git a/debian/vanilla-first-setup.install b/debian/vanilla-first-setup.install index 057aa5ce..dc3b81d6 100644 --- a/debian/vanilla-first-setup.install +++ b/debian/vanilla-first-setup.install @@ -1,4 +1,5 @@ recipe.json usr/share/org.vanillaos.FirstSetup/ +tests.json usr/share/org.vanillaos.FirstSetup/ __first_setup_reset_session usr/bin/ __first_setup_cleanup usr/bin/ first-setup.txt etc/vanilla/ diff --git a/tests.json b/tests.json new file mode 100644 index 00000000..656ca698 --- /dev/null +++ b/tests.json @@ -0,0 +1,9 @@ +{ + "current": { + "flatpak": ["/usr/bin/flatpak", "/usr/lib/x86_64-linux-gnu/gnome-software/plugins-20/libgs_plugin_flatpak.so"], + "appimage": ["/bin/fusermount", "/lib/x86_64-linux-gnu/libfuse3.so.3"], + "timeshift": ["/usr/bin/timeshift"], + "vm": ["/usr/bin/vmtoolsd", "/usr/bin/vmware-user"], + "codecs": ["/usr/share/doc/libavcodec-extra/copyright", "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstlibav.so", "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgsta52dec.so", "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvaapi.so", "/usr/bin/unrar-nonfree"] + } +} diff --git a/vanilla_first_setup/defaults/hostname.py b/vanilla_first_setup/defaults/hostname.py index 6a54bcd5..3407e524 100644 --- a/vanilla_first_setup/defaults/hostname.py +++ b/vanilla_first_setup/defaults/hostname.py @@ -55,6 +55,7 @@ def get_finals(self): "if": "setHostname", "type": "command", "commands": ["hostnamectl set-hostname " + self.hostname], + "tests": [] } ], } diff --git a/vanilla_first_setup/defaults/user.py b/vanilla_first_setup/defaults/user.py index 4c0a832b..e2b9023a 100644 --- a/vanilla_first_setup/defaults/user.py +++ b/vanilla_first_setup/defaults/user.py @@ -72,7 +72,7 @@ def get_finals(self): f'adduser --quiet --disabled-password --shell /bin/bash --gecos "{self.fullname}" {self.username}', f'echo "{self.username}:{self.password_entry.get_text()}" | chpasswd', f"usermod -a -G sudo,adm,lpadmin {self.username}", - ], + ] } ], } diff --git a/vanilla_first_setup/utils/parser.py b/vanilla_first_setup/utils/parser.py index 89fb8157..864982e1 100644 --- a/vanilla_first_setup/utils/parser.py +++ b/vanilla_first_setup/utils/parser.py @@ -24,7 +24,7 @@ class Parser: supported_types = ["command"] @staticmethod - def parse(finals): + def parse(finals, tests): commands = [] warps = [] all_vars = [] @@ -85,6 +85,8 @@ def parse(finals): cmd = cmd.replace(f"exposed::{k}", v) commands.append(cmd) + tests.append(_condition) + # set-up warps if any for warp in warps: _vars = warp["vars"] diff --git a/vanilla_first_setup/utils/tests.py b/vanilla_first_setup/utils/tests.py new file mode 100644 index 00000000..eb4382ce --- /dev/null +++ b/vanilla_first_setup/utils/tests.py @@ -0,0 +1,51 @@ +# tests.py +# +# +# 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 . + +import os +import json + + +class Tests: + + def __init__(self): + self.__selected_tests = [""] + self.__tests = {} + self.__tests_path = "/usr/share/org.vanillaos.FirstSetup/tests.json" + self.__selected_tests_path = "/home/$REAL_USER/.local/share/selected_tests.json" + self.__selected_tests_path = "/home/{}/.local/share/selected_tests.json".format(os.getenv("REAL_USER")) + + def add_test(self, test): + self.__selected_tests.append(test) + + def test(self): + for i, v in self.__tests["current"]: + if i in self.__selected_tests: + for j in v: + if not os.path.isfile(j): + return False + return True + + def load(self): + with open(self.__tests_path, 'r') as f: + self.__tests = json.load(f) + with open(self.__selected_tests_path, 'r') as f: + self.__selected_tests = json.load(f) + + def write(self): + with open(self.__selected_tests_path, 'w') as f: + json.dump(self.__selected_tests, f) + + def remove(self): + os.remove(self.__selected_tests_path) diff --git a/vanilla_first_setup/window.py b/vanilla_first_setup/window.py index 0fcdf454..efa9b8db 100644 --- a/vanilla_first_setup/window.py +++ b/vanilla_first_setup/window.py @@ -22,11 +22,14 @@ from vanilla_first_setup.utils.builder import Builder from vanilla_first_setup.utils.parser import Parser from vanilla_first_setup.utils.processor import Processor +from vanilla_first_setup.utils.tests import Tests from vanilla_first_setup.views.progress import VanillaProgress from vanilla_first_setup.views.done import VanillaDone from vanilla_first_setup.views.post_script import VanillaPostScript +from dialog import VanillaDialog + @Gtk.Template(resource_path="/org/vanillaos/FirstSetup/gtk/window.ui") class VanillaWindow(Adw.ApplicationWindow): @@ -56,6 +59,20 @@ def __init__(self, post_script: str, user: str, new_user: bool = False, **kwargs # True/False = managed result self.__last_result = None + # Create and run the tests to make sure the previous run installed + # all the packages properly + if self.__init_mode == 1: + self.__tests = Tests() + self.__tests.load() + + # 0 = succeeded + # 1 = did not succeed + # -1 = did not test + self.__tests_succeeded = 0 if self.__tests.test() else 1 + post_script = 0 if self.__tests_succeeded == 1 else 1 + else: + self.__tests_succeeded = -1 + # if a post_script is provided, we are in the post setup # so we can skip the builder and just run the post script # in the Vte terminal @@ -63,6 +80,9 @@ def __init__(self, post_script: str, user: str, new_user: bool = False, **kwargs # set the initialization mode to 1 self.__init_mode = 1 + # delete the tests file + self.__tests.remove() + # system views self.__view_done = VanillaDone( self, @@ -96,6 +116,9 @@ def __init__(self, post_script: str, user: str, new_user: bool = False, **kwargs # connect system signals self.__connect_signals() + if self.__tests_succeeded == 1: + dialog = VanillaDialog(self, "Previous setup failed", "The packages you installed in the previous boot of First Setup could not be installed. Therefore, you will have to go through the First Setup again.") + def __build_post_script_ui(self, post_script): self.__view_post_script = VanillaPostScript(self, post_script) @@ -168,16 +191,17 @@ def __on_page_changed(self, *args): # this parses the finals to compatible commands, by replacing the # placeholders with the actual values and generating shell commands - commands = Parser.parse(finals) + commands = Parser.parse(finals, self.__tests) # process the commands res = Processor.get_setup_commands( self.recipe.get("log_file", "/tmp/vanilla_first_setup.log"), self.recipe.get("pre_run", []), self.recipe.get("post_run"), - commands, + commands ) + self.__tests.write() self.__view_progress.start(res, Processor.hide_first_setup, self.__user) def set_installation_result(self, result, terminal):