예제 #1
0
def remove_command(to_remove: list):
    config = CFBSConfig.get_instance()
    modules = config["build"]

    def _get_module_by_name(name) -> dict:
        if not name.startswith("./") and name.endswith(
                ".cf") and os.path.exists(name):
            name = "./" + name

        for module in modules:
            if module["name"] == name:
                return module
        return None

    def _get_modules_by_url(name) -> list:
        r = []
        for module in modules:
            if "url" in module and module["url"] == name:
                r.append(module)
        return r

    num_removed = 0
    for name in to_remove:
        if name.startswith(("https://", "ssh://", "git://")):
            matches = _get_modules_by_url(name)
            if not matches:
                user_error("Could not find module with URL '%s'" % name)
            for module in matches:
                answer = prompt_user(
                    "Do you wish to remove '%s'?" % module["name"],
                    choices=YES_NO_CHOICES,
                    default="yes",
                )
                if answer.lower() in ("yes", "y"):
                    print("Removing module '%s'" % module["name"])
                    modules.remove(module)
                    num_removed += 1
        else:
            module = _get_module_by_name(name)
            if module:
                print("Removing module '%s'" % name)
                modules.remove(module)
                num_removed += 1
            else:
                print("Module '%s' not found" % name)

    config.save()
    if num_removed:
        try:
            _clean_unused_modules(config)
        except CFBSReturnWithoutCommit:
            pass
        return 0
    else:
        raise CFBSReturnWithoutCommit(0)
예제 #2
0
def _clean_unused_modules(config=None):
    if not config:
        config = CFBSConfig.get_instance()
    modules = config["build"]

    def _someone_needs_me(this) -> bool:
        if "added_by" not in this or this["added_by"] == "cfbs add":
            return True
        for other in modules:
            if not "dependencies" in other:
                continue
            if this["name"] in other["dependencies"]:
                return _someone_needs_me(other)
        return False

    to_remove = list()
    for module in modules:
        if not _someone_needs_me(module):
            to_remove.append(module)

    if not to_remove:
        raise CFBSReturnWithoutCommit(0)

    print(
        "The following modules were added as dependencies but are no longer needed:"
    )
    for module in to_remove:
        name = module["name"] if "name" in module else ""
        description = module["description"] if "description" in module else ""
        added_by = module["added_by"] if "added_by" in module else ""
        print("%s - %s - added by: %s" % (name, description, added_by))

    answer = prompt_user("Do you wish to remove these modules?",
                         choices=YES_NO_CHOICES,
                         default="yes")
    if answer.lower() in ("yes", "y"):
        for module in to_remove:
            modules.remove(module)
        config.save()

    return 0
예제 #3
0
파일: git_magic.py 프로젝트: cfengine/cfbs
def git_commit_maybe_prompt(commit_msg, non_interactive, scope="all"):
    edit_commit_msg = False
    args = get_args()

    # Override message if --git-commit-message option is used
    if args.git_commit_message:
        global first_commit
        if first_commit:
            commit_msg = args.git_commit_message
            non_interactive = True
            first_commit = False
        else:
            log.warning(
                "Commit message specified, but command produced multiple commits, using default commit message"
            )

    if not non_interactive:
        prompt = "The default commit message is '{}' - edit it?".format(
            commit_msg)
        if "\n" in commit_msg:
            prompt = "The default commit message is:\n\n"
            for line in commit_msg.split("\n"):
                prompt += "\n" if line == "" else "\t" + line + "\n"
            prompt += "\nEdit it?"

        ans = prompt_user(
            prompt,
            choices=YES_NO_CHOICES,
            default="no",
        )
        edit_commit_msg = ans.lower() in ("yes", "y")

    git_commit(
        commit_msg,
        edit_commit_msg,
        args.git_user_name,
        args.git_user_email,
        scope,
    )
