<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Trux</title>
	<atom:link href="http://trux.info/feed/" rel="self" type="application/rss+xml" />
	<link>http://trux.info</link>
	<description>Partage de mes astuces et découvertes</description>
	<lastBuildDate>Tue, 09 Jun 2009 19:47:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Publicité BMW</title>
		<link>http://trux.info/2009/06/135/</link>
		<comments>http://trux.info/2009/06/135/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 19:46:58 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[humour]]></category>

		<guid isPermaLink="false">http://trux.info/?p=135</guid>
		<description><![CDATA[
Vu sur http://wtanaka.com/node/7656. C&#8217;est une publicité de BMW qui date de 1998. On peut y lire « Notre matériel fonctionne mieux sans fenêtres (windows) »..
]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://trux.info/wp-content/uploads/2009/06/bmw.jpg" alt="our hardware runs better without windows" title="pub bmw" width="301" height="400" class="size-full wp-image-134" /></center><br />
Vu sur <a href="http://wtanaka.com/node/7656">http://wtanaka.com/node/7656</a>. C&#8217;est une publicité de BMW qui date de 1998. On peut y lire « <i>Notre matériel fonctionne mieux sans fenêtres (windows) ».</i>.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/06/135/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Rake aborted! undefined method &#8216;reenable&#8217;</title>
		<link>http://trux.info/2009/06/rake-aborted-undefined-method-reenable/</link>
		<comments>http://trux.info/2009/06/rake-aborted-undefined-method-reenable/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 20:45:00 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Non classé]]></category>

		<guid isPermaLink="false">http://trux.info/?p=128</guid>
		<description><![CDATA[Petit coup de pouce : si vous passez à rails 2.3 et que vous avez une ancienne version de rake installée, vous verrez peut-être le message suivant au lancement de commandes rake

rake aborted!
undefined method `reenable' for  [environment]>:Rake::Task

La raison ? Vous utilisez rake 0.8.x là où la version 0.8.4 est nécessaire. Il suffit de mettre [...]]]></description>
			<content:encoded><![CDATA[<p>Petit coup de pouce : si vous passez à rails 2.3 et que vous avez une ancienne version de rake installée, vous verrez peut-être le message suivant au lancement de commandes rake</p>
<pre>
rake aborted!
undefined method `reenable' for <Rake::Task db:schema:dump => [environment]>:Rake::Task
</pre>
<p>La raison ? Vous utilisez rake 0.8.x là où la version 0.8.4 est nécessaire. Il suffit de mettre à jour la gemme. Si le paquet rake est installé mais est trop vieux, désinstallez le. Tout devrait rentrer dans l&#8217;ordre.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/06/rake-aborted-undefined-method-reenable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reverse SSH, ou comment se faufiler entre NAT et Firewall</title>
		<link>http://trux.info/2009/05/reverse-ssh-ou-comment-se-faufiler-entre-nat-et-firewall/</link>
		<comments>http://trux.info/2009/05/reverse-ssh-ou-comment-se-faufiler-entre-nat-et-firewall/#comments</comments>
		<pubDate>Fri, 15 May 2009 06:58:35 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[réseau]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://trux.info/?p=122</guid>
		<description><![CDATA[ssh est un outil merveilleux : il permet de se connecter à un hôte et exécuter des commandes à distances de manière sécurisée.
Il permet également de tunneler un port local vers un port distant d&#8217;une autre machine. Ainsi tout ce qui est envoyé sur le port local va être transmis au port distant via la [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.openssh.com/">ssh</a> est un <a href="http://doc.ubuntu-fr.org/ssh">outil merveilleux</a> : il permet de se connecter à un hôte et exécuter des commandes à distances de manière sécurisée.</p>
<p>Il permet également de tunneler un port local vers un port distant d&#8217;une autre machine. Ainsi tout ce qui est envoyé sur le port local va être transmis au port distant via la communication ssh sécurisée. Cette manipulation s&#8217;avère très pratique pour sortir d&#8217;un réseau dont seuls les ports 22 et 80 sont ouverts.</p>
<p>Je viens d&#8217;apprendre récemment comment faire l&#8217;inverse : tunneler un port d&#8217;une machine distante vers un port d&#8217;une machine locale. Ainsi tout ce qui est envoyé sur le port de la machine distante va être transmis au port de la machine locale. En résumé, si votre machine locale est sur un réseau protégé par un NAT et un firewall, çette manipulation met en place une backdoor vers le réseau protégé.<br />
<span id="more-122"></span><br />
Par exemple, vous avez une machine, nommée dest, qui est sur un réseau NATé protégé par un firewall. On ne peut pas s&#8217;y connecter en ssh par l&#8217;extérieur car le pare feu bloque ce port (ou bien il le redirige sur une autre machine qui ne vous intéresse pas). Prenons maintenant une autre machine, nommée middle, qui se trouve à l&#8217;extérieur du réseau protégé. Il suffit de créer un reverse tunnel pour exposer le port 22 de la machine dest sur un autre port de la machine middle. Cette commande est à exécuter au préalable sur dest :</p>
<pre>destuser@dest$ ssh -R 2200:localhost:22 middleuser@middle</pre>
<p>Tant que la connexion ssh est active, le port 2200 de middle est en écoute et transmet les paquets au port 22 de dest.Ensuite de l&#8217;extérieur, depuis chez vous sur votre machine home, il suffit de se connecter à middle de manière classique, puis de se connecter une nouvelle fois en utilisant le port exposé, 2200, pour se connecter à dest.</p>
<pre>user@home$ ssh middleuser@middle
middleuser@middle$ ssh destuser@localhost -p 2200
destuser@dest$</pre>
<p>Voilà, vous êtes connecté à dest.</p>
<p>Si vous pouvez sortir sur le port 2200 directement, vous n&#8217;êtes pas obligé de faire ce double saut. Vous pouvez vous connecter directement au port 2200 de la machine middle :</p>
<pre>user@home$ ssh destuser@middle -p 2200</pre>
<p>Si vous ne pouvez pas sortir sur un autre port que le prt 22 et que vous voulez vous connecter en une seule commande, on peut rajouter un petit tunnel supplémentaire entre le port 2200 de la machine home et le port 2200 de la machine middle :</p>
<pre>user@home$ ssh -L2200:localhost:2200 middleuser@middle</pre>
<p>et on se connecte alors ainsi :</p>
<pre>user@home$ ssh destuser@localhost -p 2200</pre>
<p>Dans cet exemple, j&#8217;ai présenté une connexion vers le port 22, pour ssh, mais le plus souvent, vous avez déjà établi un mécanisme permettant une connexion à votre réseau domestique. Dans ce cas cette astuce peut être pratique quand vous êtes à l&#8217;extérieur, pour exposer temporairement le port d&#8217;un service de votre réseau local à l&#8217;extérieur (au hasard, des ports POP et IMAP pour relever votre mail). Attention à bien protéger les accès dans ce cas.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/05/reverse-ssh-ou-comment-se-faufiler-entre-nat-et-firewall/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>assertThat(JUnit4, canHave(betterSyntax));</title>
		<link>http://trux.info/2009/03/assertthatjunit4-canhavebettersyntax/</link>
		<comments>http://trux.info/2009/03/assertthatjunit4-canhavebettersyntax/#comments</comments>
		<pubDate>Tue, 31 Mar 2009 20:50:54 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jmock]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://trux.info/?p=113</guid>
		<description><![CDATA[Lors de l&#8217;écriture de tests unitaires, on peut se retrouver à écrire ce genre de code :

assertEquals&#40;42, answer&#41;;
assertFalse&#40;answer == 34&#41;;
assertTrue&#40;info.matches&#40;&#34;color&#34;&#41; &#124;&#124; info.matches&#40;&#34;colour&#34;&#41;&#41;;
assertTrue&#40;colorsList.contains&#40;&#34;red&#34;&#41;&#41;;
assertTrue&#40;s instanceof MagicString&#41;;

Mais JUnit propose depuis la version 4.4 une nouvelle syntaxe à base de Matchers. En fait, cette syntaxe n&#8217;est pas totalement nouvelle : elle est empruntée à JMock qui possède déjà les [...]]]></description>
			<content:encoded><![CDATA[<p>Lors de l&#8217;écriture de tests unitaires, on peut se retrouver à écrire ce genre de code :</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">assertEquals<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">42</span>, answer<span style="color: #009900;">&#41;</span>;
assertFalse<span style="color: #009900;">&#40;</span>answer <span style="color: #339933;">==</span> <span style="color: #cc66cc;">34</span><span style="color: #009900;">&#41;</span>;
assertTrue<span style="color: #009900;">&#40;</span>info.<span style="color: #006633;">matches</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;color&quot;</span><span style="color: #009900;">&#41;</span> || info.<span style="color: #006633;">matches</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;colour&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertTrue<span style="color: #009900;">&#40;</span>colorsList.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;red&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertTrue<span style="color: #009900;">&#40;</span>s <span style="color: #000000; font-weight: bold;">instanceof</span> MagicString<span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>Mais JUnit propose depuis la version 4.4 une <a href="http://junit.sourceforge.net/doc/ReleaseNotes4.4.html">nouvelle syntaxe</a> à base de <a href="http://junit.org/apidocs/org/junit/matchers/JUnitMatchers.html">Matchers</a>. En fait, cette syntaxe n&#8217;est pas totalement nouvelle : elle est empruntée à <a href="http://www.jmock.org/">JMock</a> qui possède déjà les <a href="http://www.jmock.org/matchers.html">Matchers JMock</a> pour décrire les contraintes d&#8217;un mock. L&#8217;idée vient de <a href="http://joewalnes.com/">Joe Walnes</a> dans son article <a href="http://joe.truemesh.com/blog/000511.html">Flexible JUnit assertions with assertThat()</a>.</p>
<p>Les assertions précédentes peuvent alors s&#8217;écrire de la manière suivante :</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">assertThat<span style="color: #009900;">&#40;</span>answer, is<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">42</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertThat<span style="color: #009900;">&#40;</span>answer, is<span style="color: #009900;">&#40;</span>not<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">34</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertThat<span style="color: #009900;">&#40;</span>info, either<span style="color: #009900;">&#40;</span>containsString<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;color&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span>containsString<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;colour&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertThat<span style="color: #009900;">&#40;</span>colorsList, hasItem<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;red&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
assertThat<span style="color: #009900;">&#40;</span>s, <span style="color: #000000; font-weight: bold;">instanceOf</span><span style="color: #009900;">&#40;</span>MagicString.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;</pre></div></div>

<p>Les avantages sont multiples :</p>
<ul>
<li>Ça se lit mieux : le développeur communique donc mieux son intention aux autres développeurs, ce qui est essentiel !</li>
<li>Contrairement aux méthodes assertEquals et consorts, on ne risque pas de tromper dans l&#8217;ordre des arguments : la syntaxe d&#8217;assertEquals est <code>assertEquals([expected], [actual])</code> mais beaucoup de gens se trompent et écrivent <code>assertEquals(answer, 42)</code>. Avec assertThat, aucun risque.</li>
<li>Les matchers peuvent être modifiés: par exemple : <code>not(s)</code> pour inverser la condition, <code>either(s).or(t)</code> pour combiner des conditions, <code>each(s)</code> pour appliquer une condition sur chaque élément d&#8217;une collection, <code>afterFiveSeconds(s)</code> pour attendre 5 secondes avant de tester&#8230;</li>
<li>En cas d&#8217;échec de l&#8217;assertion, les messages sont beaucoup plus lisibles. Si on reprend l&#8217;exemple précédents, avec les assertXxx classiques, les messages ressembleraient à ça :
<pre>
assertEquals(42, answer);
 => expected:<42> but was:<36>
assertFalse(answer == 34);
 => junit.framework.AssertionFailedError:
assertTrue(info.matches("color") || info.matches("colour"));
 => junit.framework.AssertionFailedError:
assertTrue(colorsList.contains("red"));
 => junit.framework.AssertionFailedError:
assertTrue(s instanceof MagicString);
 => junit.framework.AssertionFailedError:
</pre>
<p>Avec assertThat, les message ressemblent plutôt à ça :
<pre>
assertThat(answer, is(42));
 => Expected: is <42>
         got: <36>
assertThat(answer, is(not(34)));
 => Expected: is not <34>
         got: <34>
assertThat(info, either(containsString("color")).or(containsString("colour")));
 => Expected: (a string containing "colour" or a string containing "color")
         got: "rainbow"
assertThat(colorsList, hasItem("red"));
 => Expected: a collection containing "hello"
         got: <[bonjour, ia orana]>
assertThat(s, instanceOf(MagicString.class));
 => Expected: an instance of sandbox.FooTest$MagicString
         got: "polop"
</pre>
<p>Inutile de dire qu&#8217;il est beaucoup plus facile de débugguer des tests écrits avec assertThat&#8230;</li>
<li>Il est plus facile d&#8217;écrire des Matcher maison plutôt que des méthodes assertXxxx maison. En plus ces Matchers pourront être réutilisés dans des tests JMock.</li>
<li>C&#8217;est sexy <img src='http://trux.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p>Pour plus d&#8217;informations, je vous recommande la lecture de <a href="http://blog.xebia.fr/2008/04/02/simplifier-les-assertions-junit-et-ameliorer-vos-tests/">ce billet</a>. Il est en français, il est très détaillé et je suis tombé dessus en écrivant cet article.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/03/assertthatjunit4-canhavebettersyntax/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>En plomberie, le téflon est ton ami !</title>
		<link>http://trux.info/2009/02/en-plomberie-le-teflon-est-ton-ami/</link>
		<comments>http://trux.info/2009/02/en-plomberie-le-teflon-est-ton-ami/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 21:40:48 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[ma vie]]></category>
		<category><![CDATA[bricolage]]></category>
		<category><![CDATA[plomberie]]></category>

		<guid isPermaLink="false">http://trux.info/?p=91</guid>
		<description><![CDATA[ Pas facile de remplacer son vieux lavabo par un beau meuble avec vasque, robinet neuf, miroir, et bonde Champi clic-clac quand on n&#8217;y connaît rien.
Et pour corser le tout, Murphy était de la partie : entre le robinet général d&#8217;eau froide grippé, le robinet général d&#8217;eau chaude qui ne ferme pas complètement, les cotes [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://trux.info/wp-content/uploads/2009/02/meuble_sdb.jpg" alt="meuble_sdb" title="Le meuble et la vasque que j'ai installés" width="200" height="200" class="alignleft size-full wp-image-92" /> Pas facile de remplacer son vieux lavabo par un beau meuble avec vasque, robinet neuf, miroir, et <a href="http://www.leroymerlin.fr/catalogue_leroy_merlin/evacuation/vidages/BONDE_CHAMPI_CLIC_CLAC_CULOTLG_ECROU_ref66278093.htm">bonde Champi clic-clac</a> quand on n&#8217;y connaît rien.</p>
<p>Et pour corser le tout, <a href="http://fr.wikipedia.org/wiki/Loi_de_Murphy">Murphy</a> était de la partie : entre le robinet général d&#8217;eau froide grippé, le robinet général d&#8217;eau chaude qui ne ferme pas complètement, les cotes de la notice qui sont fausses, l&#8217;installation de robinets d&#8217;arrêt impossible, une coulisse de tiroir qui est plus basse que les autres, la conduite d&#8217;évacuation trop loin du mur et qui oblige à tailler le meuble à la scie sauteuse pour qu&#8217;il puisse plaquer, l&#8217;évacuation du siphon qui tombe 12 cm plus haut que le conduit d&#8217;évacuation parce que la nouvelle vasque est plus haute que le vieux lavabo, les aller-retours aux magasins de bricolage pour trouver une solution, et une fois que tout est fini, on essaie enfin, et là, ça fuit&#8230;<br />
<span id="more-91"></span><br />
<img src="http://trux.info/wp-content/uploads/2009/02/rouleau_teflon.jpg" alt="Un rouleau de téflon" title="Un rouleau de téflon" width="200" height="150" class="size-full wp-image-93 alignright" />Mon salut ? Le rouleau de téflon ! Pour colmater une fuite sur un raccord vissé, il suffit de démonter la pièce, d&#8217;enrouler du téflon sur le filetage et de resserrer la pièce. Le téflon est suffisamment fin et glissant pour qu&#8217;on puisse visser dessus et assure ainsi l&#8217;étanchéité.</p>
<p>C&#8217;est assez terrible de voir qu&#8217;en plomberie comme en informatique, alors que la réalisation semble simple et évidente, un tas de petits trucs s&#8217;opposent à tout optimisme. On passe alors énormément de temps sur des petits problèmes inattendus et à la fin de la journée on a bien avancé mais pas autant qu&#8217;on l&#8217;espérait.</p>
<p>En tout cas, j&#8217;aurai appris à changer un lavabo et j&#8217;ai la fierté de l&#8217;avoir fait moi-même en me documentant.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/02/en-plomberie-le-teflon-est-ton-ami/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Assurer la sérialisation d&#8217;un objet</title>
		<link>http://trux.info/2009/02/assurer-la-serialisation-dun-objet/</link>
		<comments>http://trux.info/2009/02/assurer-la-serialisation-dun-objet/#comments</comments>
		<pubDate>Sun, 08 Feb 2009 14:09:39 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[sérialisation]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://trux.info/?p=84</guid>
		<description><![CDATA[En java, n&#8217;importe quel objet implémentant l&#8217;interface Serializable peut être converti facilement en une séquence d&#8217;octets. Cette même séquence peut ensuite être reconverti en l&#8217;objet original. Ce mécanisme est par exemple utilisé pour transmettre des objets par RMI.
Voici une petite méthode pour vérifier que votre classe est bien sérialisable

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import static [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://trux.info/wp-content/uploads/2009/02/conserve.jpg" alt="boîte de conserve" title="boîte de conserve" class="alignright size-full wp-image-83" />En java, n&#8217;importe quel objet implémentant l&#8217;interface <a href="http://java.sun.com/javase/6/docs/api/java/io/Serializable.html">Serializable</a> peut être converti facilement en une séquence d&#8217;octets. Cette même séquence peut ensuite être reconverti en l&#8217;objet original. Ce mécanisme est par exemple utilisé pour transmettre des objets par <a href="http://fr.wikipedia.org/wiki/Remote_method_invocation_(Java)">RMI</a>.</p>
<p>Voici une petite méthode pour vérifier que votre classe est bien sérialisable</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.ByteArrayInputStream</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.ByteArrayOutputStream</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.IOException</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.ObjectInputStream</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.ObjectOutputStream</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">junit</span>.<span style="color: #000000; font-weight: bold;">Assert</span>.<span style="color: #006633;">assertEquals</span>;
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">junit</span>.<span style="color: #000000; font-weight: bold;">Assert</span>.<span style="color: #006633;">fail</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000000; font-weight: bold;">Assert</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #008000; font-style: italic; font-weight: bold;">/**
     * Assert that an object is serializable by dumping it and then reading it
     * back and finally by checking the original object and the dumped and read
     * object are equals.
     *
     * &lt;p&gt;Obviously, the method &lt;code&gt;equals()&lt;/code&gt; has to be implemented
     * correctly for this method can work.
     * @param objOriginal the instance which will be checked against serialization;
     * must implement &lt;code&gt;equals()&lt;/code&gt; or it won't work
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> assertSerializable<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> objOriginal<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">ByteArrayOutputStream</span> stream <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ByteArrayOutputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
            <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">ObjectOutputStream</span> out <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ObjectOutputStream</span><span style="color: #009900;">&#40;</span>stream<span style="color: #009900;">&#41;</span>;
            out.<span style="color: #006633;">writeObject</span><span style="color: #009900;">&#40;</span>objOriginal<span style="color: #009900;">&#41;</span>;
            out.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
            <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">ObjectInputStream</span> in <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ObjectInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ByteArrayInputStream</span><span style="color: #009900;">&#40;</span>stream.<span style="color: #006633;">toByteArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
            <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> objSerialized <span style="color: #339933;">=</span> in.<span style="color: #006633;">readObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
            assertEquals<span style="color: #009900;">&#40;</span>objOriginal, objSerialized<span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">IOException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            fail<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;unable to serialize or deserialize object &quot;</span> <span style="color: #339933;">+</span> objOriginal <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;: &quot;</span> <span style="color: #339933;">+</span> e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">ClassNotFoundException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// unlikely to happen...</span>
            fail<span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><span id="more-84"></span>Cette méthode sérialise une classe dans un buffer, puis relit ce buffer et s&#8217;assure que l&#8217;objet lu est bien égal à l&#8217;objet sérialisé.</p>
<p>Si ce test échoue, alors c&#8217;est que certaines données membres de l&#8217;objet testé ne sont pas sérialisables. Par exemple, un <a href="http://www.slf4j.org/apidocs/org/slf4j/Logger.html">Logger</a> ou un <a href="http://java.sun.com/javase/6/docs/api/java/lang/Thread.html">Thread</a> ne peuvent pas être sérialisés. Des données membres de ce type doivent donc être déclarés <code>transient</code> de la manière suivante</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Foo <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">transient</span> <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Thread</span> thread;
    <span style="color: #000000; font-weight: bold;">transient</span> <span style="color: #000000; font-weight: bold;">private</span> Logger logger <span style="color: #339933;">=</span> LoggerFactory.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">getClass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> name;
&nbsp;
    <span style="color: #666666; font-style: italic;">// etc...</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Attention une fois l&#8217;objet sérialisé puis désérialisé, les membres transients sont perdus. C&#8217;est ainsi qu&#8217;on se retrouve avec un logger à <code>null</code> et un <code>NullPointerException</code> assez rapidement&#8230; Dans ce cas, on peut implémenter une méthode privée ayant la signature <code>readObject(ObjectInputStream)</code> pour y restaurer le logger. La méthode doit être privée pour éviter tout appel par une autre classe ou toute surcharge par une classe fille.</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #666666; font-style: italic;">// code...</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> readObject<span style="color: #009900;">&#40;</span><span style="color: #003399;">ObjectInputStream</span> in<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>, <span style="color: #003399;">ClassNotFoundException</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// default implementation</span>
        in.<span style="color: #006633;">defaultReadObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #666666; font-style: italic;">// restore our logger object</span>
        logger <span style="color: #339933;">=</span> LoggerFactory.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">getClass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// code...</span></pre></div></div>

<p>Tout les détails de la sérialisation sont expliqués <a href="http://java.sun.com/developer/technicalArticles/Programming/serialization/">sur le site de Sun</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/02/assurer-la-serialisation-dun-objet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convertir un entier en binaire, the ruby way</title>
		<link>http://trux.info/2009/02/convertir-un-entier-en-binaire-the-ruby-way/</link>
		<comments>http://trux.info/2009/02/convertir-un-entier-en-binaire-the-ruby-way/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 20:59:20 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://trux.info/?p=76</guid>
		<description><![CDATA[Dans un article précédent, je donnais une méthode pour convertir rapidement un nombre en binaire et inversement quand on n&#8217;avait pas python 3. Ça m&#8217;est pratique quand j&#8217;ai besoin de faire une conversion rapide : un terminal, on lance python, on tape l&#8217;expression et on a le résultat. En regardant les nouveautés de ruby 1.8.7, [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://trux.info/wp-content/uploads/2009/02/ruby-language.png" alt="ruby" title="ruby" width="89" height="101" class="alignleft size-full wp-image-77" /><a href="http://trux.info/2009/01/python-convertir-un-entier-en-binaire/">Dans un article précédent</a>, je donnais une méthode pour convertir rapidement un nombre en binaire et inversement quand on n&#8217;avait pas <a href="http://www.python.org/download/releases/3.0/">python 3</a>. Ça m&#8217;est pratique quand j&#8217;ai besoin de faire une conversion rapide : un terminal, on lance python, on tape l&#8217;expression et on a le résultat. En regardant <a href="http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7/NEWS">les nouveautés de ruby 1.8.7</a>, j&#8217;ai découvert que c&#8217;était encore plus trivial.</p>
<pre>
% irb
irb(main):001:0> 42.to_s(2)
=> "101010"
irb(main):002:0> "%b" % 42
=> "101010"
irb(main):003:0> "1001".to_i(2)
=> 9
irb(main):004:0> 0b1001
=> 9
</pre>
<p>Enfantin non ?</p>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/02/convertir-un-entier-en-binaire-the-ruby-way/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Débuts avec zsh</title>
		<link>http://trux.info/2009/01/debuts-avec-zsh/</link>
		<comments>http://trux.info/2009/01/debuts-avec-zsh/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 19:56:09 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[zsh]]></category>

		<guid isPermaLink="false">http://trux.info/?p=62</guid>
		<description><![CDATA[zsh est un shell complet qui remplace avantageusement bash dont on entend beaucoup parler en bien. J&#8217;ai décidé de l&#8217;essayer récemment.
Sans chercher à exploiter toutes les fonctionnalités qu&#8217;il propose, certaines facilités me sont maintenant indispensables lorsque je passe à bash. Une seule en fait : le ** qui se substitue à n&#8217;importe quel dossier ou [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.cooking2000.com/fr/dossier/coquille-saint-jacques.htm"><img alt="" src="http://www.cooking2000.com/image/dossier/divers/coquille-st-jacques.jpg" title="shell signifie aussi coquille, ici une St Jacques" class="alignright" width="200" height="257" /></a><code>zsh</code> est un <a href="http://fr.wikipedia.org/wiki/Shell_(informatique)">shell</a> complet qui remplace avantageusement <code>bash</code> dont on entend <a href="http://doc.ubuntu-fr.org/zsh">beaucoup parler</a> en bien. J&#8217;ai décidé de l&#8217;essayer récemment.</p>
<p>Sans chercher à exploiter toutes les fonctionnalités qu&#8217;il propose, certaines facilités me sont maintenant indispensables lorsque je passe à bash. Une seule en fait : le <code>**</code> qui se substitue à n&#8217;importe quel dossier ou sous-dossier. Un <a href="http://en.wikipedia.org/wiki/Glob_(programming)">globbing</a> puissant qui permet de s&#8217;affranchir de <a href="http://pwet.fr/man/linux/commandes/find">find</a>.</p>
<p><span id="more-62"></span></p>
<pre>
# liste tous les fichiers, equivalent de find .
ls **/*
# recherche la chaine 'foo' dans tous les fichiers java
grep foo **/*.java
# recherche la chaine 'bar' dans tous les fichiers java qui ont pour
# repertoire parent le dossier src
grep foo **/src/**/*.java
</pre>
<p>De plus, on peut ajouter des options de recherche</p>
<pre>
# tous les fichiers contenant le nom 'dupont' en Ignorant la casse
# correspond à dupond, DUPOND, Dupond, DuPOnD, mais pas Durand
ls (#i)dupont
# liste uniquement les fichiers
ls **/*(.)
# liste uniquement les dossiers
ls -d **/*(/)
# liste tous les dossiers pleins (Full)
ls -d **/*(F)
# liste tous les dossiers vides (not Full)
ls -d **/*(^F)
</pre>
<p>Il existe <a href="http://www.manpagez.com/man/1/zshexpn/">beaucoup d&#8217;autres possibilités</a>, mais juste ces quelques commandes m&#8217;ont permis de m&#8217;affranchir du sempiternel <code>find . -type f -iname "*dupont*" | xargs svn revert</code>.</p>
<p>L&#8217;autre truc bien de zsh, évidemment, c&#8217;est l&#8217;aide à la <a href="http://zsh.sourceforge.net/Guide/zshguide06.html">complétion de commande</a>. Il est remarquable dans bien des cas, notamment</p>
<ul>
<li>tâches ant : <code>$ ant &lt;TAB&gt;</code> => liste les tâches ant disponibles</li>
<li>arguments ant : <code>$ ant --n&lt;TAB&gt;</code> => liste les options de ant commençant par <i>&#8211;n</i></li>
<li>adresses svn : <code>$ svn checkout http://some.svn.server/svn/trunk/src/&lt;TAB&gt;</code> => liste les fichiers disponibles</li>
</ul>
<p>Bref ça vaut le coup d&#8217;essayer. Pour mettre un pied à l&#8217;étrier (et me servir d&#8217;aide mémoire), voici le <code>.zshrc</code> que j&#8217;utilise. Il n&#8217;a rien d&#8217;exceptionnel, même le prompt est des plus basiques.</p>
<pre>
# Lines configured by zsh-newuser-install
HISTFILE=~/.histfile
HISTSIZE=1000
SAVEHIST=1000
setopt appendhistory autocd extendedglob nomatch notify
unsetopt beep
bindkey -e
# End of lines configured by zsh-newuser-install
# The following lines were added by compinstall
zstyle :compinstall filename '/home/cbliard/.zshrc'

autoload -Uz compinit
compinit
# End of lines added by compinstall

# Add ~/bin directory to PATH if possible
[ -d $HOME/bin ] &#038;&#038; export PATH=$PATH:$HOME/bin

# colors
eval "`dircolors -b`"
alias ls='ls --color=auto'

function l() {
	clear; pwd; echo; ls -lh $*; echo
}

# Set up aliases
alias mv='nocorrect mv'       # no spelling correction on mv
alias cp='nocorrect cp'       # no spelling correction on cp
alias mkdir='nocorrect mkdir' # no spelling correction on mkdir
alias grep='egrep --exclude-dir=\.svn --color=auto'
alias ll='ls -l'
alias la='ls -a'
alias less='less -i'
alias diff='diff -u -x .svn'

# Less verbose ant
alias ant='ant -logger org.apache.tools.ant.NoBannerLogger'

# List only directories and symbolic
# links that point to directories
alias lsd='ls -ld *(-/DN)'

# List only file beginning with "."
alias lsa='ls -ld .*'

# Simple bold prompt
PROMPT="%{%B%}%n@%m:%~%{%b%}%# "

# select words as in bash (for Meta-backspace and Meta-d)
autoload -U select-word-style
select-word-style bash
</pre>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/01/debuts-avec-zsh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python : convertir un entier en binaire</title>
		<link>http://trux.info/2009/01/python-convertir-un-entier-en-binaire/</link>
		<comments>http://trux.info/2009/01/python-convertir-un-entier-en-binaire/#comments</comments>
		<pubDate>Sat, 03 Jan 2009 20:50:36 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://trux.info/?p=53</guid>
		<description><![CDATA[Depuis python 2.6, le langage python peut gérer les nombres entier dans leur représentation binaire.

$ python2.6
>>> 0b101111
47
>>> int('1101', 2)
13
>>> int('0b1101', 2)
13
>>> bin(13)
'0b1101'

Cependant, avec les versions précédentes, seule la conversion de binaire vers décimal est possible facilement.

$ python2.5
>>> int('1101', 2)
13
>>> bin(13)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'bin' is not [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://docs.python.org/whatsnew/2.6.html#pep-3127-integer-literal-support-and-syntax">Depuis python 2.6</a>, le langage python peut gérer les nombres entier dans leur représentation binaire.</p>
<pre>
$ python2.6
>>> 0b101111
47
>>> int('1101', 2)
13
>>> int('0b1101', 2)
13
>>> bin(13)
'0b1101'
</pre>
<p>Cependant, avec les versions précédentes, seule la conversion de binaire vers décimal est possible facilement.</p>
<pre>
$ python2.5
>>> int('1101', 2)
13
>>> bin(13)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bin' is not defined
</pre>
<p>Voici donc une petite fonction <code>bin</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> bin<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Convert an integer to its binary string representation&quot;&quot;&quot;</span>
    res = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> n <span style="color: #66cc66;">&gt;</span> 0:
        res.<span style="color: black;">insert</span><span style="color: black;">&#40;</span>0, <span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>n <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        n = n // <span style="color: #ff4500;">2</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>res<span style="color: black;">&#41;</span></pre></div></div>

<p>Et ainsi :</p>
<pre>
$ python2.5
>>> def bin(n):
...     """Convertit un nombre en binaire"""
...     res = []
...     while n > 0:
...         res.insert(0, str(int(n % 2)))
...         n = n // 2
...     return "".join(res)
...
>>> bin(13)
'1101'
>>> int(bin(13), 2)
13
</pre>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2009/01/python-convertir-un-entier-en-binaire/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Utiliser rubygems avec Netbeans sur Ubuntu grâce aux ACLs</title>
		<link>http://trux.info/2008/12/utiliser-rubygems-avec-netbeans-sur-ubuntu-grace-aux-acls/</link>
		<comments>http://trux.info/2008/12/utiliser-rubygems-avec-netbeans-sur-ubuntu-grace-aux-acls/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 08:00:06 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[astuce]]></category>
		<category><![CDATA[acl]]></category>
		<category><![CDATA[netbeans]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://trux.info/?p=29</guid>
		<description><![CDATA[En installant rubygems et en l&#8217;utilisant avec Netbeans, on se rend vite compte que rubygems est configuré pour stocker ses gemmes dans /var/lib/gems et que Netbeans n&#8217;a pas les droits d&#8217;écriture à cet endroit. En effet, la manière traditionnelle d&#8217;installer gem implique d&#8217;utiliser sudo, en ligne de commande :
$ sudo gems install rails -y
Oui mais [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-32" title="netbeans_ruby_debian" src="http://trux.info/wp-content/uploads/2008/12/netbeans_ruby_debian.png" alt="" width="300" height="83" />En installant rubygems et en l&#8217;utilisant avec <a href="http://www.netbeans.org/">Netbeans</a>, on se rend vite compte que rubygems est configuré pour stocker ses gemmes dans <code>/var/lib/gems</code> et que Netbeans n&#8217;a pas les droits d&#8217;écriture à cet endroit. En effet, la manière traditionnelle d&#8217;installer gem implique d&#8217;utiliser sudo, en ligne de commande :</p>
<pre>$ sudo gems install rails -y</pre>
<p>Oui mais voilà, Netbeans n&#8217;utilise pas sudo. Pour que Netbeans puisse gérer les gemmes lui-même, il lui faut donc les droits d&#8217;écriture sur le dossier <code>/var/lib/gems</code> et ses sous-répertoires. Le plus naïf est de donner tous les droits en écriture, mais c&#8217;est mal ! Sinon, on peut aussi créer un groupe nommé <code>rubygems</code> et donner le droit d&#8217;écriture à ce groupe. Cette approche est meilleure mais un problème se pose lorsque l&#8217;utilisateur y crée un nouveau fichier ou dossier : non seulement celui-ci appartient à l&#8217;utilisateur et non pas à root, mais en plus le groupe n&#8217;a pas le droit d&#8217;écriture. C&#8217;est là qu&#8217;interviennent les ACLs&#8230;</p>
<p><span id="more-29"></span></p>
<h3>Démonstration avec l&#8217;utilisateur foo.</h3>
<p>On crée un groupe ruby gems et on s&#8217;y ajoute</p>
<pre>
$ sudo addgroup rubygems
$ sudo adduser foo rubygems
</pre>
<p>On se déconnecte puis reconnecte pour prendre en compte le nouveau groupe, puis on vérifie les permissions</p>
<pre>
$ sudo mkdir /test
$ sudo chgrp rubygems /test
$ sudo chmod g+w /test
$ ls -ld /test
drwxrwxr-x 2 root rubygems 4096 2008-12-03 22:16 /test
$ touch /test/bar
$ ls -l /test/bar
-rw-r--r-- 1 foo foo 0 2008-12-03 22:21 /test/bar
</pre>
<p>Ce n&#8217;est pas bon du tout. On préférerait avoir quelque chose comme <code>-rw-rw-r-- 1 foo rubygems</code> afin que les autres membres du groupe <code>rubygems</code> puissent eux aussi modifier ce fichier. De manière plus générale, on veut que :</p>
<ul>
<li>le groupe soit <code>rubygems</code> ;</li>
<li>les permissions du groupe soient rwx pour un dossier et rw- pour un fichier ;</li>
<li>et que les permissions des autres soient r-x pour un dossier et r&#8211; pour un fichier.</li>
</ul>
<p>La partie qui va suivre est issu des connaissances acquises grâce à l&#8217;article <a href="http://www.udel.edu/topics/os/unix/general/groupsharing.html">Group sharing a directory</a>.</p>
<h3>Attribuer le groupe automatiquement</h3>
<p>Il est simple d&#8217;affecter le groupe <code>rubygems</code> automatiquement à chaque nouveau dossier créé dès qu&#8217;on connait l&#8217;astuce : il suffit de lever le bit &#8217;set groupid&#8217; du groupe du dossier pour que tout nouveau fichier ou dossier créé appartienne au groupe du dossier parent plutôt qu&#8217;au groupe de l&#8217;utilisateur</p>
<pre>
$ sudo chmod g+s /test
$ ls -ld /test
drwxrwsr-x 2 root rubygems 4096 2008-12-05 07:54 /test
$ touch f
$ mkdir /test/d
$ ls -l /test
total 4
drwxr-sr-x 2 foo rubygems 4096 2008-12-05 07:59 d
-rw-r--r-- 1 foo rubygems    0 2008-12-05 07:59 f
$ cd /test/d
$ touch bar
$ ls -l
-rw-r--r-- 1 foo rubygems 0 2008-12-05 08:00 bar
</pre>
<h3>Permettre l&#8217;écriture au groupe automatiquement </h3>
<p>Cette solution fait usage des ACLs. La commande</p>
<pre>
$ sudo setfacl -m default:user::rwx,default:group::rwx,default:mask:rwx,default:other:r-x /test
</pre>
<p>permet de définir les permissions par défaut pour les futurs fichiers du dossier <code>/test</code>. La commande est longue et peut être abrégée en</p>
<pre>
$ sudo setfacl -m d:u::rwx,d:g::rwx,d:m:rwx,d:o:r-x /test
</pre>
<p>Si la commande <code>setfacl</code> ne fonctionne pas, c&#8217;est parce que l&#8217;option <code>acl</code> n&#8217;est pas active pour votre volume. Assurez-vous d&#8217;avoir une ligne qui ressemble contienne l&#8217;option <code>acl</code> dans votre <code>/etc/fstab</code> :</p>
<pre>
/dev/hda2 / ext3 defaults,acl 0 1
</pre>
<p>Ensuite remontez votre volume pour prendre en compte les modifications</p>
<pre>
sudo mount / -o remount
</pre>
<p>Observons maintenant d&#8217;un peu plus près la définition d&#8217;ACLs</p>
<pre>
$ sudo setfacl -m d:u::rwx,d:g::rwx,d:m:rwx,d:o:r-x /test
$ ls -ld /test
drwxrwsr-x+ 3 root rubygems 4096 2008-12-05 07:59 /test
$ getfacl /test
getfacl: Removing leading '/' from absolute path names
# file: test
# owner: root
# group: rubygems
user::rwx
group::rwx
other::r-x
default:user::rwx
default:group::rwx
default:mask::rwx
default:other::r-x
</pre>
<p>Le + à droite des permissions affichées par la commande <code>ls</code> indique qu&#8217;il y a des permissions supplémentaires visibles par <code>getfacl</code>. Ce dernier permet d&#8217;afficher les permissions définies avec <code>setfacl</code>. Essayons de créer des fichiers.</p>
<pre>
$ cd /test
$ touch polop.txt
$ mkdir hello
$ ls -l
total 16
drwxr-sr-x  2 foo rubygems 4096 2008-12-05 08:00 d
-rw-r--r--  1 foo rubygems    0 2008-12-05 07:59 f
drwxrwsr-x+ 2 foo rubygems 4096 2008-12-05 08:17 hello
-rw-rw-r--+ 1 foo rubygems    0 2008-12-05 08:17 polop.txt
$ getfacl hello
# file: hello
# owner: foo
# group: rubygems
user::rwx
group::rwx
mask::rwx
other::r-x
default:user::rwx
default:group::rwx
default:mask::rwx
default:other::r-x
</pre>
<p>Les ACLs ont bien rempli leur rôle : les nouveaux fichiers créés ont la permission d&#8217;écriture pour le groupe et ont aux aussi les ACLs définis (notez le +).</p>
<h3>Application au dossier de gemmes de ruby</h3>
<p>Il nous faut définir le groupe les permissions pour tout fichier ou dossier existant du dossier <code>/var/lib/gems</code> et les ACLs ainsi que le &#8217;set groupid&#8217; bit pour tout dossier, sans oublier de changer le groupe pour qu&#8217;il devienne <code>rubygems</code>.</p>
<pre>
$ sudo chgrp -R rubygems /var/lib/gems
$ sudo chmod -R -s,g=rwX,o=rX /var/lib/gems
$ for dir in $(find /var/lib/gems -type d) ; do
> sudo chmod g+s "$dir"
> sudo setfacl -m d:u::rwx,d:g::rwx,d:o:r--,d:m:rwx "$dir"
> done
</pre>
<p>notez que si vous étiez sous <a href="http://fr.wikipedia.org/wiki/Zsh">zsh</a>, vous auriez pu écrire</p>
<pre>
$ sudo chgrp rubygems /var/lib/gems/**/*
$ sudo chmod -s,g=rwX,o=rX /var/lib/gems/**/*
$ sudo chmod g+s /var/lib/gems/**/*(/)
$ sudo setfacl -m d:u::rwx,d:g::rwx,d:o:r--,d:m:rwx /var/lib/gems/**/*(/)
</pre>
<p>Voilà ! désomais vous pouvez taper</p>
<pre>
$ gems install rails -y
</pre>
<p>en simple utilisateur, ce qui signifie que d&#8217;autres programmes tiers comme NetBeans peuvent également installer des gemmes.</p>
<h3>Autres applications</h3>
<p>On peut trouver d&#8217;autres application très utiles au partage de dossier par ACL. Comme ça de tête :</p>
<ul>
<li>Quand votre serveur web est partagé entre plusieurs personnes, partager le dossier <code>/var/www</code> d&#8217;apache pour que l&#8217;utilisateur système <code>www-data</code> ait le droit d&#8217;écriture sur tous les fichiers sans donner ces droits à tout le monde ;</li>
<li>Partager des fichiers sur un disque dur externe pour que chacun puisse y gérer ses films et photos sans se retrouver bloqué quand on veut déplacer ou supprimer certains éléments créés par d&#8217;autres utilisateurs.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://trux.info/2008/12/utiliser-rubygems-avec-netbeans-sur-ubuntu-grace-aux-acls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

