Exemple #1
0
    def add_sidebars(self, pagename, ctx):
        def has_wildcard(pattern):
            return any(char in pattern for char in '*?[')

        sidebars = None
        matched = None
        customsidebar = None
        for pattern, patsidebars in self.config.html_sidebars.iteritems():
            if patmatch(pagename, pattern):
                if matched:
                    if has_wildcard(pattern):
                        # warn if both patterns contain wildcards
                        if has_wildcard(matched):
                            self.warn('page %s matches two patterns in '
                                      'html_sidebars: %r and %r' %
                                      (pagename, matched, pattern))
                        # else the already matched pattern is more specific
                        # than the present one, because it contains no wildcard
                        continue
                matched = pattern
                sidebars = patsidebars
        if sidebars is None:
            # keep defaults
            pass
        elif isinstance(sidebars, basestring):
            # 0.x compatible mode: insert custom sidebar before searchbox
            customsidebar = sidebars
            sidebars = None
        ctx['sidebars'] = sidebars
        ctx['customsidebar'] = customsidebar
Exemple #2
0
 def add_sidebars(self, pagename, ctx):
     def has_wildcard(pattern):
         return any(char in pattern for char in '*?[')
     sidebars = None
     matched = None
     customsidebar = None
     for pattern, patsidebars in iteritems(self.config.html_sidebars):
         if patmatch(pagename, pattern):
             if matched:
                 if has_wildcard(pattern):
                     # warn if both patterns contain wildcards
                     if has_wildcard(matched):
                         self.warn('page %s matches two patterns in '
                                   'html_sidebars: %r and %r' %
                                   (pagename, matched, pattern))
                     # else the already matched pattern is more specific
                     # than the present one, because it contains no wildcard
                     continue
             matched = pattern
             sidebars = patsidebars
     if sidebars is None:
         # keep defaults
         pass
     elif isinstance(sidebars, string_types):
         # 0.x compatible mode: insert custom sidebar before searchbox
         customsidebar = sidebars
         sidebars = None
     ctx['sidebars'] = sidebars
     ctx['customsidebar'] = customsidebar
Exemple #3
0
    def add_sidebars(self, pagename, ctx):
        # type: (str, Dict) -> None
        def has_wildcard(pattern):
            # type: (str) -> bool
            return any(char in pattern for char in '*?[')
        sidebars = None
        matched = None
        customsidebar = None

        # default sidebars settings for selected theme
        if self.theme.name == 'alabaster':
            # provide default settings for alabaster (for compatibility)
            # Note: this will be removed before Sphinx-2.0
            try:
                # get default sidebars settings from alabaster (if defined)
                theme_default_sidebars = self.theme.config.get('theme', 'sidebars')
                if theme_default_sidebars:
                    sidebars = [name.strip() for name in theme_default_sidebars.split(',')]
            except Exception:
                # fallback to better default settings
                sidebars = ['about.html', 'navigation.html', 'relations.html',
                            'searchbox.html', 'donate.html']
        else:
            theme_default_sidebars = self.theme.get_config('theme', 'sidebars', None)
            if theme_default_sidebars:
                sidebars = [name.strip() for name in theme_default_sidebars.split(',')]

        # user sidebar settings
        html_sidebars = self.get_builder_config('sidebars', 'html')
        for pattern, patsidebars in html_sidebars.items():
            if patmatch(pagename, pattern):
                if matched:
                    if has_wildcard(pattern):
                        # warn if both patterns contain wildcards
                        if has_wildcard(matched):
                            logger.warning(__('page %s matches two patterns in '
                                              'html_sidebars: %r and %r'),
                                           pagename, matched, pattern)
                        # else the already matched pattern is more specific
                        # than the present one, because it contains no wildcard
                        continue
                matched = pattern
                sidebars = patsidebars

        if sidebars is None:
            # keep defaults
            pass

        ctx['sidebars'] = sidebars
        ctx['customsidebar'] = customsidebar
