We don't need no namespaces ... but let's it customizable through a var env if needed...

This commit is contained in:
Alexandre Aubin 2020-05-01 03:48:01 +02:00
parent 1849d1aa3b
commit c750226a3b
3 changed files with 43 additions and 53 deletions

View file

@ -72,13 +72,12 @@ def init(logging_config=None, **kwargs):
# Easy access to interfaces # Easy access to interfaces
def api(namespaces, host="localhost", port=80, routes={}): def api(host="localhost", port=80, routes={}):
"""Web server (API) interface """Web server (API) interface
Run a HTTP server with the moulinette for an API usage. Run a HTTP server with the moulinette for an API usage.
Keyword arguments: Keyword arguments:
- namespaces -- The list of namespaces to use
- host -- Server address to bind to - host -- Server address to bind to
- port -- Server port to bind to - port -- Server port to bind to
- routes -- A dict of additional routes to add in the form of - routes -- A dict of additional routes to add in the form of
@ -88,31 +87,27 @@ def api(namespaces, host="localhost", port=80, routes={}):
from moulinette.actionsmap import ActionsMap from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.api import Interface, ActionsMapParser from moulinette.interfaces.api import Interface, ActionsMapParser
try: try:
actionsmap = ActionsMap(ActionsMapParser(), actionsmap = ActionsMap(ActionsMapParser())
namespaces=namespaces)
interface = Interface(actionsmap=actionsmap, interface = Interface(actionsmap=actionsmap,
routes=routes) routes=routes)
interface.run(host, port) interface.run(host, port)
except MoulinetteError as e: except MoulinetteError as e:
import logging import logging
logging.getLogger().error(e.strerror)
logging.getLogger(namespaces[0]).error(e.strerror) return 1
return e.errno if hasattr(e, "errno") else 1
except KeyboardInterrupt: except KeyboardInterrupt:
import logging import logging
logging.getLogger().info(m18n.g("operation_interrupted"))
logging.getLogger(namespaces[0]).info(m18n.g("operation_interrupted"))
return 0 return 0
def cli(namespaces, args, top_parser, output_as=None, timeout=None): def cli(args, top_parser, output_as=None, timeout=None):
"""Command line interface """Command line interface
Execute an action with the moulinette from the CLI and print its Execute an action with the moulinette from the CLI and print its
result in a readable format. result in a readable format.
Keyword arguments: Keyword arguments:
- namespaces -- The list of namespaces to use
- args -- A list of argument strings - args -- A list of argument strings
- output_as -- Output result in another format, see - output_as -- Output result in another format, see
moulinette.interfaces.cli.Interface for possible values moulinette.interfaces.cli.Interface for possible values
@ -122,14 +117,12 @@ def cli(namespaces, args, top_parser, output_as=None, timeout=None):
from moulinette.actionsmap import ActionsMap from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import Interface, ActionsMapParser from moulinette.interfaces.cli import Interface, ActionsMapParser
try: try:
actionsmap = ActionsMap(ActionsMapParser(top_parser=top_parser), actionsmap = ActionsMap(ActionsMapParser(top_parser=top_parser))
namespaces=namespaces)
interface = Interface(actionsmap=actionsmap) interface = Interface(actionsmap=actionsmap)
interface.run(args, output_as=output_as, timeout=timeout) interface.run(args, output_as=output_as, timeout=timeout)
except MoulinetteError as e: except MoulinetteError as e:
import logging import logging
logging.getLogger().error(e.strerror)
logging.getLogger(namespaces[0]).error(e.strerror)
return 1 return 1
return 0 return 0

View file

