1# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2#
3# SPDX-License-Identifier: Apache-2.0
4
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18
19# Mechanism to generate static HTML redirect pages in the output
20#
21# Uses redirect_template.html and the list of pages given in
22# conf.html_redirect_pages
23#
24# Adapted from ideas in https://tech.signavio.com/2017/managing-sphinx-redirects
25import os.path
26
27from sphinx.builders.html import StandaloneHTMLBuilder
28from sphinx.util import logging
29
30logger = logging.getLogger(__name__)
31
32REDIRECT_TEMPLATE = r"""
33<html>
34  <head>
35    <meta http-equiv="refresh" content="0; url=$NEWURL" />
36    <script>
37     var id=window.location.href.split("#")[1];
38
39     if (id && (/^[a-zA-Z\:\/0-9\_\-\.]+$/.test(id))) {
40        window.location.href = "$NEWURL"+"#"+id;
41        }
42     else {
43        window.location.href = "$NEWURL";
44     };
45    </script>
46  </head>
47  <body>
48  <p>Page has moved <a href="$NEWURL">here</a>.</p>
49  </body>
50</html>
51"""
52
53
54def setup(app):
55    app.add_config_value('html_redirect_pages', [], 'html')
56    app.connect('build-finished', create_redirect_pages)
57
58    # Since we're just setting up a build-finished hook, which runs
59    # after both reading and writing, this extension is safe for both.
60    return {
61        'parallel_read_safe': True,
62        'parallel_write_safe': True,
63    }
64
65
66def create_redirect_pages(app, exception):
67    if not isinstance(app.builder, StandaloneHTMLBuilder):
68        return  # only relevant for standalone HTML output
69
70    for (old_url, new_url) in app.config.html_redirect_pages:
71        if old_url.startswith('/'):
72            old_url = old_url[1:]
73
74        # check that new_url is a valid docname, or if not that it is at least
75        # covered as the "old" part of another redirect rule
76        if new_url not in app.env.all_docs and not any(
77            old == new_url for (old, _) in app.config.html_redirect_pages
78        ):
79            logger.warning(
80                f"{new_url} is not a valid destination for a redirect."
81                "Check that both the source and destination are complete docnames."
82            )
83
84        new_url = app.builder.get_relative_uri(old_url, new_url)
85        out_file = app.builder.get_outfilename(old_url)
86
87        out_dir = os.path.dirname(out_file)
88        if not os.path.exists(out_dir):
89            os.makedirs(out_dir)
90
91        content = REDIRECT_TEMPLATE.replace("$NEWURL", new_url)
92
93        if not os.path.exists(out_file):
94            with open(out_file, "w") as rp:
95                rp.write(content)
96