Пример #1
0
def run_commands(commands, working_directory):
    """
    Run the given list of commands in the given folder.
    :param commands: List of commands to execute
    :param working_directory: Path to the folder where the commands should be executed
    :return: 0 on success, 1 on error.
    """
    for command in commands:
        logger.info(f"Running command '{command}'")
        with subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                cwd=working_directory,
                shell=True,
        ) as p:
            try:
                stdout, stderr = p.communicate()
                logger.debug(stdout.decode("utf-8"))
                ret_val = p.returncode
                if ret_val != 0:
                    logger.error(
                        f"Commands execution failed with error code {ret_val}")
                    logger.error(stderr)
            except Exception as e:
                p.kill()
                raise e
Пример #2
0
def run(args):
    """
    Run the command.
    :param args: Arguments given to the command
    """
    # Init some useful variables
    output_path = os.path.abspath(args.output)
    project_name = os.path.basename(output_path)
    data = {
        "project": {
            "path": output_path,
            "name": project_name,
            "slug": slugify(project_name),
        },
    }

    # Load template metadata
    logger.info(f"Loading template '{args.template}'")
    template_metadata = templates.metadata(args.template)
    if template_metadata is None:
        return 1

    # Keep only requested options
    template_metadata["options"] = filter_options(args.options,
                                                  template_metadata)
    if template_metadata["options"] is None:
        return 1

    # Complete data for future parsing
    data = {**data, **template_metadata}
    logger.debug(f"Data: {data}")

    # Parse commands
    parse_commands(data)
    commands = data["commands"]
    logger.debug(f"Commands: {commands}")

    logger.info(f"Creating project '{project_name}'")

    try:
        copy_template_files(args.template, data, output_path, args.force)
        run_commands(commands, output_path)
    except Exception as e:
        logger.error(e)
        return 1

    # Success message
    logger.info(f"Project created at '{output_path}'")
    logger.info(f"Run `grep -Ri FIXME '{output_path}'` to complete the setup")
Пример #3
0
def _filter_options(patterns, options_tree):
    """
    Recursive iteration on nested options. If an option matches one of
    the given names, it is added to the list of returned options.
    :param patterns: List of the options patterns to look for (separated with config.options_sep if nested)
    :param options_tree: The options dictionary tree
    :return: Dictionary of key/value options that matched the given names. None on error.
    """
    # Stop recursion
    if len(patterns) == 0:
        return {}

    options = {}

    # For each option
    for name, value in options_tree.get("options", {}).items():
        # For each pattern
        for pattern in patterns:
            try:
                if config.options_sep not in pattern:
                    # Handle simple option
                    if re.match(pattern, name):
                        # No need for nested options on match
                        if "options" in value.keys():
                            value.pop("options")
                        # Add option in options list
                        options[name] = value
                else:
                    # Handle nested option
                    if re.match(pattern.split(config.options_sep)[0], name):
                        # Move patterns one option forward
                        new_patterns = [
                            re.sub(r"^.*?" + config.options_sep, "", p)
                            for p in patterns if config.options_sep in p
                        ]
                        # Get nested options
                        new_options = _filter_options(new_patterns, value)
                        if new_options is None:
                            return None
                        # Ensure the key exists
                        options[name] = options.setdefault(name, value)
                        # Set the new options
                        options[name]["options"] = new_options
            except re.error as e:
                logger.error(f"option pattern '{pattern}' is invalid: {e}")
                return None

    return options
Пример #4
0
def mkdir(path, ignore_errors=False):
    """
    Create a directory if folder does not exist. It creates every folder in
    the given path.
    :param ignore_errors: If True, do not throw error when folder already exists
    :returns: True on success, False on error
    """
    if not ignore_errors and os.path.exists(path):
        logger.warning(f"Folder '{path}' already exists.")
        return False

    try:
        os.makedirs(path)
    except IOError as e:
        if not ignore_errors:
            logger.error(e)
        return ignore_errors

    return True
Пример #5
0
def _create_destination_folder(path, force=False):
    """
    Create a folder at the given path.
    :param path: Path of the folder to create
    :param force: Should the folder be removed if it already exists
    """
    # Try to create the folder
    if files.mkdir(path) is False:
        # On fail, if not force, display an error message
        if not force:
            logger.error(
                "Destination folder already exists. You can force its removal with the --force option."
            )
            raise Exception("Destination folder already exists")

        # Else, remove the old folder and create a new one
        logger.warning(f"Force option set: removing folder '{path}'")
        files.rm(path)

        if files.mkdir(path) is False:
            logger.error("Something went wrong when trying to create destination folder.")
            raise Exception("Something went wrong")
Пример #6
0
def filter_options(patterns, options_tree):
    """
    Recursive iteration on nested options. If an option matches one of
    the given names, it is added to the list of returned options.
    If the list of patterns is empty, then all options are filterd.
    :param patterns: List of the options patterns to look for (separated with config.options_sep if nested)
    :param options_tree: The options dictionary tree
    :return: Dictionary of key/value options that matched the given names. None on error.
    """
    if len(patterns) == 0:
        # Retrieve all
        filtered_options = options_tree.get("options", {})
    else:
        # Retrieve partial
        filtered_options = _filter_options(patterns, options_tree)

    # Display unmatched options
    pattern_has_not_matched = False
    for pattern in patterns:
        if pattern.split(config.options_sep)[0] not in filtered_options.keys():
            pattern_has_not_matched = True
            logger.error(f"Option pattern '{pattern}' did not match anything.")

    return None if pattern_has_not_matched else filtered_options