Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -6,11 +6,11 @@ NAME := streamtuner2 VERSION := $(shell version get:plugin st2.py || echo 2.1dev) DEST := /usr/share/streamtuner2 INST := install -m 644 PACK := xpm -DEPS := -n $(NAME) -d python-pyquery -d python-gtk2 -d python-requests -d python-keybinder +DEPS := -n $(NAME) -d python -d python-pyquery -d python-gtk2 -d python-requests -d python-keybinder OPTS := -s src -u man,fixperms -f --prefix=$(DEST) --deb-compression xz --rpm-compression xz --exe-autoextract .PHONY: bin all: gtk3 #(most used) pack: all ver docs xpm src gtk3: gtk3.xml.gz Index: cli.py ================================================================== --- cli.py +++ cli.py @@ -39,26 +39,30 @@ current_channel = "cli" plugins = {} # only populated sparsely by .stream() # start - def __init__(self): + def __init__(self, actions): # fake init action.action.main = empty_parent() action.action.main.current_channel = self.current_channel # check if enough arguments, else help - if len(sys.argv)<3: + if not actions: a = self.help # first cmdline arg == action else: - command = sys.argv[1] - a = self.__getattribute__(command) + command = actions[0] + if command in self.__dict__: + cmd = self.__getattribute__(command) + else: + print "No such command:", command + return # run - result = a(*sys.argv[2:]) + result = cmd(*actions[1:]) if result: self.json(result) # show help Index: config.py ================================================================== --- config.py +++ config.py @@ -2,11 +2,16 @@ # encoding: UTF-8 # api: streamtuner2 # type: class # title: global config object # description: reads ~/.config/streamtuner/*.json files -# config: {type:var, name:z, description:v} +# config: +# { arg: -d, type: str, name: plugin[], description: omit plugin from initialization } +# { arg: --gtk3, type: boolean, name: gtk3, description: use gtk3 interface } +# { arg: -D, type: boolean, name: debug, description: enable debug messages on console } +# { arg: action, type: str*, name: action[], description: commandline actions } +# { arg: -x, type: boolean, name: exit, description: terminate right away } # # In the main application or module files which need access # to a global conf.* object, just import this module as follows: # # from config import * @@ -29,10 +34,11 @@ from compat2and3 import gzip_decode, find_executable import zlib import zipfile import inspect import pkgutil +import argparse # export symbols __all__ = ["conf", "__print__", "dbg", "plugin_meta", "module_list", "get_data", "find_executable"] @@ -50,10 +56,11 @@ # Autointializes itself on startup, makes conf.vars available. # Also provides .load() and .save() for JSON data/cache files. # class ConfigDict(dict): + args = {} # start def __init__(self): # object==dict means conf.var is conf["var"] @@ -75,10 +82,13 @@ self.migrate() # store defaults in file else: self.save("settings") self.firstrun = 1 + + # add argv + self.args = self.init_args(argparse.ArgumentParser()) # some defaults def defaults(self): self.play = { @@ -247,11 +257,50 @@ except: pass for server in varhosts: if server in netrc: return netrc[server] - + + # Use config: definitions for argv extraction + def init_args(self, ap): + for opt in plugin_meta(frame=0).get("config"): + kwargs = self.argparse_map(opt) + #print kwargs + if kwargs: + args = kwargs["args"] + del kwargs["args"] + ap.add_argument(*args, **kwargs) + return ap.parse_args() + + # Transform config: description into quirky ArgumentParser list + def argparse_map(self, opt): + if not ("arg" in opt and opt["name"] and opt["type"]): + return {} + + # Extract --flag names + args = opt["arg"].split() + re.findall("-+\w+", opt["name"]) + + # Prepare mapping options + typing = re.findall("bool|str|\[\]|store|append|const", opt["type"]) + naming = re.findall("\[\]", opt["name"]) + name = re.findall("(?