From 03e6a46e5eb1a946bbc066974e4defc7eda96c4f Mon Sep 17 00:00:00 2001 From: Jean28518 Date: Sat, 9 Mar 2024 21:16:37 +0100 Subject: [PATCH] Add arch linux support #172 --- PKGBUILD | 36 +++ README.md | 6 + additional/python/check_security_arch.py | 62 ++++ .../python/setup_automatic_snapshots.py | 34 +- build-arch-pkg.sh | 6 + build-bundle.sh | 2 + features.csv | 74 ++--- lib/content/basic_entries.dart | 9 +- lib/content/recommendations.dart | 3 + lib/enums/distros.dart | 3 + lib/enums/softwareManagers.dart | 3 + lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 1 + .../automatic_configuration_selection.dart | 18 ++ .../after_installation/office_selection.dart | 2 + .../main_screen/action_entry_card.dart | 4 +- lib/layouts/main_screen/main_search.dart | 10 +- lib/layouts/security_check/overview.dart | 95 +++--- lib/linux/linux_filesystem.dart | 2 + lib/main.dart | 3 + lib/services/action_handler.dart | 31 ++ lib/services/after_installation_service.dart | 1 + lib/services/linux.dart | 298 ++++++++++++++++-- 23 files changed, 592 insertions(+), 112 deletions(-) create mode 100644 PKGBUILD create mode 100644 additional/python/check_security_arch.py create mode 100644 build-arch-pkg.sh diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..678d96d --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,36 @@ +# Maintainer: Jean28518@Github +pkgname=linux-assistant +pkgdesc="A daily linux helper with powerful integrated search, routines and checks." +pkgver=0.4.4 +pkgrel=1 +arch=('x86_64') +license=('GPL-3.0-or-later') + +source=("https://github.com/Jean28518/linux-assistant/releases/latest/download/linux-assistant-bundle.zip") + +depends=("libkeybinder3", "wmctrl", "wget", "python", "mesa-utils", "polkit") + +package() { + mkdir -p "$pkgdir/usr/bin" + cp -f "$srcdir/linux-assistant-bundle/linux-assistant.sh" "$pkgdir/usr/bin/linux-assistant" + chmod +x "$srcdir/usr/bin/linux-assistant" + + mkdir -p "$pkgdir/usr/share/polkit-1/actions" + cp -f "$srcdir/linux-assistant-bundle/org.linux-assistant.operations.policy" "$pkgdir/usr/share/polkit-1/actions/org.linux-assistant.operations.policy" + + mkdir -p "$pkgdir/usr/share/applications" + cp -f "$srcdir/linux-assistant-bundle/linux-assistant.desktop" "$pkgdir/usr/share/applications/linux-assistant.desktop" + + mkdir -p "$pkgdir/usr/share/icons/hicolor/256x256/apps" + cp -f "$srcdir/linux-assistant-bundle/linux-assistant.png" "$pkgdir/usr/share/icons/hicolor/256x256/apps/linux-assistant.png" + + mkdir -p "$pkgdir/usr/lib/linux-assistant" + cp -r "$srcdir/linux-assistant-bundle/lib" "$pkgdir/usr/lib/linux-assistant/" + cp -r "$srcdir/linux-assistant-bundle/data" "$pkgdir/usr/lib/linux-assistant/" + cp -r "$srcdir/linux-assistant-bundle/additional" "$pkgdir/usr/lib/linux-assistant/" + cp -f "$srcdir/linux-assistant-bundle/version" "$pkgdir/usr/lib/linux-assistant/" + cp -f "$srcdir/linux-assistant-bundle/linux-assistant" "$pkgdir/usr/lib/linux-assistant/" + + + tar -czf "$pkgname-$pkgver-$arch.pkg.tar.gz" -C "$pkgdir" . +} \ No newline at end of file diff --git a/README.md b/README.md index 2dee7c9..0126945 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ sudo dpkg --install linux-assistant.deb # Option 3: Build .rpm package: bash ./build-rpm.sh + +# Option 3: Build Arch package +# You can only do this on an arch based distro +bash ./build-arch-pkg.sh +# To Install: +makepkg -s --skipchecksums --install ``` ## Run as flatpak diff --git a/additional/python/check_security_arch.py b/additional/python/check_security_arch.py new file mode 100644 index 0000000..552ccd2 --- /dev/null +++ b/additional/python/check_security_arch.py @@ -0,0 +1,62 @@ +import os +import jessentials +import jfolders +import jfiles +from check_home_folder_rights import check_home_folder_rights + + + +def get_additional_sources(): + # Check if yay is installed + if (jfiles.does_file_exist("/usr/bin/yay")): + # lines = jessentials.run_command("/usr/bin/yay -Q", False, True) + # for line in lines: + # print(f"aurpackage: {line.split(" ")[0]}") + print("yayinstalled") + +def get_available_updates(): + jessentials.run_command("pacman -Sy", False, False, {'DEBIAN_FRONTEND': 'noninteractive'}) + lines = jessentials.run_command("pacman -Qu", False, True) + for line in lines: + print(f"upgradeablepackage: {line}") + +def check_server_access(): + # Check for firewall + if (jfiles.does_file_exist("/usr/sbin/ufw")): + lines = jessentials.run_command("/usr/sbin/iptables -L", False, True) + ufwUserFound = False + for line in lines: + if "ufw-user" in line: + ufwUserFound = True + break + if not ufwUserFound: + print("firewallinactive") + # Check for firewalld + elif (jfiles.does_file_exist("/usr/bin/firewalld")): + lines = jessentials.run_command("/usr/bin/firewall-cmd --list-all", False, True) + if (len(lines) > 1): + pass + else: + print("firewallinactive") + else: + print("nofirewall") + + # Check for Xrdp + lines = jessentials.run_command("/usr/bin/systemctl status xrdp", False, True) + if (len(lines) > 1): + print("xrdprunning") + # Check for ssh: + lines = jessentials.run_command("/usr/bin/systemctl status ssh", False, True) + if (len(lines) > 1): + print("sshrunning") + lines = jessentials.run_command("/usr/bin/systemctl status fail2ban", False, True) + if (len(lines) == 0): + print("fail2bannotrunning") + +if __name__ == "__main__": + jessentials.ensure_root_privileges() + get_additional_sources() + get_available_updates() + check_home_folder_rights(jessentials.get_value_from_arguments("home", "")) + check_server_access() + print("#!script ran successfully.") diff --git a/additional/python/setup_automatic_snapshots.py b/additional/python/setup_automatic_snapshots.py index 02b2dab..e068e24 100644 --- a/additional/python/setup_automatic_snapshots.py +++ b/additional/python/setup_automatic_snapshots.py @@ -8,16 +8,32 @@ if not jfiles.does_file_exist("/etc/timeshift/timeshift.json"): jfiles.copy_file("/etc/timeshift/default.json", "/etc/timeshift/timeshift.json") timeshift_config = jfiles.get_dict_of_json_file("/etc/timeshift/timeshift.json") -print(timeshift_config) -fstab_line = jfiles.get_value_from_file("/etc/fstab", "UUID").strip() -fstab_line = re.sub(' +', ' ', fstab_line) # Remove all multiple whitespaces within string -uuid = fstab_line.split(" ")[0] -mount = fstab_line.split(" ")[1] -filesystem = fstab_line.split(" ")[2] -if len(uuid) == 36 and mount == "/" and filesystem == "ext4": +# Get all lines in /etc/fstab and search for the line with / as mount point +lines = jfiles.get_all_lines_from_file("/etc/fstab") +uuid = "" +mount = "" +filesystem = "" +for line in lines: + line = line.replace("\t", " ") + line = re.sub(' +', ' ', line) # Remove all multiple whitespaces within string + if line.strip().startswith("#"): + continue + if "/ " in line: + uuid = line.split(" ")[0].strip() + mount = line.split(" ")[1].strip() + filesystem = line.split(" ")[2].strip() + break + +if "UUID=" in uuid: + uuid = uuid.replace("UUID=", "") + +if len(uuid) == 36 and mount == "/" and (filesystem == "ext4" or filesystem == "btrfs"): timeshift_config["backup_device_uuid"] = uuid timeshift_config["schedule_monthly"] = "true" + if "--daily" in jessentials.get_arguments(): + timeshift_config["schedule_daily"] = "true" timeshift_config["exclude"].append("/home/***") - print(timeshift_config) + if filesystem == "btrfs": + timeshift_config["btrfs_mode"] = "true" jfiles.write_dict_to_json_file(dict=timeshift_config, file_path="/etc/timeshift/timeshift.json") - pass + pass \ No newline at end of file diff --git a/build-arch-pkg.sh b/build-arch-pkg.sh new file mode 100644 index 0000000..2da303f --- /dev/null +++ b/build-arch-pkg.sh @@ -0,0 +1,6 @@ +# Build bundle +VERSION="$( cat version )" + +sed -i "s/pkgver=.*/pkgver=\"$VERSION\"/" pkg/PKGBUILD + +makepkg -s --skipchecksums \ No newline at end of file diff --git a/build-bundle.sh b/build-bundle.sh index 32552db..c391b70 100644 --- a/build-bundle.sh +++ b/build-bundle.sh @@ -16,6 +16,8 @@ cp linux-assistant.sh linux-assistant-bundle/ cp linux-assistant.png linux-assistant-bundle/ cp -r flatpak linux-assistant-bundle/ cp version linux-assistant-bundle/ +cp linux-assistant.desktop linux-assistant-bundle/ +cp org.linux-assistant.operations.policy linux-assistant-bundle/ # Get libkeybinder.so cp /lib/x86_64-linux-gnu/libkeybinder-3.0.so.0 linux-assistant-bundle/lib/ diff --git a/features.csv b/features.csv index c6d3ab9..80673fe 100644 --- a/features.csv +++ b/features.csv @@ -1,37 +1,37 @@ -Feature,Flatpak,Debian,Ubuntu,Linux Mint,LMDE,PopOS,MX Linux,Zorin OS,KDE neon,openSUSE,Fedora,Gnome,Xfce,Cinnamon,KDE,Notes -Adabtable dark mode,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes *,yes,yes,yes,"*) depends on window theme,not gtk " -Hotkey handling,yes,yes *,yes *,yes,yes,yes,yes,yes,yes,yes,yes *,yes *,yes,yes,yes,*) only works on wayland with workaround described in #24 -Feedback function,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -Automatic recognition of environment,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, -App search,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, -Folder structure search,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, -Bookmark/Places folder search,yes,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, -Recent file search,yes,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, -Favorite file search,yes,-,-,-,-,-,-,-,-,-,-,no,no,yes,no, -Browser bookmark search,yes,yes,?,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes," Currently works with firefox,chromium and chrome; needs to checked with firefox on snap " -Security check,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, -Health check,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,,,,, -After installation routine,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, -Warpinator,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,Only works if flatpak is installed/available in the sources -Nvidia installation,-,(yes),yes,yes,(yes),(yes),(yes),(yes),(yes),no,no,-,-,-,-, -Multimedia codecs installation,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -Timeshift setup,yes,yes,yes,yes,yes,yes,yes,yes *,yes,no,no,-,-,-,-,*) When you start timeshift the welcome dialog with config is started. But the timeshift.json is configured successfully?? -Automatic update setup,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-,integrates on Linux Mint with mintupdate -Update full system (all packages of all pack. man.),yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -Search and installation of system packages,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -General integration of system package manager,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -General integration of flatpak,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -General integration of snapd,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -Recognition of drive space utilization,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,,,,, -Change user passwort dialog,yes,-,-,-,-,-,yes,-,no,-,yes,yes,yes,yes,no, -open system information,yes,-,-,-,-,-,yes,-,no,-,yes,yes,yes,yes,no, -automatic update check & install of linux assistant,no,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, -openAdditionalSoftwareSourcesSettings,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes *,-,-,-,-,*) We can only open gnome-software here -Change Power Mode,yes,yes,yes,yes,yes,yes,yes,no,yes,?,yes,-,-,-,-, -Change user profile,yes,-,-,-,yes,-,yes,-,no,-,yes,yes,yes,yes,no, -hardinfo,yes,yes,yes,yes,yes,yes,yes,yes,yes,?,no *,-,-,-,-,*) Fedora does not package hardinfo anymore -redshift,yes,yes,yes,yes,yes,yes,yes,yes,yes,?,yes,yes,yes,yes,yes, -makeCurrentUserToAdministrator,?,yes,yes,yes,yes,yes,yes,yes,yes,?,yes,-,-,-,-, -setupSnapAndInstallSnapStore,?,yes,yes,yes,yes,yes,yes,yes,yes,no,yes,-,-,-,-, -Commands in Searchbar,?,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, -AutomaticRepairOfPackageManager,?,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +Feature,Flatpak,Debian,Ubuntu,Linux Mint,LMDE,PopOS,MX Linux,Zorin OS,KDE neon,openSUSE,Fedora,Arch,Gnome,Xfce,Cinnamon,KDE,Notes +Adabtable dark mode,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes *,yes,yes,yes,"*) depends on window theme,not gtk " +Hotkey handling,yes,yes *,yes *,yes,yes,yes,yes,yes,yes,yes,yes *,yes,yes *,yes,yes,yes,*) only works on wayland with workaround described in #24 +Feedback function,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +Automatic recognition of environment,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, +App search,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, +Folder structure search,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, +Bookmark/Places folder search,yes,-,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, +Recent file search,yes,-,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, +Favorite file search,yes,-,-,-,-,-,-,-,-,-,-,-,no,no,yes,no, +Browser bookmark search,yes,yes,?,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes," Currently works with firefox,chromium and chrome; needs to checked with firefox on snap " +Security check,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, +Health check,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,,,,, +After installation routine,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes, +Warpinator,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,Only works if flatpak is installed/available in the sources +Nvidia installation,-,(yes),yes,yes,(yes),(yes),(yes),(yes),(yes),no,no,no,-,-,-,-, +Multimedia codecs installation,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +Timeshift setup,yes,yes,yes,yes,yes,yes,yes,yes *,yes,no,no,yes,-,-,-,-,*) When you start timeshift the welcome dialog with config is started. But the timeshift.json is configured successfully?? +Automatic update setup,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,-,-,-,-,integrates on Linux Mint with mintupdate +Update full system (all packages of all pack. man.),yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +Search and installation/uninstallation of system packages,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +General integration of system package manager,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +General integration of flatpak,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +General integration of snapd,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,-,-,-,-, +Recognition of drive space utilization,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,,,,, +Change user passwort dialog,yes,-,-,-,-,-,yes,-,no,-,yes,-,yes,yes,yes,no, +open system information,yes,-,-,-,-,-,yes,-,no,-,yes,-,yes,yes,yes,no, +automatic update check & install of linux assistant,no,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,-,-,-,-, +openAdditionalSoftwareSourcesSettings,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes *,no,-,-,-,-,*) We can only open gnome-software here +Change Power Mode,yes,yes,yes,yes,yes,yes,yes,no,yes,?,yes,yes,-,-,-,-, +Change user profile,yes,-,-,-,yes,-,yes,-,no,-,yes,-,yes,yes,yes,no, +hardinfo,yes,yes,yes,yes,yes,yes,yes,yes,yes,?,no *,no *,-,-,-,-,*) Fedora and arch do not have package hardinfo anymore +redshift,yes,yes,yes,yes,yes,yes,yes,yes,yes,?,yes,no *,yes,yes,yes,yes,*) Does only work with further complicated setup. +makeCurrentUserToAdministrator,?,yes,yes,yes,yes,yes,yes,yes,yes,?,yes,yes,-,-,-,-, +setupSnapAndInstallSnapStore,?,yes,yes,yes,yes,yes,yes,yes,yes,no,yes,yes,-,-,-,-, +Commands in Searchbar,?,-,-,-,-,-,-,-,-,-,-,-,yes,yes,yes,yes, +AutomaticRepairOfPackageManager,?,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,-,-,-,-, diff --git a/lib/content/basic_entries.dart b/lib/content/basic_entries.dart index 31bfa69..d92b6f6 100644 --- a/lib/content/basic_entries.dart +++ b/lib/content/basic_entries.dart @@ -73,7 +73,8 @@ List getBasicEntries(BuildContext context) { color: MintY.currentColor, ), disableEntryIf: () { - return [DISTROS.FEDORA].contains(Linux.currentenvironment.distribution); + return [DISTROS.FEDORA, DISTROS.ARCH] + .contains(Linux.currentenvironment.distribution); }, ), ActionEntry( @@ -130,6 +131,9 @@ List getBasicEntries(BuildContext context) { size: 48, color: MintY.currentColor, ), + disableEntryIf: () => + // We disable this entry on arch because the user should check the update manager by himself. + Linux.currentenvironment.distribution == DISTROS.ARCH, ), ActionEntry( name: AppLocalizations.of(context)!.automaticSnapshots, @@ -163,6 +167,9 @@ List getBasicEntries(BuildContext context) { action: "fix_package_manager", iconWidget: Icon(Icons.bug_report, size: 48, color: MintY.currentColor), keywords: ["fix", "package", "manager", "apt", "dpkg", "rpm", "zypper"], + disableEntryIf: () { + return [DISTROS.ARCH].contains(Linux.currentenvironment.distribution); + }, ), ActionEntry( name: AppLocalizations.of(context)!.setupSnap, diff --git a/lib/content/recommendations.dart b/lib/content/recommendations.dart index 93e1b12..c1b12de 100644 --- a/lib/content/recommendations.dart +++ b/lib/content/recommendations.dart @@ -56,6 +56,9 @@ List getRecommendations(BuildContext context) { size: 48, color: MintY.currentColor, ), + disableEntryIf: () { + return [DISTROS.ARCH].contains(Linux.currentenvironment.distribution); + }, ), ActionEntry( name: AppLocalizations.of(context)!.powerMode, diff --git a/lib/enums/distros.dart b/lib/enums/distros.dart index 0e0899b..a484d83 100644 --- a/lib/enums/distros.dart +++ b/lib/enums/distros.dart @@ -9,6 +9,7 @@ enum DISTROS { OPENSUSE, LMDE, FEDORA, + ARCH, } String getNiceStringOfDistrosEnum(var distro) { @@ -33,6 +34,8 @@ String getNiceStringOfDistrosEnum(var distro) { return "LMDE"; case DISTROS.FEDORA: return "Fedora"; + case DISTROS.ARCH: + return "Arch"; default: return ""; } diff --git a/lib/enums/softwareManagers.dart b/lib/enums/softwareManagers.dart index 0b26dac..43258cc 100644 --- a/lib/enums/softwareManagers.dart +++ b/lib/enums/softwareManagers.dart @@ -4,6 +4,7 @@ enum SOFTWARE_MANAGERS { APT, ZYPPER, DNF, + PACMAN, } String getNiceStringOfSoftwareManagerEnum(SOFTWARE_MANAGERS input) { @@ -18,6 +19,8 @@ String getNiceStringOfSoftwareManagerEnum(SOFTWARE_MANAGERS input) { return "Zypper"; case SOFTWARE_MANAGERS.DNF: return "DNF"; + case SOFTWARE_MANAGERS.PACMAN: + return "Pacman"; default: return ""; } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0693c06..65ae46b 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -345,6 +345,7 @@ "vivaldiDescription": "Proprietärer Browser mit Fokus auf Privatsphäre und vielen Anpassungsmöglichkeiten.", "makeAdministrator": "Aktuellen Benutzer zum Administrator machen", "makeAdministratorDescription": "Füge den aktuellen Benutzer zur Gruppe 'sudo' hinzu, um Root-Rechte zu erhalten. Dafür ist das Passwort des Root-Benutzers nötig.\nDanach ist ein Neustart des Rechners empfohlen.", + "yayInstalled": "Es wurde Yay gefunden. Yay ist ein AUR-Helper, der Dir das Installieren von AUR-Paketen erleichtert. Das AUR ist ein Community-Repository, in dem viele Pakete von der Community gepflegt werden und eventuell schädlich sein könnten.", "@helloWorld": { "placeholders": {}, "description": "", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fe6fdba..a5e4157 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -345,6 +345,7 @@ "vivaldiDescription": "Proprietary browser with focus on privacy and many customization options.", "makeAdministrator": "Make the current user an administrator", "makeAdministratorDescription": "Add the current user to the 'sudo' group to obtain root rights. The password of the root user is required for this.\nAfterwards a restart of the computer is recommended.", + "yayInstalled": "Yay was found. Yay is an AUR helper that makes it easier for you to install AUR packages. The AUR is a community repository where many packages are maintained by the community and could be potentially harmful.", "@helloWorld": { "placeholders": {}, "description": "The conventional newborn programmer greeting", diff --git a/lib/layouts/after_installation/automatic_configuration_selection.dart b/lib/layouts/after_installation/automatic_configuration_selection.dart index 459eea0..4ca8310 100644 --- a/lib/layouts/after_installation/automatic_configuration_selection.dart +++ b/lib/layouts/after_installation/automatic_configuration_selection.dart @@ -25,6 +25,11 @@ class AfterInstallationAutomaticConfiguration extends StatelessWidget { false; // disabled because of snapper } + if (Linux.currentenvironment.distribution == DISTROS.ARCH) { + AfterInstallationService.setupAutomaticUpdates = false; + AfterInstallationService.installNvidiaDrivers = false; + } + List content = [ MintYSelectableEntryWithIconHorizontal( icon: const SystemIcon( @@ -124,6 +129,19 @@ class AfterInstallationAutomaticConfiguration extends StatelessWidget { content.removeWhere((element) => element.runtimeType != MintYSelectableEntryWithIconHorizontal); + // Remove the Nvidia Card Installation and the Automatic Update Manager Configuration if the distribution is Arch + if (Linux.currentenvironment.distribution == DISTROS.ARCH) { + content.removeWhere((element) => + element.runtimeType == MintYSelectableEntryWithIconHorizontal && + (element as MintYSelectableEntryWithIconHorizontal).title == + AppLocalizations.of(context)! + .automaticUpdateManagerConfiguration); + content.removeWhere((element) => + element.runtimeType == MintYSelectableEntryWithIconHorizontal && + (element as MintYSelectableEntryWithIconHorizontal).title == + AppLocalizations.of(context)!.automaticNvidiaDriverInstallation); + } + return MintYPage( title: AppLocalizations.of(context)!.automaticConfiguration, customContentElement: MintYGrid( diff --git a/lib/layouts/after_installation/office_selection.dart b/lib/layouts/after_installation/office_selection.dart index 0dc2a41..4b53084 100644 --- a/lib/layouts/after_installation/office_selection.dart +++ b/lib/layouts/after_installation/office_selection.dart @@ -11,6 +11,8 @@ class AfterInstallationOfficeSelection extends StatelessWidget { static Future libreOfficeInstalled = Linux.areApplicationsInstalled([ "libreoffice-common", + "libreoffice-still", + "libreoffice-fresh", "org.libreoffice.LibreOffice", "libreoffice", "libreoffice-writer" diff --git a/lib/layouts/main_screen/action_entry_card.dart b/lib/layouts/main_screen/action_entry_card.dart index 681ada9..5e6b733 100644 --- a/lib/layouts/main_screen/action_entry_card.dart +++ b/lib/layouts/main_screen/action_entry_card.dart @@ -43,13 +43,13 @@ class _ActionEntryCardState extends State { ? Theme.of(context).focusColor : const Color.fromARGB(0, 0, 0, 0), title: Text(widget.actionEntry.name), - subtitle: Text(widget.actionEntry.description), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), + subtitle: Text(widget.actionEntry.description), // For debugging search index: // subtitle: Text( - // "${widget.actionEntry.description} | ${widget.actionEntry.priority} | ${widget.actionEntry.tmpPriority} | ${widget.actionEntry.action} "), + // "${widget.actionEntry.description} | ${widget.actionEntry.priority} | ${widget.actionEntry.tmpPriority} | ${widget.actionEntry.action} "), leading: icon, ), onTap: () { diff --git a/lib/layouts/main_screen/main_search.dart b/lib/layouts/main_screen/main_search.dart index c932ac8..2faa96a 100644 --- a/lib/layouts/main_screen/main_search.dart +++ b/lib/layouts/main_screen/main_search.dart @@ -439,7 +439,8 @@ class _MainSearchState extends State { /// This runs fast but only removes direct neighbours. void _removeDuplicatedEntries() { for (int i = 0; i < _foundEntries.length - 1; i++) { - if (_foundEntries[i].action == _foundEntries[i + 1].action) { + if (_foundEntries[i].action.trim() == + _foundEntries[i + 1].action.trim()) { _foundEntries.removeAt(i); } } @@ -482,6 +483,13 @@ class _MainSearchState extends State { heavyEntries.addAll(snaps); } + if (Linux.currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + List pacmanEntries = + await Linux.getInstallablePacmanPakagesForKeyword(keyword); + heavyEntries.addAll(pacmanEntries); + } + // If in the meantime the user cleared the search bar, we don't want to // show the results. if (keyword.trim() == "" || _lastKeyword == "") { diff --git a/lib/layouts/security_check/overview.dart b/lib/layouts/security_check/overview.dart index 8dbe0b7..bccadf0 100644 --- a/lib/layouts/security_check/overview.dart +++ b/lib/layouts/security_check/overview.dart @@ -22,11 +22,16 @@ class SecurityCheckOverview extends StatelessWidget { root: true, arguments: ["--home=${Platform.environment['HOME']}"], getErrorMessages: true); - } else if (Linux.currentenvironment.distribution == DISTROS.FEDORA) { + } else if (Linux.currentenvironment.distribution == DISTROS.FEDORA) { checkerOutputString = Linux.runPythonScript("check_security_fedora.py", root: true, arguments: ["--home=${Platform.environment['HOME']}"], getErrorMessages: true); + } else if (Linux.currentenvironment.distribution == DISTROS.ARCH) { + checkerOutputString = Linux.runPythonScript("check_security_arch.py", + root: true, + arguments: ["--home=${Platform.environment['HOME']}"], + getErrorMessages: true); } else { checkerOutputString = Linux.runPythonScript("check_security.py", root: true, @@ -75,6 +80,7 @@ class SecurityCheckOverview extends StatelessWidget { // At first set everything to "safe": List additionalSources = []; + bool yayInstalled = false; int availableUpdatePackages = 0; bool homeFolderSecure = true; bool firewallNotInstalled = false; @@ -88,6 +94,9 @@ class SecurityCheckOverview extends StatelessWidget { additionalSources .add(line.replaceFirst("additionalsource: ", "")); } + if (line.startsWith("yayinstalled")) { + yayInstalled = true; + } if (line.startsWith("upgradeablepackage:")) { availableUpdatePackages++; } @@ -115,7 +124,9 @@ class SecurityCheckOverview extends StatelessWidget { body: MintYPage( title: AppLocalizations.of(context)!.securityCheck, contentElements: [ - AdditionSoftwareSources(additionalSources: additionalSources), + AdditionSoftwareSources( + additionalSources: additionalSources, + yayInstalled: yayInstalled), const SizedBox(height: 16), UpdateCheck(availableUpdatePackages: availableUpdatePackages), const SizedBox(height: 16), @@ -299,9 +310,11 @@ class AdditionSoftwareSources extends StatelessWidget { const AdditionSoftwareSources({ Key? key, required this.additionalSources, + required this.yayInstalled, }) : super(key: key); final List additionalSources; + final bool yayInstalled; @override Widget build(BuildContext context) { @@ -310,6 +323,16 @@ class AdditionSoftwareSources extends StatelessWidget { additionalSourceTexts.add(Text(element)); } + // If yay is installed, then we show a warning message instead of the success message. + Widget ourChild = SuccessMessage( + text: AppLocalizations.of(context)!.noAdditionalSoftwareSourcesFound); + + if (yayInstalled) { + ourChild = WarningMessage( + text: AppLocalizations.of(context)!.yayInstalled, + ); + } + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -318,43 +341,41 @@ class AdditionSoftwareSources extends StatelessWidget { style: Theme.of(context).textTheme.headlineLarge, ), Padding( - padding: const EdgeInsets.all(8.0), - child: additionalSources.isNotEmpty - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - WarningMessage( - text: AppLocalizations.of(context)! - .additionalSoftwareSourcesDetected, - fixAction: () { - Linux.openAdditionalSoftwareSourcesSettings(); - }, - ), - const SizedBox( - height: 8, - ), - Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8)), - color: Colors.grey), - padding: const EdgeInsets.all(8), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: additionalSourceTexts, + padding: const EdgeInsets.all(8.0), + child: additionalSources.isNotEmpty + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + WarningMessage( + text: AppLocalizations.of(context)! + .additionalSoftwareSourcesDetected, + fixAction: () { + Linux.openAdditionalSoftwareSourcesSettings(); + }, + ), + const SizedBox( + height: 8, + ), + Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Colors.grey), + padding: const EdgeInsets.all(8), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: additionalSourceTexts, + ), ), - ), - ], + ], + ), ), - ), - ], - ) - : SuccessMessage( - text: AppLocalizations.of(context)! - .noAdditionalSoftwareSourcesFound), - ) + ], + ) + // If no software source found we wether show a correct success message or a warning message if yay is installed. + : ourChild) ], ); } diff --git a/lib/linux/linux_filesystem.dart b/lib/linux/linux_filesystem.dart index 2b7b24e..5edb7a5 100644 --- a/lib/linux/linux_filesystem.dart +++ b/lib/linux/linux_filesystem.dart @@ -15,6 +15,8 @@ class DeviceInfo { abstract class LinuxFilesystem { static final List _ignoreDevices = [ + "dev", + "run", "df:", "udev", "tmpfs", diff --git a/lib/main.dart b/lib/main.dart index 7ec764f..24cfe37 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -134,6 +134,9 @@ class MyApp extends StatelessWidget { case DISTROS.FEDORA: MintY.currentColor = const Color.fromARGB(255, 81, 162, 218); break; + case DISTROS.ARCH: + MintY.currentColor = const Color.fromARGB(255, 15, 148, 210); + break; default: MintY.currentColor = Colors.blue; } diff --git a/lib/services/action_handler.dart b/lib/services/action_handler.dart index 43941f2..35451c0 100644 --- a/lib/services/action_handler.dart +++ b/lib/services/action_handler.dart @@ -280,6 +280,37 @@ class ActionHandler { )); } + if (actionEntry.action.startsWith("pacman-install:")) { + String pkg = actionEntry.action.replaceFirst("pacman-install:", ""); + Linux.commandQueue.add(LinuxCommand( + userId: 0, + command: + "${Linux.getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -S $pkg --noconfirm")); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RunCommandQueue( + title: "Pacman", + message: AppLocalizations.of(context)!.packageWillBeInstalled, + route: const MainSearchLoader(), + )), + ); + } + + if (actionEntry.action.startsWith("pacman-uninstall:")) { + String pkg = actionEntry.action.replaceFirst("pacman-uninstall:", ""); + Linux.commandQueue.add(LinuxCommand( + userId: 0, + command: + "${Linux.getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -R $pkg --noconfirm")); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + UninstallerQuestion(action: actionEntry.action), + )); + } + if (actionEntry.action.startsWith("flatpak-install:")) { String pkg = actionEntry.action.replaceFirst("flatpak-install:", ""); Linux.commandQueue.add(LinuxCommand( diff --git a/lib/services/after_installation_service.dart b/lib/services/after_installation_service.dart index 8ab627d..7c48d8b 100644 --- a/lib/services/after_installation_service.dart +++ b/lib/services/after_installation_service.dart @@ -71,6 +71,7 @@ class AfterInstallationService { static Future applyCurrentOfficeSituation() async { Future fLibreOffice = applyApplicationActionIfNecessary([ "libreoffice-common", + "libreoffice-still", "libreoffice", "org.libreoffice.LibreOffice", "libreoffice-writer", diff --git a/lib/services/linux.dart b/lib/services/linux.dart index 5b3720f..e1fb084 100644 --- a/lib/services/linux.dart +++ b/lib/services/linux.dart @@ -266,7 +266,7 @@ class Linux { return; } else { // if app is not installed: - await installApplications(["redshift-gtk"]); + await installApplications(["redshift-gtk", "redshift"]); if (currentenvironment.desktop == DESKTOPS.KDE) { await installApplications(["plasma-applet-redshift-control"]); } @@ -351,6 +351,24 @@ class Linux { return; } + if (softwareManager == SOFTWARE_MANAGERS.PACMAN) { + // Check, if package is available: + bool available = await isPacmanPackageAvailable(appCode); + if (!available) { + continue; + } + + commandQueue.add( + LinuxCommand( + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -S $appCode --noconfirm", + userId: 0, + environment: {}, + ), + ); + return; + } + if (softwareManager == SOFTWARE_MANAGERS.FLATPAK) { // Check, if package is available: String repo = await isFlatpakAvailable(appCode); @@ -431,6 +449,17 @@ class Linux { return output.replaceAll(" ", "").contains("InstalledPackages"); } + static Future isSpecificPacmanPackageInstalled(appCode) async { + if (!currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + return false; + } + String output = await runCommand( + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -Q $appCode", + environment: {"LC_ALL": "C"}); + return !output.contains("was not found"); + } + static Future isSpecificSnapInstalled(appCode) async { String output = await runCommand( "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.SNAP)} info $appCode"); @@ -504,6 +533,24 @@ class Linux { } } + // Pacman + if (softwareManager == null || + softwareManager == SOFTWARE_MANAGERS.PACMAN) { + bool isPacmanPackageInstalled = + await isSpecificPacmanPackageInstalled(appCode); + if ((softwareManager == null || + softwareManager == SOFTWARE_MANAGERS.PACMAN) && + isPacmanPackageInstalled) { + commandQueue.add( + LinuxCommand( + userId: 0, + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -R $appCode --noconfirm", + ), + ); + } + } + // Flatpak if (softwareManager == null || softwareManager == SOFTWARE_MANAGERS.FLATPAK) { @@ -572,6 +619,16 @@ class Linux { } } } + if (currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + for (String appCode in appCodes) { + bool isPacmanPackageInstalled = + await isSpecificPacmanPackageInstalled(appCode); + if (isPacmanPackageInstalled) { + return true; + } + } + } if (currentenvironment.installedSoftwareManagers .contains(SOFTWARE_MANAGERS.FLATPAK)) { for (String appCode in appCodes) { @@ -613,6 +670,13 @@ class Linux { return !output.toLowerCase().contains("no matching packages to list"); } + static Future isPacmanPackageAvailable(String appCode) async { + String output = await runCommand( + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -Ss $appCode"); + return output.contains("community/$appCode") || + output.contains("extra/$appCode"); + } + /// returns the source under which the Flatpak is available, otherwise empty String static Future isFlatpakAvailable(String appCode) async { String output = await runCommand( @@ -856,6 +920,8 @@ class Linux { newEnvironment.distribution = DISTROS.LMDE; } else if (lines[0].toLowerCase().contains("fedora")) { newEnvironment.distribution = DISTROS.FEDORA; + } else if (lines[0].toLowerCase().contains("arch")) { + newEnvironment.distribution = DISTROS.ARCH; } // get version: @@ -944,6 +1010,8 @@ class Linux { return "/usr/bin/zypper"; case SOFTWARE_MANAGERS.DNF: return "/usr/bin/dnf"; + case SOFTWARE_MANAGERS.PACMAN: + return "/usr/bin/pacman"; default: return ""; } @@ -1071,6 +1139,13 @@ class Linux { "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.DNF)} group upgrade --with-optional Multimedia -y", )); break; + case DISTROS.ARCH: + commandQueue.add(LinuxCommand( + userId: 0, + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -S --noconfirm vlc gstreamer libdvdcss libdvdread libdvdnav ffmpeg gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly", + )); + break; default: } } @@ -1164,10 +1239,14 @@ class Linux { /// Only appends commands to [commandQueue] static Future enableAutomaticSnapshots() async { await ensureApplicationInstallation(["timeshift"]); + String additional = ""; + if (currentenvironment.distribution == DISTROS.ARCH) { + additional = "--daily"; + } commandQueue.add(LinuxCommand( userId: 0, command: - "python3 ${executableFolder}additional/python/setup_automatic_snapshots.py")); + "python3 ${executableFolder}additional/python/setup_automatic_snapshots.py $additional")); } /// Only appends commands to [commandQueue] @@ -1191,27 +1270,31 @@ class Linux { command: "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.DNF)} update --refresh -y", )); - } else { - if (currentenvironment.installedSoftwareManagers - .contains(SOFTWARE_MANAGERS.ZYPPER)) { - // Check if we are in tumbleweed: - String file = await getEtcOsRelease(); - if (file.toLowerCase().contains("tumbleweed")) { - // Tumbleweed - commandQueue.add(LinuxCommand( - userId: 0, - command: - "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.ZYPPER)} --non-interactive dup", - )); - } else { - // Leap or other - commandQueue.add(LinuxCommand( - userId: 0, - command: - "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.ZYPPER)} --non-interactive up", - )); - } + } else if (currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.ZYPPER)) { + String file = await getEtcOsRelease(); + if (file.toLowerCase().contains("tumbleweed")) { + // Tumbleweed + commandQueue.add(LinuxCommand( + userId: 0, + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.ZYPPER)} --non-interactive dup", + )); + } else { + // Leap or other + commandQueue.add(LinuxCommand( + userId: 0, + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.ZYPPER)} --non-interactive up", + )); } + } else if (currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + commandQueue.add(LinuxCommand( + userId: 0, + command: + "${getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN)} -Syu --noconfirm", + )); } if (currentenvironment.installedSoftwareManagers @@ -1473,6 +1556,53 @@ class Linux { return results; } + static Future> getInstallablePacmanPakagesForKeyword( + keyword) { + if (keyword.length <= 3) { + return Future.value([]); + } + return runCommandWithCustomArguments( + getExecutablePathOfSoftwareManager(SOFTWARE_MANAGERS.PACMAN), + ["-Ss", keyword]).then((output) { + output = output.trim(); + List lines = output.split("\n"); + + // Cancel search, if too many search results. + if (lines.length > 100) { + return []; + } + +// $ pacman -Ss htop +// extra/bashtop 0.9.25-1 +// Linux resource monitor + + List results = []; + for (String line in lines) { + if (line.trim() == "") { + continue; + } + List lineParts = line.split(" "); + String packageName = lineParts[0].trim(); + if (!packageName.contains("/")) { + continue; + } + packageName = packageName.split("/")[1]; + results.add(ActionEntry( + iconWidget: Icon( + Icons.download_rounded, + size: 48, + color: MintY.currentColor, + ), + name: "Install $packageName", + description: "Install via pacman", + action: "pacman-install:$packageName", + priority: -20, + )); + } + return results; + }); + } + static Future> getInstalledAPTPackages() async { if (!currentenvironment.installedSoftwareManagers .contains(SOFTWARE_MANAGERS.APT)) { @@ -1561,6 +1691,35 @@ class Linux { return returnValue; } + /// Returns List of [package name] + static Future> getInstalledPacmanPackages() async { + if (!currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + return []; + } + List returnValue = []; + + /// Run: pacman -Q + String output = await Linux.runCommandWithCustomArguments( + "/usr/bin/pacman", + [ + "-Q", + ], + ); + + List lines = output.split("\n"); + + for (String line in lines) { + List lineParts = line.split(" "); + if (lineParts.length < 2) { + continue; + } + String packageName = lineParts[0].trim(); + returnValue.add(packageName); + } + return returnValue; + } + /// Return value: List of [app id, app name, app description]; static Future>> getInstalledFlatpaks() async { if (!currentenvironment.installedSoftwareManagers @@ -1611,6 +1770,8 @@ class Linux { getInstalledZypperPackages(); Future>> installedDNFPackagesFuture = getInstalledDNFPackages(); + Future> installedPackagesPacmanFuture = + getInstalledPacmanPackages(); Future>> installedFlatpaksFuture = getInstalledFlatpaks(); Future> installedSnapsFuture = getInstalledSnaps(); @@ -1680,6 +1841,25 @@ class Linux { ); } + /// Pacman + List installedPacmanPackages = await installedPackagesPacmanFuture; + for (String pacmanEntry in installedPacmanPackages) { + returnValue.add( + ActionEntry( + name: AppLocalizations.of(context)!.uninstallApp(pacmanEntry), + description: "(Pacman)", + action: "pacman-uninstall:$pacmanEntry", + iconWidget: Icon( + Icons.delete, + size: 48, + color: MintY.currentColor, + ), + priority: -10, + excludeFromSearchProposal: true, + ), + ); + } + /// Flatpak List> installedFlatpaks = await installedFlatpaksFuture; @@ -2005,7 +2185,11 @@ class Linux { } static Future getHostname() async { - return (await runCommand("hostname")).trim(); + if (File("/etc/hostname").existsSync()) { + return (await File("/etc/hostname").readAsString()).trim(); + } else { + return (await runCommand("hostname")).trim(); + } } static Future getOsPrettyName() async { @@ -2050,6 +2234,21 @@ class Linux { } static Future getGpuModel() async { + // If glxinfo is not installed we are doing this with lspci: + // lspci -k | grep -A 2 -E "(VGA|3D)" + if (!File("/usr/bin/glxinfo").existsSync()) { + String output = + // await runCommand("bash -c \"lspci -k | grep -A 2 -E '(VGA|3D)'\""); + await runCommandWithCustomArguments( + "bash", ["-c", "lspci -k | grep -A 2 -E '(VGA|3D)'"]); + List lines = output.split("\n"); + for (String line in lines) { + if (line.contains("VGA") || line.contains("3D")) { + return line.split(":").last.trim(); + } + } + } + try { return (await runCommand("glxinfo -B")) .split("\n") @@ -2188,6 +2387,13 @@ class Linux { command: "/usr/bin/dnf clean all", )); } + if (currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + commandQueue.add(LinuxCommand( + userId: 0, + command: "/usr/bin/pacman -Sc --noconfirm", + )); + } if (currentenvironment.installedSoftwareManagers .contains(SOFTWARE_MANAGERS.FLATPAK)) { commandQueue.add(LinuxCommand( @@ -2246,6 +2452,7 @@ class Linux { commandQueue.add(LinuxCommand( userId: 0, command: "/usr/sbin/ufw enable", + environment: {"PATH": getPATH()}, )); } Navigator.of(context).push(MaterialPageRoute( @@ -2331,8 +2538,12 @@ class Linux { break; case DESKTOPS.GNOME: case DESKTOPS.CINNAMON: - runCommandWithCustomArguments( - "gnome-terminal", ["--", "bash", "-c", command]); + if (File("/usr/bin/kgx").existsSync()) { + runCommandWithCustomArguments("kgx", ["-e", "bash", "-c", command]); + } else if (File("/usr/bin/gnome-terminal").existsSync()) { + runCommandWithCustomArguments( + "gnome-terminal", ["--", "bash", "-c", command]); + } break; case DESKTOPS.XFCE: runCommandWithCustomArguments( @@ -2381,6 +2592,43 @@ class Linux { command: "/usr/bin/snap install snapd", )); } + // Arch: https://snapcraft.io/install/snapd/arch + // pacman -S git --noconfirm + // Clone it to the tmp folder + // git clone https://aur.archlinux.org/snapd.git + // cd snapd + // makepkg -si --noconfirm + // sudo systemctl enable --now snapd.socket + // sudo ln -s /var/lib/snapd/snap /snap + // sudo snap install snapd + if (currentenvironment.installedSoftwareManagers + .contains(SOFTWARE_MANAGERS.PACMAN)) { + installApplications(["git"], + preferredSoftwareManager: SOFTWARE_MANAGERS.PACMAN); + String bashCode = + "git clone https://aur.archlinux.org/snapd.git /tmp/snapd; cd /tmp/snapd; makepkg -si --noconfirm;"; + commandQueue.add(LinuxCommand( + userId: currentenvironment.currentUserId, + command: "bash -c '$bashCode'", + environment: {"PATH": getPATH(), "HOME": getHomeDirectory()}, + )); + commandQueue.add(LinuxCommand( + userId: 0, + command: "/usr/bin/systemctl enable --now snapd.socket", + )); + commandQueue.add(LinuxCommand( + userId: 0, + command: "ln -s /var/lib/snapd/snap /snap", + )); + commandQueue.add(LinuxCommand( + userId: 0, + command: "/usr/bin/snap install snapd", + )); + commandQueue.add(LinuxCommand( + userId: 0, + command: "/usr/bin/rm -rf /tmp/snapd", + )); + } // openSUSE is a bit more complicated: https://snapcraft.io/install/snapd/opensuse // if (currentenvironment.installedSoftwareManagers // .contains(SOFTWARE_MANAGERS.ZYPPER)) {