@ -4,6 +4,7 @@ import os
import re import re
import logging import logging
import yaml import yaml
import glob
import cPickle as pickle import cPickle as pickle
from time import time from time import time
from collections import OrderedDict from collections import OrderedDict
@ -398,16 +399,14 @@ class ActionsMap(object):
Moreover, the action can have specific argument(s). Moreover, the action can have specific argument(s).
This class allows to manipulate one or several actions maps This class allows to manipulate one or several actions maps
associated to a namespace. If no namespace is given, it will load associated to a namespace.
all available namespaces.
Keyword arguments: Keyword arguments:
- top_parser -- A BaseActionsMapParser-derived instance to use for - top_parser -- A BaseActionsMapParser-derived instance to use for
parsing the actions map parsing the actions map
- namespaces -- The list of namespaces to use
""" """
def __init__(self, top_parser, namespaces=[]): def __init__(self, top_parser):
assert isinstance(top_parser, BaseActionsMapParser), "Invalid parser class '%s'" % top_parser.__class__.__name__ assert isinstance(top_parser, BaseActionsMapParser), "Invalid parser class '%s'" % top_parser.__class__.__name__
@ -415,12 +414,10 @@ class ActionsMap(object):
DATA_DIR = moulinette_env["DATA_DIR"] DATA_DIR = moulinette_env["DATA_DIR"]
CACHE_DIR = moulinette_env["CACHE_DIR"] CACHE_DIR = moulinette_env["CACHE_DIR"]
if len(namespaces) == 0:
namespaces = self.get_namespaces()
actionsmaps = OrderedDict() actionsmaps = OrderedDict()
# Iterate over actions map namespaces # Iterate over actions map namespaces
for n in namespaces: for n in self.get_namespaces():
logger.debug("loading actions map namespace '%s'", n) logger.debug("loading actions map namespace '%s'", n)
actionsmap_yml = "%s/actionsmap/%s.yml" % (DATA_DIR, n) actionsmap_yml = "%s/actionsmap/%s.yml" % (DATA_DIR, n)
@ -441,10 +438,10 @@ class ActionsMap(object):
# TODO: Switch to python3 and catch proper exception # TODO: Switch to python3 and catch proper exception
except (IOError, EOFError): except (IOError, EOFError):
self.from_cache = False self.from_cache = False
actionsmaps = self.generate_cache(namespaces) actionsmaps[n] = self.generate_cache(n)
else: # cache file doesn't exists else: # cache file doesn't exists
self.from_cache = False self.from_cache = False
actionsmaps = self.generate_cache(namespaces) actionsmaps[n] = self.generate_cache(n)
# Load translations # Load translations
m18n.load_namespace(n) m18n.load_namespace(n)
@ -587,56 +584,55 @@ class ActionsMap(object):
moulinette_env = init_moulinette_env() moulinette_env = init_moulinette_env()
DATA_DIR = moulinette_env["DATA_DIR"] DATA_DIR = moulinette_env["DATA_DIR"]
for f in os.listdir("%s/actionsmap" % DATA_DIR): # This var is ['*'] by default but could be set for example to
if f.endswith(".yml"): # ['yunohost', 'yml_*']
namespaces.append(f[:-4]) NAMESPACE_PATTERNS = moulinette_env["NAMESPACES"]
# Look for all files that match the given patterns in the actionsmap dir
for namespace_pattern in NAMESPACE_PATTERNS:
namespaces.extend(glob.glob("%s/actionsmap/%s.yml" % (DATA_DIR, namespace_pattern)))
# Keep only the filenames with extension
namespaces = [os.path.basename(n)[:-4] for n in namespaces]
return namespaces return namespaces
@classmethod @classmethod
def generate_cache(klass, namespaces=None): def generate_cache(klass, namespace):
""" """
Generate cache for the actions map's file(s) Generate cache for the actions map's file(s)
Keyword arguments: Keyword arguments:
- namespaces -- A list of namespaces to generate cache for - namespace -- The namespace to generate cache for
Returns: Returns:
A dict of actions map for each namespaces The action map for the namespace
""" """
moulinette_env = init_moulinette_env() moulinette_env = init_moulinette_env()
CACHE_DIR = moulinette_env["CACHE_DIR"] CACHE_DIR = moulinette_env["CACHE_DIR"]
DATA_DIR = moulinette_env["DATA_DIR"] DATA_DIR = moulinette_env["DATA_DIR"]
actionsmaps = {}
if not namespaces:
namespaces = klass.get_namespaces()
# Iterate over actions map namespaces # Iterate over actions map namespaces
for n in namespaces: logger.debug("generating cache for actions map namespace '%s'", namespace)
logger.debug("generating cache for actions map namespace '%s'", n)
# Read actions map from yaml file # Read actions map from yaml file
am_file = "%s/actionsmap/%s.yml" % (DATA_DIR, n) am_file = "%s/actionsmap/%s.yml" % (DATA_DIR, namespace)
with open(am_file, "r") as f: with open(am_file, "r") as f:
actionsmaps[n] = ordered_yaml_load(f) actionsmap = ordered_yaml_load(f)
# at installation, cachedir might not exists # at installation, cachedir might not exists
if os.path.exists("%s/actionsmap/" % CACHE_DIR): for old_cache in glob.glob("%s/actionsmap/%s-*.pkl" % (CACHE_DIR, namespace)):
# clean old cached files os.remove(old_cache)
for i in os.listdir("%s/actionsmap/" % CACHE_DIR):
if i.endswith(".pkl"):
os.remove("%s/actionsmap/%s" % (CACHE_DIR, i))
# Cache actions map into pickle file # Cache actions map into pickle file
am_file_stat = os.stat(am_file) am_file_stat = os.stat(am_file)
pkl = "%s-%d-%d.pkl" % (n, am_file_stat.st_size, am_file_stat.st_mtime) pkl = "%s-%d-%d.pkl" % (namespace, am_file_stat.st_size, am_file_stat.st_mtime)
with open_cachefile(pkl, "w", subdir="actionsmap") as f: with open_cachefile(pkl, "w", subdir="actionsmap") as f:
pickle.dump(actionsmaps[n], f) pickle.dump(actionsmap, f)
return actionsmaps return actionsmap
# Private methods # Private methods

View file

@ -11,4 +11,5 @@ def init_moulinette_env():
"MOULINETTE_LOCALES_DIR", "/usr/share/moulinette/locale" "MOULINETTE_LOCALES_DIR", "/usr/share/moulinette/locale"
), ),
"CACHE_DIR": environ.get("MOULINETTE_CACHE_DIR", "/var/cache/moulinette"), "CACHE_DIR": environ.get("MOULINETTE_CACHE_DIR", "/var/cache/moulinette"),
"NAMESPACES": environ.get("MOULINETTE_NAMESPACES", "*").split(), # By default we'll load every namespace we find
} }