From a2682e042fd1ef95d80c254b08883df9466bf31f Mon Sep 17 00:00:00 2001 From: Frede Hundewadt Date: Thu, 14 Nov 2019 18:03:03 +0100 Subject: [PATCH] local fhdk --- launch.sh | 2 + src/app-install | 118 --------------- src/app-utility | 371 ------------------------------------------------ 3 files changed, 2 insertions(+), 489 deletions(-) delete mode 100755 src/app-install delete mode 100755 src/app-utility diff --git a/launch.sh b/launch.sh index 8bf29ab..7200f96 100755 --- a/launch.sh +++ b/launch.sh @@ -1,6 +1,8 @@ #!/bin/sh # Script to generate mo files in a temp locale folder # Use it only for testing purpose +export PLUGIN_HELLO=True +export PYTHONPATH="/home/fh/Data/projects/application-utility" rm -rf locale mkdir locale cd po diff --git a/src/app-install b/src/app-install deleted file mode 100755 index c7dc46b..0000000 --- a/src/app-install +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# MIT License -# -# Copyright (c) 2018 Fredes Computer Service -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -#set -x -if [[ -n ${APP_UTILITY} ]]; then - echo "This script is part of Manjaro Application Utility\nIt is not meant to be run from command line\n exit()" -fi - -# files -IN_PKG_FILE="/tmp/.install-packages.txt" -RM_PKG_FILE="/tmp/.remove-packages.txt" -PM_STATUS_FILE="/tmp/.pm-status.txt" -PM_LOCK_FILE="/var/lib/pacman/db.lck" - -echo ${IN_PKG_FILE} -echo ${RM_PKG_FILE} - -# messages -TITLE="Manjaro Application Utility" -UPD_DB_MSG="Updating Package Database..." -DB_LOCKED_MSG="Another package manager is running.\n -If you are updating the system\n -you MUST finish before continuing.\n -If you are not, it is safe to kill the other process.\n -What would you like to do?" -KILL_PROCESS="Kill other process and continue" -WAIT_PROCESS="Wait to finish updating" -IN_WORKING_MSG="Installing Packages..." -RM_WORKING_MSG="Uninstalling Packages..." -DONE="Your System has Been Successfully Updated" - -if [[ -f ${IN_PKG_FILE} ]]; then - IN_PKG=` cat ${IN_PKG_FILE} ` - echo ${IN_PKG} -fi - -if [[ -f ${RM_PKG_FILE} ]]; then - RM_PKG=` cat ${RM_PKG_FILE} ` - echo ${RM_PKG} -fi - -# Make sure only root can run our script -if [[ $EUID -ne 0 ]]; then - echo "Superuser required ..." 1>&2 - exit 1 -fi - -# updating databases and writing results to a file -pacman -Syy | tee ${PM_STATUS_FILE} | zenity --progress --title="${TITLE}" --no-cancel --pulsate --text "${UPD_DB_MSG}" --width=500 --auto-close - -PM_STATUS=` cat ${PM_STATUS_FILE} ` - -# checking for other running package managers -if [[ $(cat ${PM_STATUS_FILE} | grep -i 'core.db') = "" ]] - then # giving choice to user to kill other process or wait - ans=$(zenity --list --title="${TITLE}" --radiolist --text "${DB_LOCKED_MSG}" --column Select --column Choice TRUE "${KILL_PROCESS}" FALSE "${WAIT_PROCESS}" --width=500 --height=300) - # killing pamac and unlocking db - if [ "$ans" = "${KILL_PROCESS}" ] - then - killall pamac-updater - killall pamac-manager - rm ${PM_LOCK_FILE} - pacman -Syy | zenity --progress --title="${TITLE}" --no-cancel --pulsate --text "${UPD_DB_MSG}" --width=500 --auto-close - else # exiting according to user choice - exit - fi -fi - -# Installing packages -if [[ -n ${IN_PKG} ]]; then - pacman -Syu --noconfirm ${IN_PKG} | zenity --progress --title="${TITLE}" --no-cancel --pulsate --text "${IN_WORKING_MSG}" --width=500 --auto-close -fi - -# Uninstalling packages -if [[ -n ${RM_PKG} ]]; then - pacman -R --noconfirm ${RM_PKG} | zenity --progress --title="${TITLE}" --no-cancel --pulsate --text "${RM_WORKING_MSG}" --width=500 --auto-close -fi - -# Letting user know that packages have been installed -zenity --info --text="${DONE}" --width=500 --height=300 - -# removing files no longer needed -if [[ -f ${IN_PKG_FILE} ]]; then - rm ${IN_PKG_FILE} -fi - -if [[ -f ${RM_PKG_FILE} ]]; then - rm ${RM_PKG_FILE} -fi - -if [[ -f ${PM_STATUS_FILE} ]]; then - rm ${PM_STATUS_FILE} -fi - -if [[ -f ${PM_LOCK_FILE} ]]; then - rm ${PM_LOCK_FILE} -fi diff --git a/src/app-utility b/src/app-utility deleted file mode 100755 index 651e999..0000000 --- a/src/app-utility +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# MIT License -# -# Copyright (c) 2018 Fredes Computer Service -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import collections -import json -import glob -import os -import subprocess -import sys -import urllib.request - -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk, GLib - -VERSION = "0.8" -TITLE = "Manjaro Application Utility {}".format(VERSION) -DEBUG = True - -GROUP = 0 -ICON = 1 -APPLICATION = 2 -DESCRIPTION = 3 -ACTIVE = 4 -PACKAGE = 5 -INSTALLED = 6 - - -class AppWindow(Gtk.Window): - def __init__(self): - Gtk.Window.__init__(self, title=TITLE, border_width=6) - self.app = "app-utility" - self.pref = { - "data_set": "default", - "conf_dir": "~/.config", - "share_dir": "/usr/share/{}".format(self.app), - "data_sets": ["default", "advanced"], - "url": "https://gitlab.manjaro.org/fhdk/application-utility/raw/master" - } - - self.dev = "--dev" in sys.argv - if self.dev: - self.pref["share_dir"] = "." - - self.set_position(Gtk.WindowPosition.CENTER_ALWAYS) - GLib.set_prgname("{}".format(self.app)) - icon="system-software-install" - pixbuf24 = Gtk.IconTheme.get_default().load_icon(icon, 24, 0) - pixbuf32 = Gtk.IconTheme.get_default().load_icon(icon, 32, 0) - pixbuf48 = Gtk.IconTheme.get_default().load_icon(icon, 48, 0) - pixbuf64 = Gtk.IconTheme.get_default().load_icon(icon, 64, 0) - pixbuf96 = Gtk.IconTheme.get_default().load_icon(icon, 96, 0) - self.set_icon_list([pixbuf24, pixbuf32, pixbuf48, pixbuf64, pixbuf96]) - - # set data - self.app_store = None - self.pkg_selected = None - self.pkg_installed = None - self.pkg_list_install = [] - self.pkg_list_removal = [] - - # setup main box - self.set_default_size(800, 650) - self.application_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - self.add(self.application_box) - - # create title box - self.title_box = Gtk.Box() - self.title_image = Gtk.Image() - self.title_image.set_size_request(100, 100) - self.title_image.set_from_file("/usr/share/icons/manjaro/maia/96x96.png") - self.title_label = Gtk.Label() - self.title_label.set_markup("Manjaro Application Maintenance\n" - "Select/Deselect apps you want to install/remove.\n" - "Click UPDATE SYSTEM button when ready.") - self.title_box.pack_start(self.title_image, expand=False, fill=False, padding=0) - self.title_box.pack_start(self.title_label, expand=True, fill=True, padding=0) - - # pack title box to main box - self.application_box.pack_start(self.title_box, expand=False, fill=False, padding=0) - - # setup grid - self.grid = Gtk.Grid() - self.grid.set_column_homogeneous(True) - self.grid.set_row_homogeneous(True) - self.application_box.add(self.grid) - - # setup list store model - self.app_store = self.load_app_data(self.pref["data_set"]) - - # create a tree view with the model store - self.tree_view = Gtk.TreeView.new_with_model(self.app_store) - self.tree_view.set_activate_on_single_click(True) - - # column model: icon - icon = Gtk.CellRendererPixbuf() - column = Gtk.TreeViewColumn("", icon, icon_name=ICON) - self.tree_view.append_column(column) - - # column model: group name column - renderer = Gtk.CellRendererText() - column = Gtk.TreeViewColumn("Group", renderer, text=GROUP) - self.tree_view.append_column(column) - - # column model: app name column - renderer = Gtk.CellRendererText() - column = Gtk.TreeViewColumn("Application", renderer, text=APPLICATION) - self.tree_view.append_column(column) - - # column model: description column - renderer = Gtk.CellRendererText() - column = Gtk.TreeViewColumn("Description", renderer, text=DESCRIPTION) - self.tree_view.append_column(column) - - # column model: install column - toggle = Gtk.CellRendererToggle() - toggle.connect("toggled", self.on_app_toggle) - column = Gtk.TreeViewColumn("Installed", toggle, active=ACTIVE) - self.tree_view.append_column(column) - - # button box - self.button_box = Gtk.Box(spacing=10) - self.advanced = Gtk.ToggleButton(label="Advanced") - self.advanced.connect("clicked", self.on_expert_clicked) - self.download = Gtk.Button(label="download") - self.download.connect("clicked", self.on_download_clicked) - self.reload_button = Gtk.Button(label="reload") - self.reload_button.connect("clicked", self.on_reload_clicked) - self.update_system_button = Gtk.Button(label="UPDATE SYSTEM") - self.update_system_button.connect("clicked", self.on_update_system_clicked) - self.close_button = Gtk.Button(label="close") - self.close_button.connect("clicked", Gtk.main_quit) - self.button_box.pack_start(self.advanced, expand=False, fill=False, padding=10) - self.button_box.pack_end(self.update_system_button, expand=False, fill=False, padding=10) - self.button_box.pack_end(self.close_button, expand=False, fill=False, padding=10) - self.button_box.pack_end(self.reload_button, expand=False, fill=False, padding=10) - self.button_box.pack_end(self.download, expand=False, fill=False, padding=10) - self.application_box.pack_end(self.button_box, expand=False, fill=False, padding=10) - - # create a scrollable window - self.app_window = Gtk.ScrolledWindow() - self.app_window.set_vexpand(True) - self.app_window.add(self.tree_view) - self.grid.attach(self.app_window, 0, 0, 5, len(self.app_store)) - - # show start - self.show_all() - - def load_app_data(self, data_set): - if os.path.isfile("{}/{}.json".format(self.pref["conf_dir"], data_set)): - app_data = self.read_json_file("{}/{}.json".format(self.pref["conf_dir"], data_set)) - else: - app_data = self.read_json_file("{}/{}.json".format(self.pref["share_dir"], data_set)) - - store = Gtk.TreeStore(str, str, str, str, bool, str, bool) - for group in app_data: - index = store.append(None, - [group["name"], - group["icon"], - None, group["description"], None, None, None]) - for app in group["apps"]: - status = self.app_installed(app["pkg"]) - tree_item = (None, - app["icon"], - app["name"], - app["description"], - status, - app["pkg"], - status) - store.append(index, tree_item) - return store - - def reload_app_data(self, dataset): - self.pkg_selected = None - self.pkg_installed = None - self.pkg_list_install = [] - self.pkg_list_removal = [] - self.app_store.clear() - self.app_store = self.load_app_data(dataset) - self.tree_view.set_model(self.app_store) - - def on_reload_clicked(self, widget): - self.reload_app_data(self.pref["data_set"]) - - def on_expert_clicked(self, widget): - if widget.get_active(): - self.pref["data_set"] = "advanced" - else: - self.pref["data_set"] = "default" - self.reload_app_data(self.pref["data_set"]) - - def on_download_clicked(self, widget): - if self.net_check(): - # noinspection PyBroadException - try: - for download in self.pref["data_sets"]: - url = "{}/{}.json".format(self.pref["url"], download) - file = self.fix_path("{}/{}.json".format(self.pref["conf_dir"], download)) - req = urllib.request.Request(url=url) - with urllib.request.urlopen(req, timeout=2) as response: - data = json.loads(response.read().decode("utf8")) - self.write_json_file(data, file) - - except Exception as e: - print(e) - - else: - dialog = Gtk.MessageDialog(self, 0, - Gtk.MessageType.ERROR, - Gtk.ButtonsType.CANCEL, - "Download not available") - dialog.format_secondary.text("The server 'gitlab.manjaro.org' could not be reached") - dialog.run() - - def on_app_toggle(self, cell, path): - # a group has no package attached and we don't install groups - if self.app_store[path][PACKAGE] is not None: - self.app_store[path][ACTIVE] = not self.app_store[path][ACTIVE] - self.pkg_selected = self.app_store[path][PACKAGE] - self.pkg_installed = self.app_store[path][INSTALLED] - - if self.app_store[path][ACTIVE] is False: - if self.pkg_installed is True: - # to uninstall - self.pkg_list_removal.append(self.pkg_selected) - if self.dev: - print("for removal : {}".format(self.pkg_selected)) - if self.pkg_selected in self.pkg_list_install: - # cancel install - self.pkg_list_install.remove(self.pkg_selected) - if self.dev: - print("cancel install: {}".format(self.pkg_selected)) - else: - # don't reinstall - if self.pkg_installed is False: - # only install - if self.pkg_selected not in self.pkg_list_install: - self.pkg_list_install.append(self.pkg_selected) - if self.dev: - print("to install : {}".format(self.pkg_selected)) - if self.pkg_selected in self.pkg_list_removal: - # cancel uninstall - self.pkg_list_removal.remove(self.pkg_selected) - if self.dev: - print("pkg list install: {}".format(self.pkg_list_install)) - print("pkg list removal: {}".format(self.pkg_list_removal)) - - def on_update_system_clicked(self, widget): - file_install = "/tmp/.install-packages.txt" - file_uninstall = "/tmp/.remove-packages.txt" - - os.environ["APP_UTILITY"] = "PACKAGES" - shell_fallback = False - - if self.pkg_list_install: - if os.path.isfile("/usr/bin/pamac-installer"): - subprocess.run(["pamac-installer"] + self.pkg_list_install) - else: - shell_fallback = True - with open(file_install, "w") as outfile: - for p in self.pkg_list_install: - outfile.write("{} ".format(p)) - - if self.pkg_list_removal: - shell_fallback = True - with open(file_uninstall, "w") as outfile: - for p in self.pkg_list_removal: - outfile.write("{} ".format(p)) - - if shell_fallback: - if self.dev: - os.system('gksu-polkit ./app-install') - else: - os.system('gksu-polkit app-install') - - self.reload_app_data(self.pref["data_set"]) - - @staticmethod - def app_installed(package): - if glob.glob("/var/lib/pacman/local/{}-[0-9]*".format(package)): - return True - return False - - @staticmethod - def fix_path(path): - """Make good paths. - :param path: path to fix - :type path: str - :return: fixed path - :rtype: str - """ - if "~" in path: - path = path.replace("~", os.path.expanduser("~")) - return path - - @staticmethod - def net_check(): - """Check for internet connection""" - resp = None - host = "https://gitlab.manjaro.org" - # noinspection PyBroadException - try: - resp = urllib.request.urlopen(host, timeout=2) - except Exception: - pass - return bool(resp) - - @staticmethod - def read_json_file(filename, dictionary=True): - """Read json data from file""" - result = list() - try: - if dictionary: - with open(filename, "rb") as infile: - result = json.loads( - infile.read().decode("utf8"), - object_pairs_hook=collections.OrderedDict) - else: - with open(filename, "r") as infile: - result = json.load(infile) - except OSError: - pass - return result - - @staticmethod - def write_json_file(data, filename, dictionary=False): - """Writes data to file as json - :param data - :param filename: - :param dictionary: - """ - try: - if dictionary: - with open(filename, "wb") as outfile: - json.dump(data, outfile) - else: - with open(filename, "w") as outfile: - json.dump(data, outfile, indent=2) - return True - except OSError: - return False - - -if __name__ == "__main__": - win = AppWindow() - win.connect("delete-event", Gtk.main_quit) - win.connect("destroy", Gtk.main_quit) - win.show_all() - Gtk.main()