Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

too much to say about it

  • Loading branch information...
commit 201ebb75ff060bf2faf77b19a0d70bc126a69d8a 1 parent 69f5f5e
Nicolas Perriault authored
Showing with 4,432 additions and 2,232 deletions.
  1. +61 −0 build/403.html
  2. +2 −1  build/404.html
  3. +2 −1  build/carnet/2010/back-from-djangocong-2010/index.html
  4. +3 −2 build/carnet/2010/choisir-son-metier/index.html
  5. +2 −1  build/carnet/2010/index.html
  6. +2 −1  build/carnet/2011/index.html
  7. +2 −1  build/carnet/2011/sudweb/index.html
  8. +2 −1  build/carnet/2012/index.html
  9. +2 −1  build/carnet/2012/nouveau-site/index.html
  10. +12 −12 build/carnet/feed/index.html
  11. +2 −1  build/carnet/index.html
  12. +55 −46 build/code/2010/about-rest-frameworks/index.html
  13. +58 −51 build/code/2010/custom-deployment-tasks/index.html
  14. +108 −75 build/code/2010/django-with-pip-virtualenv/index.html
  15. +69 −52 build/code/2010/express/index.html
  16. +2 −1  build/code/2010/index.html
  17. +31 −26 build/code/2010/pil-install/index.html
  18. +29 −18 build/code/2010/python-tab-completion/index.html
  19. +94 −81 build/code/2010/symfony-nginx-php-fpm/index.html
  20. +48 −35 build/code/2011/clever-settings/index.html
  21. +48 −41 build/code/2011/djt/index.html
  22. +2 −1  build/code/2011/index.html
  23. +151 −132 build/code/2011/scrape-and-test-any-webpage-using-phantomjs/index.html
  24. +14 −9 build/code/2011/setup-jenkins-github-private-repository-ubuntu/index.html
  25. +226 −189 build/code/2012/dead-easy-yet-powerful-static-website-generator-with-flask/index.html
  26. +34 −23 build/code/2012/gandi-standard-ssl-certificate-nginx/index.html
  27. +10 −1 build/code/2012/index.html
  28. +238 −0 build/code/2012/introducing-casperjs-toolkit-phantomjs/index.html
  29. +1,134 −802 build/code/feed/index.html
  30. +10 −9 build/code/index.html
  31. +2 −1  build/contact/index.html
  32. +635 −416 build/feed/index.html
  33. +18 −17 build/index.html
  34. +3 −1 build/photography/2009/climbers/index.html
  35. +3 −1 build/photography/2009/cross/index.html
  36. +3 −1 build/photography/2009/crossing-of-the-berezina-river/index.html
  37. +3 −1 build/photography/2009/dark-street/index.html
  38. +3 −1 build/photography/2009/euro/index.html
  39. +3 −1 build/photography/2009/fishers/index.html
  40. +3 −1 build/photography/2009/flying-home/index.html
  41. +2 −1  build/photography/2009/index.html
  42. +3 −1 build/photography/2009/last-chance-for-love/index.html
  43. +3 −1 build/photography/2009/last-cigarette/index.html
  44. +3 −1 build/photography/2009/mantis/index.html
  45. +3 −1 build/photography/2009/paris-night-light/index.html
  46. +3 −1 build/photography/2009/ray/index.html
  47. +3 −1 build/photography/2009/showoff/index.html
  48. +3 −1 build/photography/2009/smoke/index.html
  49. +3 −1 build/photography/2009/space-mountains/index.html
  50. +3 −1 build/photography/2009/steep/index.html
  51. +3 −1 build/photography/2009/thau-tot/index.html
  52. +3 −1 build/photography/2009/the-biker/index.html
  53. +3 −1 build/photography/2009/the-cyclop/index.html
  54. +3 −1 build/photography/2009/usual-puppets/index.html
  55. +3 −1 build/photography/2009/walking-shadows/index.html
  56. +3 −1 build/photography/2009/zebra-crossing/index.html
  57. +3 −1 build/photography/2010/angry-bird/index.html
  58. +2 −1  build/photography/2010/index.html
  59. +3 −1 build/photography/2010/soldes-en-arles/index.html
  60. +3 −1 build/photography/2010/sunny-plaza/index.html
  61. +3 −1 build/photography/2010/temple-of-consumption/index.html
  62. +3 −1 build/photography/2010/the-shadow/index.html
  63. +3 −1 build/photography/2010/timing-is-everything/index.html
  64. +3 −1 build/photography/2010/updown-side/index.html
  65. +3 −1 build/photography/2011/beach-boy/index.html
  66. +3 −1 build/photography/2011/blur/index.html
  67. +3 −1 build/photography/2011/bulls-raid/index.html
  68. +3 −1 build/photography/2011/cairn/index.html
  69. +3 −1 build/photography/2011/cloudy/index.html
  70. +3 −1 build/photography/2011/dolce-vita/index.html
  71. +2 −1  build/photography/2011/index.html
  72. +3 −1 build/photography/2011/moving-on/index.html
  73. +3 −1 build/photography/2011/ovation/index.html
  74. +3 −1 build/photography/2011/path/index.html
  75. +3 −1 build/photography/2011/presqu-ile-de-maguelone/index.html
  76. +3 −1 build/photography/2011/reading-desk/index.html
  77. +3 −1 build/photography/2011/reflections/index.html
  78. +3 −1 build/photography/2011/saint-guilhem-le-desert/index.html
  79. +3 −1 build/photography/2011/sandscape/index.html
  80. +3 −1 build/photography/2011/thau/index.html
  81. +3 −1 build/photography/2011/the-sheriff/index.html
  82. +3 −1 build/photography/2011/walkers-on-the-moon/index.html
  83. +104 −0 build/photography/2012/cadaques/index.html
  84. +3 −1 build/photography/2012/communism-is-dead/index.html
  85. +107 −0 build/photography/2012/dali-s-cadillac/index.html
  86. +8 −4 build/photography/2012/espiguette/index.html
  87. +6 −2 build/photography/2012/follow-the-black-dog/index.html
  88. +10 −1 build/photography/2012/index.html
  89. +3 −1 build/photography/2012/mystery-door/index.html
  90. +3 −1 build/photography/2012/presqu-ile-de-maguelone/index.html
  91. +3 −1 build/photography/2012/sunset-shooters/index.html
  92. +63 −63 build/photography/feed/index.html
  93. +10 −9 build/photography/index.html
  94. +3 −1 build/robots.txt
  95. +508 −0 build/sitemap.xml
  96. BIN  build/static/code/2012/testsuiteok.png
  97. +14 −2 build/static/css/style.css
  98. BIN  build/static/img/home.jpg
  99. BIN  build/static/js/libs/highlight/styles/brown_papersq.png
  100. BIN  build/static/js/libs/highlight/styles/school_book.png
  101. +22 −2 build/static/less/style.less
  102. +1 −1  build/static/packed.css
  103. BIN  build/static/photography/2012/cadaques/main.jpg
  104. BIN  build/static/photography/2012/cadaques/original.jpg
  105. BIN  build/static/photography/2012/cadaques/thumb.jpg
  106. BIN  build/static/photography/2012/dali-s-cadillac/main.jpg
  107. BIN  build/static/photography/2012/dali-s-cadillac/thumb.jpg
  108. +3 −1 build/static/robots.txt
  109. +2 −1  build/talks/2008/index.html
  110. +2 −1  build/talks/2008/methodes-et-processus-agiles/index.html
  111. +2 −1  build/talks/2009/30-symfony-best-practices/index.html
  112. +2 −1  build/talks/2009/index.html
  113. +2 −1  build/talks/2009/scrum-py/index.html
  114. +2 −1  build/talks/2010/django-pour-les-developpeurs-symfony-et-reciproquement/index.html
  115. +2 −1  build/talks/2010/index.html
  116. +2 −1  build/talks/2011/index.html
  117. +2 −1  build/talks/2011/integration-continue-projet-django/index.html
  118. +13 −13 build/talks/feed/index.html
  119. +2 −1  build/talks/index.html
  120. 0  import_photos.py → import_500px.py
  121. +1 −1  pages/carnet/2010/choisir-son-metier.md
  122. +8 −10 pages/code/2012/introducing-casperjs-toolkit-phantomjs.md
  123. +7 −0 pages/photography/2012/cadaques.md
  124. +8 −0 pages/photography/2012/dali-s-cadillac.md
  125. +2 −0  requirements.txt
  126. +88 −2 site
  127. BIN  static/code/2012/testsuiteok.png
  128. +14 −2 static/css/style.css
  129. BIN  static/img/home.jpg
  130. BIN  static/js/libs/highlight/styles/brown_papersq.png
  131. BIN  static/js/libs/highlight/styles/school_book.png
  132. +22 −2 static/less/style.less
  133. +1 −1  static/packed.css
  134. BIN  static/photography/2012/cadaques/main.jpg
  135. BIN  static/photography/2012/cadaques/original.jpg
  136. BIN  static/photography/2012/cadaques/thumb.jpg
  137. BIN  static/photography/2012/dali-s-cadillac/main.jpg
  138. BIN  static/photography/2012/dali-s-cadillac/thumb.jpg
  139. +3 −1 static/robots.txt
  140. +14 −0 templates/403.html
  141. +4 −0 templates/404.html
  142. +1 −0  templates/base.html
  143. +2 −2 templates/base.rss
  144. +4 −1 templates/page.html
  145. +54 −0 templates/sitemap.xml
  146. +43 −0 thumb.py