Exemple #4
0
def bestmatch(patmap, source, default=None, param="source"):
    """return best match given a dictionary mapping glob pattersn -> values"""
    best = None
    best_rank = None
    for pattern in patmap:
        if not patmatch(pattern, source):
            continue
        cur_rank = _rank_pattern(pattern)
        if best is None or cur_rank < best_rank:
            best = pattern
            best_rank = cur_rank
        elif cur_rank == best_rank:
            raise KeyError("%s %r matches too many patterns: %r and %r" % (param, source, best, pattern))
    if best is None:
        return default
    else:
        return patmap[best]
Exemple #5
0
def bestmatch(patmap, source, default=None, param="source"):
    """return best match given a dictionary mapping glob pattersn -> values"""
    best = None
    best_rank = None
    for pattern in patmap:
        if not patmatch(pattern, source):
            continue
        cur_rank = _rank_pattern(pattern)
        if best is None or cur_rank < best_rank:
            best = pattern
            best_rank = cur_rank
        elif cur_rank == best_rank:
            raise KeyError("%s %r matches too many patterns: %r and %r" %
                           (param, source, best, pattern))
    if best is None:
        return default
    else:
        return patmap[best]
Exemple #6
0
def parse_toc_to_env(app: Sphinx, config: Config) -> None:
    """Parse the external toc file and store it in the Sphinx environment.

    Also, change the ``master_doc`` and add to ``exclude_patterns`` if necessary.
    """
    # TODO this seems to work in the tests, but I still want to double check
    external_toc_path = PurePosixPath(app.config["external_toc_path"])
    if not external_toc_path.is_absolute():
        path = Path(app.srcdir) / str(external_toc_path)
    else:
        path = Path(str(external_toc_path))
    if not path.exists():
        raise ExtensionError(f"[etoc] `external_toc_path` does not exist: {path}")
    if not path.is_file():
        raise ExtensionError(f"[etoc] `external_toc_path` is not a file: {path}")
    try:
        site_map = parse_toc_yaml(path)
    except Exception as exc:
        raise ExtensionError(f"[etoc] {exc}") from exc
    config.external_site_map = site_map

    # Update the master_doc to the root doc of the site map
    if config["master_doc"] != site_map.root.docname:
        logger.info("[etoc] Changing master_doc to '%s'", site_map.root.docname)
    config["master_doc"] = site_map.root.docname

    if config["external_toc_exclude_missing"]:
        # add files not specified in ToC file to exclude list
        new_excluded: List[str] = []
        already_excluded = Matcher(config["exclude_patterns"])
        for suffix in config["source_suffix"]:
            # recurse files in source directory, with this suffix, note
            # we do not use `Path.glob` here, since it does not ignore hidden files:
            # https://stackoverflow.com/questions/49862648/why-do-glob-glob-and-pathlib-path-glob-treat-hidden-files-differently
            for path_str in glob.iglob(
                str(Path(app.srcdir) / "**" / f"*{suffix}"), recursive=True
            ):
                path = Path(path_str)
                if not path.is_file():
                    continue
                posix = path.relative_to(app.srcdir).as_posix()
                posix_no_suffix = posix[: -len(suffix)]
                components = posix.split("/")
                if not (
                    # files can be stored with or without suffixes
                    posix in site_map
                    or posix_no_suffix in site_map
                    # ignore anything already excluded, we have to check against
                    # the file path and all its sub-directory paths
                    or any(
                        already_excluded("/".join(components[: i + 1]))
                        for i in range(len(components))
                    )
                    # don't exclude docnames matching globs
                    or any(patmatch(posix_no_suffix, pat) for pat in site_map.globs())
                ):
                    new_excluded.append(posix)
        if new_excluded:
            logger.info(
                "[etoc] Excluded %s extra file(s) not in toc", len(new_excluded)
            )
            logger.debug("[etoc] Excluded extra file(s) not in toc: %r", new_excluded)
            # Note, don't `extend` list, as it alters the default `Config.config_values`
            config["exclude_patterns"] = config["exclude_patterns"] + new_excluded