A new Riff-radio.org site with a static approach.

internals.html 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>Nikola Internals | Riff</title>
  7. <link href="../assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
  8. <link rel="alternate" type="application/rss+xml" title="RSS" href="../rss.xml">
  9. <link rel="canonical" href="http://media.pagelibre.org/riff/site/pages/internals.html">
  10. <link rel="icon" href="../favicon.ico" sizes="16x16">
  11. <!--[if lt IE 9]><script src="../assets/js/html5.js"></script><![endif]--><meta name="author" content="The Nikola Team">
  12. <meta property="og:site_name" content="Riff">
  13. <meta property="og:title" content="Nikola Internals">
  14. <meta property="og:url" content="http://media.pagelibre.org/riff/site/pages/internals.html">
  15. <meta property="og:description" content="When trying to guide someone into adding a feature in Nikola, it hit me that
  16. while the way it's structured makes sense to me it is far from obvious.
  17. So, this is a short document explaining what each p">
  18. <meta property="og:type" content="article">
  19. <meta property="article:published_time" content="2012-03-30T23:00:00-03:00">
  20. </head>
  21. <body>
  22. <a href="#content" class="sr-only sr-only-focusable">Skip to main content</a>
  23. <!-- Menubar -->
  24. <div class="blog-masthead">
  25. <div class="container">
  26. <!-- This keeps the margins nice -->
  27. <nav class="blog-nav" role="navigation"><a href="../index.html" class="blog-nav-item">Accueil</a>
  28. <a href="about.html" class="blog-nav-item">About Riff</a>
  29. <a href="../rss.xml" class="blog-nav-item">RSS feed</a>
  30. </nav>
  31. </div>
  32. <!-- /.container -->
  33. </div>
  34. <!-- End of Menubar -->
  35. <div class="container" id="content" role="main">
  36. <div class="body-content">
  37. <div class="blog-header">
  38. <h1 class="blog-title">
  39. <a href="http://media.pagelibre.org/riff/site/">
  40. <span id="blog-title">Riff</span>
  41. </a>
  42. </h1>
  43. <p class="lead blog-description">Riff la radio rock</p>
  44. </div>
  45. <!--Body content-->
  46. <div class="row">
  47. <div class="col-sm-8 blog-main">
  48. <article class="post-text storypage" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h2 class="p-name entry-title blog-post-title" itemprop="headline name"><a href="#" class="u-url">Nikola Internals</a></h2>
  49. </header><div class="e-content entry-content" itemprop="articleBody text">
  50. <p class="lead">When trying to guide someone into adding a feature in Nikola, it hit me that
  51. while the way it's structured makes sense <strong>to me</strong> it is far from obvious.</p>
  52. <p>So, this is a short document explaining what each piece of Nikola does and
  53. how it all fits together.</p>
  54. <dl>
  55. <dt>Nikola is a Pile of Plugins</dt>
  56. <dd>
  57. <p>Most of Nikola is implemented as plugins using <a class="reference external" href="http://yapsy.sourceforge.net/">Yapsy</a>.
  58. You can ignore that they are plugins and just think of them as regular python
  59. modules and packages with a funny little <code class="docutils literal">.plugin</code> file next to them.</p>
  60. <p>So, 90% of the time, what you want to do is either write a new plugin or extend
  61. an existing one.</p>
  62. <p>There are several kinds of plugins, all implementing interfaces defined in
  63. <code class="docutils literal">nikola/plugin_categories.py</code> and documented in
  64. <a class="reference external" href="https://getnikola.com/extending.html">Extending Nikola</a></p>
  65. <p>If your plugin has a dependency, please make sure it doesn't make Nikola
  66. throw an exception when the dependency is missing. Try to fail gracefully
  67. with an informative message.</p>
  68. </dd>
  69. <dt>Commands are plugins</dt>
  70. <dd>
  71. <p>When you use <code class="docutils literal">nikola foo</code> you are using the plugin <code class="docutils literal">command/foo</code>. Those are
  72. used to extend Nikola's command line. Their interface is defined in the <code class="docutils literal">Command</code>
  73. class. They take options and arguments and do whatever you want, so go wild.</p>
  74. </dd>
  75. <dt>The <code class="docutils literal">build</code> command is special</dt>
  76. <dd>
  77. <p>The <code class="docutils literal">build</code> command triggers a whole lot of things, and is the core of Nikola
  78. because it's the one that you use to build sites. So it deserves its own section.</p>
  79. </dd>
  80. </dl>
  81. <section id="the-build-command"><h2>The Build Command</h2>
  82. <p>Nikola's goal is similar, deep at heart, to a Makefile. Take sources, compile them
  83. into something, in this case a website. Instead of a Makefile, Nikola uses
  84. <a class="reference external" href="https://pydoit.org">doit</a>.</p>
  85. <p>Doit has the concept of "tasks". The 1 minute summary of tasks is that they have:</p>
  86. <dl class="simple">
  87. <dt>actions</dt>
  88. <dd>
  89. <p>What the task <strong>does</strong>. For example, convert a markdown document into HTML.</p>
  90. </dd>
  91. <dt>dependencies</dt>
  92. <dd>
  93. <p>If this file changes, then we need to redo the actions. If this configuration
  94. option changes, redo it, etc.</p>
  95. </dd>
  96. <dt>targets</dt>
  97. <dd>
  98. <p>Files that the action generates. No two actions can have the same targets.</p>
  99. </dd>
  100. <dt>basename:name</dt>
  101. <dd>
  102. <p>Each task is identified by either a name or a basename:name pair.</p>
  103. </dd>
  104. </dl>
  105. <aside class="sidebar"><p class="sidebar-title">More about tasks</p>
  106. <p>If you ever want to do your own tasks, you really should read the doit
  107. <a class="reference external" href="https://pydoit.org/tasks.html">documentation on tasks</a>.</p>
  108. <p>Notably, by default doit redirects <code class="docutils literal">stdout</code> and <code class="docutils literal">stderr</code>. To get a
  109. proper PDB debugging shell, you need to use doit's own
  110. <a class="reference external" href="https://pydoit.org/tools.html#set-trace">set_trace</a> function.</p>
  111. </aside><p>So, what Nikola does, when you use the build command, is to read the
  112. configuration <code class="docutils literal">conf.py</code> from the current folder, instantiate
  113. the <code class="docutils literal">Nikola</code> class, and have it generate a whole list of tasks for doit
  114. to process. Then doit will decide which tasks need doing, and do them, in
  115. the right order.</p>
  116. <p>The place where the tasks are generated is in <code class="docutils literal">Nikola.gen_tasks</code>, which collects tasks
  117. from all the plugins inheriting <code class="docutils literal">BaseTask</code>, massages them a bit, then passes them
  118. to doit.</p>
  119. <p>So, if you want things to happen on <code class="docutils literal">build</code> you want to create a Task plugin, or extend
  120. one of the existing ones.</p>
  121. <aside class="sidebar"><p class="sidebar-title">Tests</p>
  122. <p>While Nikola is not a hardcore TDD project, we like tests. So, please add them if you can.
  123. You can write unit tests or integration tests. (Doctests are not supported
  124. anymore due to fragility.)</p>
  125. </aside></section><section id="posts-and-pages"><h2>Posts and Pages</h2>
  126. <p>Nikola has a concept of posts and pages. Both are more or less the same thing, except
  127. posts are added into RSS feeds and pages are not. All of them are in a list called
  128. "the timeline" formed by objects of class <code class="docutils literal">Post</code>.</p>
  129. <p>When you are creating a task that needs the list of posts and/or pages (for example,
  130. the RSS creation plugin) on task execution time, your plugin should call <code class="docutils literal">self.site.scan_posts()</code>
  131. in <code class="docutils literal">gen_tasks</code> to ensure the timeline is created and available in
  132. <code class="docutils literal">self.site.timeline</code>. You should not modify the timeline, because it will cause consistency issues.</p>
  133. <aside class="sidebar"><p class="sidebar-title">scan_posts</p>
  134. <p>The <code class="docutils literal">Nikola.scan_posts</code> function can be used in plugins to force the
  135. timeline creation, for example, while creating the tasks.</p>
  136. </aside><p>Your plugin can use the timeline to generate "stuff" (technical term). For example,
  137. Nikola comes with plugins that use the timeline to create a website (surprised?).</p>
  138. <p>The workflow included with nikola is as follows (incomplete!):</p>
  139. <ol class="arabic simple">
  140. <li><p>The post is assigned a compiler based on its extension and the <code class="docutils literal">COMPILERS</code> option.</p></li>
  141. <li><p>The compiler is applied to the post data and a "HTML fragment" is produced. That
  142. fragment is stored in a cache (the <code class="docutils literal">posts</code> plugin).</p></li>
  143. <li><p>The configured theme has templates (and a template engine), which are applied to the post's
  144. HTML fragment and metadata (the <code class="docutils literal">pages</code> plugin).</p></li>
  145. <li><p>The original sources for the post are copied to some accessible place (the <code class="docutils literal">sources</code> plugin).</p></li>
  146. <li><p>If the post is tagged, some pages and RSS feeds for each tag are updated (the <code class="docutils literal">tags</code> plugin).</p></li>
  147. <li><p>If the post is new, it's included in the blog's RSS feed (the <code class="docutils literal">rss</code> plugin).</p></li>
  148. <li><p>The post is added in the right place in the index pages for the blog (the <code class="docutils literal">indexes</code> plugin).</p></li>
  149. <li><p>CSS/JS/Images for the theme are put in the right places (the <code class="docutils literal">copy_assets</code> and <code class="docutils literal">bundles</code> plugins).</p></li>
  150. <li><p>A File describing the whole site is created (the <code class="docutils literal">sitemap</code> plugin).</p></li>
  151. </ol>
  152. <p>You can add whatever you want to that list: just create a plugin for it.</p>
  153. <p>You can also expand Nikola's capabilities at several points:</p>
  154. <dl class="simple">
  155. <dt>compilers</dt>
  156. <dd>
  157. <p>Nikola supports a variety of markups. If you want to add another one, you need to create
  158. a <code class="docutils literal">Compiler</code> plugin.</p>
  159. </dd>
  160. <dt>templates</dt>
  161. <dd>
  162. <p>Nikola's themes can use Jinja2 or Mako templates. If you prefer another template system,
  163. you have to create a <code class="docutils literal">TemplateSystem</code> plugin.</p>
  164. </dd>
  165. <dt>themes</dt>
  166. <dd>
  167. <p>To change how the generated site looks, you can create custom themes.</p>
  168. </dd>
  169. </dl>
  170. <p>And of course, you can also replace or extend each of the existing plugins.</p>
  171. <section id="nikola-architecture"><h3>Nikola Architecture</h3>
  172. <a class="reference external image-reference" href="https://getnikola.com/images/architecture.png"><img alt="https://getnikola.com/images/architecture.thumbnail.png" src="https://getnikola.com/images/architecture.thumbnail.png"></a>
  173. </section></section>
  174. </div>
  175. </article>
  176. </div>
  177. <div class="col-sm-3 col-sm-offset-1 blog-sidebar">
  178. <div class="sidebar-module sidebar-module-inset">
  179. <h4>About</h4>
  180. <div id="shoutcastdiv">
  181. <script type="text/javascript">
  182. refreshdiv();
  183. </script>
  184. </div>
  185. </div>
  186. <div class="sidebar-module">
  187. <h4>Links</h4>
  188. <ol class="list-unstyled">
  189. <li><a href="http://getbootstrap.com/examples/blog/">Bootstrap Blog Theme</a></li>
  190. <li><a href="https://getnikola.com/">Nikola</a></li>
  191. <li><a href="https://twitter.com/mdo">@mdo</a></li>
  192. <li><a href="https://twitter.com/Kwpolska">@Kwpolska</a></li>
  193. <li><a href="https://twitter.com/GetNikola">@GetNikola</a></li>
  194. </ol>
  195. </div>
  196. </div>
  197. <!--End of body content-->
  198. </div>
  199. </div>
  200. </div>
  201. <footer class="blog-footer" id="footer">
  202. Contents © 2023 <a href="mailto:contact@riff-radio.org">Riff</a> - Powered by <a href="https://getnikola.com" rel="nofollow">Nikola</a>
  203. </footer><script src="../assets/js/all-nocdn.js"></script><!-- fancy dates --><script>
  204. moment.locale("en");
  205. fancydates(0, "YYYY-MM-DD HH:mm");
  206. </script><!-- end fancy dates --><script>
  207. baguetteBox.run('div#content', {
  208. ignoreClass: 'islink',
  209. captions: function(element) {
  210. return element.getElementsByTagName('img')[0].alt;
  211. }});
  212. </script><script type="text/javascript" src="../refresh.js"></script>
  213. </body>
  214. </html>