Esempio n. 1
0
def _expand_virtual_root(
    repo: IConfigRepository,
    root: DefaultsTreeNode,
    overrides: Overrides,
    skip_missing: bool,
) -> DefaultsTreeNode:
    children: List[Union[DefaultsTreeNode, InputDefault]] = []
    assert root.children is not None
    for d in reversed(root.children):
        assert isinstance(d, InputDefault)
        new_root = DefaultsTreeNode(node=d, parent=root)
        d.update_parent("", "")

        subtree = _create_defaults_tree_impl(
            repo=repo,
            root=new_root,
            is_root_config=d.primary,
            skip_missing=skip_missing,
            interpolated_subtree=False,
            overrides=overrides,
        )
        if subtree.children is None:
            children.append(d)
        else:
            children.append(subtree)

    if len(children) > 0:
        root.children = list(reversed(children))

    return root
Esempio n. 2
0
def _create_defaults_tree_impl(
    repo: IConfigRepository,
    root: DefaultsTreeNode,
    is_root_config: bool,
    skip_missing: bool,
    interpolated_subtree: bool,
    overrides: Overrides,
) -> DefaultsTreeNode:
    parent = root.node
    children: List[Union[InputDefault, DefaultsTreeNode]] = []
    if parent.is_virtual():
        if is_root_config:
            return _expand_virtual_root(repo, root, overrides, skip_missing)
        else:
            return root

    if is_root_config:
        root.node.update_parent("", "")
        if not repo.config_exists(root.node.get_config_path()):
            config_not_found_error(repo=repo, tree=root)

    update_package_header(repo=repo, node=parent)

    if overrides.is_deleted(parent):
        overrides.delete(parent)
        return root

    overrides.set_known_choice(parent)

    if parent.get_name() is None:
        return root

    if _check_not_missing(repo=repo, default=parent,
                          skip_missing=skip_missing):
        return root

    path = parent.get_config_path()
    loaded = repo.load_config(config_path=path)

    if loaded is None:
        if parent.is_optional():
            assert isinstance(parent, (GroupDefault, ConfigDefault))
            parent.deleted = True
            return root
        config_not_found_error(repo=repo, tree=root)

    assert loaded is not None
    defaults_list = copy.deepcopy(loaded.defaults_list)
    if defaults_list is None:
        defaults_list = []

    self_added = False
    if (len(defaults_list) > 0
            or is_root_config and len(overrides.append_group_defaults) > 0):
        self_added = _validate_self(containing_node=parent,
                                    defaults=defaults_list)

    if is_root_config:
        # To ensure config overrides are last, insert the external overrides before the first config override.
        insert_idx = len(defaults_list)
        for idx, default in enumerate(defaults_list):
            if default.is_override():
                insert_idx = idx
                break

        defaults_list[insert_idx:insert_idx] = overrides.append_group_defaults

    _update_overrides(defaults_list, overrides, parent, interpolated_subtree)

    def add_child(
        child_list: List[Union[InputDefault, DefaultsTreeNode]],
        new_root_: DefaultsTreeNode,
    ) -> None:
        subtree_ = _create_defaults_tree_impl(
            repo=repo,
            root=new_root_,
            is_root_config=False,
            interpolated_subtree=interpolated_subtree,
            skip_missing=skip_missing,
            overrides=overrides,
        )
        if subtree_.children is None:
            child_list.append(new_root_.node)
        else:
            child_list.append(subtree_)

    for d in reversed(defaults_list):
        if d.is_self():
            d.update_parent(root.node.parent_base_dir, root.node.get_package())
            children.append(d)
        else:
            if d.is_override():
                continue

            d.update_parent(parent.get_group_path(),
                            parent.get_final_package())

            if overrides.is_overridden(d):
                assert isinstance(d, GroupDefault)
                overrides.override_default_option(d)

            if isinstance(d, GroupDefault) and d.is_options():
                # overriding may change from options to name
                if d.is_options():
                    for item in reversed(d.get_options()):
                        if "${" in item:
                            raise ConfigCompositionException(
                                f"In '{path}': Defaults List interpolation is not supported in options list items"
                            )

                        assert d.group is not None
                        node = ConfigDefault(
                            path=d.group + "/" + item,
                            package=d.package,
                            optional=d.is_optional(),
                        )
                        node.update_parent(parent.get_group_path(),
                                           parent.get_final_package())
                        new_root = DefaultsTreeNode(node=node, parent=root)
                        add_child(children, new_root)
                else:
                    new_root = DefaultsTreeNode(node=d, parent=root)
                    add_child(children, new_root)

            else:
                if d.is_interpolation():
                    children.append(d)
                    continue

                new_root = DefaultsTreeNode(node=d, parent=root)
                add_child(children, new_root)

    # processed deferred interpolations
    known_choices = _create_interpolation_map(overrides, defaults_list,
                                              self_added)

    for idx, dd in enumerate(children):
        if isinstance(dd, InputDefault) and dd.is_interpolation():
            dd.resolve_interpolation(known_choices)
            new_root = DefaultsTreeNode(node=dd, parent=root)
            dd.update_parent(parent.get_group_path(),
                             parent.get_final_package())
            subtree = _create_defaults_tree_impl(
                repo=repo,
                root=new_root,
                is_root_config=False,
                skip_missing=skip_missing,
                interpolated_subtree=True,
                overrides=overrides,
            )
            if subtree.children is not None:
                children[idx] = subtree

    if len(children) > 0:
        root.children = list(reversed(children))

    return root
