def run(self): """ Run the Facio processes. """ interface = CommandLineInterface() interface.start() config = ConfigurationFile() parsed = config.read() settings = Settings(interface, parsed) state.update_context_variables(settings.get_variables()) template = Template(settings.get_template_path()) template.update_copy_ignore_globs(settings.copy_ignore_globs()) template.update_render_ignore_globs(settings.render_ignore_globs()) template.copy() pipeline = Hook() pipeline.load(os.path.join( state.get_project_root(), HOOKS_FILE_NAME)) if pipeline.has_before(): pipeline.run_before() template.rename() template.render() if pipeline.has_after(): pipeline.run_after() self.success('Done')
def run(self): """ Runs the python setup.py command. :returns: bool -- Based on return code subprocess call return code """ project_root = state.get_project_root() working_dir = state.get_working_directory() python = self.get_path_to_python() setup = os.path.join(project_root, 'setup.py') arg = self.get_install_arg() self.out('Running: {0} ...'.format(' '.join([python, setup, arg]))) os.chdir(project_root) call = subprocess.Popen([python, setup, arg], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, errors = call.communicate() os.chdir(working_dir) if call.returncode: self.log_errors(errors) return False return True
def run(self): """ Run the Facio processes. """ interface = CommandLineInterface() interface.start() config = ConfigurationFile() parsed = config.read() settings = Settings(interface, parsed) state.update_context_variables(settings.get_variables()) template = Template(settings.get_template_path()) template.update_copy_ignore_globs(settings.copy_ignore_globs()) template.update_render_ignore_globs(settings.render_ignore_globs()) template.copy() pipeline = Hook() pipeline.load(os.path.join(state.get_project_root(), HOOKS_FILE_NAME)) if pipeline.has_before(): pipeline.run_before() template.rename() template.render() if pipeline.has_after(): pipeline.run_after() self.success('Done')
def test_copy_callback_call(self, mock_copy_tree, mock_pwd): from facio.state import state instance = Template('/foo/bar') callback = MagicMock() self.assertTrue(instance.copy(callback=callback)) callback.assert_called_once_with( origin=instance.origin, destination=state.get_project_root())
def rename_direcories(self): """ Renames directories that are named after context variables, for example: ``{{PROJECT_NAME}}``. :returns: generator """ for root, dirs, files in os.walk(state.get_project_root()): for directory in fnmatch.filter(dirs, '*{{*}}*'): var_name = get_var_name_pattern.findall(directory)[0] var_value = state.get_context_variable(var_name) if var_value: old_path = os.path.join(root, directory) new_path = os.path.join(root, var_value) shutil.move(old_path, new_path) yield (old_path, new_path)
def log_errors(self, errors): """ Called with errors are encountered running setup.py and are logged to a setup.error.log. :param errors: Errors from setup.py :type errors: str """ project_root = state.get_project_root() log_path = os.path.join(project_root, 'setup.error.log') with open(log_path, 'a') as handler: handler.write(errors) self.error('Errors detected with running setup.py, ' 'please check {0}'.format(log_path))
def rename_files(self): """ Rename files that are named after context variables, for example: ``{{PROJECT_NAME}}.py`` :returns: generator """ for root, dirs, files in os.walk(state.get_project_root()): for filename in fnmatch.filter(files, '*{{*}}*'): var_name = get_var_name_pattern.findall(filename)[0] var_value = state.get_context_variable(var_name) if var_value: name, ext = os.path.splitext(filename) old_path = os.path.join(root, filename) new_path = os.path.join(root, '{0}{1}'.format(var_value, ext)) shutil.move(old_path, new_path) yield (old_path, new_path)
def rename_files(self): """ Rename files that are named after context variables, for example: ``{{PROJECT_NAME}}.py`` :returns: generator """ for root, dirs, files in os.walk(state.get_project_root()): for filename in fnmatch.filter(files, '*{{*}}*'): var_name = get_var_name_pattern.findall(filename)[0] var_value = state.get_context_variable(var_name) if var_value: name, ext = os.path.splitext(filename) old_path = os.path.join(root, filename) new_path = os.path.join(root, '{0}{1}'.format( var_value, ext)) shutil.move(old_path, new_path) yield (old_path, new_path)
def render(self): """ Reads the template and uses Jinja 2 to replace context variables with their real values. """ variables = state.get_context_variables() for root, dirs, files in os.walk(state.get_project_root()): jinja_loader = FileSystemLoader(root) jinja_environment = Environment(loader=jinja_loader) ignores = self.get_render_ignore_files(files) for filename in files: if filename not in ignores: path = os.path.join(root, filename) try: template = jinja_environment.get_template(filename) rendered = template.render(variables) except: import sys e = sys.exc_info()[1] self.warning('Failed to render {0}: {1}'.format( path, e)) else: with open(path, 'w', encoding='utf8') as handler: handler.write(rendered)
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
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