61 build/403.html
View
@@ -0,0 +1,61 @@
+<!doctype html>
+<html class="no-js" lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="robots" content="noindex, nofollow">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <title>Home | Nicolas Perriault</title>
+ <meta name="description" content="Nicolas Perriault's homepage.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
+ <link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
+ <link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
+ <link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
+ <link rel="alternate" type="application/rss+xml" href="/carnet/feed/" title="Carnet (RSS)">
+ <link rel="alternate" type="application/rss+xml" href="/feed/" title="Everything (RSS)">
+ <!--[if lt IE 9]>
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+</head>
+<body class="home ">
+ <!--[if lt IE 7]>
+ <p class="chromeframe">Your browser is <em>ancient!</em> Please <a href="http://www.quirksmode.org/upgrade.html">upgrade</a>.</p>
+ <![endif]-->
+ <div class="container">
+ <header class="main-title">
+ <h1><a href="/">Hi, I'm <strong>Nicolas.</strong></a></h1>
+ <small>I code stuff. I take photos. I write rants.</small>
+ </header>
+ <div class="contents">
+
+<h2>Can't touch this</h2>
+<iframe width="640" height="480" src="https://www.youtube-nocookie.com/embed/NyEE0qpfeig" frameborder="0" allowfullscreen></iframe>
+
+ </div>
+ <nav class="sidebar">
+ <ul>
+ <li class="home"><a href="/" hreflang="en">Home</a></li>
+ <li class="code"><a href="/code/" hreflang="en">Code</a></li>
+ <li class="photography"><a href="/photography/" hreflang="en">Photography</a></li>
+ <li class="talks"><a href="/talks/" hreflang="en">Talks</a></li>
+ <li class="carnet"><a href="/carnet/" hreflang="fr">Carnet <span>fr</span></a></li>
+ <li class="contact"><a href="/contact/" hreflang="en">Contact</a></li>
+ </ul>
+ </nav>
+ <footer class="site-footer">
+ <p>
+ &copy; 2012 Nicolas Perriault
+ — <a href="https://twitter.com/n1k0">Tweet at me</a>
+ — <a href="https://github.com/n1k0">Get my code</a>
+ — <a href="http://500px.com/n1k0">Enjoy my pics</a>
+ — <a href="/contact/">Contact me</a>
+ </p>
+ </footer>
+ </div>
+ <!-- /container -->
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script>window.jQuery || document.write('<script src="js/libs/jquery-1.7.1.min.js"><\/script>')</script>
+ <script type="text/javascript" src="/static/packed.js?1331026602"></script>
+ <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
+</body>
+</html>
3  build/404.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+ <meta name="robots" content="noindex, nofollow">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Home | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
3  build/carnet/2010/back-from-djangocong-2010/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>De retour de Djangocong | Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
5 build/carnet/2010/choisir-son-metier/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Choisir son métier, arrêter de le (faire) subir | Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -152,7 +153,7 @@
<h3&nbsp;Bon, tu conclues là&nbsp;? J'vais rater l'apéro&nbsp;»</h3>
<p>Oui, je suis un peu décontenancé à la lecture de ces quelques commentaires. On constate tous que bien des commanditaires ne comprennent pas les enjeux de leur métier d'acheteur de prestation de développements informatiques. Je découvre qu'il est des professionnels tellement désabusés qu'ils ont visiblement renoncé à toute vélléité d'éducation de leurs prospects sur les questions d'organisation méthodologique et collaborative du travail, part intégrante du champ d'expertise de tout prestataire de développement informatique un tant soit peu digne de ce nom et prétendant offrir un conseil de qualité. Je ne peux me résoudre à croire qu'ils n'ont pas le choix, que tout ceci est inévitable, et que «&nbsp;c'est la crise, il faut bien bouffer, ma pauvre dame&nbsp;».</p>
<p><strong>Je pense au contraire qu'une part importante de notre métier, j'irai même jusqu'à parler de notre devoir déontologique, est de les accompagner dans la compréhension de leur rôle dans les processus collaboratifs projet afin de maximiser le potentiel de réussite de ces derniers coûte que coûte.</strong> Et d'<a href="http://www.alistapart.com/articles/no-one-nos-learning-to-say-no-to-bad-ideas/">apprendre à dire non</a> lorsque cela s'avère nécessaire, plutôt que de s'engluer dans cette vision fataliste, nivelant par le bas la qualité globale d'une partie grandissante des réalisations auquel le Web est confronté (france.fr anyone?).</p>
-<p>Vous pouvez maintenant basher <del>en commentaire</del> <a href="/contact">par email</a>, c'est fait pour ça ;)</p>
+<p>Vous pouvez maintenant basher <del>en commentaire</del> <a href="/contact">par email</a>, c'est fait pour ça.</p>
</section>
<aside>
<p>
3  build/carnet/2010/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
3  build/carnet/2011/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
3  build/carnet/2011/sudweb/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Du Sud avec du Web dedans, et réciproquement | Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
3  build/carnet/2012/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
3  build/carnet/2012/nouveau-site/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Nouveau site | Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
24 build/carnet/feed/index.html
View
@@ -2,15 +2,15 @@
<rss version="2.0">
<channel>
<title>Carnet</title>
- <link>http://nicolas.perriault.net</link>
+ <link>https://nicolas.perriault.net</link>
<description>Le petit coin d'aigreur sur la toile de Nicolas Perriault.</description>
<language>fr</language>
- <pubDate>Tue, 06 Mar 2012 10:36:50 +0000</pubDate>
- <lastBuildDate>Tue, 06 Mar 2012 10:36:50 +0000</lastBuildDate>
+ <pubDate>Tue, 13 Mar 2012 17:45:35 +0000</pubDate>
+ <lastBuildDate>Tue, 13 Mar 2012 17:45:35 +0000</lastBuildDate>
<item>
<title>Nouveau site</title>
- <link>http://nicolas.perriault.net/carnet/2012/nouveau-site</link>
+ <link>https://nicolas.perriault.net/carnet/2012/nouveau-site/</link>
<description>&lt;p&gt;&lt;strong&gt;J&#39;avais envie de fédérer l&#39;ensemble de ma &lt;em&gt;production numérique&lt;/em&gt; au sein d&#39;un seul et même site, c&#39;est donc chose faite si vous lisez ces quelques lignes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J&#39;ai essayé de résumer au maximum mes activités principales, du moins celles que je trouve potentiellement dignes d&#39;intérêt pour autrui et sur lesquelles j&#39;ai envie de communiquer publiquement&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
@@ -31,11 +31,11 @@
&lt;h2&gt;À venir&lt;/h2&gt;
&lt;p&gt;Il me reste pas mal de photos à importer et quelques redirections permanentes à mettre en place, mais je suis globalement plutôt satisfait du résultat. Surtout, je vais pouvoir me remettre à écrire autre chose que des &lt;a href=&#34;https://twitter.com/n1k0&#34;&gt;&lt;em&gt;tweets&lt;/em&gt;&lt;/a&gt;, et ça c&#39;est plutôt cool.&lt;/p&gt;</description>
<pubDate>Sat, 03 Mar 2012 00:00:00 +0000</pubDate>
- <guid>http://nicolas.perriault.net/carnet/2012/nouveau-site</guid>
+ <guid>https://nicolas.perriault.net/carnet/2012/nouveau-site/</guid>
</item>
<item>
<title>Du Sud avec du Web dedans, et réciproquement</title>
- <link>http://nicolas.perriault.net/carnet/2011/sudweb</link>
+ <link>https://nicolas.perriault.net/carnet/2011/sudweb/</link>
<description>&lt;p&gt;Ceux qui me connaissent le savent, je suis partisan d&#39;une gestion intransigeante de la qualité sur le Web, et suis donc&amp;nbsp;— comme souvent dans ce cas&amp;nbsp;— un grand fan du cycle de conférences &lt;a href=&#34;http://www.paris-web.fr/&#34;&gt;Paris&amp;nbsp;Web&lt;/a&gt; qui a lieu tous les ans en octobre à Paris. C&#39;est l&#39;occasion d&#39;y faire un état des lieux des meilleurs pratiques, d&#39;attraper un rhume, de découvrir de nouvelles techniques, de profiter des joies du métro, ou de rafraîchir ses connaissances (au propre comme au figuré). Surtout, c&#39;est l&#39;occasion d&#39;échanger avec d&#39;autres passionnés de la profession autour de breuvages houblonnés le soir venu en refaisant le Web jusqu&#39;à plus d&#39;heure ni soif.&lt;/p&gt;
&lt;p&gt;Mais voila, Paris, c&#39;est &lt;a href=&#34;http://blog.breizh.bz/?166-la-france-vue-parles-toulousains-episode-7&#34;&gt;loin&lt;/a&gt;. Et Paris, ça a tendance à un peu trop vouloir centraliser tout ce qui remue à mon goût. Je m&#39;en rends forcément mieux compte depuis que j&#39;ai déménagé à Montpellier il y a un an et demi (fichtre comme le temps passe). Et surtout, je constate que la région dans laquelle je vis est immensément riche de passion et de compétences autour de ce noble medium qui est le nôtre. Des gens bien, un peu partout autour de moi, qui n&#39;ont pas toujours la possibilité de se déplacer jusqu&#39;à la capitale, de s&#39;y loger, de s&#39;y nourrir, de s&#39;y acheter le nombre d&#39;écharpes nécessaires pour survivre, etc.&lt;/p&gt;
&lt;p&gt;Aussi, durant le trajet en voiture qui nous conduisait au dernier Paris&amp;nbsp;Web moi et mes compagnons de route, nous avons une idée assez folle&amp;nbsp;: organiser un évènement du même type que Paris&amp;nbsp;Web, mais dans le sud. C&#39;est à dire plus proche de nous géographiquement et assurant une meilleure compatibilité feinéantique et calorifère. Ainsi naquit l&#39;idée d&#39;un &lt;a href=&#34;http://sudweb.fr/&#34;&gt;SubWeb&lt;/a&gt;.&lt;/p&gt;
@@ -62,11 +62,11 @@
&lt;p&gt;Enfin, sachez qu&#39;un financement du prix du ticket d&#39;entrée est possible dans le cadre du &lt;a href=&#34;http://sudweb.fr/post/Prenez-un-pack-Web-UXSud-Web-et-profitez-du-DIF&#34;&gt;Droit Individuel à la Formation (DIF)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ne tardez pas pour &lt;a href=&#34;http://tickets.web-ux.org/&#34;&gt;commander votre place en ligne&lt;/a&gt;, la &lt;strong&gt;clôture des inscriptions est prévue pour le 2 mai&lt;/strong&gt;.&lt;/p&gt;</description>
<pubDate>Fri, 28 Jan 2011 00:00:00 +0000</pubDate>
- <guid>http://nicolas.perriault.net/carnet/2011/sudweb</guid>
+ <guid>https://nicolas.perriault.net/carnet/2011/sudweb/</guid>
</item>
<item>
<title>Choisir son métier, arrêter de le (faire) subir</title>
- <link>http://nicolas.perriault.net/carnet/2010/choisir-son-metier</link>
+ <link>https://nicolas.perriault.net/carnet/2010/choisir-son-metier/</link>
<description>&lt;p&gt;Je viens de finir la lecture de l&#39;excellent billet de &lt;a href=&#34;http://www.miximum.fr/&#34;&gt;Thibault&lt;/a&gt;, «&amp;nbsp;&lt;a href=&#34;http://www.miximum.fr/bien-developper/525-dialogue-avec-un-client&#34;&gt;Dialogue avec un client&lt;/a&gt;&amp;nbsp;». Ce billet présente point pour point ma vision de ce qu&#39;est une collaboration efficace autour d&#39;un projet informatique&amp;nbsp;; je n&#39;y apprends rien de vraiment nouveau (ayant partiellement nourri la conversation qu&#39;il y relate), mais je suis ravi de voir que je ne suis pas le seul à partager le sentiment que la collaboration est vraiment à réinventer dans ce métier.&lt;/p&gt;
&lt;p&gt;Ce qui me chagrine plus en revanche, c&#39;est la lecture de certains commentaires, relativement fatalistes et désabusés&amp;nbsp;; je ne resiste pas à la tentation d&#39;en commenter certains.&lt;/p&gt;
&lt;h3&gt;La métaphore du concessionnaire automobile&lt;/h3&gt;
@@ -185,18 +185,18 @@
&lt;h3&gt;«&amp;nbsp;Bon, tu conclues là&amp;nbsp;? J&#39;vais rater l&#39;apéro&amp;nbsp;»&lt;/h3&gt;
&lt;p&gt;Oui, je suis un peu décontenancé à la lecture de ces quelques commentaires. On constate tous que bien des commanditaires ne comprennent pas les enjeux de leur métier d&#39;acheteur de prestation de développements informatiques. Je découvre qu&#39;il est des professionnels tellement désabusés qu&#39;ils ont visiblement renoncé à toute vélléité d&#39;éducation de leurs prospects sur les questions d&#39;organisation méthodologique et collaborative du travail, part intégrante du champ d&#39;expertise de tout prestataire de développement informatique un tant soit peu digne de ce nom et prétendant offrir un conseil de qualité. Je ne peux me résoudre à croire qu&#39;ils n&#39;ont pas le choix, que tout ceci est inévitable, et que «&amp;nbsp;c&#39;est la crise, il faut bien bouffer, ma pauvre dame&amp;nbsp;».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je pense au contraire qu&#39;une part importante de notre métier, j&#39;irai même jusqu&#39;à parler de notre devoir déontologique, est de les accompagner dans la compréhension de leur rôle dans les processus collaboratifs projet afin de maximiser le potentiel de réussite de ces derniers coûte que coûte.&lt;/strong&gt; Et d&#39;&lt;a href=&#34;http://www.alistapart.com/articles/no-one-nos-learning-to-say-no-to-bad-ideas/&#34;&gt;apprendre à dire non&lt;/a&gt; lorsque cela s&#39;avère nécessaire, plutôt que de s&#39;engluer dans cette vision fataliste, nivelant par le bas la qualité globale d&#39;une partie grandissante des réalisations auquel le Web est confronté (france.fr anyone?).&lt;/p&gt;
-&lt;p&gt;Vous pouvez maintenant basher &lt;del&gt;en commentaire&lt;/del&gt; &lt;a href=&#34;/contact&#34;&gt;par email&lt;/a&gt;, c&#39;est fait pour ça ;)&lt;/p&gt;</description>
+&lt;p&gt;Vous pouvez maintenant basher &lt;del&gt;en commentaire&lt;/del&gt; &lt;a href=&#34;/contact&#34;&gt;par email&lt;/a&gt;, c&#39;est fait pour ça.&lt;/p&gt;</description>
<pubDate>Wed, 27 Oct 2010 00:00:00 +0000</pubDate>
- <guid>http://nicolas.perriault.net/carnet/2010/choisir-son-metier</guid>
+ <guid>https://nicolas.perriault.net/carnet/2010/choisir-son-metier/</guid>
</item>
<item>
<title>De retour de Djangocong</title>
- <link>http://nicolas.perriault.net/carnet/2010/back-from-djangocong-2010</link>
+ <link>https://nicolas.perriault.net/carnet/2010/back-from-djangocong-2010/</link>
<description>&lt;p&gt;Les rencontres &lt;a href=&#34;http://rencontres.django-fr.org/&#34;&gt;Django francophones 2010&lt;/a&gt;, tenues à Marseille, viennent de s&#39;achever.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://welldev.fr/&#34;&gt;David Larlet&lt;/a&gt; m&#39;ayant invité à y participer, j&#39;y ai présenté une conférence &#34;Django pour les développeurs Symfony&#34; puisqu&#39;étant moi-meme utilisateur des deux frameworks.&lt;/p&gt;
&lt;p&gt;Vous trouverez les slides de la présentation &lt;a href=&#34;http://www.slideshare.net/nperriault/symfony-pour-les-dveloppeurs-django-et-rciproquement&#34;&gt;sur slideshare&lt;/a&gt;, ou sur la page dédiée à &lt;a href=&#34;http://www.akei.com/fr/services/django&#34;&gt;Django sur le site d&#39;Akei&lt;/a&gt;.&lt;/p&gt;</description>
<pubDate>Mon, 26 Apr 2010 00:00:00 +0000</pubDate>
- <guid>http://nicolas.perriault.net/carnet/2010/back-from-djangocong-2010</guid>
+ <guid>https://nicolas.perriault.net/carnet/2010/back-from-djangocong-2010/</guid>
</item>
</channel>
3  build/carnet/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="fr">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Carnet | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
101 build/code/2010/about-rest-frameworks/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>About RESTful features of modern Web frameworks | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -37,57 +38,65 @@
<p>Frameworks like <a href="http://www.symfony-project.org/">Symfony</a> or <a href="http://rubyonrails.org/">rails</a> (and probably many others) provide a very convenient feature named <em>RESTful</em> routing, aka HTTP-aware urls and controllers, generally associated with an object/url mapping mechanism to expose Model entites and several available actions on them over HTTP.</p>
<p>This is really useful, especially when you deal with WebServices on a daily basis, or if you want to reuse your controllers in both <em>standard html</em> or <em>service oriented architecture</em> (SOA) contexts.</p>
<p>For example, with Symfony, you can declare an HTTP routes collection this way (all examples are taken from the <a href="http://github.com/n1k0/sftunes">Sftunes Symfony application</a> I recently released on <em>github</em>):</p>
-<pre><code># routing.yml
-fortune:
- class: sfDoctrineRouteCollection
- options:
- model: Fortune
- action: [list, new, create, edit, show]
- object_actions:
- comment: post
- down: put
- up: put
- collection_actions:
- top: get
- worst: get
-</code></pre>
+<div class="codehilite"><pre><span class="c"># routing.yml</span>
+<span class="n">fortune</span><span class="p">:</span>
+ <span class="nb">class</span><span class="p">:</span> <span class="n">sfDoctrineRouteCollection</span>
+ <span class="n">options</span><span class="p">:</span>
+ <span class="n">model</span><span class="p">:</span> <span class="n">Fortune</span>
+ <span class="n">action</span><span class="p">:</span> <span class="p">[</span><span class="n">list</span><span class="p">,</span> <span class="n">new</span><span class="p">,</span> <span class="n">create</span><span class="p">,</span> <span class="n">edit</span><span class="p">,</span> <span class="n">show</span><span class="p">]</span>
+ <span class="n">object_actions</span><span class="p">:</span>
+ <span class="n">comment</span><span class="p">:</span> <span class="n">post</span>
+ <span class="n">down</span><span class="p">:</span> <span class="n">put</span>
+ <span class="n">up</span><span class="p">:</span> <span class="n">put</span>
+ <span class="n">collection_actions</span><span class="p">:</span>
+ <span class="n">top</span><span class="p">:</span> <span class="k">get</span>
+ <span class="n">worst</span><span class="p">:</span> <span class="k">get</span>
+</pre></div>
+
+
<p>Here the <code>fortune</code> route collection will expose the <code>Fortune</code> Doctrine ORM model over HTTP, using available HTTP verbs like <code>GET</code>, <code>PUT</code>, <code>POST</code> or <code>DELETE</code> for example, hence providing basic CRUD operations (see <a href="http://www.symfony-project.org/reference/1_4/en/10-Routing#chapter_10_sfroutecollection">documentation</a>).</p>
<p>You will then be able to obtain several Symfony routes, to list them just run the <code>app:routes</code> task from the command line:</p>
-<pre><code>~ $ ./symfony app:routes main
-&gt;&gt; app Current routes for application "main"
-Name Method Pattern
-fortune_top GET /fortune/top.:sf_format
-fortune_worst GET /fortune/worst.:sf_format
-fortune GET /fortune.:sf_format
-fortune_new GET /fortune/new.:sf_format
-fortune_create POST /fortune.:sf_format
-fortune_edit GET /fortune/:id/edit.:sf_format
-fortune_update PUT /fortune/:id.:sf_format
-fortune_delete DELETE /fortune/:id.:sf_format
-fortune_show GET /fortune/:id.:sf_format
-fortune_comment POST /fortune/:id/comment.:sf_format
-fortune_down PUT /fortune/:id/down.:sf_format
-fortune_up PUT /fortune/:id/up.:sf_format
-homepage ANY /
-</code></pre>
+<div class="codehilite"><pre><span class="o">~</span> $ <span class="o">./</span><span class="n">symfony</span> <span class="n">app</span><span class="p">:</span><span class="n">routes</span> <span class="n">main</span>
+<span class="o">&gt;&gt;</span> <span class="n">app</span> <span class="n">Current</span> <span class="n">routes</span> <span class="k">for</span> <span class="n">application</span> &quot;<span class="n">main</span>&quot;
+<span class="n">Name</span> <span class="n">Method</span> <span class="n">Pattern</span>
+<span class="n">fortune_top</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="n">top</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_worst</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="n">worst</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_new</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="n">new</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_create</span> <span class="n">POST</span> <span class="o">/</span><span class="n">fortune</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_edit</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="o">/</span><span class="n">edit</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_update</span> <span class="n">PUT</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_delete</span> <span class="n">DELETE</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_show</span> <span class="n">GET</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_comment</span> <span class="n">POST</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="o">/</span><span class="n">comment</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_down</span> <span class="n">PUT</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="o">/</span><span class="n">down</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">fortune_up</span> <span class="n">PUT</span> <span class="o">/</span><span class="n">fortune</span><span class="o">/</span><span class="p">:</span><span class="n">id</span><span class="o">/</span><span class="n">up</span><span class="p">.:</span><span class="n">sf_format</span>
+<span class="n">homepage</span> <span class="n">ANY</span> <span class="o">/</span>
+</pre></div>
+
+
<p>By calling an url such as <code>/fortune/2.html</code> using the <code>GET</code> verb, you'll obtain a response in <em>text/html</em> format, and Symfony will use a standard HTML template to decorate it -- whereas if you call <code>/fortune/2.json</code> using the <code>DELETE</code> verb, you'll ask for the deletion of the fortune related instance and receive a response in JSON format (at least if you provided the related JSON decoration template, of course).</p>
<p>That's pretty fancy, but a common mistake is to generate links from templates calling verbs other than <code>GET</code>, for example here the <code>fortune_up</code> and <code>fortune_down</code> routes aim to be called via <code>PUT</code> (because they imply a modification of a <code>Fortune</code> object instance), and you may be tempted to write something like this in you templates:</p>
-<pre><code>&lt;?php echo link_to('Vote down this fortune', 'fortune_down', $fortune, array(
- 'method' =&gt; 'put',
-)) ?&gt;
-</code></pre>
+<div class="codehilite"><pre><span class="cp">&lt;?php</span> <span class="k">echo</span> <span class="nx">link_to</span><span class="p">(</span><span class="s1">&#39;Vote down this fortune&#39;</span><span class="p">,</span> <span class="s1">&#39;fortune_down&#39;</span><span class="p">,</span> <span class="nv">$fortune</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span>
+ <span class="s1">&#39;method&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;put&#39;</span><span class="p">,</span>
+<span class="p">))</span> <span class="cp">?&gt;</span>
+</pre></div>
+
+
<p>While this is perfectly possible technically speaking, a quick look at the rendered HTML code will temper the interest of this approach:</p>
-<pre><code>&lt;a onclick="var f = document.createElement('form'); f.style.display = 'none';
- this.parentNode.appendChild(f); f.method = 'post'; f.action = this.href;
- var m = document.createElement('input'); m.setAttribute('type', 'hidden');
- m.setAttribute('name', 'sf_method'); m.setAttribute('value', 'put');
- f.appendChild(m);var m=document.createElement('input');m.setAttribute('type', 'hidden');
- m.setAttribute('name', '_csrf_token');
- m.setAttribute('value', 'd26d99f7f4f97lsdhklqejshdjkshdf860124');
- f.appendChild(m);f.submit();return false;" href="/main_dev.php/fortune/19/down"&gt;
+<div class="codehilite"><pre><span class="nt">&lt;a</span> <span class="na">onclick=</span><span class="s">&quot;var f = document.createElement(&#39;form&#39;); f.style.display = &#39;none&#39;;</span>
+<span class="s"> this.parentNode.appendChild(f); f.method = &#39;post&#39;; f.action = this.href;</span>
+<span class="s"> var m = document.createElement(&#39;input&#39;); m.setAttribute(&#39;type&#39;, &#39;hidden&#39;);</span>
+<span class="s"> m.setAttribute(&#39;name&#39;, &#39;sf_method&#39;); m.setAttribute(&#39;value&#39;, &#39;put&#39;);</span>
+<span class="s"> f.appendChild(m);var m=document.createElement(&#39;input&#39;);m.setAttribute(&#39;type&#39;, &#39;hidden&#39;);</span>
+<span class="s"> m.setAttribute(&#39;name&#39;, &#39;_csrf_token&#39;);</span>
+<span class="s"> m.setAttribute(&#39;value&#39;, &#39;d26d99f7f4f97lsdhklqejshdjkshdf860124&#39;);</span>
+<span class="s"> f.appendChild(m);f.submit();return false;&quot;</span> <span class="na">href=</span><span class="s">&quot;/main_dev.php/fortune/19/down&quot;</span><span class="nt">&gt;</span>
Vote down this fortune
-&lt;/a&gt;
-</code></pre>
+<span class="nt">&lt;/a&gt;</span>
+</pre></div>
+
+
<p>Yes, calling <code>link_to()</code> with the <code>method</code> option set to something else than <code>GET</code> will generate a form to challenge the url with the correct HTTP verb (through the kinda magic <code>sf_method</code> request parameter), dynamically using Javascript. Not really clean, unobstrusive and accessible. <strong>A link should always only handle <code>GET</code> verb, because it's just a link to another resource in <em>view mode</em>, not a modification of it.</strong> So you should rather use a <code>&lt;form/&gt;</code> tag to deal with such kind of operations in your code, always.</p>
<p>But there's more: imagine you want to deal with a <code>Fortune</code> modification form, still by using the <code>PUT</code> http verb and the <code>fortune_update</code> route, in a <em>standard html</em> context (not a WebService one); you have a form so it's okay? It's not, a browser, even the most modern one in 2010, will not understand something else than <code>GET</code> and <code>POST</code>. That's a shame actually. Symfony circumvents the problem by adding a supplementary <code>sf_method</code> hidden parameter to the form fields, so the targetted controller will be able to detect an incoming <code>PUT</code> request, but <strong>this is clearly a kind of patch applied to HTTP support in Browsers</strong>.</p>
<p>I'm searching for a conclusion, but can't find one except <strong>why on Earth modern browsers don't deal with something else than <code>GET</code> and <code>POST</code> nowadays?</strong></p>
109 build/code/2010/custom-deployment-tasks/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Tâches de déploiement spécifiques avec Symfony | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -35,65 +36,71 @@
<section>
<p><a href="http://www.symfony-project.org/">Symfony</a> propose une tâche de déploiement distant utilisant <a href="http://fr.wikipedia.org/wiki/Rsync"><code>rsync</code></a> fort pratique&nbsp;: une fois configurés les <a href="http://www.symfony-project.org/jobeet/1_4/Doctrine/en/22#chapter_22_deploying">paramètres du serveur distant</a> dans le fichier <code>config/properties.ini</code> de votre projet, un simple appel en ligne de commande synchronisera les fichiers du projet présents sur votre système de fichiers local vers l'hôte distant. Et si vous utilisez une <a href="http://prendreuncafe.com/blog/post/2005/08/29/262-installer-sa-cle-ssh-sur-un-serveur-distant">clé SSH</a>, l'opération ne vous demandera même pas de saisir votre mot de passe&nbsp;!</p>
-<pre><code>$ ./symfony project:deploy monserveur --go
-</code></pre>
+<div class="codehilite"><pre>$ <span class="o">./</span><span class="n">symfony</span> <span class="n">project</span><span class="p">:</span><span class="n">deploy</span> <span class="n">monserveur</span> <span class="o">--</span><span class="n">go</span>
+</pre></div>
+
+
<p>Mais bien souvent, nous avons besoin de plus&nbsp;: préparer un certain nombre de fichiers statiques comme les assets CSS, JavaScript ou les images, ou vider le cache sur la ou les machines distantes pour prendre en compte d'éventuelles modifications de la configuration ou du templating sur la plateforme de production (qui exploite l'environnement du même nom, nous sommes bien d'accord).</p>
<p>Aussi, il est très simple de faire face à ces besoins spécifiques en créant vous même une tâche de déploiement projet, en surclassant la classe <code>sfProjectDeployTask</code> fournie en standard par Symfony. Par exemple, voici la tâche de déploiement que j'utilise pour la mise à jour du site <a href="http://www.akei.com/">Akei</a>, exploitant mon plugin <a href="http://github.com/n1k0/npAssetsOptimizerPlugin"><code>npAssetsOptimizerPlugin</code></a> pour la gestion de la minification et l'assemblage des fichiers JavaScript, CSS et images PNG &nbsp;:</p>
-<pre><code>&lt;?php
-class AkeiDeployTask extends sfProjectDeployTask
-{
- /**
- * @see sfProjectDeployTask
- */
- protected function configure()
- {
- $this-&gt;addArguments(array(
- new sfCommandArgument('server', sfCommandArgument::REQUIRED, 'The server name'),
- ));
+<div class="codehilite"><pre><span class="cp">&lt;?php</span>
+<span class="k">class</span> <span class="nc">AkeiDeployTask</span> <span class="k">extends</span> <span class="nx">sfProjectDeployTask</span>
+<span class="p">{</span>
+ <span class="sd">/**</span>
+<span class="sd"> * @see sfProjectDeployTask</span>
+<span class="sd"> */</span>
+ <span class="k">protected</span> <span class="k">function</span> <span class="nf">configure</span><span class="p">()</span>
+ <span class="p">{</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addArguments</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
+ <span class="k">new</span> <span class="nx">sfCommandArgument</span><span class="p">(</span><span class="s1">&#39;server&#39;</span><span class="p">,</span> <span class="nx">sfCommandArgument</span><span class="o">::</span><span class="na">REQUIRED</span><span class="p">,</span> <span class="s1">&#39;The server name&#39;</span><span class="p">),</span>
+ <span class="p">));</span>
+
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addOptions</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
+ <span class="k">new</span> <span class="nx">sfCommandOption</span><span class="p">(</span><span class="s1">&#39;go&#39;</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="nx">sfCommandOption</span><span class="o">::</span><span class="na">PARAMETER_NONE</span><span class="p">,</span> <span class="s1">&#39;Do the deployment&#39;</span><span class="p">),</span>
+ <span class="k">new</span> <span class="nx">sfCommandOption</span><span class="p">(</span><span class="s1">&#39;rsync-dir&#39;</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="nx">sfCommandOption</span><span class="o">::</span><span class="na">PARAMETER_REQUIRED</span><span class="p">,</span> <span class="s1">&#39;The directory where to look for rsync*.txt files&#39;</span><span class="p">,</span> <span class="s1">&#39;config&#39;</span><span class="p">),</span>
+ <span class="k">new</span> <span class="nx">sfCommandOption</span><span class="p">(</span><span class="s1">&#39;rsync-options&#39;</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="nx">sfCommandOption</span><span class="o">::</span><span class="na">PARAMETER_OPTIONAL</span><span class="p">,</span> <span class="s1">&#39;To options to pass to the rsync executable&#39;</span><span class="p">,</span> <span class="s1">&#39;-azC --force --delete --progress&#39;</span><span class="p">),</span>
+ <span class="k">new</span> <span class="nx">sfCommandOption</span><span class="p">(</span><span class="s1">&#39;optimize&#39;</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="nx">sfCommandOption</span><span class="o">::</span><span class="na">PARAMETER_OPTIONAL</span><span class="p">,</span> <span class="s1">&#39;The asset optimizations to make before deploying&#39;</span><span class="p">),</span>
+ <span class="p">));</span>
- $this-&gt;addOptions(array(
- new sfCommandOption('go', null, sfCommandOption::PARAMETER_NONE, 'Do the deployment'),
- new sfCommandOption('rsync-dir', null, sfCommandOption::PARAMETER_REQUIRED, 'The directory where to look for rsync*.txt files', 'config'),
- new sfCommandOption('rsync-options', null, sfCommandOption::PARAMETER_OPTIONAL, 'To options to pass to the rsync executable', '-azC --force --delete --progress'),
- new sfCommandOption('optimize', null, sfCommandOption::PARAMETER_OPTIONAL, 'The asset optimizations to make before deploying'),
- ));
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">namespace</span> <span class="o">=</span> <span class="s1">&#39;akei&#39;</span><span class="p">;</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">name</span> <span class="o">=</span> <span class="s1">&#39;deploy&#39;</span><span class="p">;</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">briefDescription</span> <span class="o">=</span> <span class="s1">&#39;Deploys Akei website to a given server&#39;</span><span class="p">;</span>
+ <span class="p">}</span>
- $this-&gt;namespace = 'akei';
- $this-&gt;name = 'deploy';
- $this-&gt;briefDescription = 'Deploys Akei website to a given server';
- }
+ <span class="sd">/**</span>
+<span class="sd"> * @see sfProjectDeployTask</span>
+<span class="sd"> */</span>
+ <span class="k">protected</span> <span class="k">function</span> <span class="nf">execute</span><span class="p">(</span><span class="nv">$arguments</span> <span class="o">=</span> <span class="k">array</span><span class="p">(),</span> <span class="nv">$options</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
+ <span class="p">{</span>
+ <span class="c1">// Assets</span>
+ <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$options</span><span class="p">[</span><span class="s1">&#39;optimize&#39;</span><span class="p">]))</span>
+ <span class="p">{</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">logSection</span><span class="p">(</span><span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;assets optimization before deploying&#39;</span><span class="p">);</span>
+ <span class="nv">$task</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">npOptimizeAssetsTask</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">dispatcher</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">formatter</span><span class="p">);</span>
+ <span class="nv">$task</span><span class="o">-&gt;</span><span class="na">run</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s1">&#39;application&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;main&#39;</span><span class="p">),</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;type&#39;</span> <span class="o">=&gt;</span> <span class="nv">$options</span><span class="p">[</span><span class="s1">&#39;optimize&#39;</span><span class="p">]));</span>
+ <span class="p">}</span>
- /**
- * @see sfProjectDeployTask
- */
- protected function execute($arguments = array(), $options = array())
- {
- // Assets
- if (!is_null($options['optimize']))
- {
- $this-&gt;logSection('deploy', 'assets optimization before deploying');
- $task = new npOptimizeAssetsTask($this-&gt;dispatcher, $this-&gt;formatter);
- $task-&gt;run(array('application' =&gt; 'main'), array('type' =&gt; $options['optimize']));
- }
+ <span class="c1">// Deployment</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">logSection</span><span class="p">(</span><span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;deploying...&#39;</span><span class="p">);</span>
+ <span class="k">parent</span><span class="o">::</span><span class="na">execute</span><span class="p">(</span><span class="nv">$arguments</span><span class="p">,</span> <span class="nv">$options</span><span class="p">);</span>
- // Deployment
- $this-&gt;logSection('deploy', 'deploying...');
- parent::execute($arguments, $options);
+ <span class="c1">// Remote symfony cc</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nv">$options</span><span class="p">[</span><span class="s1">&#39;go&#39;</span><span class="p">])</span>
+ <span class="p">{</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">logSection</span><span class="p">(</span><span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;remote cache clear&#39;</span><span class="p">);</span>
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getFilesystem</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">(</span><span class="s1">&#39;ssh user@monserveur.foo &quot;/path/to/www/akei/symfony cache:clear&quot;&#39;</span><span class="p">);</span>
+ <span class="p">}</span>
+
+ <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">logSection</span><span class="p">(</span><span class="s1">&#39;deploy&#39;</span><span class="p">,</span> <span class="s1">&#39;done.&#39;</span><span class="p">);</span>
+ <span class="p">}</span>
+<span class="p">}</span>
+</pre></div>
- // Remote symfony cc
- if ($options['go'])
- {
- $this-&gt;logSection('deploy', 'remote cache clear');
- $this-&gt;getFilesystem()-&gt;execute('ssh user@monserveur.foo "/path/to/www/akei/symfony cache:clear"');
- }
- $this-&gt;logSection('deploy', 'done.');
- }
-}
-</code></pre>
<p>Comme vous pouvez le constater, cette tâche déclare un espace de nom <code>akei</code> et propose une option supplémentaire, <code>optimize</code>, permettant de préparer les assets avant déploiement&nbsp;:</p>
-<pre><code>$ ./symfony akei:deploy monserveur --optimize=stylesheet --go
-</code></pre>
+<div class="codehilite"><pre>$ <span class="o">./</span><span class="n">symfony</span> <span class="n">akei</span><span class="p">:</span><span class="n">deploy</span> <span class="n">monserveur</span> <span class="o">--</span><span class="n">optimize</span><span class="p">=</span><span class="n">stylesheet</span> <span class="o">--</span><span class="n">go</span>
+</pre></div>
+
+
<p>Cette commande va tout simplement minifier et assembler les feuilles de style définies par la configuration du plugin <code>npAssetsOptimizerPlugin</code>, déployer les fichiers en production sur la machine <code>monserveur</code> et vider le cache sur la machine distante une fois l'opération effectuée.</p>
<p>Notez d'ailleurs l'emploi du très pratique appel à <code>$this-&gt;getFilesystem()-&gt;execute()</code>, qui permet d'executer des appels à la ligne de commande locale depuis la classe de tâche elle-même&nbsp;; ici, une execution distante à travers SSH.</p>
<p>Bien entendu, cet exemple est très spécifique aux besoins du site Akei, mais vous pourriez en quelques minutes gérer plus finement une tâche de déploiement plus générique et configurable. Pensez-y pour vos projets ;)</p>
183 build/code/2010/django-with-pip-virtualenv/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Installer Django dans un environnement Python virtuel avec pip, virtualenv et virtualenvwrapper | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -46,45 +47,61 @@
<h3><code>pip</code>, un installeur de paquet simple et efficace</h3>
<p>D'aucuns de ceux qui utilisent une distribution Linux connaissent le bonheur d'utiliser un gestionnaire de paquets. L'installation de programmes et de librairies s'effectuent la plupart du temps en ligne de commande, et la résolution des dépendances est totalement prise en charge de façon transparente.</p>
<p><a href="http://pypi.python.org/pypi/pip">pip</a> est un gestionnaire de paquets Python, écrit lui-même en Python, qui tient ce rôle à merveille. L'installation de <code>pip</code> est fort simple, pour peu de disposer de <a href="http://pypi.python.org/pypi/setuptools">setup_tools</a>&nbsp;:</p>
-<pre><code>$ sudo easy_install pip
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">sudo</span> <span class="n">easy_install</span> <span class="n">pip</span>
+</pre></div>
+
+
<p>Pour installer un paquet, par exemple la dernière version stable de Django (la 1.1.1), il vous suffit de taper en ligne de commande&nbsp;:</p>
-<pre><code>$ sudo pip install Django
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">sudo</span> <span class="n">pip</span> <span class="n">install</span> <span class="n">Django</span>
+</pre></div>
+
+
<p>Pour chercher un paquet, c'est aussi simple que&nbsp;:</p>
-<pre><code>$ pip search django-debug-toolbar
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">pip</span> <span class="n">search</span> <span class="n">django</span><span class="o">-</span><span class="n">debug</span><span class="o">-</span><span class="n">toolbar</span>
+</pre></div>
+
+
<h3><code>virtualenv</code>, un environnement Python virtuel étanche et cloisonné</h3>
<p><a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> vous propose ni plus ni moins de créer à la demande des environnements de travail virtuels pour tout ce qui touche à Python&nbsp;: chaque environnement possède ses propres paquets et librairies, voire dispose de sa propre version de l'interpréteur !</p>
<p><a href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a>, quand à lui, est un jeu de scripts utilitaires permettant de créer, modifier, supprimer et - d'une façon plus générale - de travailler efficacement avec <code>virtualenv</code>.</p>
<p>L'installation de <code>virtualenv</code> et de <code>virtualenvwrapper</code>, ça tombe bien, peuvent se faire directement via <code>pip</code>&nbsp;:</p>
-<pre><code>$ sudo pip install virtualenv virtualenvwrapper
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">sudo</span> <span class="n">pip</span> <span class="n">install</span> <span class="n">virtualenv</span> <span class="n">virtualenvwrapper</span>
+</pre></div>
+
+
<p>Pour finir de configurer l'installation de <code>virtualenv</code>, il nous reste cependant quelques étapes supplémentaires.</p>
<p>Tout d'abord, il nous faut créer le répertoire qui contiendra nos environnements virtuels sur notre machine [^envpath]&nbsp;:</p>
-<pre><code>$ mkdir ~/.virtualenvs
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">mkdir</span> <span class="o">~/</span><span class="p">.</span><span class="n">virtualenvs</span>
+</pre></div>
+
+
<p>[^envpath]: Vous pouvez bien entendu créer ce répertoire où bon vous semble sur votre système, à partir du moment où votre utilisateur a les droits de lecture et d'écriture dessus.</p>
<p>Il faut également renseigner ce chemin dans la variable d'environnement <code>$WORKON_HOME</code> et instancier la gestion des environnements virtuels, le plus simple étant alors de placer les déclarations ad-hoc dans le fichier <code>~/.profile</code> de votre compte utilisateur [^prf]&nbsp;:</p>
-<pre><code>$ echo "export WORKON_HOME=$HOME/.virtualenvs" &gt;&gt; ~/.profile
-$ echo "export PIP_VIRTUALENV_BASE=$WORKON_HOME" &gt;&gt; ~/.profile
-$ echo "export PIP_RESPECT_VIRTUALENV=true" &gt;&gt; ~/.profile
-$ echo "source /usr/local/bin/virtualenvwrapper.sh" &gt;&gt; ~/.profile
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">echo</span> &quot;<span class="n">export</span> <span class="n">WORKON_HOME</span><span class="p">=</span>$<span class="n">HOME</span><span class="o">/</span><span class="p">.</span><span class="n">virtualenvs</span>&quot; <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">profile</span>
+$ <span class="n">echo</span> &quot;<span class="n">export</span> <span class="n">PIP_VIRTUALENV_BASE</span><span class="p">=</span>$<span class="n">WORKON_HOME</span>&quot; <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">profile</span>
+$ <span class="n">echo</span> &quot;<span class="n">export</span> <span class="n">PIP_RESPECT_VIRTUALENV</span><span class="p">=</span><span class="n">true</span>&quot; <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">profile</span>
+$ <span class="n">echo</span> &quot;<span class="n">source</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">virtualenvwrapper</span><span class="p">.</span><span class="n">sh</span>&quot; <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">profile</span>
+</pre></div>
+
+
<p>[^prf]: le fichier <code>~/.profile</code> est chargé à chaque démarrage de session Max OS X. Utilisateurs de GNU/Linux, l'équivalent est le fichier <code>~/.bashrc</code>.</p>
<blockquote>
<p><strong>Note&nbsp;:</strong> il se peut que selon le mode d'installation utilisé, le chemin vers le fichier <code>/usr/local/bin/virtualenvwrapper.sh</code> soit à adapter spécifiquement.</p>
</blockquote>
<p>Comme nous venons d'ajouter des directives à notre fichier <code>~/.profile</code>, il faut le recharger&nbsp;:</p>
-<pre><code>$ source ~/.profile
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">source</span> <span class="o">~/</span><span class="p">.</span><span class="n">profile</span>
+</pre></div>
+
+
<h3>Créer son premier environnement virtuel</h3>
<p>Reprenons le cas de nos deux projets <code>A</code> et <code>B</code> ; nous avons besoin de créer deux environnements virtuels distincts pour travailler sereinement avec les paquets adéquats pour chacun d'eux&nbsp;:</p>
<p>Nous allons nous concentrer sur la création du premier environnement, pour l'occasion destiné à travailler sur le projet <code>A</code>&nbsp;:</p>
-<pre><code>$ mkvirtualenv DjangoEnvX --no-site-packages
-New python executable in DjangoEnvX/bin/python
-Installing setuptools............done.
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">mkvirtualenv</span> <span class="n">DjangoEnvX</span> <span class="o">--</span><span class="n">no</span><span class="o">-</span><span class="n">site</span><span class="o">-</span><span class="n">packages</span>
+<span class="n">New</span> <span class="n">python</span> <span class="n">executable</span> <span class="n">in</span> <span class="n">DjangoEnvX</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">python</span>
+<span class="n">Installing</span> <span class="n">setuptools</span><span class="p">............</span><span class="n">done</span><span class="p">.</span>
+</pre></div>
+
+
<p>L'environnement a été créé. Notez trois choses importantes&nbsp;:</p>
<ul>
<li>Les <em>setuptools</em> ont été installés dans l'environnement, ainsi que <code>pip</code> même s'il n'en est pas fait mention ; cela nous permettra de disposer de moyens d'installation depuis l'environnement en question&nbsp;;</li>
@@ -92,17 +109,19 @@
<li>Je ne nomme pas l'environnement de travail du nom du «&nbsp;Projet&nbsp;A&nbsp;», dans la mesure où cet environnement pourrait éventuellement être réutilisé pour d'autres projets ayant des besoins et contraintes similaires.</li>
</ul>
<p>Mais examinons de plus près ce que la commande <code>mkvirtualenv</code> a créé pour nous&nbsp;:</p>
-<pre><code>~$ workon DjangoEnvX
-(DjangoEnvX)~ $ cdvirtualenv
-(DjangoEnvX)~/.virtualenvs/DjangoEnvX $ ls -l
-total 8
-drwxr-xr-x 6 niko staff 204 May 5 16:08 .
-drwxr-xr-x 14 niko staff 476 May 5 16:08 ..
-lrwxr-xr-x 1 niko staff 63 May 5 16:08 .Python -&gt; /System/Library/Frameworks/Python.framework/Versions/2.6/Python
-drwxr-xr-x 9 niko staff 306 May 5 16:08 bin
-drwxr-xr-x 3 niko staff 102 May 5 16:08 include
-drwxr-xr-x 3 niko staff 102 May 5 16:08 lib
-</code></pre>
+<div class="codehilite"><pre><span class="o">~</span>$ <span class="n">workon</span> <span class="n">DjangoEnvX</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">cdvirtualenv</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="p">.</span><span class="n">virtualenvs</span><span class="o">/</span><span class="n">DjangoEnvX</span> $ <span class="n">ls</span> <span class="o">-</span><span class="n">l</span>
+<span class="n">total</span> 8
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 6 <span class="n">niko</span> <span class="n">staff</span> 204 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="p">.</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 14 <span class="n">niko</span> <span class="n">staff</span> 476 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="p">..</span>
+<span class="n">lrwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 1 <span class="n">niko</span> <span class="n">staff</span> 63 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="p">.</span><span class="n">Python</span> <span class="o">-&gt;</span> <span class="o">/</span><span class="n">System</span><span class="o">/</span><span class="n">Library</span><span class="o">/</span><span class="n">Frameworks</span><span class="o">/</span><span class="n">Python</span><span class="p">.</span><span class="n">framework</span><span class="o">/</span><span class="n">Versions</span><span class="o">/</span>2<span class="p">.</span>6<span class="o">/</span><span class="n">Python</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 9 <span class="n">niko</span> <span class="n">staff</span> 306 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="n">bin</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 3 <span class="n">niko</span> <span class="n">staff</span> 102 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="n">include</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 3 <span class="n">niko</span> <span class="n">staff</span> 102 <span class="n">May</span> 5 16<span class="p">:</span>08 <span class="n">lib</span>
+</pre></div>
+
+
<p>Notez les éléments suivants&nbsp;:</p>
<ul>
<li>L'utilisation de la commande <code>workon</code>, fournie par <code>virtualenvwrapper</code>, qui permet d'activer un environnement virtuel de travail ; l'autocomplétion du nom de l'environnement virtuel est d'ailleurs disponible&nbsp;!</li>
@@ -111,54 +130,68 @@
<li>Un préfixe (ici <code>(DjangoEnvX)</code>) est ajouté devant le prompt lorqu'on travaille dans un environnement spécifique&nbsp;: cela permet de toujours savoir dans quel environnement on travaille, afin d'éviter les mauvaises surprises ;)</li>
</ul>
<p>Je peux maintenant installer sereinement les paquets dont j'ai besoin dans le cadre de mon projet <code>A</code>, où que je sois sur le système de fichiers. Par exemple, pour installer la version de dev de Django 1.2 depuis son mirroir git&nbsp;:</p>
-<pre><code>(DjangoEnvX)~ $ cd ~
-(DjangoEnvX)~ $ pip install -e git+http://github.com/django/django.git#egg=django
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">cd</span> <span class="o">~</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">pip</span> <span class="n">install</span> <span class="o">-</span><span class="n">e</span> <span class="n">git</span><span class="o">+</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">django</span><span class="o">/</span><span class="n">django</span><span class="p">.</span><span class="n">git</span>#<span class="n">egg</span><span class="p">=</span><span class="n">django</span>
+</pre></div>
+
+
<p>Vérifions que la version de développement de Django a bien été installée dans notre environnement <code>DjangoEnvX</code>&nbsp;:</p>
-<pre><code>(DjangoEnvX)~ $ cdvirtualenv
-(DjangoEnvX)~/.virtualenvs/DjangoEnvX $ ll src
-total 0
-drwxr-xr-x 3 niko staff 102 May 5 17:07 .
-drwxr-xr-x 7 niko staff 238 May 5 17:08 ..
-drwxr-xr-x 16 niko staff 544 May 5 17:08 django
-(DjangoEnvX)~/.virtualenvs/DjangoEnvX $ echo -e "import django\nprint django.get_version()"|python
-1.2 beta 1
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">cdvirtualenv</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="p">.</span><span class="n">virtualenvs</span><span class="o">/</span><span class="n">DjangoEnvX</span> $ <span class="n">ll</span> <span class="n">src</span>
+<span class="n">total</span> 0
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 3 <span class="n">niko</span> <span class="n">staff</span> 102 <span class="n">May</span> 5 17<span class="p">:</span>07 <span class="p">.</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 7 <span class="n">niko</span> <span class="n">staff</span> 238 <span class="n">May</span> 5 17<span class="p">:</span>08 <span class="p">..</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 16 <span class="n">niko</span> <span class="n">staff</span> 544 <span class="n">May</span> 5 17<span class="p">:</span>08 <span class="n">django</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="p">.</span><span class="n">virtualenvs</span><span class="o">/</span><span class="n">DjangoEnvX</span> $ <span class="n">echo</span> <span class="o">-</span><span class="n">e</span> &quot;<span class="n">import</span> <span class="n">django</span><span class="o">\</span><span class="n">nprint</span> <span class="n">django</span><span class="p">.</span><span class="n">get_version</span><span class="p">()</span>&quot;<span class="o">|</span><span class="n">python</span>
+1<span class="p">.</span>2 <span class="nb">beta</span> 1
+</pre></div>
+
+
<p>Installons maintenant de la même façon le paquet <code>django-debug-toolbar</code> en version 0.8.3&nbsp;:</p>
-<pre><code>(DjangoEnvX)~ $ pip install -e git+git://github.com/robhudson/django-debug-toolbar@0.8.3#egg=django-debug-toolbar
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">pip</span> <span class="n">install</span> <span class="o">-</span><span class="n">e</span> <span class="n">git</span><span class="o">+</span><span class="n">git</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">robhudson</span><span class="o">/</span><span class="n">django</span><span class="o">-</span><span class="n">debug</span><span class="o">-</span><span class="n">toolbar</span><span class="p">@</span>0<span class="p">.</span>8<span class="p">.</span>3#<span class="n">egg</span><span class="p">=</span><span class="n">django</span><span class="o">-</span><span class="n">debug</span><span class="o">-</span><span class="n">toolbar</span>
+</pre></div>
+
+
<p>Nous avons maintenant nos paquets installés, créons un nouveau projet Django. On peut créer un répertoire n'importe où sur le système de fichiers, cela n'a aucune importance&nbsp;: les environnements virtuels et les projets ne sont pas directement liés.</p>
-<pre><code>(DjangoEnvX)~ $ cd ~/Sites/
-(DjangoEnvX)~/Sites $ django-admin.py startproject my_django_project
-(DjangoEnvX)~/Sites $ cd my_django_project/
-(DjangoEnvX)~/Sites/my_django_project $ ll
-total 24
-drwxr-xr-x 6 niko staff 204 May 5 17:36 .
-drwxr-xr-x 94 niko staff 3196 May 5 17:36 ..
--rw-r--r-- 1 niko staff 0 May 5 17:36 __init__.py
--rwxr-xr-x 1 niko staff 546 May 5 17:36 manage.py
--rw-r--r-- 1 niko staff 3313 May 5 17:36 settings.py
--rw-r--r-- 1 niko staff 564 May 5 17:36 urls.py
-(DjangoEnvX)~/Sites/my_django_project $ ./manage.py runserver
-Validating models...
-0 errors found
-
-Django version 1.2 beta 1, using settings 'my_django_project.settings'
-Development server is running at http://127.0.0.1:8000/
-Quit the server with CONTROL-C.
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~</span> $ <span class="n">cd</span> <span class="o">~/</span><span class="n">Sites</span><span class="o">/</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span> $ <span class="n">django</span><span class="o">-</span><span class="n">admin</span><span class="p">.</span><span class="n">py</span> <span class="n">startproject</span> <span class="n">my_django_project</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span> $ <span class="n">cd</span> <span class="n">my_django_project</span><span class="o">/</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span><span class="o">/</span><span class="n">my_django_project</span> $ <span class="n">ll</span>
+<span class="n">total</span> 24
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 6 <span class="n">niko</span> <span class="n">staff</span> 204 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="p">.</span>
+<span class="n">drwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 94 <span class="n">niko</span> <span class="n">staff</span> 3196 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="p">..</span>
+<span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--</span> 1 <span class="n">niko</span> <span class="n">staff</span> 0 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="n">__init__</span><span class="p">.</span><span class="n">py</span>
+<span class="o">-</span><span class="n">rwxr</span><span class="o">-</span><span class="n">xr</span><span class="o">-</span><span class="n">x</span> 1 <span class="n">niko</span> <span class="n">staff</span> 546 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="n">manage</span><span class="p">.</span><span class="n">py</span>
+<span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--</span> 1 <span class="n">niko</span> <span class="n">staff</span> 3313 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="n">settings</span><span class="p">.</span><span class="n">py</span>
+<span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--</span> 1 <span class="n">niko</span> <span class="n">staff</span> 564 <span class="n">May</span> 5 17<span class="p">:</span>36 <span class="n">urls</span><span class="p">.</span><span class="n">py</span>
+<span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span><span class="o">/</span><span class="n">my_django_project</span> $ <span class="o">./</span><span class="n">manage</span><span class="p">.</span><span class="n">py</span> <span class="n">runserver</span>
+<span class="n">Validating</span> <span class="n">models</span><span class="p">...</span>
+0 <span class="n">errors</span> <span class="n">found</span>
+
+<span class="n">Django</span> <span class="n">version</span> 1<span class="p">.</span>2 <span class="nb">beta</span> 1<span class="p">,</span> <span class="n">using</span> <span class="n">settings</span> <span class="s">&#39;my_django_project.settings&#39;</span>
+<span class="n">Development</span> <span class="n">server</span> <span class="n">is</span> <span class="n">running</span> <span class="n">at</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span>127<span class="p">.</span>0<span class="p">.</span>0<span class="p">.</span>1<span class="p">:</span>8000<span class="o">/</span>
+<span class="n">Quit</span> <span class="n">the</span> <span class="n">server</span> <span class="n">with</span> <span class="n">CONTROL</span><span class="o">-</span><span class="n">C</span><span class="p">.</span>
+</pre></div>
+
+
<p>Voila, nous pouvons travailler sur notre projet dans l'environnement <code>DjangoEnvX</code> l'esprit serein. On pourra éventuellement ajouter d'autre paquets, ceux-ci ne seront toujours installés que pour cet environnement. Si d'aventure nous voulions versionner la liste des dépendances installées va <code>pip</code>, c'est aussi simple que&nbsp;:</p>
-<pre><code>(DjangoEnvX)~/Sites/my_django_project $ pip freeze &gt; requirements.txt
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span><span class="o">/</span><span class="n">my_django_project</span> $ <span class="n">pip</span> <span class="n">freeze</span> <span class="o">&gt;</span> <span class="n">requirements</span><span class="p">.</span><span class="n">txt</span>
+</pre></div>
+
+
<p>Le fichier <code>requirements.txt</code> ainsi créé contiendra la liste de tous les paquets installés dans l'environnement <code>DjangoEnvX</code>&nbsp;:</p>
-<pre><code>(DjangoEnvX)~/Sites/my_django_project $ cat requirements.txt
--e git+http://github.com/django/django.git@25a45619fe5d7ff3d4f2dbf8f8879a3a00c3625d#egg=Django-1.2_beta_1-py2.6-dev
--e git://github.com/robhudson/django-debug-toolbar@ee1811238e91ae0ad33413b0d40d2f8482101951#egg=django_debug_toolbar-0.8.3-py2.6-dev
-wsgiref==0.1.2
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">DjangoEnvX</span><span class="p">)</span><span class="o">~/</span><span class="n">Sites</span><span class="o">/</span><span class="n">my_django_project</span> $ <span class="nb">cat</span> <span class="n">requirements</span><span class="p">.</span><span class="n">txt</span>
+<span class="o">-</span><span class="n">e</span> <span class="n">git</span><span class="o">+</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">django</span><span class="o">/</span><span class="n">django</span><span class="p">.</span><span class="n">git</span><span class="p">@</span>25<span class="n">a45619fe5d7ff3d4f2dbf8f8879a3a00c3625d</span>#<span class="n">egg</span><span class="p">=</span><span class="n">Django</span><span class="o">-</span>1<span class="p">.</span>2<span class="n">_beta_1</span><span class="o">-</span><span class="n">py2</span><span class="p">.</span>6<span class="o">-</span><span class="n">dev</span>
+<span class="o">-</span><span class="n">e</span> <span class="n">git</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">robhudson</span><span class="o">/</span><span class="n">django</span><span class="o">-</span><span class="n">debug</span><span class="o">-</span><span class="n">toolbar</span><span class="p">@</span><span class="n">ee1811238e91ae0ad33413b0d40d2f8482101951</span>#<span class="n">egg</span><span class="p">=</span><span class="n">django_debug_toolbar</span><span class="o">-</span>0<span class="p">.</span>8<span class="p">.</span>3<span class="o">-</span><span class="n">py2</span><span class="p">.</span>6<span class="o">-</span><span class="n">dev</span>
+<span class="n">wsgiref</span><span class="o">==</span>0<span class="p">.</span>1<span class="p">.</span>2
+</pre></div>
+
+
<p>Libre à vous alors de versionner ce fichier, ce qui permettra à vos collaborateurs d'instancier un nouvel envronnement de travail et d'installer les dépendances requises d'une simple ligne de commande sur son poste de travail&nbsp;:</p>
-<pre><code>(WtfDevEnv)$ pip install -r /path/to/requirements.txt
-</code></pre>
+<div class="codehilite"><pre><span class="p">(</span><span class="n">WtfDevEnv</span><span class="p">)</span>$ <span class="n">pip</span> <span class="n">install</span> <span class="o">-</span><span class="n">r</span> <span class="o">/</span><span class="n">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">requirements</span><span class="p">.</span><span class="n">txt</span>
+</pre></div>
+
+
<p>En espérant vous avoir été utile avec ce billet, je m'en retourne vaquer à mes occupations, et vous rappelle à toutes fins utiles qu'<a href="http://www.akei.com/">Akei</a> serait quand même super contente d'avoir <a href="http://www.akei.com/fr/contact">un coup de fil de votre part</a> pour travailler sur vos chouettes projets en devenir, pourquoi pas en créant plein de <code>virtualenv</code> Python sympas comme tout ;)</p>
<p><strong>Edit&nbsp;:</strong> Prise en compte de la variable d'environnement <code>PIP_RESPECT_VIRTUALENV</code> pour que <code>pip</code> detecte automatiquement la présence d'un environnement virtuel lors de son utilisation (merci Mathieu !)</p>
</section>
121 build/code/2010/express/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>A First Look at node.js and Express | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -38,75 +39,91 @@
<p>Node is described as an <em>Evented I/O Framework for Google's V8 JavaScript Engine</em>. Think of it as a toolkit to produce high-performance distributed, event-driven and scalable non-blocking network servers. Okay, whatever the way I want to describe the project, it's buzzword-bingo™. Let's say it's mainly about catching events and react accordingly, to make load distribution and parallel processing easier and more effective.</p>
<h3>Installing Node</h3>
<p>Installation on my Mac went smoothly and took nearly two minutes by compiling it from the sources; here's how I did (there might be easier or better ways, I don't really care):</p>
-<pre><code>$ mkdir tmp
-$ git clone http://github.com/ry/node.git
-$ cd node
-$ ./configure &amp;&amp; make &amp;&amp; sudo make install
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">mkdir</span> <span class="n">tmp</span>
+$ <span class="n">git</span> <span class="n">clone</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">ry</span><span class="o">/</span><span class="n">node</span><span class="p">.</span><span class="n">git</span>
+$ <span class="n">cd</span> <span class="n">node</span>
+$ <span class="o">./</span><span class="n">configure</span> <span class="o">&amp;&amp;</span> <span class="n">make</span> <span class="o">&amp;&amp;</span> <span class="n">sudo</span> <span class="n">make</span> <span class="n">install</span>
+</pre></div>
+
+
<p>You now have access to the <code>node</code> executable available on your system.</p>
<p>A simple example of a Node HTTP server (put the code below in a <code>test.js</code> file):</p>
-<pre><code>var http = require('http');
+<div class="codehilite"><pre><span class="n">var</span> <span class="n">http</span> <span class="p">=</span> <span class="n">require</span><span class="p">(</span><span class="s">&#39;http&#39;</span><span class="p">);</span>
+
+<span class="n">var</span> <span class="n">server</span> <span class="p">=</span> <span class="n">http</span><span class="p">.</span><span class="n">createServer</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
+ <span class="n">res</span><span class="p">.</span><span class="n">writeHead</span><span class="p">(</span>200<span class="p">,</span> <span class="p">{</span><span class="s">&#39;Content-Type&#39;</span><span class="p">:</span> <span class="s">&#39;text/plain&#39;</span><span class="p">});</span>
+ <span class="n">res</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">&#39;Hello World&#39;</span><span class="p">);</span>
+ <span class="n">res</span><span class="p">.</span><span class="k">end</span><span class="p">();</span>
+<span class="p">});</span>
+
+<span class="n">server</span><span class="p">.</span><span class="n">listen</span><span class="p">(</span>3000<span class="p">,</span> &quot;127<span class="p">.</span>0<span class="p">.</span>0<span class="p">.</span>1&quot;<span class="p">);</span>
+</pre></div>
-var server = http.createServer(function(req, res) {
- res.writeHead(200, {'Content-Type': 'text/plain'});
- res.write('Hello World');
- res.end();
-});
-server.listen(3000, "127.0.0.1");
-</code></pre>
<p>Then launch the created webserver using the command line:</p>
-<pre><code>$ node test.js
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">node</span> <span class="n">test</span><span class="p">.</span><span class="n">js</span>
+</pre></div>
+
+
<p>And point your browser at <code>http://127.0.0.1:3000</code> to get printed <code>Hello World</code>. Neat, huh?</p>
<h3>Introducing Express, a Web Framework on top of Node</h3>
<p><a href="http://expressjs.com/">Express</a> is a Web framework built on top of Node, HTTP and <a href="http://github.com/senchalabs/connect">Connect</a>, allowing easy creation of full-fledged Web applications. It has <a href="http://expressjs.com/guide.html#Routing">routing</a>, handles <a href="http://expressjs.com/guide.html#Configuration">environments</a> as well as several <a href="http://expressjs.com/guide.html#Template-Engines">template engines</a> and <a href="http://expressjs.com/guide.html">much more</a>.</p>
<p>Installation is as easy as Node's one, so here we go:</p>
-<pre><code>$ git clone http://github.com/visionmedia/express.git
-$ cd express
-$ git submodule update --init
-$ sudo make install &amp;&amp; sudo make install-support
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">git</span> <span class="n">clone</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">visionmedia</span><span class="o">/</span><span class="n">express</span><span class="p">.</span><span class="n">git</span>
+$ <span class="n">cd</span> <span class="n">express</span>
+$ <span class="n">git</span> <span class="n">submodule</span> <span class="n">update</span> <span class="o">--</span><span class="n">init</span>
+$ <span class="n">sudo</span> <span class="n">make</span> <span class="n">install</span> <span class="o">&amp;&amp;</span> <span class="n">sudo</span> <span class="n">make</span> <span class="n">install</span><span class="o">-</span><span class="n">support</span>
+</pre></div>
+
+
<p>That's it. You can now write your own test application, eg. in a new <code>hello.js</code> file:</p>
-<pre><code>var app = require('express').createServer();
+<div class="codehilite"><pre><span class="n">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">require</span><span class="p">(</span><span class="s">&#39;express&#39;</span><span class="p">).</span><span class="n">createServer</span><span class="p">();</span>
-app.get('/', function(req, res){
- res.send('Hello World');
-});
+<span class="n">app</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">){</span>
+ <span class="n">res</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="s">&#39;Hello World&#39;</span><span class="p">);</span>
+<span class="p">});</span>
-app.get('/hello/:name', function(req, res){
- res.send('Hello ' + req.param('name') + '!');
-});
+<span class="n">app</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;/hello/:name&#39;</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">){</span>
+ <span class="n">res</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="s">&#39;Hello &#39;</span> <span class="o">+</span> <span class="n">req</span><span class="p">.</span><span class="n">param</span><span class="p">(</span><span class="s">&#39;name&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#39;!&#39;</span><span class="p">);</span>
+<span class="p">});</span>
+
+<span class="n">app</span><span class="p">.</span><span class="n">listen</span><span class="p">(</span>3000<span class="p">,</span> &quot;127<span class="p">.</span>0<span class="p">.</span>0<span class="p">.</span>1&quot;<span class="p">);</span>
+
+<span class="n">console</span><span class="p">.</span><span class="nb">log</span><span class="p">(</span><span class="s">&#39;Server running at http://127.0.0.1:3000/&#39;</span><span class="p">);</span>
+</pre></div>
-app.listen(3000, "127.0.0.1");
-console.log('Server running at http://127.0.0.1:3000/');
-</code></pre>
<p>Launch your webapp server by the command line:</p>
-<pre><code>$ node hello.js
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">node</span> <span class="n">hello</span><span class="p">.</span><span class="n">js</span>
+</pre></div>
+
+
<p>Express and will create a Node server listening to the local port 3000, so head your favorite browser to <code>http://127.0.0.1:3000/</code> then <code>http://127.0.0.1:3000/hello/niko</code> to get the picture of what the above code does. Those familiar with Web framework such as rails, django or symfony won't be much disturbed.</p>
<p>Express also ships with an <code>express</code> executable which provides useful commands. To create a new <code>hello</code> application skeleton, just run:</p>
-<pre><code> $ express hello
- create : hello
- create : hello/app.js
- create : hello/logs
- create : hello/public/javascripts
- create : hello/pids
- create : hello/public/stylesheets
- create : hello/public/stylesheets/style.less
- create : hello/public/images
- create : hello/views/partials
- create : hello/views/layout.jade
- create : hello/views/index.jade
- create : hello/test
- create : hello/test/app.test.js
-</code></pre>
+<div class="codehilite"><pre> $ <span class="n">express</span> <span class="n">hello</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">app</span><span class="p">.</span><span class="n">js</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">logs</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">javascripts</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">pids</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">stylesheets</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">stylesheets</span><span class="o">/</span><span class="n">style</span><span class="p">.</span><span class="n">less</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">images</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">views</span><span class="o">/</span><span class="n">partials</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">views</span><span class="o">/</span><span class="n">layout</span><span class="p">.</span><span class="n">jade</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">views</span><span class="o">/</span><span class="n">index</span><span class="p">.</span><span class="n">jade</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">test</span>
+ <span class="n">create</span> <span class="p">:</span> <span class="n">hello</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">app</span><span class="p">.</span><span class="n">test</span><span class="p">.</span><span class="n">js</span>
+</pre></div>
+
+
<p>Above command just created an <code>hello</code> project directory where you can cd into and launch the server by its default front controller <code>app.js</code>:</p>
-<pre><code>$ cd hello
-$ node app.js
-Express server listening on port 3000
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">cd</span> <span class="n">hello</span>
+$ <span class="n">node</span> <span class="n">app</span><span class="p">.</span><span class="n">js</span>
+<span class="n">Express</span> <span class="n">server</span> <span class="n">listening</span> <span class="n">on</span> <span class="n">port</span> 3000
+</pre></div>
+
+
<p>Note that the generated project skeleton implies using <a href="jade-lang.com/">Jade</a> as a tremplate engine and the <a href="http://lesscss.org/">Less CSS syntax</a>, while one might want to use something else, which is perfectly possible by <a href="http://expressjs.com/guide.html#Configuration">configuring</a> the project differently.</p>
<p>Next steps documentation will be provided by <a href="http://expressjs.com/guide.html">official Express documentation</a>.</p>
<p>Of course, Express might not be as full-featured as older well-established Web frameworks, but for simple needs it can be pretty easy to setup and deploy, and — probably equally importantly — fun to play with and learn.</p>
3  build/code/2010/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
57 build/code/2010/pil-install/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Install PIL within a virtualenv on Snow Leopard | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -35,34 +36,38 @@
<section>
<p>As a personal reminder, here's how to install <a href="http://www.pythonware.com/products/pil/">PIL</a> with jpeg and freetype support in a Python <a href="/post/573774396/installer-django-dans-un-environnement-python-virtuel">virtualenv</a> with a little help from <a href="https://github.com/mxcl/homebrew">Homebrew</a>:</p>
-<pre><code>$ brew install jpeg
-$ wget http://mirrors.fe.up.pt/pub/nongnu/freetype/freetype-2.4.4.tar.gz
-$ tar xvzf freetype-2.4.4.tar.gz &amp;&amp; cd freetype-2.4.4
-$ ./configure &amp;&amp; make &amp;&amp; sudo make install
-$ cd .. &amp;&amp; rm -rf freetype-2.4.4*
-$ mkvirtualenv fubar --no-site-packages
-(fubar)$ pip install PIL
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">brew</span> <span class="n">install</span> <span class="n">jpeg</span>
+$ <span class="n">wget</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">mirrors</span><span class="p">.</span><span class="n">fe</span><span class="p">.</span><span class="n">up</span><span class="p">.</span><span class="n">pt</span><span class="o">/</span><span class="n">pub</span><span class="o">/</span><span class="n">nongnu</span><span class="o">/</span><span class="n">freetype</span><span class="o">/</span><span class="n">freetype</span><span class="o">-</span>2<span class="p">.</span>4<span class="p">.</span>4<span class="p">.</span><span class="n">tar</span><span class="p">.</span><span class="n">gz</span>
+$ <span class="n">tar</span> <span class="n">xvzf</span> <span class="n">freetype</span><span class="o">-</span>2<span class="p">.</span>4<span class="p">.</span>4<span class="p">.</span><span class="n">tar</span><span class="p">.</span><span class="n">gz</span> <span class="o">&amp;&amp;</span> <span class="n">cd</span> <span class="n">freetype</span><span class="o">-</span>2<span class="p">.</span>4<span class="p">.</span>4
+$ <span class="o">./</span><span class="n">configure</span> <span class="o">&amp;&amp;</span> <span class="n">make</span> <span class="o">&amp;&amp;</span> <span class="n">sudo</span> <span class="n">make</span> <span class="n">install</span>
+$ <span class="n">cd</span> <span class="p">..</span> <span class="o">&amp;&amp;</span> <span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="n">freetype</span><span class="o">-</span>2<span class="p">.</span>4<span class="p">.</span>4<span class="o">*</span>
+$ <span class="n">mkvirtualenv</span> <span class="n">fubar</span> <span class="o">--</span><span class="n">no</span><span class="o">-</span><span class="n">site</span><span class="o">-</span><span class="n">packages</span>
+<span class="p">(</span><span class="n">fubar</span><span class="p">)</span>$ <span class="n">pip</span> <span class="n">install</span> <span class="n">PIL</span>
+</pre></div>
+
+
<p>You should obtain something like this at the end of the installation process:</p>
-<pre><code>--------------------------------------------------------------------
-PIL 1.1.7 SETUP SUMMARY
---------------------------------------------------------------------
-version 1.1.7
-platform darwin 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
- [GCC 4.2.1 (Apple Inc. build 5646)]
---------------------------------------------------------------------
---- TKINTER support available
---- JPEG support available
---- ZLIB (PNG/ZIP) support available
---- FREETYPE2 support available
-*** LITTLECMS support not available
---------------------------------------------------------------------
-</code></pre>
+<div class="codehilite"><pre><span class="o">--------------------------------------------------------------------</span>
+<span class="n">PIL</span> 1<span class="p">.</span>1<span class="p">.</span>7 <span class="n">SETUP</span> <span class="n">SUMMARY</span>
+<span class="o">--------------------------------------------------------------------</span>
+<span class="n">version</span> 1<span class="p">.</span>1<span class="p">.</span>7
+<span class="n">platform</span> <span class="n">darwin</span> 2<span class="p">.</span>6<span class="p">.</span>1 <span class="p">(</span><span class="n">r261</span><span class="p">:</span>67515<span class="p">,</span> <span class="n">Jun</span> 24 2010<span class="p">,</span> 21<span class="p">:</span>47<span class="p">:</span>49<span class="p">)</span>
+ <span class="p">[</span><span class="n">GCC</span> 4<span class="p">.</span>2<span class="p">.</span>1 <span class="p">(</span><span class="n">Apple</span> <span class="n">Inc</span><span class="p">.</span> <span class="n">build</span> 5646<span class="p">)]</span>
+<span class="o">--------------------------------------------------------------------</span>
+<span class="o">---</span> <span class="n">TKINTER</span> <span class="n">support</span> <span class="n">available</span>
+<span class="o">---</span> <span class="n">JPEG</span> <span class="n">support</span> <span class="n">available</span>
+<span class="o">---</span> <span class="n">ZLIB</span> <span class="p">(</span><span class="n">PNG</span><span class="o">/</span><span class="n">ZIP</span><span class="p">)</span> <span class="n">support</span> <span class="n">available</span>
+<span class="o">---</span> <span class="n">FREETYPE2</span> <span class="n">support</span> <span class="n">available</span>
+<span class="o">***</span> <span class="n">LITTLECMS</span> <span class="n">support</span> <span class="n">not</span> <span class="n">available</span>
+<span class="o">--------------------------------------------------------------------</span>
+</pre></div>
+
+
<p>That's all for today folks, thanks for your attention.</p>
<p><strong>EDIT:</strong> If you want <a href="http://www.littlecms.com/">little-cms</a> support, just run:</p>
-<pre><code>$ brew install little-cms
-(fubar)$ pip install PIL
-</code></pre>
+<div class="codehilite"><pre>$ <span class="n">brew</span> <span class="n">install</span> <span class="n">little</span><span class="o">-</span><span class="n">cms</span>
+<span class="p">(</span><span class="n">fubar</span><span class="p">)</span>$ <span class="n">pip</span> <span class="n">install</span> <span class="n">PIL</span>
+</pre></div>
</section>
<aside>
<p>
47 build/code/2010/python-tab-completion/index.html
View
@@ -2,11 +2,12 @@
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Enabling tab completion in OS X Python interactive interpreter | Code | Nicolas Perriault</title>
<meta name="description" content="Nicolas Perriault's homepage.">
<meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/packed.css?1330958175">
+ <link rel="stylesheet" type="text/css" href="/static/packed.css?1331656984">
<link rel="alternate" type="application/rss+xml" href="/code/feed/" title="Code (RSS)">
<link rel="alternate" type="application/rss+xml" href="/photography/feed/" title="Photography (RSS)">
<link rel="alternate" type="application/rss+xml" href="/talks/feed/" title="Talks (RSS)">
@@ -36,29 +37,39 @@
<section>
<p>Python is awesome, and so is its native interactive interpreter. I <a href="http://sontek.net/tips-and-tricks-for-the-python-interpreter">discovered today</a> that it can even provide autocompletion using a very simple trick:</p>
<p>Append this to your <code>~/.profile</code>:</p>
-<pre><code>export PYTHONSTARTUP=$HOME/.pythonrc.py
-</code></pre>
+<div class="codehilite"><pre><span class="n">export</span> <span class="n">PYTHONSTARTUP</span><span class="p">=</span>$<span class="n">HOME</span><span class="o">/</span><span class="p">.</span><span class="n">pythonrc</span><span class="p">.</span><span class="n">py</span>
+</pre></div>
+
+
<p>And in a new <code>~/.pythonrc.py</code> file:</p>
-<pre><code>try:
- import readline
-except ImportError:
- print("Module readline not available.")
-else:
- import rlcompleter
- readline.parse_and_bind("tab: complete")
-</code></pre>
+<div class="codehilite"><pre><span class="k">try</span><span class="o">:</span>
+ <span class="k">import</span> <span class="nn">readline</span>
+<span class="n">except</span> <span class="n">ImportError</span><span class="o">:</span>
+ <span class="n">print</span><span class="o">(</span><span class="s2">&quot;Module readline not available.&quot;</span><span class="o">)</span>
+<span class="k">else</span><span class="o">:</span>
+ <span class="k">import</span> <span class="nn">rlcompleter</span>
+ <span class="n">readline</span><span class="o">.</span><span class="na">parse_and_bind</span><span class="o">(</span><span class="s2">&quot;tab: complete&quot;</span><span class="o">)</span>
+</pre></div>
+
+