Esempio n. 3
0
def _create_defaults_tree_impl(
    repo: IConfigRepository,
    root: DefaultsTreeNode,
    is_root_config: bool,
    skip_missing: bool,
    interpolated_subtree: bool,
    overrides: Overrides,
) -> DefaultsTreeNode:
    parent = root.node
    children: List[Union[InputDefault, DefaultsTreeNode]] = []
    if parent.is_virtual():
        if is_root_config:
            return _expand_virtual_root(repo, root, overrides, skip_missing)
        else:
            return root
    else:
        if is_root_config:
            root.node.update_parent("", "")

        if is_root_config:
            if not repo.config_exists(root.node.get_config_path()):
                config_not_found_error(repo=repo, tree=root)

        update_package_header(repo=repo, node=parent)

        if overrides.is_overridden(parent):
            assert isinstance(parent, GroupDefault)
            overrides.override_default_option(parent)
            # clear package header and obtain updated one from overridden config
            # (for the rare case it has changed)
            parent.package_header = None
            update_package_header(repo=repo, node=parent)

        if overrides.is_deleted(parent):
            overrides.delete(parent)
            return root

        overrides.set_known_choice(parent)

        if parent.get_name() is None:
            return root

        if _check_not_missing(repo=repo,
                              default=parent,
                              skip_missing=skip_missing):
            return root

        path = parent.get_config_path()
        loaded = repo.load_config(config_path=path)

        if loaded is None:
            if parent.is_optional():
                assert isinstance(parent, GroupDefault)
                parent.deleted = True
                return root
            config_not_found_error(repo=repo, tree=root)

        assert loaded is not None
        defaults_list = copy.deepcopy(loaded.defaults_list)
        if defaults_list is None:
            defaults_list = []

        self_added = False
        if (len(defaults_list) > 0 or is_root_config
                and len(overrides.append_group_defaults) > 0):
            self_added = _validate_self(containing_node=parent,
                                        defaults=defaults_list)

        if is_root_config:
            defaults_list.extend(overrides.append_group_defaults)

        _update_overrides(defaults_list, overrides, parent,
                          interpolated_subtree)

        for d in reversed(defaults_list):
            if d.is_self():
                d.update_parent(root.node.parent_base_dir,
                                root.node.get_package())
                children.append(d)
            else:
                if d.is_override():
                    continue
                new_root = DefaultsTreeNode(node=d, parent=root)
                d.update_parent(parent.get_group_path(),
                                parent.get_final_package())

                if d.is_interpolation():
                    children.append(d)
                    continue

                subtree = _create_defaults_tree_impl(
                    repo=repo,
                    root=new_root,
                    is_root_config=False,
                    interpolated_subtree=interpolated_subtree,
                    skip_missing=skip_missing,
                    overrides=overrides,
                )
                if subtree.children is None:
                    children.append(d)
                else:
                    children.append(subtree)

        # processed deferred interpolations
        known_choices = _create_interpolation_map(overrides, defaults_list,
                                                  self_added)

        for idx, dd in enumerate(children):
            if isinstance(dd, InputDefault) and dd.is_interpolation():
                if not parent.primary:
                    # Interpolations from nested configs would require much more work
                    # If you have a compelling use case please file an feature request.
                    path = parent.get_config_path()
                    raise ConfigCompositionException(
                        f"In '{path}': Defaults List interpolation is only supported in the primary config"
                    )
                dd.resolve_interpolation(known_choices)
                new_root = DefaultsTreeNode(node=dd, parent=root)
                dd.update_parent(parent.get_group_path(),
                                 parent.get_final_package())
                subtree = _create_defaults_tree_impl(
                    repo=repo,
                    root=new_root,
                    is_root_config=False,
                    skip_missing=skip_missing,
                    interpolated_subtree=True,
                    overrides=overrides,
                )
                if subtree.children is not None:
                    children[idx] = subtree

    if len(children) > 0:
        root.children = list(reversed(children))

    return root