def _load_tasks(self, herringfile, settings): """ Loads the given herringfile then loads any herringlib files. :param herringfile: the herringfile path :type herringfile: str :return: None """ herringfile_path = Path(herringfile).parent library_paths = self._locate_library(herringfile_path, settings) self.union_dir = mkdir_p(os.path.join(tempfile.mkdtemp(), 'herringlib')) for src_dir in [os.path.abspath(str(path)) for path in reversed(library_paths)]: if not settings.json: info("src_dir: %s" % src_dir) for src_root, dirs, files in os.walk(src_dir): files = [f for f in files if not (f[0] == '.' or f.endswith('.pyc'))] dirs[:] = [d for d in dirs if not (d[0] == '.' or d == '__pycache__')] rel_root = os.path.relpath(src_root, start=src_dir) dest_root = os.path.join(self.union_dir, rel_root) mkdir_p(dest_root) for basename in [name for name in files]: src_name = os.path.join(src_root, basename) dest_name = os.path.join(dest_root, basename) try: shutil.copy(src_name, dest_name) except shutil.Error: pass self._load_modules(herringfile, [Path(self.union_dir)])
def setup(self): """ Command Line Interface. Exits the application in the following conditions: * user requested the applications version, * user requested help or longhelp, * can not find the herringfile. :return: None """ parser, settings, argv = HerringSettings().parse() Logger.set_verbose(not settings.quiet) Logger.set_debug(settings.herring_debug) TaskWithArgs.argv = argv TaskWithArgs.kwargs = ArgumentHelper.argv_to_dict(argv) if settings.longhelp: info(sys.modules['herring'].__doc__) exit(0) if settings.version: info("Herring version %s" % self._load_version()) exit(0) return settings
def task_lookup(task_name_): info("Running: {name} ({description})".format(name=task_name_, description=HerringTasks[task_name_]['description'])) TaskWithArgs.arg_prompt = HerringTasks[task_name_]['arg_prompt'] try: return HerringTasks[task_name_]['task'] except Exception as ex: error(str(ex))
def _header(self, message): """ Output table header message followed by a horizontal rule. :param message: the table header text :type message: str :return: None """ (console_width, console_height) = get_terminal_size() info(message) info("=" * console_width)
def _populate_union_dir(self, union_dir, library_paths, output_json): for src_dir in [os.path.abspath(str(path)) for path in reversed(library_paths)]: if not output_json: info("src_dir: %s" % src_dir) for src_root, dirs, files in os.walk(src_dir): files[:] = filter(lambda file_: not file_.startswith('.') and not file_.endswith('.pyc'), files) dirs[:] = filter(lambda dir_: not dir_.startswith('.') and dir_ != '__pycache__', dirs) rel_root = os.path.relpath(src_root, start=src_dir) dest_root = os.path.join(union_dir, rel_root) mkdir_p(dest_root) # for basename in [name for name in files]: for basename in files: try: shutil.copy(os.path.join(src_root, basename), os.path.join(dest_root, basename)) except shutil.Error: pass
def _row_list(self, c1_value, c2_value, c1_width, c2_width): """ Output the two columns in the table row. :param c1_value: value for first column :type c1_value: str :param c2_value: value for second column :type c2_value: str :param c1_width: width (number of characters) for first column :type c1_width: int :param c2_width: width (number of characters) for second column :type c2_width: int :return: None """ # values = textwrap.fill(self._unindent(c2_value), c2_width).split("\n") values = textwrap.fill(c2_value, c2_width).split("\n") info(ROW_FORMAT.format(c1_value, values[0], width1=c1_width, width2=c2_width)) for line in values[1:]: info(ROW_FORMAT.format(' ', line, width1=c1_width, width2=c2_width))
def show_depends(self, tasks, herring_tasks, settings): """ Shows the tasks and their dependencies. :param tasks: generator for list of task names to show. :type tasks: iterator :param herring_tasks: all of the herring tasks :type herring_tasks: dict :param settings: the application settings :return: None """ if settings.json: info('[') for name, description, dependencies, dependent_of, kwargs, arg_prompt, width in tasks: info(json.dumps({'name': name, 'description': description, 'dependencies': dependencies, 'dependent_of': dependent_of, 'kwargs': kwargs, 'arg_prompt': arg_prompt})) info(']') else: self._header("Show tasks and their dependencies") for name, description, dependencies, dependent_of, kwargs, arg_prompt, width in tasks: self._row(name=name, description=description.strip().splitlines()[0], dependencies=dependencies, dependent_of=dependent_of, max_name_length=width) self._footer(herring_tasks)
def run_tasks(task_list): """ Runs the tasks given on the command line. :param task_list: a task name or a list of task names to run :type task_list: str|list :return: None """ if not is_sequence(task_list): task_list = [task_list] verified_task_list = HerringApp._verified_tasks(task_list) debug("task_list: {tasks}".format(tasks=task_list)) debug("verified_task_list: {tasks}".format(tasks=verified_task_list)) if not verified_task_list: raise ValueError('No tasks given. Run "herring -T" to see available tasks.') TaskWithArgs.argv = list([arg for arg in task_list if arg not in verified_task_list]) for task_name in HerringApp._resolve_dependencies(verified_task_list, HerringTasks): info("Running: {name} ({description})".format(name=task_name, description=HerringTasks[task_name]['description'])) TaskWithArgs.arg_prompt = HerringTasks[task_name]['arg_prompt'] HerringTasks[task_name]['task']()
def _footer(self, tasks): tasks_help = [] for task_name in tasks: task = tasks[task_name] if task['help']: tasks_help.append("{name}: {help}".format(name=task_name, help=task['help'])) if tasks_help: info('') info('Notes:') info("\n".join(tasks_help))
def show_task_usages(self, tasks, herring_tasks, settings): """ Shows the tasks. :param tasks: generator for list of task names to show. :type tasks: iterator :param herring_tasks: all of the herring tasks :type herring_tasks: dict :param settings: the application settings :return: None """ if settings.json: info('[') for name, description, dependencies, dependent_of, kwargs, arg_prompt, width in tasks: info(json.dumps({'name': name, 'description': description, 'dependencies': dependencies, 'dependent_of': dependent_of, 'kwargs': kwargs, 'arg_prompt': arg_prompt})) info(']') else: self._header("Show task usages") for name, description, dependencies, dependent_of, kwargs, arg_prompt, width in tasks: info("#" * 40) info("# herring %s" % name) info(textwrap.dedent(description).replace("\n\n", "\n").strip()) info('') self._footer(herring_tasks)
def show_environment(self): """Show the runtime environment for herring""" info('os.environ: {data}'.format(data=pformat(os.environ))) info('sys.argv: {data}'.format(data=pformat(sys.argv))) info('sys.executable: {data}'.format(data=pformat(sys.executable))) info('sys.path: {data}'.format(data=pformat(sys.path))) info('sys.platform: {data}'.format(data=pformat(sys.platform))) info('sys.version_info: {data}'.format(data=pformat(sys.version_info)))
def execute(self, cli, settings): """ Execute the tasks specified in the _settings object. Currently: * settings.list_task asserted shows the available tasks. * settings.list_dependencies asserted shows the available tasks and their dependencies. * settings.list_all_tasks asserted modifies the listing to include tasks that do not have a docstring. * if both settings.list_task and settings.list_dependencies are deasserted, then run the tasks from settings.tasks :param cli: the command line interface instance :type cli: herring.HerringCLI :param settings: the application settings :return: None """ try: HerringFile.settings = settings herring_file = self._find_herring_file(settings.herringfile) HerringFile.directory = str(os.path.realpath(os.path.dirname(herring_file))) sys.path.insert(1, HerringFile.directory) herringfile_is_nonempty = self._is_herring_file_nonempty(herring_file) global debug_mode global verbose_mode debug_mode = settings.debug verbose_mode = not settings.quiet # the tasks are always ran with the current working directory # set to the directory that contains the herringfile os.chdir(HerringFile.directory) if not settings.json: info("Using: %s" % herring_file) if not settings.json and settings.environment: cli.show_environment() with HerringLoader(settings) as loader: loader.load_tasks(herring_file) # populates HerringTasks task_list = list(self._get_tasks_list(HerringTasks, settings.list_all_tasks, herringfile_is_nonempty, settings.tasks)) if settings.list_tasks: cli.show_tasks(self._get_tasks(task_list), HerringTasks, settings) elif settings.list_task_usages: cli.show_task_usages(self._get_tasks(task_list), HerringTasks, settings) elif settings.list_dependencies: cli.show_depends(self._get_tasks(task_list), HerringTasks, settings) else: try: HerringRunner.run_tasks(settings.tasks) except Exception as ex: fatal(ex) except ValueError as ex: fatal(ex)
def execute(self, cli, settings): """ Execute the tasks specified in the _settings object. Currently: * settings.list_task asserted shows the available tasks. * settings.list_dependencies asserted shows the available tasks and their dependencies. * settings.list_all_tasks asserted modifies the listing to include tasks that do not have a docstring. * if both settings.list_task and settings.list_dependencies are deasserted, then run the tasks from settings.tasks :param cli: the command line interface instance :type cli: herring.HerringCLI :param settings: the application settings :return: None """ try: HerringFile.settings = settings herring_file = self._find_herring_file(settings.herringfile) HerringFile.directory = str(os.path.realpath(os.path.dirname(herring_file))) sys.path.insert(1, HerringFile.directory) configured_herringfile = self._configured_herring_file(herring_file) global debug_mode global verbose_mode debug_mode = settings.debug verbose_mode = not settings.quiet # the tasks are always ran with the current working directory # set to the directory that contains the herringfile os.chdir(HerringFile.directory) if not settings.json: info("Using: %s" % herring_file) if not settings.json and settings.environment: cli.show_environment() self._load_tasks(herring_file, settings) task_list = list(self._get_tasks_list(HerringTasks, settings.list_all_tasks, configured_herringfile)) # if we are doing a show (-T, -D, -U) and we give another parameter, then only show # tasks that contain the parameter. Example: "-T doc" will show only the "doc" tasks. if settings.tasks: abridged_task_list = [] for task_ in settings.tasks: abridged_task_list.extend(list([t for t in task_list if task_ in t['name']])) task_list = abridged_task_list if settings.list_tasks: cli.show_tasks(self._get_tasks(task_list), HerringTasks, settings) elif settings.list_task_usages: cli.show_task_usages(self._get_tasks(task_list), HerringTasks, settings) elif settings.list_dependencies: cli.show_depends(self._get_tasks(task_list), HerringTasks, settings) else: try: HerringApp.run_tasks(settings.tasks) except Exception as ex: fatal(ex) except ValueError as ex: fatal(ex) finally: if self.union_dir is not None and not settings.leave_union_dir: # noinspection PyTypeChecker shutil.rmtree(os.path.dirname(self.union_dir))