Source code for cement.ext.ext_generate

"""
Cement generate extension module.
"""

import re
import os
import inspect
import yaml
import shutil
from .. import Controller, minimal_logger, shell
from ..utils.version import VERSION, get_version

LOG = minimal_logger(__name__)


[docs] class GenerateTemplateAbstractBase(Controller):
[docs] class Meta: pass
def _generate(self, source, dest): msg = 'Generating %s %s in %s' % ( self.app._meta.label, self._meta.label, dest ) self.app.log.info(msg) data = {} # builtin vars maj_min = float('%s.%s' % (VERSION[0], VERSION[1])) data['cement'] = {} data['cement']['version'] = get_version() data['cement']['major_version'] = VERSION[0] data['cement']['minor_version'] = VERSION[1] data['cement']['major_minor_version'] = maj_min f = open(os.path.join(source, '.generate.yml')) yaml_load = yaml.full_load if hasattr(yaml, 'full_load') else yaml.load g_config = yaml_load(f) f.close() vars = g_config.get('variables', {}) exclude_list = g_config.get('exclude', []) ignore_list = g_config.get('ignore', []) # default ignore the .generate.yml config g_config_yml = r'^(.*)[\/\\\\]%s[\/\\\\]\.generate\.yml$' % \ self._meta.label ignore_list.append(g_config_yml) var_defaults = { 'name': None, 'prompt': None, 'validate': None, 'case': None, 'default': None, } for defined_var in vars: var = var_defaults.copy() var.update(defined_var) for key in ['name', 'prompt']: assert var[key] is not None, \ "Required generate config key missing: %s" % key val = None if var['default'] is not None and self.app.pargs.defaults: val = var['default'] elif var['default'] is not None: default_text = ' [%s]' % var['default'] else: default_text = '' # pragma: nocover if val is None: class MyPrompt(shell.Prompt): class Meta: text = "%s%s:" % (var['prompt'], default_text) default = var.get('default', None) p = MyPrompt() val = p.prompt() # pragma: nocover if var['case'] in ['lower', 'upper', 'title']: val = getattr(val, var['case'])() elif var['case'] is not None: self.app.log.warning( "Invalid configuration for variable " + "'%s': " % var['name'] + "case must be one of lower, upper, or title." ) if var['validate'] is not None: assert re.match(var['validate'], val), \ "Invalid Response (must match: '%s')" % var['validate'] data[var['name']] = val try: self.app.template.copy(source, dest, data, force=self.app.pargs.force, ignore=ignore_list, exclude=exclude_list) except AssertionError as e: if re.match('(.*)already exists(.*)', e.args[0]): raise AssertionError(e.args[0] + ' (try: --force)') else: raise # pragma: nocover def _clone(self, source, dest): msg = 'Cloning %s %s template to %s' % ( self.app._meta.label, self._meta.label, dest ) self.app.log.info(msg) if os.path.exists(dest) and self.app.pargs.force is True: shutil.rmtree(dest) elif os.path.exists(dest): msg = "Destination path already exists: %s (try: --force)" % dest raise AssertionError(msg) shutil.copytree(source, dest) def _default(self): source = self._meta.source_path dest = self.app.pargs.dest if self.app.pargs.clone is True: self._clone(source, dest) else: self._generate(source, dest)
def setup_template_items(app): template_dirs = [] template_items = [] # look in app template dirs for path in app._meta.template_dirs: subpath = os.path.join(path, 'generate') if os.path.exists(subpath) and subpath not in template_dirs: template_dirs.append(subpath) # use app template module, find it's path on filesystem if app._meta.template_module is not None: mod_parts = app._meta.template_module.split('.') mod = mod_parts.pop() try: mod = app.__import__(mod, from_module='.'.join(mod_parts)) mod_path = os.path.dirname(inspect.getfile(mod)) subpath = os.path.join(mod_path, 'generate') if os.path.exists(subpath) and subpath not in template_dirs: template_dirs.append(subpath) # FIXME: not exactly sure how to test for this so not covering except AttributeError: # pragma: nocover msg = 'unable to load template module' + \ '%s from %s' % (mod, '.'.join(mod_parts)) # pragma: nocover app.log.debug(msg) # pragma: nocover for path in template_dirs: for item in os.listdir(path): if item not in template_items: template_items.append(item) class GenerateTemplate(GenerateTemplateAbstractBase): class Meta: label = item stacked_on = 'generate' stacked_type = 'nested' help = 'generate %s from template' % item arguments = [ # ------------------------------------------------------ (['dest'], {'help': 'destination directory path'}), # ------------------------------------------------------ (['-f', '--force'], {'help': 'force operation if destination exists', 'dest': 'force', 'action': 'store_true'}), # ------------------------------------------------------ (['-D', '--defaults'], {'help': 'use all default variable values', 'dest': 'defaults', 'action': 'store_true'}), # ------------------------------------------------------ (['--clone'], {'help': 'clone this template to destination path', 'dest': 'clone', 'action': 'store_true'}), ] source_path = os.path.join(path, item) app.handler.register(GenerateTemplate)
[docs] class Generate(Controller):
[docs] class Meta: label = 'generate' stacked_on = 'base' stacked_type = 'nested' config_section = 'generate'
[docs] def _setup(self, app): super(Generate, self)._setup(app)
def _default(self): self._parser.print_help()
def load(app): app.handler.register(Generate) app.hook.register('pre_run', setup_template_items)