#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import os # Either we are in a development environment or not IN_DEVEL = False # Either cache has to be used inside the moulinette or not USE_CACHE = True # Either the output has to be encoded as a JSON encoded string or not PRINT_JSON = False # Either the output has to printed for scripting usage or not PRINT_PLAIN = 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' # Initialization & helpers functions ----------------------------------- def _die(message, title='Error:'): """Print error message and exit""" try: from moulinette.interfaces.cli import colorize except ImportError: colorize = lambda msg, c: msg print('%s %s' % (colorize(title, 'red'), message)) sys.exit(1) def _check_in_devel(): """Check and load if needed development environment""" global IN_DEVEL, LOG_DIR basedir = os.path.abspath('%s/../' % os.path.dirname(__file__)) if os.path.isdir('%s/moulinette' % basedir) and not IN_DEVEL: # Add base directory to python path sys.path.insert(0, basedir) # Update global variables IN_DEVEL = True LOG_DIR = '%s/log' % basedir def _parse_argv(): """Parse additional arguments and return remaining ones""" global USE_CACHE, PRINT_JSON, PRINT_PLAIN global TTY_LOG_LEVEL, LOGGERS_LEVEL, LOGGERS_HANDLERS argv = list(sys.argv) argv.pop(0) if '--no-cache' in argv: USE_CACHE = False argv.remove('--no-cache') if '--json' in argv: PRINT_JSON = True argv.remove('--json') if '--plain' in argv: PRINT_PLAIN = True argv.remove('--plain') if '--debug' in argv: LOGGERS_LEVEL = TTY_LOG_LEVEL = 'DEBUG' argv.remove('--debug') if '--verbose' in argv: TTY_LOG_LEVEL = 'INFO' argv.remove('--verbose') if '--quiet' in argv: if 'tty' in LOGGERS_HANDLERS: LOGGERS_HANDLERS.remove('tty') argv.remove('--quiet') return argv def _init_moulinette(): """Configure logging and initialize the moulinette""" from moulinette import init # Custom logging configuration logging = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'precise': { 'format': '%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s' }, }, 'filters': { 'action': { '()': 'moulinette.utils.log.ActionFilter', }, }, 'handlers': { 'tty': { 'level': TTY_LOG_LEVEL, 'class': 'moulinette.interfaces.cli.TTYHandler', }, 'file': { 'class': 'logging.FileHandler', 'formatter': 'precise', 'filename': '%s/%s' % (LOG_DIR, LOG_FILE), 'filters': ['action'], }, }, 'loggers': { 'moulinette': { 'handlers': LOGGERS_HANDLERS, 'level': LOGGERS_LEVEL, }, 'yunohost': { 'handlers': LOGGERS_HANDLERS, 'level': LOGGERS_LEVEL, }, }, } # 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 init(logging_config=logging, _from_source=IN_DEVEL) def _retrieve_namespaces(): """Return the list of namespaces to load""" from moulinette.actionsmap import ActionsMap 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__': _check_in_devel() args = _parse_argv() _init_moulinette() # 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')): from moulinette.interfaces.cli import get_locale # 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 from moulinette import cli ret = cli(_retrieve_namespaces(), args, use_cache=USE_CACHE, print_json=PRINT_JSON, print_plain=PRINT_PLAIN) sys.exit(ret)