#! /usr/bin/python # -*- coding: utf-8 -*- import os import sys import argparse # Either we are in a development environment or not IN_DEVEL = False # Level for which loggers will log LOGGERS_LEVEL = 'INFO' TTY_LOG_LEVEL = 'SUCCESS' # Handlers that will be used by loggers # - file: log to the file LOG_DIR/LOG_FILE # - tty: log to current tty LOGGERS_HANDLERS = ['file', 'tty'] # Directory and file to be used by logging LOG_DIR = '/var/log/yunohost' LOG_FILE = 'yunohost-cli.log' # Check and load - as needed - development environment if not __file__.startswith('/usr/'): IN_DEVEL = True if IN_DEVEL: basedir = os.path.abspath('%s/../' % os.path.dirname(__file__)) if os.path.isdir(os.path.join(basedir, 'moulinette')): sys.path.insert(0, basedir) LOG_DIR = os.path.join(basedir, 'log') import moulinette from moulinette.actionsmap import ActionsMap from moulinette.interfaces.cli import colorize, get_locale # Initialization & helpers functions ----------------------------------- def _die(message, title='Error:'): """Print error message and exit""" print('%s %s' % (colorize(title, 'red'), message)) sys.exit(1) def _parse_cli_args(): """Parse additional arguments for the cli""" parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--no-cache', action='store_false', default=True, dest='use_cache', help="Don't use actions map cache", ) parser.add_argument('--output-as', choices=['json', 'plain'], default=None, help="Output result in another format", ) parser.add_argument('--debug', action='store_true', default=False, help="Log and print debug messages", ) parser.add_argument('--verbose', action='store_true', default=False, help="Be more verbose in the output", ) parser.add_argument('--quiet', action='store_true', default=False, help="Don't produce any output", ) parser.add_argument('--admin-password', default=None, dest='password', metavar='PASSWORD', help="The admin password to use to authenticate", ) # deprecated arguments parser.add_argument('--plain', action='store_true', default=False, help=argparse.SUPPRESS ) parser.add_argument('--json', action='store_true', default=False, help=argparse.SUPPRESS ) opts, args = parser.parse_known_args() # output compatibility if opts.plain: opts.output_as = 'plain' elif opts.json: opts.output_as = 'json' return (parser, opts, args) def _init_moulinette(debug=False, verbose=False, quiet=False): """Configure logging and initialize the moulinette""" # Define loggers handlers handlers = set(LOGGERS_HANDLERS) if quiet and 'tty' in handlers: handlers.remove('tty') elif verbose and 'tty' not in handlers: handlers.append('tty') root_handlers = set(handlers) if not debug and 'tty' in root_handlers: root_handlers.remove('tty') # Define loggers level level = LOGGERS_LEVEL tty_level = TTY_LOG_LEVEL if verbose: tty_level = 'INFO' if debug: tty_level = level = 'DEBUG' # Custom logging configuration logging = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'tty-debug': { 'format': '%(relativeCreated)-4d %(fmessage)s' }, 'precise': { 'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s' }, }, 'filters': { 'action': { '()': 'moulinette.utils.log.ActionFilter', }, }, 'handlers': { 'tty': { 'level': tty_level, 'class': 'moulinette.interfaces.cli.TTYHandler', 'formatter': 'tty-debug' if debug else '', }, 'file': { 'class': 'logging.FileHandler', 'formatter': 'precise', 'filename': '%s/%s' % (LOG_DIR, LOG_FILE), 'filters': ['action'], }, }, 'loggers': { 'yunohost': { 'level': level, 'handlers': handlers, 'propagate': False, }, 'moulinette': { 'level': level, 'handlers': [], 'propagate': True, }, 'moulinette.interface': { 'level': level, 'handlers': handlers, 'propagate': False, }, }, 'root': { 'level': level, 'handlers': root_handlers, }, } # Create log directory if not os.path.isdir(LOG_DIR): try: os.makedirs(LOG_DIR, 0750) except os.error as e: _die(str(e)) # Initialize moulinette moulinette.init(logging_config=logging, _from_source=IN_DEVEL) def _retrieve_namespaces(): """Return the list of namespaces to load""" ret = ['yunohost'] for n in ActionsMap.get_namespaces(): # Append YunoHost modules if n.startswith('ynh_'): ret.append(n) return ret # Main action ---------------------------------------------------------- if __name__ == '__main__': parser, opts, args = _parse_cli_args() _init_moulinette(opts.debug, opts.verbose, opts.quiet) # Check that YunoHost is installed if not os.path.isfile('/etc/yunohost/installed') and \ (len(args) < 2 or (args[0] +' '+ args[1] != 'tools postinstall' and \ args[0] +' '+ args[1] != 'backup restore')): # Init i18n m18n.load_namespace('yunohost') m18n.set_locale(get_locale()) # Print error and exit _die(m18n.n('yunohost_not_installed'), m18n.g('error')) # Execute the action ret = moulinette.cli( _retrieve_namespaces(), args, use_cache=opts.use_cache, output_as=opts.output_as, password=opts.password, parser_kwargs={'top_parser': parser} ) sys.exit(ret)