Soporte de generadores RSS personalizados en Nikola

Nikola es un generador estático de sitios web. La enorme ventaja de que un sitio web sea estático es que se puede servir desde cualquier servidor web sin necesidad de emplear ninguna tecnología especial. No se ejecuta ningún código en el servidor, no hay base de datos. Toda la web consiste en ficheros estáticos en el disco duro. No hay nada que mantener en el servidor, problemas de seguridad de los que preocuparse, etc. Esto es especialmente importante en sitios web que deben ser longevos pero tienen pocos o ningún cambio y en los que no tenemos que mantener todo un stack software por los siglos de los siglos. Otra ventaja derivada es que al no depender de ninguna tecnología web podemos migrar la web de un servidor a otro sin necesitar ningún requisito especial en absoluto.

Un ejemplo de sitio web convertido a estático [1] para poder ser accesible por siempre jamás sin necesidad de tecnología concreta ni tener que preocuparse de la seguridad es la página web de la PyConES 2013.

[1] La web original se elaboró mediante Django, un framework web tradicional Pero una vez que se completó el evento, se añadieron los enlaces a las ponencias, etc., es una web que no se va a modificar nunca más. Mantener una pila Django permanentemente, preocupándonos de las actualizaciones de seguridad, necesitando personal especializado para mantenerla en funcionamiento, etc., es un coste inútil e injustificable. La web no emplea tecnología AJAX o similares, así que su conversión a estático con un simple comando wget fue tarea simple y apenas requirió ajustes manuales.

Naturalmente mantener un sitio web moderno modificando directamente ficheros estáticos es el servidor es poco práctico. Cambios como actualizar la fecha de copyright pueden suponer buscar y modificar miles de ficheros.

Nikola mantiene un sitio web mediante plantillas. Funciona en tu ordenador personal. Cuando haces una modificación a una plantilla, creas nuevas entradas, un cambio de reglas de estilo o lo que sea, ejecutas Nikola y te dará un directorio output con ficheros puramente estáticos que puedes subir a tu servidor web por FTP, RSYNC o similar.

El workflow de Nikola es muy flexible, soporta plugins, filtros, etc.

Esta flexibilidad, no obstante, no es completa. Hay algunas facetas no modificables y tristemente he de decir que la gente de Nikola se ha mostrado poco receptiva a mejorar esta cobertura. Un ejemplo es, por ejemplo, la gestión de los ficheros RSS. No existe una plantilla para personalizar los ficheros RSS.

Esto lo necesito, por ejemplo, para la web del calendario de eventos Python en España, porque me interesa que el RSS contenga la fecha de los eventos y no la fecha en la que fueron anunciados.

Al no tener una plantilla modificable lo que hice en su día es desactivar el componente RSS de Nikola y sustituirlo por uno mío propio. Los pasos fueron los siguientes:

  1. Busco el plugin RSS original de Nikola. Son dos ficheros, rss.plugin y rss.py. Típicamente lo tendremos en el directorio de instalación de Nikola, en el subdirectorio DIR_INSTALACIÓN/lib/pythonVERSION/site-packages/nikola/plugins/task.

  2. Copiamos los dos ficheros al directorio plugins de nuestro blog o sitio web.

  3. Modificamos el fichero rss.plugin:

    [Core]
    Name = generate_rss_jcea
    Module = rss
    
  4. Modificamos el fichero rss.py:

    --- ../../../../virtualenv-nikola/lib/python2.7/site-packages/nikola/plugins/task/rss.py    2014-05-28 14:46:21.000000000 +0200
    +++ rss.py  2014-05-29 00:11:53.809152689 +0200
    @@ -26,6 +26,8 @@
    
     from __future__ import unicode_literals, print_function
     import os
    +import calendar
    +import copy
     try:
         from urlparse import urljoin
     except ImportError:
    @@ -38,7 +40,7 @@
     class GenerateRSS(Task):
         """Generate RSS feeds."""
    
    -    name = "generate_rss"
    +    name = "generate_rss_jcea"
    
         def set_site(self, site):
             site.register_path_handler('rss', self.rss_path)
    @@ -75,13 +77,30 @@
                     posts = self.site.posts[:10]
                 else:
                     posts = [x for x in self.site.posts if x.is_translation_available(lang)][:10]
    +
                 for post in posts:
                     deps += post.deps(lang)
    
    +            # No debemos modificar los posts originales, porque
    +            # afectamos a pasos posteriores
    +            for i, post in enumerate(posts) :
    +                slug = post.meta[u'es'][u'slug']
    +                slug = slug[:slug.find('-')]
    +                dia = int(slug[-2:])
    +                anho = int(slug[:4])
    +                mes = calendar.month_name[int(slug[4:-2])]
    +                r = "%d de %s de %d" %(dia, mes, anho)
    +                post = copy.copy(post)  # Shallow copy
    +                posts[i] = post
    +                meta = post.meta.copy()  # Es un defaultdict
    +                meta[u'es'] = post.meta[u'es'].copy()  # Es un defaultdict
    +                post.meta = meta
    +                post.meta[u'es'][u'title'] += " (%s)" %r
    +
                 feed_url = urljoin(self.site.config['BASE_URL'], self.site.link("rss", None, lang).lstrip('/'))
    
                 yield {
    -                'basename': 'generate_rss',
    +                'basename': 'generate_rss_jcea',
                     'name': os.path.normpath(output_name),
                     'file_dep': deps,
                     'targets': [output_name],
    
  5. Ahora debemos indicarle a Nikola que desactive su plugin de generación RSS. En el fichero de configuración conf.py hacemos esto:

    DISABLED_PLUGINS = ["generate_rss"]
    

Estos pasos funcionaron perfectamente hasta la versión 7.0 de Nikola. A partir de esta versión no es posible desactivar el generador interno de ficheros RSS sin desactivar la generación completa de RSS, así que surge un conflicto entre el plugin interno y nuestra modificación.

Es necesario aplicar el siguiente parche para reactivar esta funcionalidad. Nikola versiones 7.0 y superiores:

--- nikola.py   2015-01-17 21:39:50.000000000 +0100
+++ /home/jcea/hg/virtualenv-nikola/lib/python2.7/site-packages/nikola/nikola.py2014-06-09 14:24:36.701459964 +0200
@@ -453,11 +453,13 @@

         # Disable RSS.  For a successful disable, we must have both the option
         # false and the plugin disabled through the official means.
-        if 'generate_rss' in self.config['DISABLED_PLUGINS']:
-            self.config['GENERATE_RSS'] = False

-        if not self.config['GENERATE_RSS'] and 'generate_rss' not in self.config['DISABLED_PLUGINS']:
-            self.config['DISABLED_PLUGINS'].append('generate_rss')
+        # JCEA: ver bug https://github.com/getnikola/nikola/issues/1307
+        #if 'generate_rss' in self.config['DISABLED_PLUGINS']:
+        #    self.config['GENERATE_RSS'] = False
+
+        #if not self.config['GENERATE_RSS'] and 'generate_rss' not in self.config['DISABLED_PLUGINS']:
+        #    self.config['DISABLED_PLUGINS'].append('generate_rss')

         # PRETTY_URLS defaults to enabling STRIP_INDEXES unless explicitly disabled
         if self.config.get('PRETTY_URLS') and 'STRIP_INDEXES' not in config:

Este tema se ha comentado en GitHub, sin éxito: #1307: Disabling plugin "generate_rss" precludes generating a RSS via a personal plugin.