diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96aeb72..bdea3bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,19 +2,18 @@ name: ci on: [push, pull_request] jobs: + check-format: + runs-on: ubuntu-latest + steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 with: python-version: 3.8 - - name: Install Black - run: | - pip install black - - name: Run Black - run: | - black --check --diff . + - uses: pre-commit/action@v2.0.0 test: name: "Build (${{ matrix.os }} Python ${{ matrix.python-version }})" diff --git a/.gitignore b/.gitignore index 566ae34..5c70e0c 100644 --- a/.gitignore +++ b/.gitignore @@ -219,4 +219,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +# VS Code config +.vscode/ + # End of https://www.toptal.com/developers/gitignore/api/python,linux,windows,macos,visualstudiocode \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..84479e8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,22 @@ +# Install pre-commit hooks via +# pre-commit install + +repos: + + # - repo: git://github.com/pre-commit/pre-commit-hooks + # rev: v2.2.3 + # hooks: + # - id: check-json + # - id: check-yaml + # - id: end-of-file-fixer + # - id: trailing-whitespace + + # - repo: https://gitlab.com/pycqa/flake8 + # rev: 3.7.9 + # hooks: + # - id: flake8 + + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black diff --git a/sphinxext/rediraffe.py b/sphinxext/rediraffe.py index 509aed2..3278f3e 100644 --- a/sphinxext/rediraffe.py +++ b/sphinxext/rediraffe.py @@ -117,6 +117,10 @@ def build_redirects(app: Sphinx, exception: Union[Exception, None]) -> None: """ Build amd write redirects """ + try: + app.env.redirected + except AttributeError: + app.env.redirected = {} if exception != None: return @@ -208,6 +212,19 @@ def build_redirects(app: Sphinx, exception: Union[Exception, None]) -> None: build_redirect_from = Path(app.outdir) / redirect_from build_redirect_to = Path(app.outdir) / redirect_to + if ( + build_redirect_from.exists() + and src_redirect_from.as_posix() in app.env.redirected + ): + # if it is still pointing to the same source, continue + if ( + app.env.redirected[src_redirect_from.as_posix()] + == src_redirect_to.as_posix() + ): + continue + # otherwise remove and rewrite + build_redirect_from.unlink() + if build_redirect_from.exists(): logger.warning( f'{yellow("(broken)")} {redirect_from} redirects to {redirect_to} but {build_redirect_from} already exists!' @@ -240,6 +257,9 @@ def build_redirects(app: Sphinx, exception: Union[Exception, None]) -> None: logger.info( f'{green("(good)")} {redirect_from} {green("-->")} {redirect_to}' ) + app.env.redirected[ + src_redirect_from.as_posix() + ] = src_redirect_to.as_posix() class CheckRedirectsDiffBuilder(Builder): diff --git a/tests/test_ext.py b/tests/test_ext.py index 23512f9..52293a0 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -5,6 +5,7 @@ from sphinx.application import Sphinx from sphinx.errors import ExtensionError from pathlib import Path +import shutil import logging from conftest import rel2url @@ -27,6 +28,16 @@ def test_simple(self, app: Sphinx, ensure_redirect): assert app.statuscode == 0 ensure_redirect("another.html", "index.html") + @pytest.mark.sphinx("html", testroot="simple") + def test_simple_rebuild(self, app: Sphinx, ensure_redirect): + if Path(app.outdir).exists(): + shutil.rmtree(Path(app.outdir)) + app.build() + assert app.statuscode == 0 + app.build() + assert app.statuscode == 0 + ensure_redirect("another.html", "index.html") + @pytest.mark.sphinx("html", testroot="no_cycle") def test_no_cycle(self, app: Sphinx, ensure_redirect): app.build() @@ -210,6 +221,16 @@ def test_simple(self, app: Sphinx, ensure_redirect): assert app.statuscode == 0 ensure_redirect("another/index.html", "index.html") + @pytest.mark.sphinx("dirhtml", testroot="simple", freshenv=False) + def test_simple_rebuild(self, app: Sphinx, ensure_redirect): + if Path(app.outdir).exists(): + shutil.rmtree(Path(app.outdir)) + app.build() + assert app.statuscode == 0 + app.build() + assert app.statuscode == 0 + ensure_redirect("another/index.html", "index.html") + @pytest.mark.sphinx("dirhtml", testroot="no_cycle") def test_no_cycle(self, app: Sphinx, ensure_redirect): app.build() diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..512e8ed --- /dev/null +++ b/tox.ini @@ -0,0 +1,19 @@ +# To use tox, see https://tox.readthedocs.io +# Simply pip or conda install tox +# If you use conda, you may also want to install tox-conda +# then run `tox` or `tox -- {pytest args}` +# To run in parallel using `tox -p` (this does not appear to work for this repo) + +# To rebuild the tox environment, for example when dependencies change, use +# `tox -r` + +# Note: if the following error is encountered: `ImportError while loading conftest` +# then then deleting compiled files has been found to fix it: `find . -name \*.pyc -delete` + +[tox] +envlist = py{36,37,38} + +[testenv:py{36,37,38}] +; recreate = false +deps = -rtest-requirements.txt +commands = pytest {posargs}