def get_template_path(self): """ Obtain the template with from the command line interface or from prompting the user to choose a template from the config file. :returns: str or bool """ templates = [] template = self.interface.arguments.get('--template', False) select = self.interface.arguments.get('--select', False) try: templates = self.config.items('template') except ConfigParser.NoSectionError: if select: raise FacioException('Missing [template] section ' 'in Facio configuration file.') # Path or template name alias if template: try: path = [p for n, p in templates if n == template][0] except IndexError: return template else: return path # Select template from configuration file if select: tries = 5 self.out('Please select a template:') for i, item in enumerate(templates, start=1): name, path = item self.out('{0}) {1}: {2}'.format(i, name, path)) for n in range(1, (tries + 1)): try: prompt = 'Please enter the number of '\ 'the template ({0} of {1} tries'\ '): '.format(n, tries) num = int(self.gather(prompt)) if num == 0: raise ValueError name, path = templates[(num - 1)] return path except (ValueError, TypeError, IndexError): self.error('Please enter a valid number') raise FacioException('A template was not selected') # Default template return Settings.default_template_path
def update_copy_ignore_globs(self, globs): """ Update the ignore glob patterns to include the list provided. ** Usage: ** .. code-block:: python from facio.template import Template t = Template('foo', '/path/to/foo') globs = [ '*.png', '*.gif', ] t.update_copy_ignore_globs(globs) :param globs: A list of globs :type globs: list """ try: self.copy_ignore_globs += globs except AttributeError: if not isinstance(globs, list): self.copy_ignore_globs = [] else: self.copy_ignore_globs = globs except TypeError: raise FacioException('Failed to add {0} to ignore globs ' 'list'.format(globs))
def clone(self): """ Clone the hg repository into a temporary directory. """ try: from sh import hg except ImportError: raise FacioException('Mercurial must be installed to use hg+ ' 'template paths') temp_diretory = self.get_temp_directory() self.out('Mercurial Cloning {0} to {1}'.format(self.path, temp_diretory)) try: hg = hg.bake(_cwd=temp_diretory) hg.clone(self.path, temp_diretory) except: raise FacioException('Failed to clone hg repository ' 'at {0}'.format(self.path)) return temp_diretory
def clone(self): """ Clone the git repository into a temporary directory. """ try: from sh import git except ImportError: raise FacioException('Git must be installed to use git+ ' 'template paths') temp_diretory = self.get_temp_directory() self.out('Git Cloning {0} to {1}'.format(self.path, temp_diretory)) try: git = git.bake(_cwd=temp_diretory) git.clone(self.path, temp_diretory) git.fetch('--all') git.checkout('master') except: raise FacioException('Failed to clone git repository ' 'at {0}'.format(self.path)) return temp_diretory
def read(self, name=CONFIG_FILE_NAME): """ Parse the config file using ConfigParser module. :param name: The file name to read in the users home dir -- optional :type name: str :returns: ConfirgParser or bool """ path = os.path.expanduser('~/{0}'.format(name)) parser = ConfigParser.ConfigParser() try: parser.readfp(open(path)) except IOError: self.warning('{0} Not found'.format(path)) except ConfigParser.Error: raise FacioException('Unable to parse {0}'.format(path)) else: self.out('Loaded {0}'.format(path)) return parser
def validate_project_name(self, name): if not re.match('^\w+$', name): raise FacioException('Project names can only contain numbers ' 'letters and underscores') else: state.set_project_name(name)
def copy(self, callback=None): """ Copy template from origin path to ``state.get_project_root()``. :param callback: A callback function to be called after copy is complete :type callback: function -- default None :returns: bool """ self.out('Copying {0} to {1}'.format(self.origin, state.get_project_root())) ignore = shutil.ignore_patterns(*self.get_copy_ignore_globs()) try: shutil.copytree(self.origin, state.get_project_root(), ignore=ignore) except shutil.Error: raise FacioException('Failed to copy {0} to {1}'.format( self.origin, state.get_project_root())) except OSError: # If we get an OSError either the template path does not exist or # the project root already exists. Check the later first and then # check if the template path is git+ or hg+ and clone, finally # raising exceptions if not os.path.isdir(state.get_project_root()): supported_vcs = [ ('git+', GitVCS), ('hg+', MercurialVCS), ] for prefix, cls in supported_vcs: if self.origin.startswith(prefix): vcs = cls(self.origin) new_path = vcs.clone() if not new_path: raise FacioException( 'New path to template not returned by ' '{0}.clone()'.format(vcs.__class__.__name__)) self.origin = new_path break else: # Loop feel through so path is not prefixed with git+ or # +hg so it must be a path that does not exist raise FacioException('{0} does not exist'.format( self.origin)) # The loop broke so we can call self.copy again if self.COPY_ATTEMPT <= self.COPY_ATTEMPT_LIMIT: self.COPY_ATTEMPT += 1 self.copy(callback=vcs.remove_tmp_dir) else: raise FacioException('Failed to copy template after ' '{0} attempts'.format( self.COPY_ATTEMPT)) else: # project root exists, raise exception raise FacioException('{0} already exists'.format( state.get_project_root())) # Call callback if callable if callable(callback): callback(origin=self.origin, destination=state.get_project_root()) return True
import fnmatch import os import re import shutil from codecs import open from facio.base import BaseFacio from facio.exceptions import FacioException from facio.state import state from facio.vcs import GitVCS, MercurialVCS try: from jinja2 import Environment, FileSystemLoader except ImportError: # pragma: no cover raise FacioException('Jinja2 must be installed to use Facio') # Regex for extracting context variable name from file or directory name get_var_name_pattern = re.compile(r'\{\{(\w+)\}\}') class Template(BaseFacio): COPY_ATTEMPT_LIMIT = 5 COPY_ATTEMPT = 1 def __init__(self, origin): """ Constructor for Template Class sets the project template origin. It also sets the default ignore globs. :param origin: The origin path to the template
def clone(self): """ This class should be overridden in VCS subclass, if not a FacioException will be raised. """ raise FacioException('The clone method on BaseVCS needs to be ' 'overridden.')