joe di castrohttp://joedicastro.com2011-07-05T23:02:00+02:00Pelican - Repositorio2011-07-05T23:02:00+02:00joe di castrohttp://joedicastro.com/pelican-repositorio.html<p>Como complemento a la <a href="http://joedicastro.com/tag/pelican.html">serie de artículos</a> que he publicado sobre <a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a>,
el software que genera este blog, añado el repositorio, <a href="http://joedicastro.com/pelican-configuracion-y-personalizacion.html">como había prometido</a>,
del contenido del mismo. El repositorio empleaba el sistema de control de
versiones <a href="http://mercurial.selenic.com/">Mercurial</a> y estába alojado en <a href="https://bitbucket.org/">Bitbucket</a>.</p>
<p>Las ventajas de disponer del contenido del blog en un repositorio son las de
poder enmendar un error con suma facilidad y en muy poco tiempo, además de la de
poder trabajar con distintas versiones del mismo (pruebas y producción). Además
el repositorio en Bitbucket me proporcionaba una copia de seguridad adicional del
sitio sin esfuerzo alguno. Y si alguien está interesado en crear su propio blog
con Pelican y quiere saber como he realizado el mio, ahí tiene las claves. Salvo
el propio Pelican (que no tendría mucho sentido) todo el material empleado para
generarlo está en el. Y disponiendo del fichero <strong>fabric</strong>, se pueden descargar
Pelican e instalar el entorno virtual en un minuto. </p>
<p>Para automatizar todas las tareas, incluso las más comunes del repositorio, he
añadido al fichero fabric <em>fabfile.py</em> dos tareas más:</p>
<div class="codehilite"><pre><span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
<span class="sd">"""Make a commit to the local mercurial repository."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"hg add"</span><span class="p">)</span>
<span class="n">local</span><span class="p">(</span><span class="s">"hg commit -m '{0}'"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">message</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">push</span><span class="p">():</span>
<span class="sd">"""Make a push to the remote mercurial repository."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"hg push ssh://hg@bitbucket.org/joedicastro/joedicastro.com"</span><span class="p">)</span>
</pre></div>
<p>Con estas puedo hacer un <code>commit</code> y un <code>push</code> a Bitbucket en un solo paso, por
ejemplo:</p>
<div class="codehilite"><pre><span class="go">fab commit:"Añadido articulo: Pelican - Repositorio" push</span>
</pre></div>
<p>También he cambiado la página que generaba los archivos del blog, ya que no me
gustaba el formato anterior: una fecha, un articulo. He pasado de esto:</p>
<div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"><section id="content" class="body"></span>
<span class="x"><h1>Archivos de </span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="x"></h1></span>
<span class="x"><dl></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> <dt></span><span class="cp">{{</span> <span class="nv">article.locale_date</span> <span class="cp">}}</span><span class="x"></dt></span>
<span class="x"> <dd><a href='</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="x">'></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="x"></a></dd></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"></dl></span>
<span class="x"></section></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
<p>a esto:</p>
<div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"><section id="content" class="body"></span>
<span class="x"><h1>Archivos de </span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="x"></h1></span>
<span class="cp">{%</span>- <span class="k">set</span> <span class="nv">years_month</span> <span class="o">=</span> <span class="o">{}</span> -<span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span>- <span class="k">set</span> <span class="nv">months</span> <span class="o">=</span> <span class="o">{</span><span class="m">1</span><span class="s1">:'Enero'</span><span class="o">,</span> <span class="m">2</span><span class="s1">:'Febrero'</span><span class="o">,</span> <span class="m">3</span><span class="s1">:'Marzo'</span><span class="o">,</span> <span class="m">4</span><span class="s1">:'Abril'</span><span class="o">,</span> <span class="m">5</span><span class="s1">:'Mayo'</span><span class="o">,</span>
<span class="m">6</span><span class="s1">:'Junio'</span><span class="o">,</span> <span class="m">7</span><span class="s1">:'Julio'</span><span class="o">,</span> <span class="m">8</span><span class="s1">:'Agosto'</span><span class="o">,</span> <span class="m">9</span><span class="s1">:'Septiembre'</span><span class="o">,</span>
<span class="m">10</span><span class="s1">:'Octubre'</span><span class="o">,</span> <span class="m">11</span><span class="s1">:'Noviembre'</span><span class="o">,</span> <span class="m">12</span><span class="s1">:'Diciembre'</span><span class="o">}</span> -<span class="cp">%}</span><span class="x"> </span>
<span class="cp">{%</span>- <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">if</span> <span class="nv">article.date.year</span> <span class="k">not</span> <span class="k">in</span> <span class="nv">years_month</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">do</span> <span class="nv">years_month.update</span><span class="o">({</span><span class="nv">article.date.year</span><span class="o">:[</span><span class="nv">article.date.month</span><span class="o">]})</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">else</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">if</span> <span class="nv">article.date.month</span> <span class="k">not</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">article.date.year</span><span class="o">]</span> -<span class="cp">%}</span><span class="x"> </span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">do</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">article.date.year</span><span class="o">]</span><span class="nv">.append</span><span class="o">(</span><span class="nv">article.date.month</span><span class="o">)</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> -<span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">year</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">|</span><span class="nf">sort</span><span class="o">(</span><span class="nv">reverse</span><span class="o">=</span><span class="kp">True</span><span class="o">)</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> <h2 class="year"></span><span class="cp">{{</span> <span class="nv">year</span> <span class="cp">}}</span><span class="x"></h2><dl> </span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">month</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">year</span><span class="o">]</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> <dt class="month"></span><span class="cp">{{</span> <span class="nv">months</span><span class="o">[</span><span class="nv">month</span><span class="o">]</span> <span class="cp">}}</span><span class="x"></dt></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">article.date.year</span> <span class="o">==</span> <span class="nv">year</span> <span class="k">and</span> <span class="nv">article.date.month</span> <span class="o">==</span> <span class="nv">month</span> -<span class="cp">%}</span><span class="x"></span>
<span class="x"> <dd><span class="day"></span><span class="cp">{{</span> <span class="nv">article.locale_date.split</span><span class="o">()[</span><span class="m">1</span><span class="o">]</span> <span class="cp">}}</span><span class="x"></span> <a href='</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="x">'></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="x"></a></dd></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></dl></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"></section></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
<p>Donde los artículos están archivados por año, mes y día, con un formato que
personalmente me agrada bastante más.</p>
<p>El repositorio de este blog se puede encontrar en <a href="http://github.com/joedicastro/joedicastro.com">github</a>.</p>Pelican - Configuración y personalización2011-06-30T01:21:00+02:00joe di castrohttp://joedicastro.com/pelican-configuracion-y-personalizacion.html<p>Con este articulo cierro la serie que le he dedicado a <a href="http://joedicastro.com/tag/pelican.html">Pelican</a> como
herramienta idónea para crear blogs estáticos con mantenimiento cero. Aquí voy a
tratar de la parte más compleja de Pelican, la que nos permite personalizarlo y
adaptarlo a nuestros gustos y necesidades. El primer nivel de personalización se
obtiene a través del fichero de configuración (aunque no es necesario, es
recomendable emplearlo). El segundo nivel vendría mediante la personalización del
tema empleado, bien creando uno nuevo o bien modificando el que viene por
defecto. El último nivel vendría de modificar el propio Pelican. Todos son
posibles y están a nuestro alcance, gracias a que es Software Libre. </p>
<p>Si bien yo he personalizado mi sitio con respecto al sitio por defecto, y aún
quedan ciertas cosas que aún quiero cambiar, no he necesitado de momento más que
modificar el fichero de configuración y el tema que viene por defecto. En
Pelican no he tocado nada exceptuando el activar por defecto <strong>Markdown Extra</strong>,
algo que Alexis tuvo como gentileza <a href="https://github.com/ametaireau/pelican/pull/138">aceptar como modificación</a> a Pelican. Es
posible que en el futuro algunas de las cosas que tengo en mente me lleven a
modificarlo, y espero poder así contribuir en alguna medida a su desarrollo. </p>
<h2 id="configuraci+n">Configuración</h2>
<p>La configuración se hace a través de un fichero python, que en el ejemplo por
defecto se llama <code>pelican.conf.py</code> y en nuestro ejemplo estaría en
<em>myblog.com/site/pelican.conf.py</em>. Para llamar al fichero de configuración se
utiliza la opción <code>-s</code> y en nuestro ejemplo sería:</p>
<div class="codehilite"><pre><span class="gp">$</span> pelican -s ./site/pelican.conf.py
</pre></div>
<p>Este es un tema que está muy bien resuelto en la <a href="http://docs.notmyidea.org/alexis/pelican/settings.html">documentación</a>. De todos
modos voy a hablar de unos cuantos campos interesantes y alguno no incluido
dentro de la documentación. Entre paréntesis indico los valores por defecto.</p>
<ul>
<li>
<p><strong>OUTPUT_PATH</strong> (<code>'output/'</code>) y <strong>PATH</strong> (<code>None</code>)</p>
<p>Empleando estos dos valores, conseguimos que solo tengamos que especificar el
fichero de configuración en la linea de comandos empleada para llamar a Pelican.
El primero define el directorio de salida donde queremos que se genere nuestro
sitio y el segundo el directorio origen de nuestro contenido. </p>
</li>
<li>
<p><strong>SITESUBTITLE</strong> (<code>u''</code>)</p>
<p>Un subtitulo que se puede poner al blog, e.g. un lema. No aparece documentado.</p>
</li>
<li>
<p><strong>JINJA_EXTENSIONS</strong> (<code>[]</code>)</p>
<p>Puede ser necesario habilitar ciertas extensiones de Jinja2 para personalizar
el tema que vamos a emplear. Por ejemplo, para mostrar la nube de etiquetas
con las etiquetas ordenadas alfabéticamente, he habilitado una extensión que
necesitaba para el proceso de esta manera:</p>
<div class="codehilite"><pre><span class="n">JINJA_EXTENSIONS</span> <span class="o">=</span> <span class="p">[</span><span class="s">'jinja2.ext.do'</span><span class="p">]</span>
</pre></div>
</li>
<li>
<p><strong>STATIC_PATHS</strong> (<code>['images',]</code>)</p>
<p>Te permite especificar los contenidos estáticos que quieres añadir a tu blog
y que acabaran colgando de la carpeta <em>static</em>. Yo por ejemplo lo empleo
para alojar las imágenes en <em>static/pictures</em> y el mapa flash que utilizo en
el articulo <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">Combatir el spam en Drupal</a> en <em>static/ammap</em> así:</p>
<div class="codehilite"><pre><span class="n">STATIC_PATHS</span> <span class="o">=</span> <span class="p">[</span><span class="s">"pictures"</span><span class="p">,</span> <span class="s">"ammap"</span><span class="p">,</span> <span class="p">]</span>
</pre></div>
</li>
<li>
<p><strong>TAG_FEED</strong> (<code>None</code>) y <strong>TAG_FEED_RSS</strong> (<code>None</code>)</p>
<p>Te permiten establecer fuentes Atom y RSS por etiqueta, que es una opción
muy interesante para quienes solo les interesa un tema de los que trates o
para formar parte de un <a href="http://es.wikipedia.org/wiki/Planeta_%28agregador%29">Planet</a> sin mezclar temas. Eso si, lo lógico es
modificar luego el tema para que aparezcan disponibles. </p>
</li>
<li>
<p><strong>DIRECT_TEMPLATES</strong> (<code>('index', 'tags', 'categories', 'archives')</code>)</p>
<p>Estas son las plantillas del tema que generan una página por si mismas. No
viene documentada, pero yo he cambiado los valores por defecto para añadir
una página personalizada a la que redirijo los errores 404 (Página no
encontrada) de esta manera:</p>
<div class="codehilite"><pre><span class="n">DIRECT_TEMPLATES</span> <span class="o">=</span> <span class="p">(</span><span class="s">'index'</span><span class="p">,</span> <span class="s">'tags'</span><span class="p">,</span> <span class="s">'categories'</span><span class="p">,</span> <span class="s">'archives'</span><span class="p">,</span> <span class="s">'notfound'</span><span class="p">)</span>
</pre></div>
</li>
<li>
<p><strong>PIWIK_URL</strong> y <strong>PIWIK_SITE_ID</strong></p>
<p>Te permiten configurar tu sitio para emplear el magnifico sistema de
analíticas web <a href="http://piwik.org/">Piwik</a>. Yo hace unos dos años que lo empleo en mis sitios,
porque tiene la ventaja de que no dependes de un script de un dominio externo.
Esto te ahorra consultas DNS y que la página se quede esperando a cargar
completamente cuando estos fallan. De esta manera tienes el control total
sobre las estadísticas de tu web sin tener que renunciar a la calidad de
otros servicios externos.</p>
</li>
<li>
<p><strong>FILES_TO_COPY</strong> (<code>()</code>)</p>
<p>Básica si queremos emplear ficheros como <em>.htaccess</em> o <em>robots.txt</em>. No está
documentada tampoco. El uso de la misma consiste en una tupla de tuplas con
los valores de las rutas del fichero origen y su destino. En este sitio por
ejemplo:</p>
<div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">'extra/robots.txt'</span><span class="p">,</span> <span class="s">'robots.txt'</span><span class="p">),</span>
<span class="p">(</span><span class="s">'extra/favicon.ico'</span><span class="p">,</span> <span class="s">'favicon.ico'</span><span class="p">),</span>
<span class="p">(</span><span class="s">'extra/.htaccess'</span><span class="p">,</span> <span class="s">'.htaccess'</span><span class="p">),)</span>
</pre></div>
</li>
</ul>
<h2 id="personalizaci+n">Personalización</h2>
<p>Pero si realmente queremos personalizar el sitio, tanto en funcionalidad básica
como en su aspecto, nos toca modificar el tema por defecto. Aquí podemos optar por
tres vías: Crear el nuestro propio, empezar un tema casi desde cero,
eligiendo el tema por defecto <code>simple</code> (solo texto) o partir de la base del tema
por defecto <code>notmyidea</code>. Este último es el que hemos estado empleado en nuestro
ejemplo y el que yo modifiqué hasta llegar donde lo tengo ahora. </p>
<p>Para comprender de que consta un tema y como podemos personalizarlo, lo mejor es
analizar el tema <code>notmyidea</code>.</p>
<div class="codehilite"><pre><span class="go">notmyidea/</span>
<span class="go">├── static</span>
<span class="go">│ ├── css</span>
<span class="go">│ │ ├── main.css</span>
<span class="go">│ │ ├── pygment.css</span>
<span class="go">│ │ ├── reset.css</span>
<span class="go">│ │ └── wide.css</span>
<span class="go">│ └── images</span>
<span class="go">│ └── icons</span>
<span class="go">│ ├── delicious.png</span>
<span class="go">│ ├── lastfm.png</span>
<span class="go">│ ├── linkedin.png</span>
<span class="go">│ ├── rss.png</span>
<span class="go">│ └── twitter.png</span>
<span class="go">└── templates</span>
<span class="go"> ├── analytics.html</span>
<span class="go"> ├── archives.html</span>
<span class="go"> ├── article.html</span>
<span class="go"> ├── article_infos.html</span>
<span class="go"> ├── base.html</span>
<span class="go"> ├── categories.html</span>
<span class="go"> ├── category.html</span>
<span class="go"> ├── comments.html</span>
<span class="go"> ├── disqus_script.html</span>
<span class="go"> ├── github.html</span>
<span class="go"> ├── index.html</span>
<span class="go"> ├── page.html</span>
<span class="go"> ├── pagination.html</span>
<span class="go"> ├── piwik.html</span>
<span class="go"> ├── skribit_tab_script.html</span>
<span class="go"> ├── skribit_widget_script.html</span>
<span class="go"> ├── tag.html</span>
<span class="go"> ├── taglist.html</span>
<span class="go"> ├── tags.html</span>
<span class="go"> ├── translations.html</span>
<span class="go"> └── twitter.html</span>
</pre></div>
<ul>
<li>
<p><strong><em>static/css</em></strong></p>
<p>Aquí es donde se guardan las <a href="http://es.wikipedia.org/wiki/CSS">Hojas de estilo en cascada (CSS)</a> que emplea el
tema. Aunque la el fichero <em>wide.css</em> no es empleado por el tema, solo para la
versión wide del mismo. Yo la eliminé como primera medida. Luego tenemos
<em>main.css</em> que es la hoja de estilo principal, <em>pygment.css</em> que es la que emplea
Pygments para el resaltado de sintaxis y <em>reset.css</em> para resetear los navegadores
a unos valores comunes por defecto. </p>
<p>Si lo que queremos es tener un sitio con un buen rendimiento, deberíamos dar
como mínimo dos pasos, consolidar todas la hojas de estilo en una sola y
minimizar el tamaño de esta. Consolidarla en este caso es realmente sencillo,
simplemente debemos insertar el contenido de <em>reset.css</em> al principio del
fichero <em>main.css</em> y <em>pygment.css</em> al final del mismo. Depués hay que
eliminar los imports de estas hojas en <em>main.css</em>*. Luego para minimizar
su tamaño eliminar comentarios y lineas en blanco y poner una regla por línea. </p>
<p>Otro paso que dí para mejorar el rendimiento es no usar las web fonts
externas (ni internas), que aunque le dan un aspecto inmejorable, hay que
reconocerlo, requieren cargar otro recurso externo, desde mi punto de vista
innecesario.</p>
<p>Lo mejor en estos casos es seguir siempre las recomendaciones de estas dos
magnificas herramientas: <a href="http://developer.yahoo.com/yslow/">YSlow</a> de <strong>Yahoo</strong> y <a href="http://code.google.com/speed/page-speed/">Page Speed</a> de
<strong>Google</strong>. Afortunadamente hay sitios web como <a href="http://gtmetrix.com/">GTmetrix</a> o
<a href="http://www.webpagetest.org/">WebPagetest</a> que nos permiten ver los resultados de ambas herramientas
en nuestro sitio web sin necesidad de instalarlas (aunque para el desarrollo
es más que recomendable). Si por ejemplo emplearamos <strong>GTmetrix</strong> los valores
que arroja un sitio con el tema por defecto son:</p>
<table>
<thead>
<tr>
<th>Page Speed (tema por defecto)</th>
<th>YSlow (tema por defecto)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>B (80%)</strong></td>
<td><strong>B (85%)</strong></td>
</tr>
</tbody>
</table>
<p>Valores bastante mejorables. Los valores actuales para este sitio, una vez
personalizado el tema y configurado correctamente el <em>.htaccess</em> son:</p>
<table>
<thead>
<tr>
<th>Page Speed (tema personalizado)</th>
<th>YSlow (tema personalizado)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (91%)</strong></td>
<td><strong>A (95%)</strong></td>
</tr>
</tbody>
</table>
<p>Y si nos fijamos en <a href="http://gtmetrix.com/reports/joedicastro.com/BeFSzvAa">los resultados</a>, las penalizaciones de rendimiento
vienen de los scrips externos de Piwik y Disqus, principalmente de este
último. Sin emplear estos scripts los valores suben a:</p>
<table>
<thead>
<tr>
<th>Page Speed (sin scripts)</th>
<th>YSlow (sin scripts)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (100%)</strong></td>
<td><strong>A (98%)</strong></td>
</tr>
</tbody>
</table>
<p>En resumen, una optimización más que correcta, solo hay que ver los valores
de las páginas del Top 1000 que ofrecen en GTmetrix. Obtener una optimización
como esta con un CMS no es imposible (había conseguido unos valores solo un
poquito peores con Drupal) pero si bastante más complicado. La experiencia
del usuario depende mucho de estos valores, hay que contar con que no todo
el mundo dispone de buenos accesos a Internet.</p>
<p>Evidentemente, después cada uno retocara el fichero CSS resultante a su
gusto para personalizar el aspecto del sitio. En este caso estoy empleando
CSS 3 y valida correctamente. </p>
</li>
</ul>
<p style="text-align:center;">
<a href="http://jigsaw.w3.org/css-validator/validator?uri=http%3A%2F%2Fjoedicastro.com%2F&profile=css3&usermedium=all&warning=1&vextwarning=&lang=es">
<img style="border:0;width:88px;height:31px"
src="pictures/valid-css3.png"
alt="¡CSS 3 Válido!" title="¡CSS 3 Válido!" />
</a>
</p>
<ul>
<li>
<p><strong>static/images/icons</strong></p>
<p>Son los iconos empleados por la hoja de estilo para los enlaces sociales de
la parte inferior de la página. Yo no los empleo. ¿Entonces como se ven?
Bueno lo primero que hice fue crear un <a href="http://www.w3schools.com/css/css_image_sprites.asp">sprite</a> para cargar una sola
imagen en lugar de 6, es decir menos solicitudes al servidor. Después
incorporé esta imagen <a href="http://www.websiteoptimization.com/speed/tweak/inline-images/">dentro del propio fichero CSS con un Data URL</a>, y
gracias a haberla optimizado hasta ocupar solamente ~3k, me compensaba
hacerlo. Una consulta menos al servidor. Lo mismo hice después con el
logotipo (1K) y al final no se carga ninguna imagen por defecto en el blog,
0 consultas. Los navegadores modernos soportan esto sin problemas, los que
no lo hacen, no muestran la imagen, solo el enlace, que tampoco es un ningún
problema.</p>
<p>Así es como queda en <em>main.css</em> la imagen que da vida a los iconos de los
enlaces a la redes sociales:</p>
<div class="codehilite"><pre><span class="nf">#extras</span> <span class="nt">div</span><span class="o">[</span><span class="nt">class</span><span class="o">=</span><span class="s1">'social'</span><span class="o">]</span> <span class="nt">a</span><span class="p">{</span><span class="k">background-repeat</span><span class="o">:</span><span class="k">no-repeat</span><span class="p">;</span><span class="k">background-image</span><span class="o">:</span><span class="sx">url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACSCAMAAAB7VbqAAAAAwFBMVEWQBQCWFxU5VpedVy+tUE5LZaBPZZZDabDdYSpke75vfZBkfbJZgc+heztshKvldjBgld91j9+Uj4p5ksZ/lLzthzLqhz+MmrAcvuaDofihpYRzq/D4mDeUp9KetkSirsnQpKWpvV/qqHvHsJjnqY/3qWK1ubbIun2jwLHEu7xm1O+6xoOtv++7wte0yNzxwH563e/3xJjK06ya5vXY3p7U2+3e3tbm6IT63cLn7czr7fbZ9Prz7+r8+O/3+fb9//z6WVfkAAADNElEQVRIx9WV4XqiPBCFoyu4aVjQBrW2ImBX3aJYdQERIbn/u9qTRKzd7/n+b88jxHlnMswEY4hIGYUcLZYKklLbtixqNBymhNl2yG/2lBFqu1LKKjD2dEioxfIKKOfaVgA+HkoptsoGoDxPA8orKZTtEIdyNWE4zXEbUgVokAq4p1JuqQHIX8G9lYK2EdOpkNuhlJxec+TTrcxpJVENAOK3iK9oLkOLEmbqGQZ4dMAtRlJj617QZErQvqpHiVLVvvhL/y6oFx40HhktaqJt9X2mtSDwHg7L1p6NAJZY9eZwB8aHsgF61zaAnr8spXxX9piMR8umxAQQZBp5ZDTSOZYgzXjkKTCbvTeKNPLgKaCTK/dCNldQlu9wL0aNHH9XADnK2UGWXil/GoDJyFx6P69gNlPPWy698cIDWOj68DzvO+Qt0D7MsXcV2v86by55+qSEPP3+pKf/ARfxF5Dy8gH2+/0N7Pc3oCUMSJIWyESBRANxgX4nyQ1cEiMDEkR8BheT4jYl2bdJW5DsdczlA9z09N/2v86bw1Vs4vl8c6xbcI7ncQxkCBFFPM8a0QAfDTjOM70453lc630bx2ezXJt5oUARx40BmQF3EfFroXJs5gaU30inF+G3vombBnuu7JFer9OJ1JQMZcQ/SK8WEekRVRYqjb+RSMq60yHF8VzXRVHAWUsV0TZVIEekctzafEPKTnS/o+qog7z361FHkfhK/5ZV0MrnPAgqEvBWYZoGPCSt6aujLGScuC5j+LAdNkAVALCrUuVndwARvhoJs3C3WSXUFB8HjtW1LFxCvz3WtQC03Bw5fOsDdEPl794BPMW9Ap3DAMuyCc5nJQ2sO2AB+BgYCU1dCkwwhjjnfNUO8ycTl/lf6pxTtzzfQXl1BduXAQ5/7jiDl50CgcMnq6Ku69WEOQHAgD8+Pq5WbysMLle78tdq8jDR4oMc4HzKsuPuBRoMLKHB6+spG2hgrwCydQZpQH0NTmsgB/4BTVe1AphyNCBXoMk2p9MvB7bT1xEitB+eFXCch3WhSl/Z/T6dcMddr581KAD6fdd9fnyoTbdvrN93+v2uXbTt17sQyvV6/AE7UZJYs2UOngAAAABJRU5ErkJggg==")</span><span class="p">;</span><span class="k">padding-left</span><span class="o">:</span><span class="m">25px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'atom.xml'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">6px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'rss.xml'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-20px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'twitter.com'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-46px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'identi.ca'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-72px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'facebook.com'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-98px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'bitbucket.org'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-124px</span><span class="p">;}</span>
</pre></div>
</li>
<li>
<p><strong>static/templates</strong></p>
<p>Estas son las plantillas que dan vida al tema y emplean Jinja2. Los nombres
son bastante descriptivos de la función que realiza cada una de ellas. En mi
caso hay una serie de ellas que no empleo, como son: <em>analytics.html</em>,
<em>article_infos.html</em>, <em>github.html</em>, <em>skribit_tab_script.html</em>,
<em>skribit_widget_script.html</em>, <em>translations.html</em> y <em>twitter.html</em>. He
realizado bastantes modificaciones en las plantillas y me extendería demasiado
explicándolo, además sigo realizando cambios. Aún no lo tengo todo como yo
lo quiero, y aún voy a personalizar y optimizar más cosas. Cuando lo tenga
todo listo, pienso publicar un repositorio con el contenido que genera este
blog, tanto a efectos de copia de seguridad, como de que le pueda servir a
alguien como guía para montar el suyo propio. </p>
<p>De todos modos si puedo decir que he añadido una que no existía,
<em>notfound.html</em> para los errores 404 y pienso crear una nueva para los
errores 403. Además he creado los enlaces para los feeds RSS y Atom de las
etiquetas y eliminado el bloque de información que aparecía en cada articulo.
Además en la plantilla <em>tags.html</em> que por defecto viene vacía, he creado lo
necesario para generar la nube de etiquetas. <em>tags.html</em> queda entonces así:</p>
<div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="nt"><section</span> <span class="na">id=</span><span class="s">"content"</span> <span class="na">class=</span><span class="s">"body"</span><span class="nt">></span>
<span class="nt"><h1></span>etiquetas<span class="nt"></h1></span>
<span class="nt"><ul</span> <span class="na">id=</span><span class="s">"cloud"</span><span class="nt">></span>
<span class="cp">{%</span>- <span class="k">set</span> <span class="nv">all_tags</span> <span class="o">=</span> <span class="o">{}</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">ctag</span> <span class="k">in</span> <span class="nv">tag_cloud</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">do</span> <span class="nv">all_tags.update</span><span class="o">({</span><span class="nv">ctag.0</span><span class="o">:</span><span class="nv">ctag.1</span><span class="o">})</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">all_tags</span><span class="o">|</span><span class="nf">sort</span> <span class="cp">%}</span>
<span class="nt"><li</span> <span class="na">class=</span><span class="s">"tag-</span><span class="cp">{{</span> <span class="nv">all_tags</span><span class="o">[</span><span class="nv">tag</span><span class="o">]</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">><a</span> <span class="na">href=</span><span class="s">"tag/</span><span class="cp">{{</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">replace</span><span class="o">(</span><span class="s2">" "</span><span class="o">,</span> <span class="s2">"%20"</span><span class="o">)</span> <span class="cp">}}</span><span class="s">.html"</span><span class="nt">></span><span class="cp">{{</span> <span class="nv">tag</span> <span class="cp">}}</span><span class="nt"></a></li></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="nt"></ul></span>
<span class="nt"></section></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
<p>También he realizado las modificaciones pertinentes para que el contenido
validara perfectamente en HTML 5. </p>
</li>
</ul>
<p style="text-align:center;">
<a href="http://validator.w3.org/check?uri=http%3A%2F%2Fjoedicastro.com%2F">
<img style="border:0;width:88px;height:31px"
src="pictures/valid-html5.png"
alt="¡HTML 5 Válido!" title="¡HTML 5 Válido!" />
</a>
</p>
<p>Pero como ya he dicho es un proceso que aún no he finalizado. Cuando lo
termine y publique el repositorio, actualizaré también este articulo.</p>Pelican - Publicación y automatización2011-06-28T23:54:00+02:00joe di castrohttp://joedicastro.com/pelican-publicacion-y-automatizacion.html<p>Una vez que sabemos como <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">instalar Pelican</a> y <a href="http://joedicastro.com/pelican-creacion-de-contenido.html">crear contenido</a> con él, es
hora de saber como convertir ese contenido en un blog real disponible en
internet. Es decir, saber como publicar ese contenido. Como hemos visto hasta
ahora, al constar básicamente de simples ficheros HTML, un servidor de archivos
es más que suficiente para servir el blog. Esto nos abre un gran abanico de
posibilidades, desde emplear un potente (y barato) servidor de ficheros en la
<em>nube</em> como <strong>Amazon S3</strong>, pasando por las páginas web estáticas que nos
permiten repositorios como <strong>Bitbucket</strong> o <strong>GitHub</strong>, por los tradiciones
hostings compartidos (e.g. este blog), hasta un servidor casero sencillo
montado sobre un <a href="http://es.wikipedia.org/wiki/Network-attached_storage">NAS</a>. </p>
<p>Aún cuando es posible emplear un simple servidor de archivos para alojar el blog,
siempre es mejor contar con un servidor web detrás (Apache, nginx, lighttpd,
...) que nos permita hacer redirecciones para nuestras antiguas páginas si ya
disponíamos de un blog anterior o manejar los errores HTTP <a href="http://es.wikipedia.org/wiki/Error_404">404</a> o <a href="http://es.wikipedia.org/wiki/Anexo:C%C3%B3digos_de_estado_HTTP">403</a>
de forma personalizada. </p>
<h2 id="publicar_el_contenido">Publicar el contenido</h2>
<p>Publicar el contenido de una web es tan sencillo como volcar el contenido del
directorio que nos genera Pelican (en nuestro ejemplo sería
<em>myblog.com/site/output/*</em>) en el directorio destino de nuestro servidor web.
Dependiendo del método que hayamos elegido para alojar nuestro blog, puede ser
tan sencillo como una copia de archivos o emplear FTP (SFTP) ó <a href="http://es.wikipedia.org/wiki/SSH">SSH</a> (<a href="http://es.wikipedia.org/wiki/SCP">SCP</a>,
<a href="http://en.wikipedia.org/wiki/Unison_%28file_synchronizer%29">Unison</a> ó <a href="http://es.wikipedia.org/wiki/Rsync">rsync</a>). Aquí el tema radica no en la primera vez que
vayamos a subir el contenido al servidor, si no en las sucesivas, a medida que
vayamos creando contenido nuevo. No tendría ningún sentido volver a subir todo
el contenido cada vez, si no solamente el nuevo o el que haya cambiado. Para eso
necesitamos sincronizar los dos directorios. </p>
<p>Si solamente disponemos de acceso FTP (o SFTP) a nuestro servidor, entonces
tendremos que emplear una herramienta que nos permita la sincronización sobre
FTP, como puede ser <strong>lftp</strong>. Y el proceso se puede automatizar con un script
como el que describo en <a href="http://joedicastro.com/sincronizar-una-carpeta-local-y-una-remota-a-traves-de-ftp-lftp-mirror.html">Sincronizar una carpeta local y una remota a través de
FTP: lftp-mirror</a>. Si disponemos de acceso a través de SSH, entonces la
elección es clarisima, <strong>rsync</strong>. Más adelante explico una manera de emplearlo
de forma automática.</p>
<p>Cualquiera de ambas soluciones nos permite subir el contenido en apenas segundos,
(sobre todo en el caso de rsync) cuando se trata de añadir un articulo nuevo,
por ejemplo. Y lo mismo a la hora de hacer una rectificación, es tan inmediato
como lo pueden ser plataformas como Wordpress, Drupal y similares. Además, con
las potentes herramientas que existen para hacer cambios múltiples en varios
ficheros de texto a la vez, se pueden realizar tareas casi imposibles con una
plataforma de blogs tradicional sin recurrir a consultas SQL en la BDD o a
plugins externos. Una de estas herramientas, sin recurrir a <code>find</code>, <code>grep</code>,
<code>awk</code> y <code>sed</code>, puede ser <a href="http://regexxer.sourceforge.net/">regexxer</a>.</p>
<h2 id="generar_el_contenido_en_el_propio_servidor">Generar el contenido en el propio servidor</h2>
<p>Si el alojamiento que hemos escogido nos permite instalar programas python,
entonces tenemos la posibilidad de instalar Pelican en el servidor remoto. De
esta formar podríamos subir únicamente los archivos markdown o reStructuredText
al servidor y generar allí mismo el contenido web. De este modo la cantidad de
datos a subir sería ridícula y un simple comando FTP nos serviría. Luego bien
podríamos lanzar Pelican a través de una consola SSH o bien dependiendo del
servidor, tener un <a href="http://es.wikipedia.org/wiki/Demonio_%28inform%C3%A1tica%29">demonio</a> corriendo que cuando detectara un cambio en el
sistema de ficheros lanzará un script que generara el contenido con Pelican. </p>
<p>Otra posibilidad que me convence más, es de la poder instalar un repositorio en
el servidor con un software de control de versiones, como Git o Mercurial. La
idea sería tener un repositorio local, y al hacer un push hacia el repositorio
remoto, a través de un <em>hook</em> activar la generación de la página con Pelican.
Esto nos permitiría además poder tener varias copias del repositorio (por
ejemplo en GitHub o Bitbucket) y por lo tanto de la web, haciendo "innecesarias"
las copias de seguridad. </p>
<h2 id="automatizar_todos_los_procesos">Automatizar todos los procesos</h2>
<p>Pero lo ideal es poder automatizar todas las tareas que hemos visto hasta ahora,
empleando unos pocos comandos para realizarlas sin esfuerzo alguno (bueno,
a menos que tengas tú <a href="http://es.wikipedia.org/wiki/Negro_%28escritor%29">ghostwriter</a> particular, me temo que los artículos los
seguirás teniendo que escribir tú). Para poder realizar esto disponemos de la
fantástica y potente herramienta <a href="http://fabfile.org">Fabric</a> (el <a href="http://en.wikipedia.org/wiki/Capistrano">Capistrano</a> para Python)
que nos permite ejecutar comandos locales o remotos en múltiples servidores. Esto
nos permite hacer despliegues de software sin apenas esfuerzo en distintas
máquinas, copiar ficheros o ejecutar tareas repetitivas empleado una corta
serie de comandos. Una grandísima herramienta para administradores de sistema y
desarrolladores.</p>
<p>Lo único que necesitamos es instalar <strong>fabric</strong> y crear un fichero llamado
<code>fabfile.py</code> donde especificaremos las tareas que queremos programar. Para
instalar la última versión estable de fabric, lo mejor es emplear <code>easy_install</code>
o <code>pip</code></p>
<div class="codehilite"><pre><span class="gp">$</span> pip install fabric
</pre></div>
<p>Una vez creado el fichero <code>fabfile.py</code>, lo único que tendremos que hacer para
ejecutar una tarea del mismo, sería escribir el comando <code>fab</code> seguido del nombre
que le hayamos dado a la tarea (este sería el funcionamiento básico). Y la tarea
se ejecutaría inmediatamente. </p>
<p>Para comprender mejor como funciona Fabric, muestro aquí el contenido actual de
mi fichero <code>fabfile.py</code><br />
</p>
<div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># -*- coding: utf8 -*-</span>
<span class="sd">"""</span>
<span class="sd"> fabfile.py: A fabric script for generate my personal blog</span>
<span class="sd">"""</span>
<span class="n">__author__</span> <span class="o">=</span> <span class="s">"joe di castro <joe@joedicastro.com>"</span>
<span class="n">__license__</span> <span class="o">=</span> <span class="s">"GNU General Public License version 3"</span>
<span class="n">__date__</span> <span class="o">=</span> <span class="s">"28/06/2011"</span>
<span class="n">__version__</span> <span class="o">=</span> <span class="s">"0.2"</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">fabric.api</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">fabric.contrib.project</span> <span class="kn">import</span> <span class="n">rsync_project</span>
<span class="kn">from</span> <span class="nn">fabric.contrib.console</span> <span class="kn">import</span> <span class="n">confirm</span>
<span class="n">PELICAN_REPOSITORY</span> <span class="o">=</span> <span class="s">"git://github.com/ametaireau/pelican.git"</span>
<span class="n">PROD</span> <span class="o">=</span> <span class="s">"joedicastro.com"</span>
<span class="n">PROD_PATH</span> <span class="o">=</span> <span class="s">"/home/joedicastro/webapps/joedicastro"</span>
<span class="n">LOCAL_WEB</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">"~/www"</span><span class="p">,</span> <span class="n">PROD</span><span class="p">)</span>
<span class="n">ROOT_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">ENV_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"env"</span><span class="p">)</span>
<span class="n">PELICAN</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"pelican"</span><span class="p">)</span>
<span class="n">CONFIG_FILE</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/pelican.conf.py"</span><span class="p">)</span>
<span class="n">OUTPUT</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/output"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_valid_HTML</span><span class="p">():</span>
<span class="sd">"""Remove the obsolete rel="" and rev="" links in footnotes."""</span>
<span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">):</span>
<span class="k">for</span> <span class="n">fil</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="k">if</span> <span class="n">fil</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]</span> <span class="o">==</span> <span class="s">".html"</span><span class="p">:</span>
<span class="n">local</span><span class="p">(</span><span class="s">"sed -i {0} -r -e 's/re[l|v]=</span><span class="se">\"</span><span class="s">footnote</span><span class="se">\"</span><span class="s">//g' {0}"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fil</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">r"\ "</span><span class="p">))))</span>
<span class="k">def</span> <span class="nf">_make_env</span><span class="p">():</span>
<span class="sd">"""Make a virtual enviroment"""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"virtualenv {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_del_env</span><span class="p">():</span>
<span class="sd">"""Delete a virtual enviroment."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_clone_pelican</span><span class="p">():</span>
<span class="sd">"""Clone Pelican from repository."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"git clone {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">PELICAN_REPOSITORY</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_install</span><span class="p">():</span>
<span class="sd">"""Install Pelican in the virtual enviroment."""</span>
<span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span>
<span class="n">local</span><span class="p">(</span><span class="s">"{0}/bin/python setup.py install"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_browse</span><span class="p">():</span>
<span class="sd">"""Browse the local Apache site."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"firefox -new-window http://localhost/joedicastro.com 2>/dev/null &"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_gen</span><span class="p">(</span><span class="n">autoreload</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="sd">"""Generate the site from source."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"{0}/bin/pelican {2} -s {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">,</span> <span class="n">CONFIG_FILE</span><span class="p">,</span>
<span class="s">"-r"</span> <span class="k">if</span> <span class="n">autoreload</span> <span class="k">else</span> <span class="s">""</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_clean</span><span class="p">():</span>
<span class="s">"Remove the output folder."</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_local_deploy</span><span class="p">():</span>
<span class="sd">"""Deploy to the local apache web server."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">LOCAL_WEB</span><span class="p">))</span>
<span class="n">local</span><span class="p">(</span><span class="s">"cp -r {0} {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">,</span> <span class="n">LOCAL_WEB</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">pull_pelican</span><span class="p">():</span>
<span class="sd">"""Update Pelican to last revision from repository."""</span>
<span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span>
<span class="n">local</span><span class="p">(</span><span class="s">"git pull"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bootstrap</span><span class="p">():</span>
<span class="sd">"""Get Pelican and install it in a virtual enviroment."""</span>
<span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">_del_env</span><span class="p">()</span>
<span class="n">_make_env</span><span class="p">()</span>
<span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">_clone_pelican</span><span class="p">()</span>
<span class="n">_install</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">regen</span><span class="p">():</span>
<span class="sd">"""Regenerate the site from source."""</span>
<span class="n">_clean</span><span class="p">()</span>
<span class="n">_gen</span><span class="p">()</span>
<span class="n">_valid_HTML</span><span class="p">()</span>
<span class="n">_local_deploy</span><span class="p">()</span>
<span class="nd">@hosts</span><span class="p">(</span><span class="s">"my_user@"</span> <span class="o">+</span> <span class="n">PROD</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">publish</span><span class="p">():</span>
<span class="sd">"""Publish into remote web server with rsync."""</span>
<span class="n">regen</span><span class="p">()</span>
<span class="n">_browse</span><span class="p">()</span>
<span class="k">if</span> <span class="n">confirm</span><span class="p">(</span><span class="s">"¿Estas seguro de querer publicarlo?"</span><span class="p">):</span>
<span class="n">rsync_project</span><span class="p">(</span><span class="n">PROD_PATH</span><span class="p">,</span> <span class="n">OUTPUT</span> <span class="o">+</span> <span class="s">"/"</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="n">title</span><span class="p">):</span>
<span class="sd">"""Create a new blog article."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"gedit --new-window {0}/site/source/blog/{1}.md 2>/dev/null &"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="n">title</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">"\ "</span><span class="p">)))</span>
<span class="n">local</span><span class="p">(</span><span class="s">"firefox --new-window {0}/index.html &"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span>
<span class="n">_gen</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">img4web</span><span class="p">(</span><span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s">""</span><span class="p">):</span>
<span class="sd">"""Optimize .jpg & .png images and copy them into source pictures dir."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"./img4web.py -d {0} {1} {2}"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/source/pictures"</span><span class="p">),</span>
<span class="s">"--delete"</span> <span class="k">if</span> <span class="n">delete</span> <span class="k">else</span> <span class="s">""</span><span class="p">,</span>
<span class="s">"-s {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">)</span> <span class="k">if</span> <span class="n">source</span> <span class="k">else</span> <span class="s">""</span><span class="p">))</span>
</pre></div>
<p>Ahora, veremos el funcionamiento básico que nos permite este script. Primero
vemos las tareas que tenemos disponibles:</p>
<div class="codehilite"><pre><span class="gp">$</span> fab -l
<span class="go"> fabfile.py: A fabric script for generate my personal blog</span>
<span class="go">Available commands:</span>
<span class="go"> bootstrap Get Pelican and install it in a virtual enviroment.</span>
<span class="go"> img4web Optimize .jpg & .png images and copy them into source pict...</span>
<span class="go"> new Create a new blog article.</span>
<span class="go"> publish Publish into remote server with rsync.</span>
<span class="go"> pull_pelican Update Pelican to last revision from repository.</span>
<span class="go"> regen Regenerate the site from source.</span>
</pre></div>
<p>Veamos que hacen cada una de ellas:</p>
<ul>
<li>
<p><strong><em>bootstrap</em></strong> Si observamos el código, veremos que lo hace es, en este orden:
eliminar cualquier entorno virtual previo, crear un entorno virtual nuevo,
descargar Pelican desde el repositorio (si no lo hemos hecho anteriormente) e
instalar Pelican dentro de este entorno virtual. Y todo esto en un solo paso, casi
todos los comandos que explicaba en <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican - Introducción e Instalación</a> con
solo teclear <code>fab bootstrap</code>. Así de fácil. Con este comando podemos tanto crear
una instalación de Pelican desde cero, como actualizar la instalación de Pelican
después de actualizar este a la última versión con <strong><em>pull-pelican</em></strong>. Siguiendo
con nuestro ejemplo, lo que haría este comando es crear los directorios <em>env</em> y
<em>pelican</em> dentro de <em>myblog.com</em> con el entorno virtual creado y pelican
instalado.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab bootstrap
</pre></div>
</li>
<li>
<p><strong><em>img4web</em></strong> Este comando hace uso del script que describía en <a href="http://joedicastro.com/optimizar-imagenes-para-la-web.html">Optimizar
imágenes para la web</a> para hacer precisamente eso, reducir el peso de las
imágenes que empleo en los artículos. Lo que hago es a medida que voy escribiendo
el articulo es ir guardando las imágenes en el directorio raíz (en nuestro
ejemplo, <em>myblog.com/</em>) y cuando lo termino, simplemente ejecuto el comando
<code>fab img4web</code> y este me optimiza las imágenes, me guarda las optimizadas en el
directorio de imágenes del contenido (<em>myblog.com/site/source/pictures/</em>) y me
elimina las imágenes originales del directorio raíz. Cuando termina me muestra un
resumen con la cantidad de imágenes procesadas y el ahorro en espacio conseguido.
Espacio en disco ahorrado que se resume en menos ancho de banda consumido y en
páginas web que se cargan más rápido.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab img4web
</pre></div>
</li>
<li>
<p><strong><em>new</em></strong> Con este creo o edito los artículos del blog. Realiza
tres funciones: me abre una venta de Gedit con el articulo que le indico con la
extensión <code>.md</code>, me abre una ventana de Firefox que me muestra el fichero
<em>index.html</em> del directorio del sitio generado por Pelican
(<em>myblog.com/site/output/index.html</em>) y finalmente me activa Pelican con la
opción <code>autoreload</code>. Luego empleando el plugin <strong>Grid</strong> de Compiz, divido la
pantalla en dos mitades y coloco a la izquierda Gedit y a la derecha Firefox.
Esto me permite, como explicaba en <a href="http://joedicastro.com/de-drupal-a-pelican.html">De Drupal a Pelican</a> editar el contenido
y previsualizar el resultado casi en tiempo real, disponiendo al mismo tiempo de
un buen corrector ortográfico. </p>
<div class="codehilite"><pre><span class="gp">$</span> fab new:<span class="s2">"Articulo de prueba"</span>
</pre></div>
</li>
<li>
<p><strong><em>publish</em></strong> El más importante, el que sube los artículos al servidor web.
Publicar el contenido de la web es tan sencillo como ejecutar este comando. Lo
que hace es regenerar el contenido (por si hubiera algún cambio sin guardar) y
luego mostrarme el resultado en firefox. Pero el resultado que me muestra no es
el del directorio de salida de Pelican, si no de una copia que tengo en un
servidor Apache local. Esto me permite ver los cambios de manera más fiel a la
versión web, puesto que hace uso del fichero .htaccess y de las reglas que tengo
establecidas en él. Finalmente me pregunta si realmente deseo publicar el
contenido, por si se me hubiera escapado algo. Si le digo que no, aborta la
publicación, pero si le digo que si, me sincroniza el contenido de la carpeta
local con la remota empleando <strong>rsync</strong>. De esta manera solo se transmiten los
ficheros nuevos, se borran los que se hayan eliminado en local y <strong>solo transmite
la parte que haya cambiado de los archivos modificados</strong>. Gracias a esto,
modificar o añadir contenido es cuestión de segundos. Y sencillisimo.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab publish
</pre></div>
</li>
<li>
<p><strong><em>pull_pelican</em></strong> Nos sirve para actualizar Pelican a la última revisión
disponible en el repositorio oficial. Si después de ejecutarlo, queremos instalar
la nueva versión en nuestro entorno virtual para poder emplearla, simplemente
tenemos que volver a ejecutar <code>fab bootstrap</code> y todo se realizará de forma
automática.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab pull_pelican
</pre></div>
</li>
<li>
<p><strong><em>regen</em></strong> El proceso principal, es el que le pide a Pelican que genere el
sitio web a partir de nuestro directorio de origen. También realiza varios
procesos: primero eliminar el directorio de salida actual (para tener una copia
fresca), genera el nuevo contenido, luego procesa los archivos para que
validen en HTML5 y finalmente hace una copia del directorio de salida a mi
servidor local Apache. El procesar los archivos para validar en HTML5 se debe a
que markdown crea unos enlaces <code>rel = "footnote"</code> y <code>rev = "footnote"</code> en las notas
al pie que se han quedado obsoletos y no son necesarios. De momento es un
post-procesado, pero puede que finalmente modifique Pelican para que se haga en
tiempo de generación del sitio. Aunque creo que el rendimiento de esta manera
sería menor que emplear el comando <code>sed</code> que ejecuta este proceso, será cuestión
de probarlo. También se podría modificar markdown.</p>
</li>
</ul>
<p>Con solo <strong>6</strong> comandos tengo automatizadas todas las tareas básicas para
administrar y crear contenido en mi blog. Ni siquiera el potente y buenísimo
<a href="http://drupal.org/project/drush">drush</a> de Drupal me permitía este nivel de automatización (aunque se
acercaba bastante). De esta manera solo me tengo que preocupar de crear
artículos y de las posibles personalizaciones que le quiera realizar al tema del
sitio. Me olvido de todo lo demás, de todo lo que conlleva un CMS. Solo hay una
manera de bloguear más cómoda para los que a estos les parezca algo complejo,
servicios como Tumblr. Aunque si quieres tener el control sobre tu sitio, no
conozco manera más cómoda y con más ventajas que esta. </p>Pelican - Creación de contenido2011-06-27T18:27:00+02:00joe di castrohttp://joedicastro.com/pelican-creacion-de-contenido.html<p>Crear contenido con <strong>Pelican</strong> es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión <em>.md</em> si queremos emplear Markdown o <em>.rst</em> si
queremos emplear reStructuredText. Vemos como lo haría, para este blog en
concreto. Este sería el texto para crearlo en formato reStructuredText:</p>
<div class="codehilite"><pre><span class="gh">Pelican - Creación de contenido</span>
<span class="gh">###############################</span>
<span class="nc">:tags:</span> <span class="nf">Pelican, python, markdown, reStructuredText, blog, HTML.</span>
Crear contenido con <span class="gs">**Pelican**</span> es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión <span class="ge">*.md*</span> si queremos emplear Markdown o <span class="ge">*.rst*</span> si
queremos emplear reStructuredText.
</pre></div>
<p>Y este el que usaría para crearlo en markdown, que es el que yo empleo:</p>
<div class="codehilite"><pre>title: Pelican - Creación de contenido
tags: Pelican, python, markdown, reStructuredText, blog, HTML, Piwik, Disqus.
Crear contenido con **Pelican** es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión *.md* si queremos emplear Markdown o *.rst* si
queremos emplear reStructuredText. Vemos como lo haría, para este blog en
concreto.
</pre></div>
<p>Ahora solo tendríamos que guardar este fichero en la carpeta raíz de nuestro
contenido y ejecutar Pelican para generar la página web resultante. Así de
sencillo. Por ejemplo, creamos una carpeta <em>prueba</em> dentro de la estructura de
ficheros que habíamos creado en el <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">articulo anterior</a> (<em>myblog.com/</em>) y
guardamos allí este fichero. Ahora ejecutamos pelican dentro del entorno virtual
y nos creara una carpeta <em>output</em> donde como resultado tendremos un blog por
defecto creado como por arte de magia. Es decir, hacemos esto:</p>
<div class="codehilite"><pre><span class="gp">$</span> mkdir prueba
<span class="gp">$</span> vi prueba/pelican.md
<span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">$</span> pelican prueba/
<span class="gp">$</span> ls
<span class="go">env output pelican prueba site temp</span>
<span class="gp">$</span> firefox output/index.html
</pre></div>
<p>y obtenemos esto:</p>
<p style="text-align:center;"><img src="pictures/sample_article.png"
alt="pelican sample article" title="pelican sample article" width=700
height=465 /></p>
<h2 id="estructura_del_articulo">Estructura del articulo</h2>
<p>En el ejemplo anterior lo único que varía entre ambos formatos (aparte de la
sintaxis) es la cabecera del mismo. En la cabecera se incluye el titulo del
mismo (no tiene porque coincidir con el nombre del fichero) y los metadatos. El
titulo en reStructuredText va subrayado con símbolos <code>#</code> y en markdown es un
metadato más. Excepto el título, todos los metadatos son opcionales. Los
metadatos en <em>.rst</em> van precedidos de dos puntos <code>:</code>. Después de los metadatos
es suficiente con dejar una linea en blanco para comenzar a redactar el
contenido de nuestro articulo. </p>
<p>Los metadatos que se pueden incorporar son los siguientes:</p>
<ul>
<li>
<p><strong>title</strong> (solo como metadato en markdown): Es el titulo del artículo o página.</p>
</li>
<li>
<p><strong>date</strong>: Es la fecha y hora de publicación. Si no se indica, tomara como tal
los valores del propio fichero de texto. El formato es el siguiente:
año-mes-dia hora:minutos, es decir, <code>%Y-%m-%d %H:%M</code></p>
</li>
<li>
<p><strong>category</strong>: La categoría en la que queremos englobar el articulo. Si no se
especifica, puede coger la categoría por defecto que se haya especificado en el
fichero de configuración si así se ha establecido (por defecto es <em>misc</em>). Otra
forma aún más simple, es crear un directorio dentro de nuestro directorio de
contenido y colgar los archivos dentro de él. Todos los que se encuentren dentro
de ese directorio caerán en la categoría que coincida con el nombre del mismo.
Así es como yo lo hago, con un directorio llamado blog, es idoneo para organizar
el contenido. </p>
<p>En el tema por defecto, las categorías se añaden como una entrada al menú
superior que al ser seleccionada, muestra todos los artículos englobados dentro
de ella.</p>
</li>
<li>
<p><strong>author / authors</strong>: El autor(es) del articulo. Si se omite, escoge por
defecto el que se haya establecido en el fichero de configuración. Yo lo omito,
pero puede ser muy útil para blogs escritos por varios autores.</p>
</li>
<li>
<p><strong>tags</strong>: Las etiquetas con las que etiquetamos a nuestro articulo. El tema
por defecto solo nos permite seleccionar una y ver todos los artículos
etiquetados de igual modo, pero es bastante sencillo crear una nube de etiquetas
como la que empleo en este blog.</p>
</li>
<li>
<p><strong>summary</strong>: Es el resumen que queremos que se vea del articulo cuando se
emplea la paginación. Por defecto, si no se especifica este campo, los artículos
se resumen con las primeras 50 palabras del mismo.</p>
</li>
<li>
<p><strong>slug</strong>: Esta es uno de los campos más curiosos, pero al mismo tiempo más
geniales. Este campo es el nexo que nos permite enlazar varias versiones del
mismo articulo en distintos idiomas. En el tema por defecto, nos muestra las
distintas traducciones de un articulo, si es que existen.</p>
</li>
<li>
<p><strong>status</strong>: Esta es un campo especial que solo admite dos valores, <code>draft</code>
(borrador) y <code>published</code> (publicado). Cualquier otro valor es ignorado. Si el
valor es <code>draft</code>, el articulo o pagina no aparece publicado ni referenciado de
algún modo al generar el contenido, y solo está disponible si accedemos a él a
través del directorio <em>drafts/</em>. Esto es una ayuda para evitar que por un
descuido subamos a la web un articulo sin terminar. Yo no lo empleo, ya veremos
cuando hable de le automatización, como he resuelto este posible problema de
otro modo. Si lo empleamos, deberíamos añadir el directorio <em>drafts/</em> a nuestro
fichero <em>robots.txt</em> como <code>Disallow</code> para que no fuera indexado por los
buscadores (de poco importaría ocultar el el borrador si lo haces accesible a
través del buscador). </p>
</li>
</ul>
<p>Para comprender el resto de opciones disponibles para crear el contenido, voy a
centrarme en el sitio de ejemplo que viene por defecto con Pelican. Empezaremos
eliminando las pruebas que acabamos de realizar.</p>
<div class="codehilite"><pre><span class="gp">$</span> rm -r output/
<span class="gp">$</span> rm -r prueba/
<span class="gp">$</span> ls
<span class="go">env pelican site</span>
</pre></div>
<h2 id="estructura_del_contenido_del_ejemplo">Estructura del contenido del ejemplo</h2>
<p>Ahora, en el directorio de contenido del sitio de ejemplo, tenemos la siguiente
estructura de ficheros:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>site/
<span class="gp">$</span> tree <span class="nb">source</span>/
<span class="go">source/</span>
<span class="go">├── another_super_article-fr.rst</span>
<span class="go">├── another_super_article.rst</span>
<span class="go">├── cat1</span>
<span class="go">│ ├── article1.rst</span>
<span class="go">│ ├── article2.rst</span>
<span class="go">│ ├── article3.rst</span>
<span class="go">│ └── markdown-article.md</span>
<span class="go">├── draft_article.rst</span>
<span class="go">├── extra</span>
<span class="go">│ └── robots.txt</span>
<span class="go">├── pages</span>
<span class="go">│ └── test_page.rst</span>
<span class="go">├── pictures</span>
<span class="go">│ ├── Fat_Cat.jpg</span>
<span class="go">│ ├── Sushi.jpg</span>
<span class="go">│ └── Sushi_Macro.jpg</span>
<span class="go">├── super_article.rst</span>
<span class="go">├── unbelievable.rst</span>
<span class="go">└── unwanted_file</span>
</pre></div>
<p>Donde:</p>
<ul>
<li>
<p><strong><em>another_super_article-fr.rst</em></strong> y <strong><em>another_super_article.rst</em></strong> son dos
versiones del mismo articulo en inglés y francés. Aunque cuelgan del directorio
raíz, ambos están englobados dentro del sitio en la categoría <em>bar</em> a través del
metadato <strong>category</strong> y enlazados traducciones mediante el metadato <strong>slug</strong>
<code>:slug: oh-yeah</code></p>
</li>
<li>
<p><strong><em>draft_article.rst</em></strong> es un articulo que no aparece publicado en el sitio
de ejemplo al estar marcado como borrador con el metadato <strong>status</strong>, pero al
que podemos acceder igualmente a través de
<code>myblog.com/site/source/drafts/a-draft-article.html</code></p>
</li>
<li>
<p><strong><em>super_article.rst</em></strong> y <strong><em>unbelievable.rst</em></strong> son ejemplos de uso de
metadados. El primero es un articulo que cuelga de la categoría <em>yeah</em> y
que sirve como ejemplo del empleo de <strong>summary</strong> y del uso de imágenes y
código. El segundo es un ejemplo de articulo sin más metadatos que la
fecha del mismo y de como cae en la categoría <strong>misc</strong> por defecto.</p>
</li>
<li>
<p><strong><em>unwanted_file</em></strong> es un articulo que no se procesa de ningún modo por
carecer de extensión que lo identifique como markdown o reStructuredText. Como
consecuencia este fichero ni siquiera se copia al sitio web generado. Puede ser
un truco útil para emplearlo como fichero de notas personales de cualquier tipo,
por ejemplo un recordatorio de como hemos definido la estructura de archivos,
una chuleta como usar marcado o reStructuredText, artículos pendientes, ...</p>
</li>
<li>
<p><strong><em>cat1</em></strong> Este directorio es un ejemplo de como todos los artículos que
cuelgan de él son englobados dentro de la categoría <em>cat1</em> de forma automática.
Esto nos evita escribir el metadato <strong>category</strong> en cada uno de ellos y nos
ayuda a clasificarlos en el directorio. Y nos muestra como se pueden mezclar
archivos markdown y reStructuredText sin ningún tipo de problemas.</p>
</li>
<li>
<p><strong><em>extra</em></strong> En esta carpeta (puede ser otra, es configurable) englobamos
archivos que queremos incluir en el sitio, pero que no han de ser procesados.
Como por ejemplo: .htaccess, .robots.txt,
<a href="http://humanstxt.org/ES">.humans.txt</a>, ... Esto puede cambiarse en el
fichero de configuración, especificando el origen dentro del directorio de
nuestro contenido y la ruta en la que queremos que esté en el sitio web. En
este caso, sería así en el fichero de configuración <code>pelican.conf.py</code></p>
<div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">'extra/robots.txt'</span><span class="p">,</span> <span class="s">'robots.txt'</span><span class="p">),)</span>
</pre></div>
</li>
<li>
<p><strong><em>pages</em></strong> Serían las páginas estáticas del sitio, lo que no son artículos.
Este nombre de directorio está reservado para esta función por defecto. Por
ejemplo la página <a href="http://joedicastro.com/pages/markdown.html"><em>markdown</em></a> que
empleo en este blog, sería una de estas páginas estáticas. En estas páginas
no están disponibles los comentarios. Si se especifica en el fichero de
configuración, estas páginas aparecerán como entradas en el menú principal
del tema por defecto. </p>
</li>
<li>
<p><strong><em>pictures</em></strong> Este es uno de los directorios que se pueden emplear para
albergar contenido estático como son las imágenes. Esto es configurable en el
fichero de configuración. En este caso lo que se guardan en el son las imágenes
empleadas en los artículos. Estas acabaran dentro del directorio
<code>static/pictures/</code> de nuestro sitio. </p>
</li>
</ul>
<p>Y ya está, es una estructura muy sencilla y que genera un resultado bastante
decente, comparado con los cientos de archivos que emplea (a parte de la BDD)
cualquier CMS como Wordpress o Drupal.</p>
<p>Si partiéramos de un blog ya creado, Pelican proporciona una herramienta, que
en nuestro caso estaría en <em>/myblog.com/pelican/tools/importer.py</em> y que nos
permite importar artículos desde Wordpress o desde un fichero RSS y que nos
genera los contenidos en reStructuredText. Si quisiéramos emplear markdown,
existe una herramienta externa, <a href="http://www.codefu.org/wiki/Main/Html2markdown"><strong>html2markdown</strong></a> que nos permite obtener
un texto en markdown desde una página web. Otra herramienta similar a esta
última sería <a href="http://www.aaronsw.com/2002/html2text/">html2text</a>.</p>
<p>No tiene más secreto que este, crear ficheros de texto plano en formato <em>.md</em> o
<em>.rst</em>, guardarlos en el directorio que empleamos para albergar el contenido
y generar el blog.</p>Pelican - Introducción e Instalación2011-06-27T10:21:00+02:00joe di castrohttp://joedicastro.com/pelican-introduccion-e-instalacion.html<p><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> es un generador de sitios web con contenido estático. Está orientado
originalmente a la creación de blogs. <strong>Pelican</strong> (Pelicano) es una anagrama de
la palabra francesa <em>Calepin</em> que significa en español "cuaderno de notas"
(blog). Su creador y desarrollador principal es el programador francés
<a href="http://blog.notmyidea.org/">Alexis Métaireau</a>. Y es la aplicación que genera el contenido para este
blog. Personalmente le veo muchas ventajas frente a una plataforma de blogs
convencional como Wordpress o Drupal, como ya comentaba en mi <a href="http://joedicastro.com/de-drupal-a-pelican.html">anterior articulo</a>. </p>
<p>Pelican genera este contenido estático (páginas HTML) a partir de ficheros de
texto plano formateados en un lenguaje de marcado ligero como <a href="http://es.wikipedia.org/wiki/Markdown">Markdown</a> o
<a href="http://es.wikipedia.org/wiki/ReStructuredText">reStructuredText</a>. También crea fuentes RSS y Atom de los artículos. Y
dependiendo del tema empleado se pueden tener un archivo de los artículos
publicados, clasificación por categorías, nube de etiquetas, un <a href="http://es.wikipedia.org/wiki/Blogroll">blogroll</a>,
enlaces a redes sociales, botón para tweeter, paginación, traducciones, etc.
Aunque viene un tema completo por defecto y están disponibles <a href="https://github.com/ametaireau/pelican-themes">algunos más</a>,
se puede crear uno completamente personalizado desde cero. La creación de
estos temas se basa en el sistema de plantillas <a href="http://jinja.pocoo.org/">jinja2</a>, lo que nos
permite una gran flexibilidad. También disponemos de varios scripts que nos
proporcionan soporte para comentarios con <a href="http://disqus.com">Disqus</a> y de analíticas con
<a href="http://www.google.com/intl/es/analytics/">Google Analytics</a> ó <a href="http://piwik.org/">Piwik</a>. También nos permite generar ficheros PDFs de
los artículos automáticamente y mostrar los enlaces a ellos, siempre que los
artículos se hayan creado con reStructuredText.</p>
<p>Es un software muy joven, el primer commit en <a href="https://github.com/ametaireau/pelican">GitHub</a> data del 13 de Agosto de
2010, pero que ha evolucionado bastante rápido y que aún sigue desarrollándose a
un buen ritmo. Es posible que por esto aún tenga alguna carencia o algún que
otro fallo, pero su autor es muy receptivo y acepta de buena gana las sugerencias,
informes de errores y colaboraciones de desarrollo. Cuenta con una documentación
bastante decente y actualizada. Alguno que otra cosa no está documentada, pero
lo veo normal dado el ritmo de desarrollo y de a quien va orientado un software
como este. Es muy sencilla su instalación y su utilización cuando se ha leído
esta, pero será mejor que lo explique con un ejemplo sobre la marcha.</p>
<h2 id="instalaci+n_para_linux">Instalación (para Linux)</h2>
<p>La instalación del mismo es relativamente sencilla si no queremos complicarnos
la vida, siempre tenemos la última versión disponible en el <a href="http://pypi.python.org/pypi/pelican/2.7.2">PyPi</a>. Así que
instalarlo podría ser tan sencillo como esto:</p>
<div class="codehilite"><pre><span class="gp">$</span> easy_install pelican
</pre></div>
<p>Aunque recomiendo emplear <a href="http://www.pip-installer.org/en/latest/index.html"><code>pip</code></a> en lugar de <code>easy_install</code>, de este modo:</p>
<div class="codehilite"><pre><span class="gp">$</span> pip install pelican
</pre></div>
<p>De todos modos desaconsejo emplear este método, me parece mejor solución, dada
la velocidad de desarrollo del software, emplear un entorno virtual para su
instalación. Un <a href="http://www.virtualenv.org/en/latest/index.html">entorno virtual</a> nos permite tener una versión de Python
independiente de la del resto del sistema, con sus propias librerías y con el
software instalado que nosotros deseemos. Todo esto solo estará disponible cuando
nos encontremos dentro de este entorno virtual, sin afectar al resto del
sistema. Y podemos eliminarlo o des/activarlo cuando deseemos. Es bastante más
sencillo de utilizar de lo que parece y es realmente potente. </p>
<p>Veamos, paso a paso, la forma en que yo lo instalaría.</p>
<p>Creamos una carpeta que contendrá Pelican, el entorno virtual y el sitio que
crearemos. Yo le daría el nombre de la URL del blog, por ejemplo, <em>myblog.com</em></p>
<div class="codehilite"><pre><span class="gp">$</span> mdkir myblog.com
<span class="gp">$</span> <span class="nb">cd </span>myblog.com
</pre></div>
<p>Descargamos la revisión actual del repositorio de Pelican en GitHub. Esto nos
creara una carpeta llamada <em>pelican</em> que contendrá una copia del repositorio en
local (lo cual nos será muy útil en el futuro para actualizarlo). </p>
<div class="codehilite"><pre><span class="gp">$</span> git clone git://github.com/ametaireau/pelican.git
<span class="go">Cloning into pelican...</span>
<span class="go">remote: Counting objects: 2603, done.</span>
<span class="go">remote: Compressing objects: 100% (1143/1143), done.</span>
<span class="go">remote: Total 2603 (delta 1541), reused 2420 (delta 1374)</span>
<span class="go">Receiving objects: 100% (2603/2603), 687.30 KiB | 397 KiB/s, done.</span>
<span class="go">Resolving deltas: 100% (1541/1541), done.</span>
</pre></div>
<p>Ahora vamos a crear nuestro entorno virtual. En caso de no tener instalado <code>pip</code>
o <code>virtualenv</code>, es rematadamente sencillo:</p>
<div class="codehilite"><pre><span class="gp">$</span> easy_install pip
<span class="gp">$</span> pip install virtualenv
</pre></div>
<p>Voy a llamar <em>env</em> a nuestro entorno virtual. Lo creamos así.</p>
<div class="codehilite"><pre><span class="gp">$</span> virtualenv env
<span class="go">New python executable in env/bin/python</span>
<span class="go">Installing distribute...........................................................</span>
<span class="go">................................................................................</span>
<span class="go">.......................................done.</span>
<span class="gp">$</span> ls
<span class="go">env pelican</span>
</pre></div>
<p>Ahora activaremos nuestro entorno virtual para "sumergirnos" dentro de él. </p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">(env)$</span>
</pre></div>
<p>Vemos que aparece el nombre del entorno virtual entre paréntesis antes de la
línea del <a href="http://es.wikipedia.org/wiki/Prompt">prompt</a>. Eso quiere decir que
nos encontramos dentro de este entorno virtual. Ahora procederemos a instalar
Pelican. </p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>pelican/
<span class="gp">$</span> python setup.py install
</pre></div>
<p>Ahora tenemos ya instalado Pelican, <strong>solo dentro de nuestro entorno virtual</strong>.
Si probamos a llamar al programa fuera de él, veremos que no está disponible,
luego necesitaremos activar este entorno cada vez que queramos emplearlo.</p>
<div class="codehilite"><pre><span class="gp">$</span> pelican
<span class="go">CRITICAL: you need to specify a path containing the content (see pelican --help for </span>
<span class="go">more information)</span>
</pre></div>
<p>Nos da un error porque no le hemos pasado los parámetros necesarios. Ahora
desactivamos el entorno y volvemos a llamar al programa y nos dice que no
existe.</p>
<div class="codehilite"><pre><span class="gp">$</span> deactivate
<span class="gp">$</span> pelican
<span class="go">pelican: orden no encontrada</span>
</pre></div>
<p>Tenemos ahora dentro de <em>myblog.com/</em> dos directorios, <em>env</em> y <em>pelican</em>.
Podríamos borrar ahora el directorio <em>pelican</em> porque ya lo tenemos instalado
dentro del entorno virtual, pero sería bueno conservarlo para poder actualizarlo
en el futuro mediante <code>git pull</code>. Yo crearía una tercer directorio, <em>site</em> donde
se alojaría nuestro sitio, organizado a su vez en tres subdirectorios: </p>
<ul>
<li>
<p><strong>source</strong>: sería la carpeta donde alojaríamos los archivos de texto de
nuestro blog y todo aquello que quisiéramos que formara parte de nuestro sitio:
imágenes, fichero <a href="http://es.wikipedia.org/wiki/Htaccess">.htacess</a>, fichero <a href="http://es.wikipedia.org/wiki/Robots.txt">robots.txt</a>, páginas
personalizadas...</p>
</li>
<li>
<p><strong>output</strong>: El resultado del procesamiento de Pelican, es decir, nuestro blog.</p>
</li>
<li><strong>theme</strong> : Sería el tema que usariamos para crear nuestro blog, en el
estarían las plantillas <strong>jinja2</strong>, las hojas de estilo .css, el contenido
estático (iconos, imágenes), ...</li>
</ul>
<p>Luego, lo haríamos así:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd</span> ..
<span class="gp">$</span> mkdir -p site/source
<span class="gp">$</span> mkdir site/output
<span class="gp">$</span> mkdir site/theme
<span class="gp">$</span> ls site/
<span class="go">output source theme</span>
</pre></div>
<p>Ya está, tenemos instalado Pelican y creada nuestra estructura para empezar a
trabajar con él. Para eso nada mejor que crear un primer sitio de ejemplo.
Entramos en el entorno virtual y creamos el sitio que viene de ejemplo con
Pelican:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">$</span> pelican pelican/samples/content/ -o site/output -s pelican/samples/pelican.conf.py
</pre></div>
<p>Y ahora si abrimos el fichero <code>myblog.com/site/output/index.html</code> en un
navegador, veremos algo como esto (en la imagen se ve la categoría cat1
seleccionada):</p>
<p style="text-align:center;"><img src="pictures/sample_blog.png"
alt="pelican sample blog" title="pelican sample blog" width=453 height=700 /></p>
<p>Es así de fácil de emplear Pelican, simplemente especificarle el directorio donde
está el origen del contenido, el directorio destino y el fichero de configuración.
Aunque con el fichero de configuración correctamente creado, solo será necesario
indicarle la ubicación del mismo. Para comprender mejor la estructura y como
funciona Pelican, sería buena idea copiar el tema, el fichero de configuración y
el contenido que han generado este sitio de ejemplo a la carpeta <em>site</em> para no
empezar nuestro blog desde cero.</p>
<div class="codehilite"><pre><span class="gp">$</span> cp -r pelican/samples/content/* site/source
<span class="gp">$</span> cp -r pelican/pelican/themes/notmyidea/* site/theme/
<span class="gp">$</span> cp pelican/samples/pelican.conf.py site/
</pre></div>
<p>En próximos artículos veremos como crear artículos, publicar el sitio,
personalizar el tema y automatizar todos estos procesos para hacerlo todo mucho
más sencillo. </p>De Drupal a Pelican2011-06-22T02:10:00+02:00joe di castrohttp://joedicastro.com/de-drupal-a-pelican.html<p>Este blog no está realizado con ningún <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, ni siquiera utiliza <abbr title="Base de datos">BDD</abbr> alguna, es
simplemente HTML + CSS y nada más. Es decir, es contenido estático, no dinámico.
Hasta hace 3 días estaba funcionando con el mejor <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> <a href="http://es.wikipedia.org/wiki/PHP">PHP</a> que conozco,
<a href="http://drupal.org">Drupal</a>. Pero persiguiendo el camino hacia el minimalismo y la productividad
(fiel al espíritu <a href="http://es.wikipedia.org/wiki/Principio_KISS"><abbr title="Keep It Simple, Stupid (en español, "Mantenlo simple, estúpido"). Ver enlace"><abbr title="Keep It Simple, Stupid (en español, "Mantenlo simple, estúpido"). Ver enlace">KISS</abbr></abbr></a>) que ya inicie cuando <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">comencé a escribir todos mis
artículos en Drupal con Markdown</a>, el siguiente paso era evidente. La pregunta
era muy sencilla, si un blog consta de contenidos que rara vez cambian
(exceptuando los comentarios) ¿para que necesito un gestor de contenidos
dinámicos?</p>
<p>La respuesta es fácil, para nada. Actualmente, gracias a servicios como los de
<a href="http://disqus.com">Disqus</a>, <a href="http://livefyre.com/">Livefyre</a>, <a href="http://intensedebate.com/">IntenseDebate</a> ó <a href="http://www.aboutecho.com/commenting">Echo</a> es posible
externalizar el único contenido dinámico básico de un blog, los comentarios.
Todo lo demás puede ser contenido puramente estático, solo HTML y CSS, sin
renunciar a prácticamente nada de lo que nos ofrece un blog basado en un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>
como Wordpress o Drupal. Se pueden emplear scripts externos en javascript si se
desea, o insertarlos dentro del HTML. Lo que nos permite implementar lo mismo
que en un blog normal. Además se puede disponer también de feeds RSS y Atom.<br />
</p>
<h2 id="elegir_un_generador_de_contenido_est+tico">Elegir un generador de contenido estático</h2>
<p>Evidentemente la idea no es crear las paginas HTML a mano, ni de broma, lo lógico
era seguir empleando la misma estrategia que ya había iniciado con Drupal,
emplear solo ficheros de texto en formato Markdown que nos generarán el HTML
necesario de forma automática. Entonces lo que tenía que encontrar era un
software que me permitiera hacer lo mismo que Drupal, pero sin toda la
parafernalia que rodea a un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Un generador de sitios web estáticos (a partir
de markdown) y que a ser posible estuviera escrito en <strong>Python</strong>, mi lenguaje
favorito. Como ya adelante en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre Markdown</a>, existen varias opciones:</p>
<ul>
<li><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> de Alexis Métaireau, que emplea en su propio <a href="http://blog.notmyidea.org/">blog</a></li>
<li><a href="http://www.blogofile.com/">Blogofile</a> de Ryan McGuire que también lo usa en su <a href="http://www.enigmacurry.com/">blog</a></li>
<li><a href="http://hyde.github.com/">Hyde</a> de Lakshmi Vyas. Su <a href="http://ringce.com/blog/">blog</a> con Hyde también.</li>
<li><a href="https://github.com/mitsuhiko/rstblog">rstblog</a> de Armin Ronacher. Solo permite reStructuredText, con él crea su
<a href="http://lucumr.pocoo.org/">blog</a>, un ejemplo de elegancia y calidad.</li>
</ul>
<p>Bueno, tenía varias posibilidades, solo tenía que elegir una que se adaptara
mejor a mis necesidades. De entrada descarté <strong>rstblog</strong> porque no permitía el
empleo de markdown, cuando los otros permitían tanto .rst como .md como formatos
de entrada. Solo me quedaban 3 candidatos. Así que lo primero que hice antes de
nada, fue buscar blogs creados con cada uno de ellos, para ver que posibilidades
reales ofrecían. Encontré ejemplos de blogs de mucha calidad de todos ellos.
Aunque enseguida me di cuenta de una cosa, en dos de ellos los mejores blogs lo
eran porque tenían una elevada personalización detrás (artículos de sus autores
contándolo). Y curiosamente con el tercero, casi todos preferían quedarse con la
configuración estándar, sin tocar prácticamente nada, y la verdad es que el
resultado era bastante decente. Luego miré que cargaba cada uno de ellos en la
página de entrada, y volvía a repetirse la misma tendencia. En los dos primeros
vi demasiadas hojas de estilo, imágenes y demasiados scripts javascript, en el
tercero, nuevamente se cargaban menos elementos. Finalmente comparé
características, modo de funcionamiento y le eché un vistazo rápido al código.
La impresión era otra vez la misma, dos de ellos, <strong>Hyde</strong> y <strong>Blogofile</strong> aunque
aparentemente potentes, los veía innecesariamente complejos, en cambió
<strong>Pelican</strong> era bastante más sencillo. Otra forma de determinar su repercusión
era contar el número de descargas de cada una de las aplicaciones desde PyPi.
Los números son los siguientes (a 27 de Junio de 2011), obtenidos con
<a href="https://github.com/aclark4life/vanity">Vanity</a> o <a href="http://pythonpackages.com/">pythonpackages.com</a>:</p>
<table>
<thead>
<tr>
<th>Paquete</th>
<th>Descargas</th>
<th>Descargas (2-12-2011)</th>
<th>Descargas (7-4-2012)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Blogofile</td>
<td>2.419</td>
<td>3.854</td>
<td>5.276</td>
</tr>
<tr>
<td>Hyde</td>
<td>1.945</td>
<td>4.518</td>
<td>7.644</td>
</tr>
<tr>
<td>Pelican</td>
<td>3.919</td>
<td>6.138</td>
<td>10.126</td>
</tr>
</tbody>
</table>
<p>La elección final era Pelican y no me arrepiento en absoluto, la prueba es que
esté blog está funcionando gracias a él (Gracias Alexis!). Aunque las otras dos
son también muy buenas opciones, y seguramente serían la primera opción para más
de uno. Y siempre podría cambiar fácilmente, porque el contenido seguiría estando
guardado en ficheros de texto con marcado markdown. </p>
<blockquote>
<p><strong>Actualización</strong> (2-12-2011): </p>
<p>La estructura de Pelican es tan sencilla y eficaz, que <a href="http://www.solberg.is/">Jökull Sólberg</a>
ha creado a partir de una versión hospedada del mismo (y modificada) una de las
plataformas de blogs más simples de utilizar que existen, <a href="http://calepin.co/">calepin.co</a>.
Publicar articulos es tán fácil como crear un archivo markdown y guardarlo en tu
cuenta de <a href="http://www.dropbox.com/">Dropbox</a>. Así de sencillo.</p>
</blockquote>
<p>No entraré en detalles ahora de como instalar y emplear <strong>Pelican</strong>, eso lo dejo
para otro próximo articulo, <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican</a>. Pero si voy a hacer un repaso de los
pros y los contras de emplear Pelican frente a un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> como Drupal para crear un
blog.</p>
<h2 id="ventajas_de_pelican_vs_cms">Ventajas de Pelican vs <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr></h2>
<h3 id="solo_ficheros_de_texto_no_bdd">Solo ficheros de texto, No <abbr title="Base de datos">BDD</abbr></h3>
<p>Simplemente te tienes que preocupar de eso, ficheros de texto, es donde guardas
el contenido que creas. Todo lo demás lo genera Pelican por ti. Nada de crear y
gestiónar bases de datos, ni copias de seguridad de la misma y un montón de
espacio y recursos desaprovechado solamente para generar dinámicamente el mismo
contenido que te genera Pelican.</p>
<h3 id="mejor_rendimiento_carga_de_p+gina_m+s_r+pida">Mejor rendimiento, carga de página más rápida</h3>
<p>Generar contenido dinámico es más caro en recursos y es más lento (consultas a
la <abbr title="Base de datos">BDD</abbr>). Sobre todo a medida que llenas tu <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> de personalizaciones y plugins.
¿Que hacen prácticamente todos los sistemas de caché?, generar contenido
estático para luego servirlo más rápidamente. ¿No es un poco estúpido crear
contenido que apenas cambia en el tiempo, en un sistema dinámico que genera ese
contenido cada vez y que para mejorar su rendimiento lo convierte en estático?
Y ya no hablemos de las múltiples hojas CSS, scripts javascript y enlaces a
contenido externo que cargan la mayoría de los <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> por defecto. Cada plugin que
añadimos pone su granito de arena y optimizar todo esto requiere dedicación y
esfuerzo (o seguir sumando aún más plugins en el mejor de los casos). Con
Pelican ya tienes directamente el contenido estático y menos recursos que
descargar. En este blog, sin contar con los ficheros javascript de Disqus y
Piwik, lo único que se descarga es un fichero HTML, una hoja CSS y las imágenes
que se incluyen en los artículos (cuando las hay). Es decir sirves el mismo
contenido pero generando menos tráfico desde tu servidor. </p>
<h3 id="soporta_mejor_el_tr+fico">Soporta mejor el tráfico</h3>
<p>Cuando un sitio web soporta mucho tráfico, emplear un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> requiere de mucha
optimización y generalmente de mucha maquina o complejas instalaciones. Y la
base principal siempre es un sistema de caché que sirva contenido lo más
estático posible. Se cachea todo lo que se puede, y si es en memoria mejor. Las
<abbr title="Base de datos">BDD</abbr> son un problema aparte, desde soluciones NoSQL a clusters o <abbr title="Base de datos">BDD</abbr> distribuidas.
Con contenido estático no te tienes que preocupar de optimizar los accesos a la
<abbr title="Base de datos">BDD</abbr>, solo de tener un buen servidor web y si quieres, cachear en memoria o
ampliar máquina. Pero poco más.</p>
<h3 id="seguridad">Seguridad</h3>
<p>Olvídate de problemas de seguridad, los únicos agujeros de seguridad de un sitio
con contenido estático están del lado del servidor web, de todo lo demás, te
olvidas. Establece bien los permisos en el sistema de ficheros y punto. El único
contenido dinámico del sitio (javascript) ni siquiera es algo que deba
preocuparte, es algo externo que le concierne a <strong>Disqus</strong> o al sistema de
analíticas web que elijas (Google Analytics o Piwik).</p>
<h3 id="olvidarse_de_gestionar_un_cms_mantenimiento_mucho_m+s_sencillo_nulo">Olvidarse de gestionar un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Mantenimiento mucho más sencillo (nulo)</h3>
<p>Instalar el <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, crear la <abbr title="Base de datos">BDD</abbr>, encontrar, instalar y probar los plugins que
necesitas, actualizaciones, actualizaciones de seguridad, personalizaciones,
temas... Todo lo que rodea a cualquier <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Y ya no digamos si hablamos de un
<abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> potente y complejo como Drupal, con cientos de posibilidades. Y sin olvidar
toda la basura que se va acumulando en las <abbr title="Base de datos">BDD</abbr> tras varias actualizaciones y
múltiples pruebas de plugins, con Pelican siempre tienes un sistema limpio.
Todo eso lo olvidas con Pelican, lo instalas, personalizas y automatizas una
sola vez, luego te olvidas de todo lo que no sea escribir (si quieres, nada te
impide seguir cambiándolo y mejorándolo). Emplea tú tiempo en crear contenido.</p>
<h3 id="backups_m+s_sencillos">Backups más sencillos</h3>
<p>Con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> <abbr title="No hacerlas es una decisión nefasta">deberías hacer Backups</abbr> del servidor web tanto del sistema de ficheros
como de la <abbr title="Base de datos">BDD</abbr>. Y sería aconsejable tener un servidor web local montado para
probar los cambios que vayas a hacer en el <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> sin miedo a romper nada. Con
Pelican ni siquiera necesitas hacer Backups del servidor ni del contenido web.
Todo lo que necesitas para generarlo ya está en tu ordenador en esos ficheros de
texto. Incluso si empleas un tema propio, también está en tu equipo. Así que las
copias de seguridad de tu sitio web no son distintas a las que
<abbr title="No me digas que aún no las haces, ¿estas de broma?">regularmente ya haces</abbr> de tu ordenador personal.</p>
<h3 id="hosting_en_cualquier_sitio">Hosting en cualquier sitio</h3>
<p>Solo tienes que alojar contenido estático, no necesitas <abbr title="Base de datos">BDD</abbr> ni soporte para
ningún lenguaje o librería en particular. Puedes hasta utilizar recursos
gratuitos como las páginas de <a href="https://github.com/">GitHub</a> o <a href="http://bitbucket.org/">BitBucket</a> o un sistema
de ficheros en la nube económico como <a href="http://aws.amazon.com/es/s3/">Amazon S3</a> (o
<a href="http://aws.amazon.com/es/cloudfront/">Amazon CloudFront</a>). Solo necesitas eso, servir ficheros, nada más. Hasta
el hosting más económico te sirve. </p>
<h3 id="emplear_un_cvs_para_gestionarlo">Emplear un <abbr title="Control Version System (en español, "Sistema de Control de Versiones")">CVS</abbr> para gestionarlo</h3>
<p>Poder emplear Git o Mercurial o cualquier otro <abbr title="Control Version System (en español, "Sistema de Control de Versiones")">CVS</abbr> para gestionar los cambios
del blog no tiene precio. Ningún sistema de revisiones de <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> es tan potente.
Además tienes la posibilidad de crear un <em>hook</em> para que al enviar un commit
después de crear un articulo (o realizar un cambio) se suba el contenido
automáticamente al servidor. Con esto realizar cualquier cambio o revertir un
error es algo trivial. Además te permite subir una copia a un sitio como GitHub
o BitBucket y tenerlo siempre disponible en cualquier sitio con conexión a la
red. Como maravillosa opción, esto permite que el contenido de un blog, incluso
de un mismo articulo, sea editado por más de una persona de manera bastante más
sencilla, potente y menos propensa a errores que con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. </p>
<h3 id="crear_los_articulos_off-line">Crear los articulos off-line</h3>
<p>Eso te permite ir creando los artículos al ritmo que te de la gana, cuando
quieras y en cualquier sitio con un portátil. No necesitas estar conectado a la
red. Esto también puede hacerse con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, pero suele ser más complejo
(exceptuando emplear cortar y pegar) e inseguro (si se habilita el envío remoto
de artículos). Yo lo había logrado en Drupal empleando markdown, pero seguía
necesitando un segundo paso on-line para personalizar las etiquetas. </p>
<h3 id="edici+n_de_art+culos_m+s_c+moda">Edición de artículos más cómoda</h3>
<p>Puede parecer que un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> con su editor WYSIWYG es más cómodo, pero todo lo
contrario. Ya lo comentaba en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre markdown</a>. Pero es que
además me proporciona una mejor experiencia de edición y más potente. Explico
como redacto yo los artículos para que se entienda mejor. Divido la pantalla en
dos mitades, a la izquierda el editor de textos y a la derecha el navegador.
Como editor de textos empleo Gedit, que tiene resaltado de texto para markdown y
un corrector ortográfico (por esto no uso vim para esto) bastante mejor que el
de Firefox (que solo examina el texto hasta cierto número de casos dudosos).
Además Pelican tiene una maravillosa opción, <code>autoreload</code> que lo hace correr en
segundo plano y cuando detecta un cambio en uno de los ficheros, vuelve a generar
el contenido. Entonces en gedit le digo que autoguarde el contenido cada 3
minutos (o a voluntad, manualmente) y cuando Pelican lo detecta, automáticamente
regenera los ficheros HTML. Como navegador empleo Firefox y tengo, abierto en
una pestaña, el fichero <code>index.html</code> que genera Pelican y empleando la extensión
<a href="https://addons.mozilla.org/es-ES/firefox/addon/auto-reload/?src=api">Auto Reload</a> el contenido de la página (en local) se actualiza
automáticamente al detectar un cambio en el fichero. Es decir, como en la
primera página se puede ver el contenido completo del último articulo, lo que
estoy viendo es una previsualización automática del contenido en la página cada
3 minutos. Y todo esto en off-line, sin estar conectado a internet. Esto si es
un verdadero editor WYSIWYG, y no los otros. Además, que demonios, los
navegadores no se diseñaron para crear texto, cualquier editor de texto es más
potente.</p>
<h3 id="control_del_spam">Control del Spam</h3>
<p>El Spam, esa lacra que azota toda la web. En Pelican, ese problema, lo tiene que
gestionar Disqus, no tú. Tú solo tienes que gestionar el poco que se le escape.
Pero el buscar un plugin, configurarlo y que funcione bien, es algo de lo que no
tienes que preocuparte. En Drupal tenía este asunto solucionado, pero fue cosa
de probar varios plugins, hasta que al final <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">di con uno que me lo solucionaba de
verdad</a>. </p>
<h3 id="recursos_de_cpu_y_ram">Recursos de CPU y RAM</h3>
<p>El contenido dinámico consume mucha más memoria RAM y CPU en el servidor que
servir contenido estático. Al fin y al cabo, en el caso del contenido estático,
es poco más complejo que servir ficheros. Si tienes que compartir el servidor
con más proyectos, agradecerás no tener que emplear un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> para servir el blog.</p>
<h3 id="resaltado_de_sintaxis_incorporada_con_pygments">Resaltado de Sintaxis incorporada con Pygments</h3>
<p>Mientras en la mayoría de <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> necesitas un plugin para habilitar el resaltado de
sintaxis para código fuente, en Pelican esto viene por defecto empleando el
excelente <a href="http://pygments.org/">Pygments</a></p>
<h3 id="cumplimiento_de_est+ndares_web">Cumplimiento de Estándares Web</h3>
<p>Con Pelican es relativamente sencillo configurar el tema para que cumpla los
estándares web y genere contenido valido. Y una vez que lo haces, es para
siempre, a no ser que modifiques algo en el tema, todo el contenido que generes
cumplirá con los estándares (a no ser que incluyas HTML dentro que no lo sea).
De este modo, este sitio valida HTML5, CSS3 y genera feeds RSS y Atom validos.
Conseguir esto con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> y empleando editores WYSIWYG es bastante más complejo
y doloroso. Aunque yo lo había conseguido con Drupal y markdown, tuve que
modificar un tema casi por completo, casi como crearlo desde cero. </p>
<h2 id="inconvenientes_de_pelican_vs_cms">Inconvenientes de Pelican vs <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr></h2>
<h3 id="comentarios_sin_resaltado_de_sintaxis">Comentarios sin resaltado de sintaxis</h3>
<p>Algo que me permitía Drupal y no me permite Disqus (por ahora) era emplear
markdown en los comentarios y resaltado de sintaxis para el código fuente. Es el
mayor inconveniente que he encontrado hasta ahora. Pero bueno, tampoco es algo
imprescindible y esperemos que Disqus lo soporte en un futuro.</p>
<h3 id="sitemap">Sitemap</h3>
<p>Tampoco Pelican genera sitemaps en xml para los buscadores. Aunque tampoco es
algo imprescindible y Drupal tampoco lo soporta por defecto, si no a través de
un módulo. El autor lo tiene como tarea pendiente, y si tarda mucho, a lo mejor
me animo y lo creo yo mismo.</p>
<h3 id="personalizaci+n_m+s_sencilla_para_non_geeks">Personalización más sencilla para non geeks</h3>
<p>Esta es la parte que menos me afecta, pero es el gran inconveniente para la gran
mayoría sin conocimientos avanzados. Aunque Pelican no es difícil de instalar y
configurar, si queremos personalizarlo bastante, la cosa cambia. Los <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> son
mucho más sencillos en ese sentido, pero el coste a pagar por otro lado no me
compensa. </p>
<h3 id="no_tiene_b+squeda_incorporada">No tiene búsqueda incorporada</h3>
<p>Es otro pequeño inconveniente que puede suplirse empleando la de Google AdSense
en el sitio, por ejemplo. Personalmente no me importa demasiado, teniendo
disponibles en el sitio recursos como el archivo de todos los artículos
publicados o la nube de etiquetas.</p>
<h3 id="no_puedes_personalizar_el_contenido_din+micamente">No puedes personalizar el contenido dinámicamente</h3>
<p>Con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> puedes hacer cosas como mostrar un contenido o un tema distinto según
el perfil del usuario, o según la carga del servidor, etc. Con contenido
estático lógicamente no puedes hacer esto. A mi me da igual, no lo necesito, es
solo un blog.</p>
<br />
<p>Llevo varios años empleando Drupal en varios sitios y me sigue pareciendo un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>
excelente y una buenísima opción para generar contenido dinámico para no
desarrollladores (de otro modo prefiero un framework como Django). Pero
actualmente, para crear blogs, si se tienen conocimientos suficientes, emplear
un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> me parece una decisión poco acertada, es matar moscas a cañonazos. Hoy en
día hay soluciones como Pelican y las mencionadas arriba (y otras alternativas
en otros lenguajes) que te permiten crear blogs con facilidad, centrándote
únicamente en crear los artículos y automatizar todo lo demás. ¿Acaso esa no es
la razón principal del grandisimo éxito de <a href="http://twitter.com/">twitter</a> o <a href="http://www.tumblr.com/">tumblr</a>?
La inmediatez de los resultados y la delegación de la gestión a terceros, tú
solo escribes. Pelican te permite lo mismo, solo requiere la personalización
inicial y listo, con la ventaja añadida de que puedes personalizarlo a tu gusto
y hasta donde te dé la gana o seas capaz.</p>