Merge branch 'master' of git://github.com/tobi-wan-kenobi/bumblebee-status
This commit is contained in:
commit
17131c5bdc
8 changed files with 122 additions and 22 deletions
|
@ -5,7 +5,7 @@
|
||||||
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
||||||
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
||||||
|
|
||||||
**Many, many thanks to all contributors! As of now, 27 of the modules are from various contributors (!), and only 16 from myself.**
|
**Many, many thanks to all contributors! As of now, 28 of the modules are from various contributors (!), and only 16 from myself.**
|
||||||
|
|
||||||
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ class Module(bumblebee.engine.Module):
|
||||||
self._states["include"].append(state)
|
self._states["include"].append(state)
|
||||||
self._format = self.parameter("format","{intf} {state} {ip} {ssid}");
|
self._format = self.parameter("format","{intf} {state} {ip} {ssid}");
|
||||||
self._update_widgets(widgets)
|
self._update_widgets(widgets)
|
||||||
|
self.iwgetid = bumblebee.util.which("iwgetid")
|
||||||
|
|
||||||
|
|
||||||
def update(self, widgets):
|
def update(self, widgets):
|
||||||
self._update_widgets(widgets)
|
self._update_widgets(widgets)
|
||||||
|
@ -106,7 +108,7 @@ class Module(bumblebee.engine.Module):
|
||||||
def get_ssid(self, intf):
|
def get_ssid(self, intf):
|
||||||
if self._iswlan(intf):
|
if self._iswlan(intf):
|
||||||
try:
|
try:
|
||||||
return subprocess.check_output(["iwgetid","-r",intf]).strip().decode('utf-8')
|
return subprocess.check_output([self.iwgetid,"-r",intf]).strip().decode('utf-8')
|
||||||
except:
|
except:
|
||||||
return ""
|
return ""
|
||||||
return ""
|
return ""
|
||||||
|
|
51
bumblebee/modules/notmuch_count.py
Normal file
51
bumblebee/modules/notmuch_count.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
|
"""Displays the result of a notmuch count query
|
||||||
|
default : unread emails which path do not contained "Trash" (notmuch count "tag:unread AND NOT path:/.*Trash.*/")
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* notmuch_count.query: notmuch count query to show result
|
||||||
|
|
||||||
|
Errors:
|
||||||
|
if the notmuch query failed, the shown value is -1
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
notmuch (https://notmuchmail.org/)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import bumblebee.input
|
||||||
|
import bumblebee.output
|
||||||
|
import bumblebee.engine
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Module(bumblebee.engine.Module):
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, engine, config):
|
||||||
|
super(Module, self).__init__(engine, config,
|
||||||
|
bumblebee.output.Widget(full_text=self.output)
|
||||||
|
)
|
||||||
|
self._notmuch_count_query = self.parameter("query", "tag:unread AND NOT path:/.*Trash.*/")
|
||||||
|
self._notmuch_count = self.count_notmuch()
|
||||||
|
|
||||||
|
|
||||||
|
def output(self, widget):
|
||||||
|
self._notmuch_count = self.count_notmuch()
|
||||||
|
return str(self._notmuch_count)
|
||||||
|
|
||||||
|
|
||||||
|
def state(self, widgets):
|
||||||
|
if self._notmuch_count == 0:
|
||||||
|
return "empty"
|
||||||
|
return "items"
|
||||||
|
|
||||||
|
|
||||||
|
def count_notmuch(self):
|
||||||
|
try:
|
||||||
|
notmuch_count_cmd = "notmuch count " + self._notmuch_count_query
|
||||||
|
notmuch_count = int(bumblebee.util.execute(notmuch_count_cmd))
|
||||||
|
return notmuch_count
|
||||||
|
except Exception:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -6,6 +6,7 @@ Aliases: pasink (use this to control output instead of input), pasource
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* pulseaudio.autostart: If set to "true" (default is "false"), automatically starts the pulseaudio daemon if it is not running
|
* pulseaudio.autostart: If set to "true" (default is "false"), automatically starts the pulseaudio daemon if it is not running
|
||||||
|
* pulseaudio.percent_change: How much to change volume by when scrolling on the module (default is 2%)
|
||||||
|
|
||||||
Requires the following executable:
|
Requires the following executable:
|
||||||
* pulseaudio
|
* pulseaudio
|
||||||
|
@ -33,6 +34,13 @@ class Module(bumblebee.engine.Module):
|
||||||
bumblebee.util.execute("pulseaudio --start")
|
bumblebee.util.execute("pulseaudio --start")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
|
percent_change = int(self.parameter("percent_change","2%").strip("%"))
|
||||||
|
except:
|
||||||
|
percent_change = 2
|
||||||
|
if percent_change < 0 or percent_change > 100:
|
||||||
|
percent_change = 2
|
||||||
|
|
||||||
|
|
||||||
self._left = 0
|
self._left = 0
|
||||||
self._right = 0
|
self._right = 0
|
||||||
|
@ -51,8 +59,8 @@ class Module(bumblebee.engine.Module):
|
||||||
|
|
||||||
events = [
|
events = [
|
||||||
{"type": "mute", "action": "toggle", "button": bumblebee.input.LEFT_MOUSE},
|
{"type": "mute", "action": "toggle", "button": bumblebee.input.LEFT_MOUSE},
|
||||||
{"type": "volume", "action": "+2%", "button": bumblebee.input.WHEEL_UP},
|
{"type": "volume", "action": "+{percent}%".format(percent=percent_change), "button": bumblebee.input.WHEEL_UP},
|
||||||
{"type": "volume", "action": "-2%", "button": bumblebee.input.WHEEL_DOWN},
|
{"type": "volume", "action": "-{percent}%".format(percent=percent_change), "button": bumblebee.input.WHEEL_DOWN},
|
||||||
]
|
]
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
|
|
|
@ -60,4 +60,23 @@ def durationfmt(duration, shorten=False, suffix=False):
|
||||||
|
|
||||||
return "{}{}".format(res, suf if suffix else "")
|
return "{}{}".format(res, suf if suffix else "")
|
||||||
|
|
||||||
|
def which(program):
|
||||||
|
import os
|
||||||
|
def is_exe(fpath):
|
||||||
|
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
||||||
|
|
||||||
|
fpath, fname = os.path.split(program)
|
||||||
|
if fpath:
|
||||||
|
if is_exe(program):
|
||||||
|
return program
|
||||||
|
else:
|
||||||
|
localPATH = os.environ["PATH"].split(os.pathsep)
|
||||||
|
localPATH += ["/sbin", "/usr/sbin/", "/usr/local/sbin"]
|
||||||
|
for path in localPATH:
|
||||||
|
exe_file = os.path.join(path, program)
|
||||||
|
if is_exe(exe_file):
|
||||||
|
return exe_file
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
echo "testing with $(python2 -V 2>&1)"
|
echo "testing with $(python2 -V 2>&1)"
|
||||||
python2 $(which nosetests) -v --with-coverage --cover-erase tests/
|
python2 $(which nosetests) -v --with-coverage --cover-erase tests/
|
||||||
|
|
||||||
if [ $? == 0 ]; then
|
if test $? -eq 0 ; then
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "testing with $(python3 -V 2>&1)"
|
echo "testing with $(python3 -V 2>&1)"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# pylint: disable=C0103,C0111
|
# pylint: disable=C0103,C0111
|
||||||
|
|
||||||
import mock
|
|
||||||
import unittest
|
import unittest
|
||||||
|
import re
|
||||||
|
|
||||||
import tests.mocks as mocks
|
import tests.mocks as mocks
|
||||||
|
|
||||||
from bumblebee.util import *
|
import bumblebee.util as bu
|
||||||
|
|
||||||
|
|
||||||
class TestUtil(unittest.TestCase):
|
class TestUtil(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -17,40 +18,56 @@ class TestUtil(unittest.TestCase):
|
||||||
self.popen.cleanup()
|
self.popen.cleanup()
|
||||||
|
|
||||||
def test_bytefmt(self):
|
def test_bytefmt(self):
|
||||||
self.assertEquals(bytefmt(10), "10.00B")
|
self.assertEquals(bu.bytefmt(10), "10.00B")
|
||||||
self.assertEquals(bytefmt(15*1024), "15.00KiB")
|
self.assertEquals(bu.bytefmt(15 * 1024), "15.00KiB")
|
||||||
self.assertEquals(bytefmt(20*1024*1024), "20.00MiB")
|
self.assertEquals(bu.bytefmt(20 * 1024 * 1024), "20.00MiB")
|
||||||
self.assertEquals(bytefmt(22*1024*1024*1024), "22.00GiB")
|
self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024), "22.00GiB")
|
||||||
self.assertEquals(bytefmt(35*1024*1024*1024*1024), "35840.00GiB")
|
self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024), "35840.00GiB")
|
||||||
|
|
||||||
def test_durationfmt(self):
|
def test_durationfmt(self):
|
||||||
self.assertEquals(durationfmt(00), "00:00")
|
self.assertEquals(bu.durationfmt(00), "00:00")
|
||||||
self.assertEquals(durationfmt(25), "00:25")
|
self.assertEquals(bu.durationfmt(25), "00:25")
|
||||||
self.assertEquals(durationfmt(60), "01:00")
|
self.assertEquals(bu.durationfmt(60), "01:00")
|
||||||
self.assertEquals(durationfmt(119), "01:59")
|
self.assertEquals(bu.durationfmt(119), "01:59")
|
||||||
self.assertEquals(durationfmt(3600), "01:00:00")
|
self.assertEquals(bu.durationfmt(3600), "01:00:00")
|
||||||
self.assertEquals(durationfmt(7265), "02:01:05")
|
self.assertEquals(bu.durationfmt(7265), "02:01:05")
|
||||||
|
|
||||||
def test_execute(self):
|
def test_execute(self):
|
||||||
execute(self.some_command_with_args)
|
bu.execute(self.some_command_with_args)
|
||||||
self.assertTrue(self.popen.mock.popen.called)
|
self.assertTrue(self.popen.mock.popen.called)
|
||||||
self.popen.mock.popen.assert_call(self.some_command_with_args)
|
self.popen.mock.popen.assert_call(self.some_command_with_args)
|
||||||
self.assertTrue(self.popen.mock.communicate.called)
|
self.assertTrue(self.popen.mock.communicate.called)
|
||||||
|
|
||||||
def test_execute_nowait(self):
|
def test_execute_nowait(self):
|
||||||
execute(self.some_command_with_args, False)
|
bu.execute(self.some_command_with_args, False)
|
||||||
self.assertTrue(self.popen.mock.popen.called)
|
self.assertTrue(self.popen.mock.popen.called)
|
||||||
self.popen.mock.popen.assert_call(self.some_command_with_args)
|
self.popen.mock.popen.assert_call(self.some_command_with_args)
|
||||||
self.assertFalse(self.popen.mock.communicate.called)
|
self.assertFalse(self.popen.mock.communicate.called)
|
||||||
|
|
||||||
def test_execute_utf8(self):
|
def test_execute_utf8(self):
|
||||||
self.popen.mock.communicate.return_value = [ self.some_utf8, None ]
|
self.popen.mock.communicate.return_value = [self.some_utf8, None]
|
||||||
self.test_execute()
|
self.test_execute()
|
||||||
|
|
||||||
def test_execute_error(self):
|
def test_execute_error(self):
|
||||||
self.popen.mock.returncode = 1
|
self.popen.mock.returncode = 1
|
||||||
|
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
execute(self.some_command_with_args)
|
bu.execute(self.some_command_with_args)
|
||||||
|
|
||||||
|
def test_which(self):
|
||||||
|
# test for a binary that has to be somewhere
|
||||||
|
print(bu.which("ls"))
|
||||||
|
self.assertTrue(re.search('/(ls)$', bu.which("ls")))
|
||||||
|
|
||||||
|
# test for a binary that is not necessarily there
|
||||||
|
program = "iwgetid"
|
||||||
|
self.assertTrue(
|
||||||
|
bu.which(program) is None or
|
||||||
|
re.search('/(' + program + ')$', bu.which(program))
|
||||||
|
)
|
||||||
|
|
||||||
|
# test if which also works with garbage input
|
||||||
|
self.assertTrue(bu.which("qwertygarbage") is None)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
"load": { "prefix": "" },
|
"load": { "prefix": "" },
|
||||||
"layout": { "prefix": "" },
|
"layout": { "prefix": "" },
|
||||||
"layout-xkb": { "prefix": "" },
|
"layout-xkb": { "prefix": "" },
|
||||||
|
"notmuch_count": { "empty": {"prefix": "\uf0e0" },
|
||||||
|
"items": {"prefix": "\uf0e0" }
|
||||||
|
},
|
||||||
"todo": { "empty": {"prefix": "" },
|
"todo": { "empty": {"prefix": "" },
|
||||||
"items": {"prefix": "" },
|
"items": {"prefix": "" },
|
||||||
"uptime": {"prefix": "" }
|
"uptime": {"prefix": "" }
|
||||||
|
|
Loading…
Reference in a new issue