diff --git a/README.md b/README.md
index c36d333..cc978ad 100644
--- a/README.md
+++ b/README.md
@@ -8,12 +8,10 @@ A GUI for basic tasks of package management using apt:
* Check for and list all available upgrades
* Download and install all available upgrades
-
-
## Dependencies
```shell
-sudo apt install python3-gi
+apt install python3-gi
```
## Installation
diff --git a/bin/simple-apt-update b/bin/simple-apt-update
index 15d9152..7170658 100755
--- a/bin/simple-apt-update
+++ b/bin/simple-apt-update
@@ -60,8 +60,9 @@ class UpdateWindow(Gtk.ApplicationWindow):
self.buffer.set_text("")
def scroll_to_bottom(self):
- self.buffer.get_end_iter()
- self.text_view.scroll_to_mark(self.text_mark_end, 0, False, 0, 0)
+ adj = self.scrolledwindow.get_vadjustment()
+ adj.set_value(adj.get_upper())
+ self.scrolledwindow.set_vadjustment(adj)
def level_to_color(self, level):
if level == "INFO":
@@ -71,76 +72,47 @@ class UpdateWindow(Gtk.ApplicationWindow):
else:
return "grey"
+ def prepend_mesg(self, level, text):
+ self.prepend(text)
+ self.prepend_color(level + ": ", self.level_to_color(level))
+
def append_mesg(self, level, text):
- self.append_color(
- level + ": ",
- self.level_to_color(level)
- )
+ self.append_color(level + ": ", self.level_to_color(level))
self.append(text)
+ def prepend_markup(self, markup):
+ self.insert_markup(markup, self.buffer.get_start_iter())
+
def append_markup(self, markup):
- self.insert_markup(
- markup,
- self.buffer.get_end_iter()
- )
+ self.insert_markup(markup, self.buffer.get_end_iter())
def insert_markup(self, markup, iter):
self.buffer.insert_markup(iter, markup, -1)
+ def prepend_color(self, text, color):
+ self.insert_color(text, color, self.buffer.get_start_iter())
+
def append_color(self, text, color):
- self.insert_color(
- text,
- color,
- self.buffer.get_end_iter()
- )
+ self.insert_color(text, color, self.buffer.get_end_iter())
def insert_color(self, text, color, iter):
self.buffer.insert_markup(
iter,
- "%s" % (
- color,
- html.escape(text)),
+ "%s" % (color, html.escape(text)),
-1)
+ def prepend(self, text):
+ self.insert(text, self.buffer.get_start_iter())
+
def append(self, text):
- self.insert(
- text,
- self.buffer.get_end_iter()
- )
+ self.insert(text, self.buffer.get_end_iter())
self.scroll_to_bottom()
def insert(self, text, iter):
self.buffer.insert(iter, text + "\n")
- def run_thread(self, args, env, prefix=None):
- if self.thread is None:
- do_run = True
- elif not self.thread.is_alive():
- do_run = True
- else:
- do_run = False
-
- if do_run:
- self.thread = threading.Thread(
- target=self.run,
- args=(args, env, prefix,))
-
- self.thread.start()
-
- return False
- else:
- return True
-
- def execute(
- self,
- args,
- ignore_stderr=False,
- output_msg=None,
- empty_msg=None,
- prefix=None,
- env={},
- clear=True
- ):
+ def execute(self, args, ignore_stderr=False, output_msg=None,
+ empty_msg=None, env={}, clear=True):
self.lock()
if clear:
@@ -151,24 +123,15 @@ class UpdateWindow(Gtk.ApplicationWindow):
self.ignore_stderr = ignore_stderr
self.stdout = ''
self.stderr = ''
- self.append_mesg(
+ self.prepend_mesg(
"INFO",
"Running command \"%s\" ..." % " ".join(args))
+ thread = threading.Thread(target=self.run, args=(args, env,))
+ thread.start()
- GLib.timeout_add(
- 250,
- self.run_thread,
- args,
- env,
- prefix
- )
-
- def run(self, args, env={}, prefix=None):
+ def run(self, args, env={}):
p = subprocess.Popen(
- args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- shell=False,
+ args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False,
env=dict(os.environ, **env))
sel = selectors.DefaultSelector()
@@ -182,10 +145,7 @@ class UpdateWindow(Gtk.ApplicationWindow):
if data:
if key.fileobj is p.stdout:
- if prefix is None:
- self.stdout_queue.put(data)
- else:
- self.stdout_queue.put(prefix + " " + data)
+ self.stdout_queue.put(data)
else:
self.stderr_queue.put(data)
@@ -216,15 +176,16 @@ class UpdateWindow(Gtk.ApplicationWindow):
env=env,
empty_msg="No package upgrades were performed.")
+ def on_upgrade(self, *args):
+ self.upgrade()
+
def update(self, clear=True):
args = ['/usr/bin/apt-get', '-y', 'update']
env = {'DEBIAN_FRONTEND': 'noninteractive'}
- self.execute(
- args,
- env=env,
- clear=clear,
- output_msg="The package cache was refreshed."
- )
+ self.execute(args, env=env, clear=clear)
+
+ def on_update(self, *args):
+ self.update()
def list(self, clear=True):
args = ['/usr/bin/apt', '-qq', 'list', '--upgradable']
@@ -232,16 +193,8 @@ class UpdateWindow(Gtk.ApplicationWindow):
args,
ignore_stderr=True,
clear=clear,
- prefix="UPDATE",
- output_msg="Done listing available upgrades.",
- empty_msg="No package upgrades found."
- )
-
- def on_update(self, *args):
- self.update()
-
- def on_upgrade(self, *args):
- self.upgrade()
+ output_msg="Found the following package upgrades:",
+ empty_msg="Currently there are no available package upgrades.")
def on_list(self, *args):
self.list()
@@ -249,39 +202,27 @@ class UpdateWindow(Gtk.ApplicationWindow):
def on_quit(self, *args):
self.application.quit()
- def process_exit(self, exit_code, empty_msg=None, output_msg=None):
- self.thread.join()
-
- if exit_code != 0:
- self.append_mesg(
- "ERROR",
- "Command exited with code %d" % exit_code
- )
- elif self.stdout == '' and self.empty_msg is not None:
- self.append_mesg("INFO", self.empty_msg)
- elif self.stdout != '' and self.output_msg is not None:
- self.append_mesg("INFO", self.output_msg)
-
- self.unlock()
-
def update_buffer(self):
try:
text = self.stdout_queue.get(block=False)
- match = re.fullmatch(r'(EXIT|UPDATE) (.*)', text)
+ match = re.fullmatch(r'EXIT (\d+)', text)
if match is None:
self.stdout += text
self.append_mesg("STDOUT", text)
- elif match.group(1) == 'EXIT':
- exit_code = int(match.group(2))
- self.process_exit(exit_code)
- elif match.group(1) == 'UPDATE':
- text = match.group(2)
- self.stdout += text
- self.append_mesg("UPDATE", text)
else:
- self.stdout += text
- self.append_mesg("UPDATE", text)
+ exit_code = int(match.group(1))
+
+ if exit_code != 0:
+ self.append_mesg(
+ "ERROR",
+ "Command exited with code %d" % exit_code)
+ elif self.stdout == '' and self.empty_msg is not None:
+ self.append_mesg("INFO", self.empty_msg)
+ elif self.stdout != '' and self.output_msg is not None:
+ self.append_mesg("INFO", self.empty_msg)
+
+ self.unlock()
except queue.Empty:
pass
@@ -299,31 +240,20 @@ class UpdateWindow(Gtk.ApplicationWindow):
return True
def __init__(self, application):
- super(
- UpdateWindow,
- self
- ).__init__(
+ super(UpdateWindow, self).__init__(
application=application,
- title="Simple APT Update"
- )
-
+ title="Simple APT Update")
self.application = application
- self.thread = None
self.stdout_queue = queue.Queue()
self.stderr_queue = queue.Queue()
-
- self.init_ui()
-
GLib.timeout_add(100, self.update_buffer)
+ self.init_ui()
def init_ui(self):
self.set_border_width(10)
self.set_default_size(630, 390)
- hbox = Gtk.Box(
- spacing=6,
- orientation=Gtk.Orientation.VERTICAL
- )
+ hbox = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL)
self.add(hbox)
grid = Gtk.Grid()
@@ -342,12 +272,9 @@ class UpdateWindow(Gtk.ApplicationWindow):
grid.attach(self.list_button, 1, 0, 1, 1)
self.upgrade_button = Gtk.Button.new_from_icon_name(
- "gtk-apply",
- Gtk.IconSize.BUTTON
- )
+ "gtk-apply", Gtk.IconSize.BUTTON)
self.upgrade_button.set_tooltip_text(
- "Download and install all available upgrades"
- )
+ "Download and install all available upgrades")
self.upgrade_button.connect("clicked", self.on_upgrade)
grid.attach(self.upgrade_button, 2, 0, 1, 1)
@@ -356,9 +283,7 @@ class UpdateWindow(Gtk.ApplicationWindow):
grid.attach(self.spinner, 3, 0, 1, 1)
self.quit_button = Gtk.Button.new_from_icon_name(
- "exit",
- Gtk.IconSize.BUTTON
- )
+ "exit", Gtk.IconSize.BUTTON)
self.quit_button.set_tooltip_text("Exit the program")
self.quit_button.set_halign(Gtk.Align.END)
self.quit_button.connect("clicked", self.on_quit)
@@ -371,43 +296,32 @@ class UpdateWindow(Gtk.ApplicationWindow):
self.scrolledwindow.set_max_content_height(300)
self.buffer = Gtk.TextBuffer()
- self.text_view = Gtk.TextView(buffer=self.buffer)
- self.text_view.set_editable(False)
- self.text_view.set_monospace(True)
- self.text_view.set_cursor_visible(False)
+ text_view = Gtk.TextView(buffer=self.buffer)
+ text_view.set_editable(False)
+ text_view.set_monospace(True)
+ text_view.set_cursor_visible(False)
- text_buffer = self.text_view.get_buffer()
- iter = text_buffer.get_end_iter()
- self.text_mark_end = text_buffer.create_mark("", iter, False)
-
- self.scrolledwindow.add(self.text_view)
+ self.scrolledwindow.add(text_view)
hbox.pack_start(self.scrolledwindow, True, True, 0)
class SimpleAptUpdate(Gtk.Application):
def __init__(self):
- super(
- SimpleAptUpdate,
- self
- ).__init__(
- application_id='de.linuxfoo.SimpleAptUpdate',
- flags=Gio.ApplicationFlags.FLAGS_NONE
- )
-
+ super().__init__(application_id='de.linuxfoo.SimpleAptUpdate',
+ flags=Gio.ApplicationFlags.FLAGS_NONE)
self.connect('activate', self.on_activate)
-
signal.signal(signal.SIGINT, signal.SIG_DFL)
+ def do_command_line(self, cmdline):
+ pass
+
def on_activate(self, application):
self.window = UpdateWindow(application)
action = Gio.SimpleAction.new("quit", None)
action.connect("activate", self.window.on_quit)
self.add_action(action)
- self.set_accels_for_action(
- 'app.quit',
- ['q', 'w']
- )
+ self.set_accels_for_action('app.quit', ['q', 'w'])
action = Gio.SimpleAction.new("update", None)
action.connect("activate", self.window.on_update)
@@ -426,6 +340,7 @@ class SimpleAptUpdate(Gtk.Application):
self.window.present()
self.window.show_all()
+ self.window.update()
self.window.list(clear=False)
@@ -440,5 +355,3 @@ def main():
if __name__ == '__main__':
main()
-
-# vim:fenc=utf-8:et:ts=4:sw=4
diff --git a/doc/screenshot.png b/doc/screenshot.png
deleted file mode 100644
index 78d3b84..0000000
Binary files a/doc/screenshot.png and /dev/null differ
diff --git a/res/icons/simple-apt-update.svg b/res/icons/simple-apt-update.svg
index ebcd35d..5d60243 100644
--- a/res/icons/simple-apt-update.svg
+++ b/res/icons/simple-apt-update.svg
@@ -7,14 +7,19 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="31.72216mm"
height="36.307823mm"
viewBox="0 0 31.72216 36.307823"
version="1.1"
- id="svg8">
+ id="svg8"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
+ sodipodi:docname="simple-apt-update.svg">
+ orient="auto"
+ inkscape:stockid="Arrow2Lend"
+ inkscape:isstock="true">
+
+
@@ -127,6 +170,8 @@
+ ry="2.9184699"
+ inkscape:transform-center-x="13.051673"
+ inkscape:transform-center-y="11.996269" />
+ id="path1321"
+ sodipodi:nodetypes="cc" />
+ id="path1869"
+ sodipodi:nodetypes="ccccc" />