mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Standardize arguments in the actions map
* Move general_arguments to _global.arguments in the actions map * Introduce global configuration in the actions map (need implementation!) * Standardize arguments addition during the parser construction * Fix action name with '-'
This commit is contained in:
parent
66f60381e4
commit
cdcfa24180
2 changed files with 75 additions and 73 deletions
|
@ -29,12 +29,14 @@
|
||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
# TODO: Add patern for all this
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# General args #
|
# Global parameters #
|
||||||
#############################
|
#############################
|
||||||
general_arguments:
|
_global:
|
||||||
|
configuration:
|
||||||
|
auth:
|
||||||
|
- api
|
||||||
|
arguments:
|
||||||
-v:
|
-v:
|
||||||
full: --version
|
full: --version
|
||||||
help: Display moulinette version
|
help: Display moulinette version
|
||||||
|
|
|
@ -19,26 +19,20 @@ class _AMapParser(object):
|
||||||
|
|
||||||
Each interfaces must implement a parser class derived from this
|
Each interfaces must implement a parser class derived from this
|
||||||
class. It is used to parse the main parts of the actions map (i.e.
|
class. It is used to parse the main parts of the actions map (i.e.
|
||||||
general arguments, categories and actions).
|
global arguments, categories and actions).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
## Optional variables
|
|
||||||
# Each parser classes can overwrite these variables.
|
|
||||||
|
|
||||||
"""Either it will parse general arguments, or not"""
|
|
||||||
parse_general_arguments = True
|
|
||||||
|
|
||||||
|
|
||||||
## Virtual methods
|
## Virtual methods
|
||||||
# Each parser classes can implement these methods.
|
# Each parser classes can implement these methods.
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_arg_name(name, full):
|
def format_arg_names(name, full):
|
||||||
"""Format argument name
|
"""Format argument name
|
||||||
|
|
||||||
Format agument name depending on its 'full' parameters and return
|
Format agument name depending on its 'full' parameter and return
|
||||||
a list to use it as option string for the argument parser.
|
a list of strings which will be used as name or option strings
|
||||||
|
for the argument parser.
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
- name -- The argument name
|
- name -- The argument name
|
||||||
|
@ -51,21 +45,17 @@ class _AMapParser(object):
|
||||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||||
self.__class__.__name__)
|
self.__class__.__name__)
|
||||||
|
|
||||||
def add_general_parser(self, **kwargs):
|
def add_global_parser(self, **kwargs):
|
||||||
"""Add a parser for general arguments
|
"""Add a parser for global arguments
|
||||||
|
|
||||||
Create and return an argument parser for general arguments.
|
Create and return an argument parser for global arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An ArgumentParser based object
|
An ArgumentParser based object
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self.parse_general_arguments:
|
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||||
msg = "doesn't parse general arguments"
|
self.__class__.__name__)
|
||||||
else:
|
|
||||||
msg = "must override this method"
|
|
||||||
raise NotImplementedError("derived class '%s' %s" % \
|
|
||||||
(self.__class__.__name__, msg))
|
|
||||||
|
|
||||||
def add_category_parser(self, name, **kwargs):
|
def add_category_parser(self, name, **kwargs):
|
||||||
"""Add a parser for a category
|
"""Add a parser for a category
|
||||||
|
@ -124,12 +114,12 @@ class CLIAMapParser(_AMapParser):
|
||||||
self._subparsers = self._parser.add_subparsers()
|
self._subparsers = self._parser.add_subparsers()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_arg_name(name, full):
|
def format_arg_names(name, full):
|
||||||
if name[0] == '-' and full:
|
if name[0] == '-' and full:
|
||||||
return [name, full]
|
return [name, full]
|
||||||
return [name]
|
return [name]
|
||||||
|
|
||||||
def add_general_parser(self, **kwargs):
|
def add_global_parser(self, **kwargs):
|
||||||
return self._parser
|
return self._parser
|
||||||
|
|
||||||
def add_category_parser(self, name, category_help=None, **kwargs):
|
def add_category_parser(self, name, category_help=None, **kwargs):
|
||||||
|
@ -145,7 +135,7 @@ class CLIAMapParser(_AMapParser):
|
||||||
parser = self._subparsers.add_parser(name, help=category_help)
|
parser = self._subparsers.add_parser(name, help=category_help)
|
||||||
return self.__class__(parser)
|
return self.__class__(parser)
|
||||||
|
|
||||||
def add_action_parser(self, name, action_help, **kwargs):
|
def add_action_parser(self, name, action_help=None, **kwargs):
|
||||||
"""Add a parser for an action
|
"""Add a parser for an action
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
|
@ -234,7 +224,6 @@ class APIAMapParser(_AMapParser):
|
||||||
"""Actions map's API Parser
|
"""Actions map's API Parser
|
||||||
|
|
||||||
"""
|
"""
|
||||||
parse_general_arguments = False
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._parsers = {} # dict({(method, path): _HTTPArgumentParser})
|
self._parsers = {} # dict({(method, path): _HTTPArgumentParser})
|
||||||
|
@ -248,7 +237,7 @@ class APIAMapParser(_AMapParser):
|
||||||
## Implement virtual methods
|
## Implement virtual methods
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_arg_name(name, full):
|
def format_arg_names(name, full):
|
||||||
if name[0] != '-':
|
if name[0] != '-':
|
||||||
return [name]
|
return [name]
|
||||||
if full:
|
if full:
|
||||||
|
@ -257,6 +246,9 @@ class APIAMapParser(_AMapParser):
|
||||||
return [name.replace('--', '@', 1)]
|
return [name.replace('--', '@', 1)]
|
||||||
return [name.replace('-', '@', 1)]
|
return [name.replace('-', '@', 1)]
|
||||||
|
|
||||||
|
def add_global_parser(self, **kwargs):
|
||||||
|
raise AttributeError("global arguments are not managed")
|
||||||
|
|
||||||
def add_category_parser(self, name, **kwargs):
|
def add_category_parser(self, name, **kwargs):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -271,17 +263,17 @@ class APIAMapParser(_AMapParser):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not api:
|
if not api:
|
||||||
return None
|
raise AttributeError("the action '%s' doesn't provide api access" % name)
|
||||||
|
|
||||||
# Validate action route
|
# Validate action route
|
||||||
m = re.match('(GET|POST|PUT|DELETE) (/\S+)', api)
|
m = re.match('(GET|POST|PUT|DELETE) (/\S+)', api)
|
||||||
if not m:
|
if not m:
|
||||||
return None
|
raise ValueError("the action '%s' doesn't provide api access" % name)
|
||||||
|
|
||||||
# Check if a parser already exists for the route
|
# Check if a parser already exists for the route
|
||||||
key = (m.group(1), m.group(2))
|
key = (m.group(1), m.group(2))
|
||||||
if key in self.routes:
|
if key in self.routes:
|
||||||
raise ValueError("A parser for '%s' already exists" % key)
|
raise AttributeError("a parser for '%s' already exists" % key)
|
||||||
|
|
||||||
# Create and append parser
|
# Create and append parser
|
||||||
parser = _HTTPArgumentParser()
|
parser = _HTTPArgumentParser()
|
||||||
|
@ -612,8 +604,8 @@ class ActionsMap(object):
|
||||||
arguments[an] = self.extraparser.parse(an, arguments[an], parameters)
|
arguments[an] = self.extraparser.parse(an, arguments[an], parameters)
|
||||||
|
|
||||||
# Retrieve action information
|
# Retrieve action information
|
||||||
namespace, category, action = arguments.pop('_info')
|
namespace, category, action = arguments.pop('_id')
|
||||||
func_name = '%s_%s' % (category, action)
|
func_name = '%s_%s' % (category, action.replace('-', '_'))
|
||||||
|
|
||||||
# Lock the moulinette for the namespace
|
# Lock the moulinette for the namespace
|
||||||
with MoulinetteLock(namespace, timeout):
|
with MoulinetteLock(namespace, timeout):
|
||||||
|
@ -690,67 +682,75 @@ class ActionsMap(object):
|
||||||
An interface relevant's parser object
|
An interface relevant's parser object
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Define setter for extra parameters
|
## Get extra parameters
|
||||||
if not self.use_cache:
|
if not self.use_cache:
|
||||||
_set_extra = lambda an, e: self.extraparser.validate(an, e)
|
_get_extra = lambda an, e: self.extraparser.validate(an, e)
|
||||||
else:
|
else:
|
||||||
_set_extra = lambda an, e: e
|
_get_extra = lambda an, e: e
|
||||||
|
|
||||||
|
## Add arguments to the parser
|
||||||
|
def _add_arguments(parser, arguments):
|
||||||
|
extras = {}
|
||||||
|
for argn, argp in arguments.items():
|
||||||
|
names = top_parser.format_arg_names(argn,
|
||||||
|
argp.pop('full', None))
|
||||||
|
extra = argp.pop('extra', None)
|
||||||
|
|
||||||
|
arg = parser.add_argument(*names, **argp)
|
||||||
|
if extra:
|
||||||
|
extras[arg.dest] = _get_extra(arg.dest, extra)
|
||||||
|
parser.set_defaults(_extra=extras)
|
||||||
|
|
||||||
# Instantiate parser
|
# Instantiate parser
|
||||||
top_parser = self._parser_class()
|
top_parser = self._parser_class()
|
||||||
|
|
||||||
# Iterate over actions map namespaces
|
# Iterate over actions map namespaces
|
||||||
for n, actionsmap in actionsmaps.items():
|
for n, actionsmap in actionsmaps.items():
|
||||||
if 'general_arguments' in actionsmap:
|
# Retrieve global parameters
|
||||||
# Parse general arguments
|
_global = actionsmap.pop('_global', {})
|
||||||
if top_parser.parse_general_arguments:
|
|
||||||
parser = top_parser.add_general_parser()
|
|
||||||
for an, ap in actionsmap['general_arguments'].items():
|
|
||||||
# Replace version number
|
|
||||||
version = ap.get('version', None)
|
|
||||||
if version:
|
|
||||||
ap['version'] = version.replace('%version%',
|
|
||||||
__version__)
|
|
||||||
argname = top_parser.format_arg_name(an, ap.pop('full', None))
|
|
||||||
parser.add_argument(*argname, **ap)
|
|
||||||
del actionsmap['general_arguments']
|
|
||||||
|
|
||||||
# Parse categories
|
# -- Parse global configuration
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# -- Parse global arguments
|
||||||
|
if 'arguments' in _global:
|
||||||
|
try:
|
||||||
|
# Get global arguments parser
|
||||||
|
parser = top_parser.add_global_parser()
|
||||||
|
except AttributeError:
|
||||||
|
# No parser for global arguments
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Add arguments
|
||||||
|
_add_arguments(parser, _global['arguments'])
|
||||||
|
|
||||||
|
# -- Parse categories
|
||||||
for cn, cp in actionsmap.items():
|
for cn, cp in actionsmap.items():
|
||||||
try:
|
try:
|
||||||
actions = cp.pop('actions')
|
actions = cp.pop('actions')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
# Invalid category without actions
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Add category parser
|
# Get category parser
|
||||||
cat_parser = top_parser.add_category_parser(cn, **cp)
|
cat_parser = top_parser.add_category_parser(cn, **cp)
|
||||||
|
|
||||||
# Parse actions
|
# -- Parse actions
|
||||||
for an, ap in actions.items():
|
for an, ap in actions.items():
|
||||||
arguments = ap.pop('arguments', {})
|
arguments = ap.pop('arguments', {})
|
||||||
|
|
||||||
# Add action parser
|
|
||||||
parser = cat_parser.add_action_parser(an, **ap)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Store action information
|
# Get action parser
|
||||||
parser.set_defaults(_info=(n, cn, an))
|
parser = cat_parser.add_action_parser(an, **ap)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# No parser for the action
|
# No parser for the action
|
||||||
break
|
continue
|
||||||
|
except ValueError:
|
||||||
# Add action arguments
|
# TODO: Log error
|
||||||
for argn, argp in arguments.items():
|
continue
|
||||||
name = top_parser.format_arg_name(argn, argp.pop('full', None))
|
else:
|
||||||
extra = argp.pop('extra', None)
|
# Store action identification and add arguments
|
||||||
|
parser.set_defaults(_id=(n, cn, an))
|
||||||
arg = parser.add_argument(*name, **argp)
|
_add_arguments(parser, arguments)
|
||||||
if not extra:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Store extra parameters
|
|
||||||
extras = parser.get_default('_extra') or {}
|
|
||||||
extras[arg.dest] = _set_extra(arg.dest, extra)
|
|
||||||
parser.set_defaults(_extra=extras)
|
|
||||||
|
|
||||||
return top_parser
|
return top_parser
|
||||||
|
|
Loading…
Add table
Reference in a new issue