From a42d78c5c551bd1f1248e6dd5b44b552499b5bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Mon, 1 Jun 2015 12:55:47 +0200 Subject: [PATCH 1/7] Added `Update` indicator module with `pacman` and `cower` backends. --- i3pystatus/updates/__init__.py | 62 ++++++++++++++++++++++++++++++++++ i3pystatus/updates/cower.py | 19 +++++++++++ i3pystatus/updates/pacman.py | 20 +++++++++++ setup.py | 1 + 4 files changed, 102 insertions(+) create mode 100644 i3pystatus/updates/__init__.py create mode 100644 i3pystatus/updates/cower.py create mode 100644 i3pystatus/updates/pacman.py diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py new file mode 100644 index 0000000..60f83f5 --- /dev/null +++ b/i3pystatus/updates/__init__.py @@ -0,0 +1,62 @@ +from i3pystatus import SettingsBase, IntervalModule, formatp + + +class Backend(SettingsBase): + """ + TODO: doc + """ + + updates = 0 + + +class Updates(IntervalModule): + """ + Generic update checker + + TODO: doc + """ + + interval = 60 * 5 # 5 minutes + + settings = ( + ("backends", "List of backends used to check for updates."), + ("format", ""), + ("format_no_updates", ""), + ("color", ""), + ("color_no_updates", ""), + ) + required = ("backends",) + + backends = None + format = "U {count}" + format_no_updates = None + color = "#00DD00" + color_no_updates = "#FFFFFF" + + on_leftclick = "run" + + def init(self): + if not isinstance(self.backends, list): + self.backends = [self.backends] + return + + def run(self): + updates_count = 0 + for backend in self.backends: + updates_count += backend.updates + + if updates_count == 0: + self.output = {} if not self.format_no_updates else { + "full_text": self.format_no_updates, + "color": self.color_no_updates, + } + return + + fdict = { + "count": updates_count, + } + self.output = { + "full_text": formatp(self.format, **fdict).strip(), + "color": self.color, + } + return diff --git a/i3pystatus/updates/cower.py b/i3pystatus/updates/cower.py new file mode 100644 index 0000000..aad1650 --- /dev/null +++ b/i3pystatus/updates/cower.py @@ -0,0 +1,19 @@ +from i3pystatus.core.command import run_through_shell + +from i3pystatus.updates import Backend + + +class Cower(Backend): + """ + Checks for updates in Arch User Repositories using the `cower` AUR helper. + """ + + @property + def updates(self): + command = ["cower", "-u"] + cower = run_through_shell(command) + out = cower.out.strip() + + return len(out.split("\n")) if len(out) > 0 else 0 + +Backend = Cower diff --git a/i3pystatus/updates/pacman.py b/i3pystatus/updates/pacman.py new file mode 100644 index 0000000..96e56ac --- /dev/null +++ b/i3pystatus/updates/pacman.py @@ -0,0 +1,20 @@ +from i3pystatus.core.command import run_through_shell + +from i3pystatus.updates import Backend + + +class Pacman(Backend): + """ + Checks for updates in Arch Linux pacman repositories using the + `checkupdates` script. + """ + + @property + def updates(self): + command = ["checkupdates"] + checkupdates = run_through_shell(command) + out = checkupdates.out.strip() + + return len(out.split("\n")) if len(out) > 0 else 0 + +Backend = Pacman diff --git a/setup.py b/setup.py index b8ef64d..8cf3168 100755 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ setup(name="i3pystatus", "i3pystatus.core", "i3pystatus.mail", "i3pystatus.pulseaudio", + "i3pystatus.updates", ], entry_points={ "console_scripts": [ From b47f099dcf724b32cbac4fe7b463a6c4532ba102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Tue, 2 Jun 2015 19:40:18 +0200 Subject: [PATCH 2/7] Added backend for apt-get. --- i3pystatus/updates/aptget.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 i3pystatus/updates/aptget.py diff --git a/i3pystatus/updates/aptget.py b/i3pystatus/updates/aptget.py new file mode 100644 index 0000000..acf583b --- /dev/null +++ b/i3pystatus/updates/aptget.py @@ -0,0 +1,32 @@ +import os + +from i3pystatus.core.command import run_through_shell +from i3pystatus.updates import Backend + + +class AptGet(Backend): + """ + Gets update count for Debian based distributions. + + This mimics the Arch Linux `checkupdates` script + but with apt-get and written in python. + """ + + @property + def updates(self): + cache_dir = "/tmp/update-cache-" + os.getenv("USER") + if not os.path.exists(cache_dir): + os.mkdir(cache_dir) + + command = "apt-get update -o Dir::State::Lists=" + cache_dir + run_through_shell(command) + command = "apt-get upgrade -s -o Dir::State::Lists=" + cache_dir + apt = run_through_shell(command) + + update_count = 0 + for line in apt.out.split("\n"): + if line.startswith("Inst"): + update_count += 1 + return update_count + +Backend = AptGet From 7d48a00b1e3d0b78fec629de0c23011a41e8f13a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Tue, 2 Jun 2015 22:49:12 +0200 Subject: [PATCH 3/7] Updated docs. --- docs/i3pystatus.rst | 13 +++++++++++-- i3pystatus/updates/__init__.py | 32 +++++++++++++++++++------------- i3pystatus/updates/cower.py | 3 ++- i3pystatus/updates/pacman.py | 5 ++--- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/docs/i3pystatus.rst b/docs/i3pystatus.rst index 80637a5..dacbbb7 100644 --- a/docs/i3pystatus.rst +++ b/docs/i3pystatus.rst @@ -7,10 +7,10 @@ Module reference :System: `clock`_ - `disk`_ - `load`_ - `mem`_ - `cpu_usage`_ :Audio: `alsa`_ - `pulseaudio`_ :Hardware: `battery`_ - `backlight`_ - `temp`_ -:Network: `network`_ +:Network: `network`_ :Music: `now_playing`_ - `mpd`_ :Websites & stuff: `weather`_ - `bitcoin`_ - `reddit`_ - `parcel`_ -:Other: `mail`_ - `pyload`_ - `text`_ +:Other: `mail`_ - `pyload`_ - `text`_ - `updates`_ :Advanced: `file`_ - `regex`_ - `runwatch`_ - `shell`_ .. autogen:: i3pystatus Module @@ -25,3 +25,12 @@ Mail Backends .. autogen:: i3pystatus.mail SettingsBase .. nothin' + +.. _updatebackends: + +Update Backends +--------------- + +.. autogen:: i3pystatus.updates SettingsBase + + .. nothin' diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py index 60f83f5..a1b62d7 100644 --- a/i3pystatus/updates/__init__.py +++ b/i3pystatus/updates/__init__.py @@ -2,33 +2,39 @@ from i3pystatus import SettingsBase, IntervalModule, formatp class Backend(SettingsBase): - """ - TODO: doc - """ - + settings = () updates = 0 class Updates(IntervalModule): """ - Generic update checker + Generic update checker. + To use select appropriate backend(s) for your system. + For list of all available backends see :ref:`updatebackends`. + + Left clicking on the module will refresh the count of upgradeable packages. + This may be used to dismiss the notification after updating your system. + + .. rubric:: Available formatters + + * `{count}` — Sum of all available updates from all backends. - TODO: doc """ - interval = 60 * 5 # 5 minutes + interval = 3600 settings = ( - ("backends", "List of backends used to check for updates."), - ("format", ""), - ("format_no_updates", ""), - ("color", ""), - ("color_no_updates", ""), + ("backends", "Required list of backends used to check for updates."), + ("format", "String shown when updates are availible. May contain formatters."), + ("format_no_updates", "String that is shown if no updates are available. If not set the module will be hidden if no updates are available."), + "color", + "color_no_updates", + ("interval", "Default interval is set to one hour."), ) required = ("backends",) backends = None - format = "U {count}" + format = "Updates: {count}" format_no_updates = None color = "#00DD00" color_no_updates = "#FFFFFF" diff --git a/i3pystatus/updates/cower.py b/i3pystatus/updates/cower.py index aad1650..3c67c56 100644 --- a/i3pystatus/updates/cower.py +++ b/i3pystatus/updates/cower.py @@ -1,11 +1,12 @@ from i3pystatus.core.command import run_through_shell - from i3pystatus.updates import Backend class Cower(Backend): """ Checks for updates in Arch User Repositories using the `cower` AUR helper. + + Depends on cower AUR agent - https://github.com/falconindy/cower """ @property diff --git a/i3pystatus/updates/pacman.py b/i3pystatus/updates/pacman.py index 96e56ac..bc6f2aa 100644 --- a/i3pystatus/updates/pacman.py +++ b/i3pystatus/updates/pacman.py @@ -1,12 +1,11 @@ from i3pystatus.core.command import run_through_shell - from i3pystatus.updates import Backend class Pacman(Backend): """ - Checks for updates in Arch Linux pacman repositories using the - `checkupdates` script. + Checks for updates in Arch Linux repositories using the + `checkupdates` script which is part of the `pacman` package. """ @property From 0b507807bcacea6760e0782c08b2128d75ffdaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Tue, 2 Jun 2015 23:22:49 +0200 Subject: [PATCH 4/7] Updated docs. --- i3pystatus/updates/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py index a1b62d7..12da10f 100644 --- a/i3pystatus/updates/__init__.py +++ b/i3pystatus/updates/__init__.py @@ -19,6 +19,22 @@ class Updates(IntervalModule): * `{count}` — Sum of all available updates from all backends. + .. rubric:: Usage example + + :: + + from i3pystatus import Status + from i3pystatus.updates import pacman, cower + + status = Status(standalone=True) + + status.register("updates", + format = "Updates: {count}", + format_no_updates = "No updates", + backends = [pacman.Pacman(), cower.Cower()]) + + status.run() + """ interval = 3600 From 3496a7bae5577c581dc9bcb31fd8127dcd60b282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Wed, 3 Jun 2015 12:19:17 +0200 Subject: [PATCH 5/7] Checks for internet connection before running backends. --- i3pystatus/updates/__init__.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py index 12da10f..157015f 100644 --- a/i3pystatus/updates/__init__.py +++ b/i3pystatus/updates/__init__.py @@ -1,4 +1,5 @@ from i3pystatus import SettingsBase, IntervalModule, formatp +from i3pystatus.core.util import internet class Backend(SettingsBase): @@ -41,8 +42,10 @@ class Updates(IntervalModule): settings = ( ("backends", "Required list of backends used to check for updates."), - ("format", "String shown when updates are availible. May contain formatters."), - ("format_no_updates", "String that is shown if no updates are available. If not set the module will be hidden if no updates are available."), + ("format", "String shown when updates are availible. " + "May contain formatters."), + ("format_no_updates", "String that is shown if no updates are available." + " If not set the module will be hidden if no updates are available."), "color", "color_no_updates", ("interval", "Default interval is set to one hour."), @@ -63,6 +66,10 @@ class Updates(IntervalModule): return def run(self): + if not internet(): + self.logger.info("Updates: No internet connection.") + return + updates_count = 0 for backend in self.backends: updates_count += backend.updates From 96ef3656c8fa30371f5abc9d733ebcba77408fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Wed, 3 Jun 2015 16:43:24 +0200 Subject: [PATCH 6/7] Simplified `pacman` and `cower` backends. Fixed bug in `aptget` backend. --- i3pystatus/updates/__init__.py | 2 -- i3pystatus/updates/aptget.py | 4 ++-- i3pystatus/updates/cower.py | 4 +--- i3pystatus/updates/pacman.py | 4 +--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py index 157015f..cc1dae2 100644 --- a/i3pystatus/updates/__init__.py +++ b/i3pystatus/updates/__init__.py @@ -63,7 +63,6 @@ class Updates(IntervalModule): def init(self): if not isinstance(self.backends, list): self.backends = [self.backends] - return def run(self): if not internet(): @@ -88,4 +87,3 @@ class Updates(IntervalModule): "full_text": formatp(self.format, **fdict).strip(), "color": self.color, } - return diff --git a/i3pystatus/updates/aptget.py b/i3pystatus/updates/aptget.py index acf583b..f73c733 100644 --- a/i3pystatus/updates/aptget.py +++ b/i3pystatus/updates/aptget.py @@ -19,9 +19,9 @@ class AptGet(Backend): os.mkdir(cache_dir) command = "apt-get update -o Dir::State::Lists=" + cache_dir - run_through_shell(command) + run_through_shell(command.split()) command = "apt-get upgrade -s -o Dir::State::Lists=" + cache_dir - apt = run_through_shell(command) + apt = run_through_shell(command.split()) update_count = 0 for line in apt.out.split("\n"): diff --git a/i3pystatus/updates/cower.py b/i3pystatus/updates/cower.py index 3c67c56..144f156 100644 --- a/i3pystatus/updates/cower.py +++ b/i3pystatus/updates/cower.py @@ -13,8 +13,6 @@ class Cower(Backend): def updates(self): command = ["cower", "-u"] cower = run_through_shell(command) - out = cower.out.strip() - - return len(out.split("\n")) if len(out) > 0 else 0 + return cower.out.count('\n') Backend = Cower diff --git a/i3pystatus/updates/pacman.py b/i3pystatus/updates/pacman.py index bc6f2aa..8f40945 100644 --- a/i3pystatus/updates/pacman.py +++ b/i3pystatus/updates/pacman.py @@ -12,8 +12,6 @@ class Pacman(Backend): def updates(self): command = ["checkupdates"] checkupdates = run_through_shell(command) - out = checkupdates.out.strip() - - return len(out.split("\n")) if len(out) > 0 else 0 + return checkupdates.out.count('\n') Backend = Pacman From 3a69a5d0eb1e00866acd4b1dc26a2db29dc4b9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Mand=C3=A1k?= Date: Wed, 3 Jun 2015 20:06:16 +0200 Subject: [PATCH 7/7] Fixed typo. --- i3pystatus/updates/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/i3pystatus/updates/__init__.py b/i3pystatus/updates/__init__.py index cc1dae2..e135cae 100644 --- a/i3pystatus/updates/__init__.py +++ b/i3pystatus/updates/__init__.py @@ -1,5 +1,5 @@ from i3pystatus import SettingsBase, IntervalModule, formatp -from i3pystatus.core.util import internet +from i3pystatus.core.util import internet, require class Backend(SettingsBase): @@ -42,7 +42,7 @@ class Updates(IntervalModule): settings = ( ("backends", "Required list of backends used to check for updates."), - ("format", "String shown when updates are availible. " + ("format", "String shown when updates are available. " "May contain formatters."), ("format_no_updates", "String that is shown if no updates are available." " If not set the module will be hidden if no updates are available."), @@ -64,11 +64,8 @@ class Updates(IntervalModule): if not isinstance(self.backends, list): self.backends = [self.backends] + @require(internet) def run(self): - if not internet(): - self.logger.info("Updates: No internet connection.") - return - updates_count = 0 for backend in self.backends: updates_count += backend.updates