[all] Major refactoring
Introduce an "Engine" class to abstract some of the details of loading modules, registering events, etc.
This commit is contained in:
parent
a6bdd0557c
commit
d62258c89d
5 changed files with 135 additions and 116 deletions
110
bumblebee-status
110
bumblebee-status
|
@ -1,114 +1,20 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import glob
|
||||
import pkgutil
|
||||
import argparse
|
||||
import textwrap
|
||||
import threading
|
||||
import importlib
|
||||
import bumblebee.theme
|
||||
import bumblebee.modules
|
||||
import bumblebee.engine
|
||||
import bumblebee.outputs.i3
|
||||
|
||||
def print_module_list():
|
||||
print "available modules:"
|
||||
path = os.path.dirname(bumblebee.modules.__file__)
|
||||
for mod in [ name for _, name, _ in pkgutil.iter_modules([path])]:
|
||||
m = importlib.import_module("bumblebee.modules.{}".format(mod))
|
||||
|
||||
desc = "n/a" if not hasattr(m, "description") else getattr(m, "description")()
|
||||
usage = "n/a" if not hasattr(m, "usage") else getattr(m, "usage")()
|
||||
notes = "n/a" if not hasattr(m, "notes") else getattr(m, "notes")()
|
||||
|
||||
print " {}: ".format(mod)
|
||||
print textwrap.fill("Description: {}".format(desc),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print textwrap.fill("Usage : {}".format(usage),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print textwrap.fill("Notes : {}".format(notes),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print ""
|
||||
|
||||
def print_theme_list():
|
||||
d = bumblebee.theme.getpath()
|
||||
|
||||
print "available themes:"
|
||||
print textwrap.fill(", ".join(
|
||||
[ os.path.basename(f).replace(".json", "") for f in glob.iglob("{}/*.json".format(d)) ]),
|
||||
80, initial_indent = " ", subsequent_indent = " "
|
||||
)
|
||||
|
||||
def init_argument_parser():
|
||||
parser = argparse.ArgumentParser(description="display system data in the i3bar")
|
||||
parser.add_argument("-m", "--modules", nargs="+", help="List of modules to load. The order of the list determines their order in the i3bar (from left to right)", default=[])
|
||||
parser.add_argument("-e", "--events", nargs="+", help="List of click events that should be handled. Format is: <module name><splitter, see -s><button ID><splitter><command to execute>", default=[])
|
||||
parser.add_argument("-l", "--list", action="store_true", help="List all available modules and themes")
|
||||
parser.add_argument("-t", "--theme", help="Specify which theme to use for drawing the modules")
|
||||
parser.add_argument("-i", "--interval", help="Specify the update interval", default=1, type=int)
|
||||
parser.add_argument("-s", "--split", help="Specify string to use for splitting modules and their arguments", default="::")
|
||||
|
||||
return parser
|
||||
|
||||
def getmodule(args, output, modulespec):
|
||||
s = args.split
|
||||
module_name = modulespec if not s in modulespec else modulespec.split(s)[0]
|
||||
module_args = None if not s in modulespec else modulespec.split(s)[1:]
|
||||
module = importlib.import_module("bumblebee.modules.{}".format(module_name))
|
||||
return getattr(module, "Module")(output, module_args)
|
||||
|
||||
def register_event(args, output, event):
|
||||
ev = event.split(args.split)
|
||||
if len(ev) < 3:
|
||||
sys.stderr.write("invalid format for click event, expect 3 parameters")
|
||||
return
|
||||
output.add_callback(
|
||||
module=ev[0],
|
||||
button=int(ev[1]),
|
||||
cmd=ev[2],
|
||||
)
|
||||
|
||||
def main():
|
||||
parser = init_argument_parser()
|
||||
args = bumblebee.engine.Arguments()
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
parser.exit()
|
||||
theme = bumblebee.theme.Theme(args.args())
|
||||
output = bumblebee.outputs.i3.Output(args.args())
|
||||
|
||||
args = parser.parse_args()
|
||||
engine = bumblebee.engine.Engine(args.args(), theme, output)
|
||||
engine.load_modules()
|
||||
engine.register_events()
|
||||
|
||||
if args.list:
|
||||
print_module_list()
|
||||
print_theme_list()
|
||||
sys.exit(0)
|
||||
|
||||
refresh = threading.Condition()
|
||||
theme = bumblebee.theme.Theme(args.theme) if args.theme else bumblebee.theme.Theme()
|
||||
output = bumblebee.outputs.i3.i3bar(refresh, theme)
|
||||
|
||||
modules = []
|
||||
for m in args.modules:
|
||||
modules.append(getmodule(args, output, m))
|
||||
|
||||
for e in args.events:
|
||||
register_event(args, output, e)
|
||||
|
||||
print output.start()
|
||||
sys.stdout.flush()
|
||||
|
||||
refresh.acquire()
|
||||
while True:
|
||||
theme.reset()
|
||||
for m in modules:
|
||||
output.add(m)
|
||||
theme.next()
|
||||
print output.get()
|
||||
sys.stdout.flush()
|
||||
refresh.wait(args.interval)
|
||||
|
||||
print output.stop()
|
||||
engine.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
118
bumblebee/engine.py
Normal file
118
bumblebee/engine.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
import os
|
||||
import sys
|
||||
import glob
|
||||
import pkgutil
|
||||
import textwrap
|
||||
import argparse
|
||||
import threading
|
||||
import importlib
|
||||
import bumblebee.theme
|
||||
|
||||
class Arguments:
|
||||
def __init__(self):
|
||||
parser = self.create_parser()
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
parser.exit()
|
||||
|
||||
self._args = parser.parse_args()
|
||||
|
||||
if self._args.list:
|
||||
self.print_module_list()
|
||||
self.print_theme_list()
|
||||
parser.exit()
|
||||
|
||||
def args(self):
|
||||
return self._args
|
||||
|
||||
def create_parser(self):
|
||||
parser = argparse.ArgumentParser(description="display system data in the i3bar")
|
||||
parser.add_argument("-m", "--modules", nargs="+", help="List of modules to load. The order of the list determines their order in the i3bar (from left to right)", default=[])
|
||||
parser.add_argument("-e", "--events", nargs="+", help="List of click events that should be handled. Format is: <module name><splitter, see -s><button ID><splitter><command to execute>", default=[])
|
||||
parser.add_argument("-l", "--list", action="store_true", help="List all available modules and themes")
|
||||
parser.add_argument("-t", "--theme", help="Specify which theme to use for drawing the modules", default="default")
|
||||
parser.add_argument("-i", "--interval", help="Specify the update interval", default=1, type=int)
|
||||
parser.add_argument("-s", "--split", help="Specify string to use for splitting modules and their arguments", default="::")
|
||||
|
||||
return parser
|
||||
|
||||
def print_theme_list(self):
|
||||
d = bumblebee.theme.getpath()
|
||||
|
||||
print "available themes:"
|
||||
print textwrap.fill(", ".join(
|
||||
[ os.path.basename(f).replace(".json", "") for f in glob.iglob("{}/*.json".format(d)) ]),
|
||||
80, initial_indent = " ", subsequent_indent = " "
|
||||
)
|
||||
|
||||
def print_module_list(self):
|
||||
print "available modules:"
|
||||
path = os.path.dirname(bumblebee.modules.__file__)
|
||||
for mod in [ name for _, name, _ in pkgutil.iter_modules([path])]:
|
||||
m = importlib.import_module("bumblebee.modules.{}".format(mod))
|
||||
|
||||
desc = "n/a" if not hasattr(m, "description") else getattr(m, "description")()
|
||||
usage = "n/a" if not hasattr(m, "usage") else getattr(m, "usage")()
|
||||
notes = "n/a" if not hasattr(m, "notes") else getattr(m, "notes")()
|
||||
|
||||
print " {}: ".format(mod)
|
||||
print textwrap.fill("Description: {}".format(desc),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print textwrap.fill("Usage : {}".format(usage),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print textwrap.fill("Notes : {}".format(notes),
|
||||
80, initial_indent=" ", subsequent_indent=" ")
|
||||
print ""
|
||||
|
||||
class Engine:
|
||||
def __init__(self, args, theme, output):
|
||||
self._modules = []
|
||||
self._output = output
|
||||
self._args = args
|
||||
self._theme = theme
|
||||
|
||||
def load_module(self, modulespec):
|
||||
name = modulespec.split(self._args.split)[0]
|
||||
args = None if name == modulespec else modulespec.split(self._args.split)[1:]
|
||||
module = importlib.import_module("bumblebee.modules.{}".format(name))
|
||||
return getattr(module, "Module")(self._output, args)
|
||||
|
||||
def load_modules(self):
|
||||
for m in self._args.modules:
|
||||
self._modules.append(self.load_module(m))
|
||||
|
||||
def register_event(self, eventspec):
|
||||
event = eventspec.split(self._args.split)
|
||||
if len(event) < 3:
|
||||
raise Exception("invalid click event format, expected 3 parameters")
|
||||
self._output.add_callback(
|
||||
module = event[0],
|
||||
button = int(event[1]),
|
||||
cmd = event[2],
|
||||
)
|
||||
|
||||
def register_events(self):
|
||||
for e in self._args.events:
|
||||
self.register_event(e)
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
print self._output.start()
|
||||
sys.stdout.flush()
|
||||
|
||||
refresh = threading.Condition()
|
||||
refresh.acquire()
|
||||
while True:
|
||||
# improve this
|
||||
self._theme.reset()
|
||||
for m in self._modules:
|
||||
self._output.add(m, self._theme)
|
||||
self._theme.next()
|
||||
print self._output.get()
|
||||
sys.stdout.flush()
|
||||
refresh.wait(self._args.interval)
|
||||
|
||||
print self._output.stop()
|
||||
|
||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
class Output(object):
|
||||
def __init__(self, refresh, theme):
|
||||
self._theme = theme
|
||||
self._refresh = refresh
|
||||
def __init__(self, args):
|
||||
self._callbacks = {}
|
||||
|
||||
def redraw(self):
|
||||
pass
|
||||
self._refresh.acquire()
|
||||
self._refresh.notify()
|
||||
self._refresh.release()
|
||||
|
@ -30,13 +29,10 @@ class Output(object):
|
|||
), None)
|
||||
return cb
|
||||
|
||||
def theme(self):
|
||||
return self._theme
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def add(self, obj):
|
||||
def add(self, obj, theme):
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
|
|
|
@ -27,9 +27,9 @@ def read_input(output):
|
|||
subprocess.Popen(shlex.split(cb), stdout=DEVNULL, stderr=DEVNULL)
|
||||
output.redraw()
|
||||
|
||||
class i3bar(bumblebee.output.Output):
|
||||
def __init__(self, refresh, theme):
|
||||
super(i3bar, self).__init__(refresh, theme)
|
||||
class Output(bumblebee.output.Output):
|
||||
def __init__(self, args):
|
||||
super(Output, self).__init__(args)
|
||||
self._data = []
|
||||
|
||||
self.add_callback("i3-msg workspace prev_on_output", 4)
|
||||
|
@ -41,8 +41,7 @@ class i3bar(bumblebee.output.Output):
|
|||
def start(self):
|
||||
return json.dumps({ "version": 1, "click_events": True }) + "["
|
||||
|
||||
def add(self, obj):
|
||||
theme = self.theme()
|
||||
def add(self, obj, theme):
|
||||
|
||||
while True:
|
||||
d = obj.data()
|
||||
|
|
|
@ -7,10 +7,10 @@ def getpath():
|
|||
class Theme:
|
||||
_cycle_index = 0
|
||||
_cycle = None
|
||||
def __init__(self, name="default"):
|
||||
def __init__(self, args):
|
||||
self._data = None
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
with open("{}/{}.json".format(getpath(), name)) as f:
|
||||
with open("{}/{}.json".format(getpath(), args.theme)) as f:
|
||||
self._data = json.load(f)
|
||||
self._defaults = self._data.get("defaults", {})
|
||||
self._cycle = self._defaults.get("cycle", [])
|
||||
|
|
Loading…
Reference in a new issue