chiark / gitweb /
plugins: new plugin m.alias.
authorVladimír Vondruš <mosra@centrum.cz>
Sun, 6 May 2018 12:33:47 +0000 (14:33 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Sun, 6 May 2018 13:03:00 +0000 (15:03 +0200)
12 files changed:
doc/plugins.rst
doc/plugins/links.rst
doc/plugins/math-and-code.rst
doc/plugins/metadata.rst
pelican-plugins/m/alias.py [new file with mode: 0644]
pelican-plugins/m/test/alias/articles/article.rst [new file with mode: 0644]
pelican-plugins/m/test/alias/blog/old-article/index.html [new file with mode: 0644]
pelican-plugins/m/test/alias/even-older-page.html [new file with mode: 0644]
pelican-plugins/m/test/alias/old-page/index.html [new file with mode: 0644]
pelican-plugins/m/test/alias/page.rst [new file with mode: 0644]
pelican-plugins/m/test/test_alias.py [new file with mode: 0644]
site/pelicanconf.py

index 5386f1444d5cf651dc141af6859c5c146e0c7d37..b216fad34288906fa2e474a39865d4c89c552abd 100644 (file)
@@ -49,7 +49,8 @@ and restart Pelican. Download the plugins below or
     :gh:`m.dox <mosra/m.css$master/pelican-plugins/m/dox.py>`,
     :gh:`m.gl <mosra/m.css$master/pelican-plugins/m/gl.py>`,
     :gh:`m.abbr <mosra/m.css$master/pelican-plugins/m/abbr.py>`,
-    :gh:`m.filesize <mosra/m.css$master/pelican-plugins/m/filesize.py>`
+    :gh:`m.filesize <mosra/m.css$master/pelican-plugins/m/filesize.py>`,
+    :gh:`m.alias <mosra/m.css$master/pelican-plugins/m/alias.py>`
 -   :gh:`m.metadata <mosra/m.css$master/pelican-plugins/m/metadata.py>`
 
 Click on the headings below to get to know more. Note that particular plugins
@@ -85,12 +86,13 @@ rendering and syntax highlighting, so they are provided as separate packages
 that you can but don't have to use. With these, math and code snippets can be
 entered directly in your :abbr:`reST <reStructuredText>` sources.
 
-`Links » <{filename}/plugins/links.rst>`_
-=========================================
+`Links and other » <{filename}/plugins/links.rst>`_
+===================================================
 
-The :py:`m.gh`, :py:`m.dox`, :py:`m.gl`, :py:`m.abbr` and :py:`m.fiilesize`
-plugins make it easy for you to link to GitHub projects, issues or PRs, to
-Doxygen documentation and do more useful things.
+The :py:`m.gh`, :py:`m.dox`, :py:`m.gl`, :py:`m.abbr`, :py:`m.fiilesize` and
+:py:`m.alias` plugins make it easy for you to link to GitHub projects, issues
+or PRs, to Doxygen documentation, query file sizes and provide URL aliases to
+preserve link compatibility.
 
 `Metadata » <{filename}/plugins/metadata.rst>`_
 ===============================================
index 329229cefa7c800230555b140e76c1c7c88d98c0..a9fb8899e3fd4ff7760ccf34d541342f3b2447e9 100644 (file)
     DEALINGS IN THE SOFTWARE.
 ..
 
-Links
-#####
+Links and other
+###############
 
 :breadcrumb: {filename}/plugins.rst Pelican plugins
 :footer:
     .. note-dim::
         :class: m-text-center
 
-        `« Math and code <{filename}/plugins/math-and-code.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_
+        `« Math and code <{filename}/plugins/math-and-code.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Metadata » <{filename}/plugins/metadata.rst>`_
 
 .. role:: py(code)
     :language: py
@@ -262,3 +262,44 @@ first before calculating the size.
     :filesize:`{filename}/../css/m-dark.compiled.css` but only
     :filesize-gz:`{filename}/../css/m-dark.compiled.css` when the server
     sends it compressed.
+
+`Aliases`_
+==========
+
+Site content almost never stays on the same place for extended periods of time
+and preserving old links for backwards compatibility is a vital thing for user
+friendliness. This plugin allows you to create a redirect alias URLs for your
+pages and articles.
+
+Download the `m/alias.py <{filename}/plugins.rst>`_ file, put it
+including the ``m/`` directory into one of your :py:`PLUGIN_PATHS` and add
+:py:`m.alias` package to your :py:`PLUGINS` in ``pelicanconf.py``. This plugin
+assumes presence of `m.htmlsanity <{filename}/plugins/htmlsanity.rst>`_.
+
+.. code:: python
+
+    PLUGINS += ['m.htmlsanity', 'm.alias']
+
+.. note-success::
+
+    This plugin is loosely inspired by :gh:`Nitron/pelican-alias`, © 2013
+    Christopher Williams, licensed under
+    :gh:`MIT <Nitron/pelican-alias$master/LICENSE.txt>`.
+
+Use the :rst:`:alias:` field to specify one or more locations that should
+redirect to your article / page. Each line is treated as one alias, the
+locations have to begin with ``/`` and are relative to the Pelican output
+directory, each of them contains just a :html:`<meta http-equiv="refresh" />`
+that points to a fully-qualified URL of the article or page.
+
+If the alias ends with ``/``, the redirector file is saved into ``index.html``
+in given directory.
+
+.. code:: rst
+
+    My Article
+    ##########
+
+    :alias:
+        /2018/05/06/old-version-of-the-article/
+        /even-older-version-of-the-article.html
index 36f7da029c3c66589e437172e52845e25f087eb7..a3210ea650c6e8da928862c1ec077e93c83feda5 100644 (file)
@@ -30,7 +30,7 @@ Math and code
     .. note-dim::
         :class: m-text-center
 
-        `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Links » <{filename}/plugins/links.rst>`_
+        `« Images <{filename}/plugins/images.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_ | `Links and other » <{filename}/plugins/links.rst>`_
 
 .. role:: css(code)
     :language: css
index 5c0878ad0fd01cc74e47ed87c39bfdb05b816273..1a65e2eedf3e0d235f06d7fc52ccdab44c3e1157 100644 (file)
@@ -32,7 +32,7 @@ Metadata
     .. note-dim::
         :class: m-text-center
 
-        `« Links <{filename}/plugins/links.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_
+        `« Links and other <{filename}/plugins/links.rst>`_ | `Pelican plugins <{filename}/plugins.rst>`_
 
 .. role:: html(code)
     :language: html
diff --git a/pelican-plugins/m/alias.py b/pelican-plugins/m/alias.py
new file mode 100644 (file)
index 0000000..c4e96fc
--- /dev/null
@@ -0,0 +1,69 @@
+#
+#   This file is part of m.css.
+#
+#   Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+#
+#   Loosely based on https://github.com/Nitron/pelican-alias,
+#   copyright © 2013 Christopher Williams
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+
+import os
+import logging
+from pelican import signals
+
+from m.htmlsanity import format_siteurl
+
+logger = logging.getLogger(__name__)
+
+class AliasGenerator:
+    def __init__(self, context, settings, path, theme, output_path, *args):
+        self.output_path = output_path
+        self.context = context
+
+    def generate_output(self, writer):
+        for page in self.context['pages'] + self.context['articles']:
+            aliases = page.metadata.get('alias', '').strip()
+            if not aliases: continue
+            for alias in aliases.split('\n'):
+                alias = alias.strip()
+
+                # Currently only supporting paths starting with /
+                if not alias.startswith('/'): assert False
+                path = os.path.join(self.output_path, alias[1:])
+
+                # If path ends with /, write it into index.html
+                directory, filename = os.path.split(path)
+                if not filename: filename = 'index.html'
+
+                alias_file = os.path.join(directory, filename)
+                alias_target = format_siteurl(page.url)
+                logger.info('m.alias: creating alias {} -> {}'.format(alias_file[len(self.output_path):], alias_target))
+
+                # Write the redirect file
+                os.makedirs(directory, exist_ok=True)
+                with open(alias_file, 'w') as f:
+                    f.write("""<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url={}" /></head></html>\n""".format(alias_target))
+
+def get_generators(generators): return AliasGenerator
+
+def register():
+    # TODO: why `lambda generators: AliasGenerator` doesn't work?
+    signals.get_generators.connect(get_generators)
diff --git a/pelican-plugins/m/test/alias/articles/article.rst b/pelican-plugins/m/test/alias/articles/article.rst
new file mode 100644 (file)
index 0000000..bec8fd5
--- /dev/null
@@ -0,0 +1,5 @@
+An Article
+##########
+
+:date: 2018-05-06
+:alias: /blog/old-article/
diff --git a/pelican-plugins/m/test/alias/blog/old-article/index.html b/pelican-plugins/m/test/alias/blog/old-article/index.html
new file mode 100644 (file)
index 0000000..356c5b3
--- /dev/null
@@ -0,0 +1,2 @@
+<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=http://my.site/article.html" /></head></html>
+
diff --git a/pelican-plugins/m/test/alias/even-older-page.html b/pelican-plugins/m/test/alias/even-older-page.html
new file mode 100644 (file)
index 0000000..529cb89
--- /dev/null
@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=http://my.site/page.html" /></head></html>
diff --git a/pelican-plugins/m/test/alias/old-page/index.html b/pelican-plugins/m/test/alias/old-page/index.html
new file mode 100644 (file)
index 0000000..529cb89
--- /dev/null
@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=http://my.site/page.html" /></head></html>
diff --git a/pelican-plugins/m/test/alias/page.rst b/pelican-plugins/m/test/alias/page.rst
new file mode 100644 (file)
index 0000000..48483a3
--- /dev/null
@@ -0,0 +1,6 @@
+A page
+######
+
+:alias:
+    /old-page/
+    /even-older-page.html
diff --git a/pelican-plugins/m/test/test_alias.py b/pelican-plugins/m/test/test_alias.py
new file mode 100644 (file)
index 0000000..9f18135
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#   This file is part of m.css.
+#
+#   Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+
+from m.test import PluginTestCase
+
+class Alias(PluginTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, '', *args, **kwargs)
+
+    def test(self):
+        self.run_pelican({
+            'PLUGINS': ['m.htmlsanity', 'm.alias'],
+            'SITEURL': 'http://my.site'
+        })
+
+        self.assertEqual(*self.actual_expected_contents('old-page/index.html'))
+        self.assertEqual(*self.actual_expected_contents('even-older-page.html'))
+        self.assertEqual(*self.actual_expected_contents('blog/old-article/index.html'))
index 18755760b9f9c69aead35a20f76f53fead8be3cd..226f3614833b8bdd348e322dae9357e98f6d5089 100644 (file)
@@ -87,7 +87,7 @@ M_LINKS_NAVBAR2 = [('Pelican plugins', 'plugins/', 'plugins', [
                         ('Components', 'plugins/components/', 'plugins/components'),
                         ('Images', 'plugins/images/', 'plugins/images'),
                         ('Math and code', 'plugins/math-and-code/', 'plugins/math-and-code'),
-                        ('Links', 'plugins/links/', 'plugins/links'),
+                        ('Links and other', 'plugins/links/', 'plugins/links'),
                         ('Metadata', 'plugins/metadata/', 'plugins/metadata')]),
                    ('Doxygen theme', 'doxygen/', 'doxygen', []),
                    ('GitHub', 'https://github.com/mosra/m.css', '', [])]
@@ -118,7 +118,7 @@ M_LINKS_FOOTER4 = [('Pelican plugins', 'plugins/'),
                    ('Components', 'plugins/components/'),
                    ('Images', 'plugins/images/'),
                    ('Math and code', 'plugins/math-and-code/'),
-                   ('Links', 'plugins/links/'),
+                   ('Links and other', 'plugins/links/'),
                    ('Metadata', 'plugins/metadata/')]
 
 M_FINE_PRINT = """