예제 #4
0
def update_command(to_update):
    config = CFBSConfig.get_instance()
    index = config.index

    if to_update:
        to_update = [Module(m) for m in to_update]
        index.translate_aliases(to_update)
        skip = (m for m in to_update
                if all(n["name"] != m.name for n in config["build"]))
        for m in skip:
            log.warning("Module '%s' not in build. Skipping its update.",
                        m.name)
            to_update.remove(m)
    else:
        # Update all modules in build if no modules are specified
        to_update = [Module(m["name"]) for m in config["build"]]

    new_deps = []
    new_deps_added_by = dict()
    changes_made = False
    msg = ""
    updated = []

    for update in to_update:
        module = config.get_module_from_build(update.name)
        assert module is not None  # Checked above when logging skipped modules

        if "version" not in module:
            print("Module '%s' not updatable" % module["name"])
            continue
        old_version = module["version"]

        if "index" in module:
            # TODO: Support custom index
            log.warning(
                "Module '%s' is not from the default index. " +
                "Updating from custom index is currently not supported. " +
                "Skipping its update.",
                module["name"],
            )
            continue

        index_info = index.get_module_object(update)
        if not index_info:
            log.warning(
                "Module '%s' not present in the index, cannot update it",
                module["name"])
            continue

        if (module["version"] != index_info["version"]
                and module["commit"] == index_info["commit"]):
            log.warning(
                "Version and commit mismatch detected." +
                " The module %s has the same commit but different version" +
                " locally (%s) and in the index (%s)." +
                " Skipping its update.",
                module["name"],
                module["version"],
                index_info["version"],
            )
            continue

        local_ver = [
            int(version_number)
            for version_number in re.split("[-\.]", module["version"])
        ]
        index_ver = [
            int(version_number)
            for version_number in re.split("[-\.]", index_info["version"])
        ]
        if local_ver == index_ver:
            continue
        elif local_ver > index_ver:
            log.warning(
                "The requested version of module '%s' is older than current version (%s < %s)."
                " Skipping its update.",
                module["name"],
                index_info["version"],
                module["version"],
            )
            continue

        commit_differs = module["commit"] != index_info["commit"]
        for key in module.keys():
            if key not in index_info or module[key] == index_info[key]:
                continue
            if key == "steps":
                # same commit => user modifications, don't revert them
                if commit_differs:
                    ans = prompt_user(
                        "Module %s has different build steps now\n" %
                        module["name"] + "old steps: %s\n" % module["steps"] +
                        "new steps: %s\n" % index_info["steps"] +
                        "Do you want to use the new build steps?",
                        choices=YES_NO_CHOICES,
                        default="yes",
                    )
                    if ans.lower() in ["y", "yes"]:
                        module["steps"] = index_info["steps"]
                    else:
                        print("Please make sure the old build steps work" +
                              " with the new version of the module")
            else:
                if key == "dependencies":
                    extra = set(index_info["dependencies"]) - set(
                        module["dependencies"])
                    new_deps.extend(extra)
                    new_deps_added_by.update(
                        {item: module["name"]
                         for item in extra})

                module[key] = index_info[key]
                changes_made = True

        # add new items
        for key in set(index_info.keys()) - set(module.keys()):
            module[key] = index_info[key]
            if key == "dependencies":
                extra = index_info["dependencies"]
                new_deps.extend(extra)
                new_deps_added_by.update(
                    {item: module["name"]
                     for item in extra})

        if not update.version:
            update.version = index_info["version"]
        updated.append(update)
        msg += "\n - Updated module '%s' from version %s to version %s" % (
            update.name,
            old_version,
            update.version,
        )

    if new_deps:
        objects = [
            index.get_module_object(d, new_deps_added_by[d]) for d in new_deps
        ]
        config.add_with_dependencies(objects)
    config.save()

    if changes_made:
        if len(updated) > 1:
            msg = "Updated %d modules\n" % len(updated) + msg
        else:
            assert updated
            msg = msg[4:]  # Remove the '\n - ' part of the message
        print("%s\n" % msg)
    else:
        print("Modules are already up to date")

    return Result(0, changes_made, msg)
예제 #5
0
def init_command(index=None, non_interactive=False) -> int:
    if is_cfbs_repo():
        user_error("Already initialized - look at %s" % cfbs_filename())

    name = prompt_user("Please enter name of this CFBS repository",
                       default="Example")
    description = prompt_user(
        "Please enter description of this CFBS repository",
        default="Example description",
    )

    config = {
        "name": name,
        "type":
        "policy-set",  # TODO: Prompt whether user wants to make a module
        "description": description,
        "build": [],
    }
    if index:
        config["index"] = index

    do_git = get_args().git
    is_git = is_git_repo()
    if do_git is None:
        if is_git:
            git_ans = prompt_user(
                "This is a git repository. Do you want cfbs to make commits to it?",
                choices=YES_NO_CHOICES,
                default="yes",
            )
        else:
            git_ans = prompt_user(
                "Do you want cfbs to initialize a git repository and make commits to it?",
                choices=YES_NO_CHOICES,
                default="yes",
            )
        do_git = git_ans.lower() in ("yes", "y")
    else:
        assert do_git in ("yes", "no")
        do_git = True if do_git == "yes" else False

    if do_git is True:
        user_name = get_args().git_user_name
        if not user_name:
            user_name = git_get_config("user.name")
            user_name = prompt_user(
                "Please enter user name to use for git commits",
                default=user_name or "cfbs",
            )

        user_email = get_args().git_user_email
        if not user_email:
            user_email = git_get_config("user.email")
            node_name = os.uname().nodename
            user_email = prompt_user(
                "Please enter user email to use for git commits",
                default=user_email or ("cfbs@%s" % node_name),
            )

        if not is_git:
            try:
                git_init(user_name, user_email, description)
            except CFBSGitError as e:
                print(str(e))
                return 1
        else:
            if not git_set_config("user.name",
                                  user_name) or not git_set_config(
                                      "user.email", user_email):
                print("Failed to set Git user name and email")
                return 1

    config["git"] = do_git

    write_json(cfbs_filename(), config)
    assert is_cfbs_repo()

    if do_git:
        try:
            git_commit_maybe_prompt(
                "Initialized a new CFEngine Build project",
                non_interactive,
                [cfbs_filename()],
            )
        except CFBSGitError as e:
            print(str(e))
            os.unlink(cfbs_filename())
            return 1

    print("Initialized an empty project called '{}' in '{}'".format(
        name, cfbs_filename()))
    """
    The CFBSConfig instance was initally created in main(). Back then
    cfbs.json did not exist, thus the instance is empty. Ensure it is reloaded
    now that the JSON exists.
    """
    CFBSConfig.reload()

    if prompt_user(
            "Do you wish to build on top of the default policy set, masterfiles? (Recommended)",
            choices=YES_NO_CHOICES,
            default="yes",
    ) in ("yes", "y"):
        to_add = "masterfiles"
    else:
        to_add = prompt_user(
            "Specify policy set to use instead (empty to skip)", default="")

    if to_add:
        return add_command([to_add])

    return 0