Code
Pomoduino

La genèse

Beaucoup de poussière ici… Voyons voir si je me rappelle comment ça fonctionne. Si vous pouvez lire ce post, c’est que j’ai réussi.

Récemment, j’ai lu un article J’ai codé la nuit de noël, très intéressant au passage, qui parlait de la méthode Pomodoro. Je ne connaissais pas du tout.

La méthode y est décrite de la façon suivante :

Le principe est très simple :

  • Je prends 4 minutes pour planifier ce que je vais faire dans le prochain cycle
  • Je code, développe ou design pendant 24 minutes précisément
  • Je prends 1 minute pour résumer ce que je viens de faire
  • Je recommence

Toutes les 4 itérations, je fais une pause plus longue de 25 minutes.

—Gilles Roustan

Je me suis dit que ça devait être fun comme méthode, d’avoir des contraintes de temps et de réalisation, ça me permettra sans doute d’avancer plus efficacement sur mes projets perso. Et puis, quand j’ai voulu démarrer un cycle, je me suis posé la question de comment j’allais chronométrer chaque étape ? Le smartphone à côté ? mais alors, il faut réarmer le réveil à chaque fois avec des temps différents, ou alors il faut surveiller le chronomètre, bref, pas pour moi. Un script qui lance des notifications au bon moment ? Mouais pourquoi pas, mais pas très intéressant. Et finalement, ça faisait longtemps que j’avais pas ressorti ma boîte à Arduino ! Une breadboard, 4 LEDs et une résistance plus tard, me voilà sur un nouveau petit projet (que je n’avais absolument pas prévu dans mon emploi du temps) : faire un timer, pour la méthode pomodoro à base d’Arduino.

C’était en plus l’occasion de mettre en place du TDD [1] dans un contexte de logiciel embarqué, vu que je suis en train de lire Test Driven Development for Embedded C de James W. Grenning sur les recommandation d’un ami.

Le projet

J’ai donc retroussé mes petits manche, dégainer le framework CppUTest, réinstaller le framework pour Arduino et, un peu plus d’une semaine plus tard, la voici : la première version fonctionnelle du Pomoduino [2].

L’ensemble des sources est disponible sous licence GNU/GPLv3 et accessible ici.

Et ça marche ! En vrai, ça ressemble à ça :

Montage

Dans l’idée, il y a une LED par étape :

  • une jaune pour l’étape d’analyse
  • une rouge pour l’étape de développement, design…
  • une bleu pour le résumé
  • et une verte pour la pause

Une fois que le timer est démarrer, il boucle sur le cycle défini plus haute.

Les évolutions

Je prévois encore quelques améliorations mais peut être pas tout de suite :

  • « quelques » secondes avant la fin d’une période, la LED peut clignoter
  • ajout d’un bouton pour augmenter le temps de la période courante
  • ajout d’un petit afficheur pour donner le temps restant dans la période courante, le nombre de cycle depuis le début, le temps qu’il reste avant la prochaine pause… et éventuellement d’autre chose

[EDIT] Problèmes

Note à moi-même : lorsqu’on programme sur Arduino des gros timer, les fonctions millis et micros overflow…

[1]Test driven development
[2]Bon pour pomoduino, je me suis pas foulé, et je me suis rendu compte bien après (genre hier) que le nom avait déjà été utilisé. Mais c’est pas grave !

Pour voir les commentaires, cliquez ici

Code
YapLog

Aujourd’hui, une nouvelle librarie pour vos projets en C et C++. Profitez en, c’est pas souvent que je fais du C++.

Quand on démarre un projet, un des premier truc que j’aime bien avoir, c’est des traces fonctionnelles, avec différents niveau, sur la sortie standard ou dans un fichier, avec des couleurs histoire de s‘y retrouver facilement, etc… Et donc, je me trouvais systématiquement à inclure une collection de macro pour faire mes traces. Au fil des années, ce fichier de macro est devenu de plus en plus gros, et surtout j’en avais de plus en plus de versions différentes (un pour chaque projet). Vous pouvez consulter la première version ici.

Très simple, fonctionnel, mais activable à la compilation et plus moyen de changer.

Histoire d’unifier tout ça, j’ai mis en place une librarie unifiée pour tout mes projets C et C++ qui permet d’avoir la même API : et c’est là qu’intervient YapLog.

Et aujourd’hui, cette librarie est maintenant disponible directement à l’installation dans AUR sur archlinux, en version stable et de dévelopement) et toujours sur la page du projet.

EDIT: Je ne l’ai pas préciser au début, mais les sources de cette librarie sont sous licence WTF-PL.

Pour voir les commentaires, cliquez ici

Code
PacmanHealth

Amis Archlinuxiens, bonjour.

Cela fait maintenant plusieurs années que j’administre sur mes heures perdues un serveur (bon en fait 2) qui tourne sous Archlinux. Comme c’est une Archlinux, il faut faire les mises à jour assez souvent, alors autant les mises à jour, je ne veux pas les automatiser parce que ça peut être dangereux mais il faut savoir quand est-ce qu’il y des mises à jour importantes à faire. Une autre opération longue, fastidieuse et répétitive est la mise à jour du fichier mirrorlist à l’aide du programme rankmirrors.

Et c’est ici que pacmanhealth débarque ! PacmanHealth se découpe en trois partie.

  • une unité systemd qui lance le programme pacmanhealth
  • un timer systemd qui permet de démarrer pacmanhealth toutes les heures
  • et enfin, le programme pacmanhealth. Ce programme met à jour les bases de données de pacman, est met à jour la liste des miroirs utilisés par pacman. Une fois que ces opérations sont effectuées, le programme envoie un rapport par mail (si disponible) et par notification (si disponible) avec la liste des paquets qui nécessitent une mise à jour, ainsi que la liste des fichiers de configuration modifiés.

Ça fait maintenant un peu plus de deux mois que je l’utilise au quotidien et ça me rends bien des services.

Si vous voulez l’utiliser, il est disponible sur AUR en version stable et en version de développement.

Pour voir les commentaires, cliquez ici

Code
LaTeX

Ça faisait bien longtemps que je n’avais pas fait de typographie et puis, au détour d’une soirée, une amie m’a parlé d’un problème de mise en page pour son mémoire. Je me suis donc proposé de lui donner un coup de main. Avec mon LaTex pour moi et l’intérêt que je porte à la typographie et à l’écriture en général, je me suis dit que tout irait bien.

Oh la grossière erreur ! Ce qu’il y a de bien avec LaTeX, c’est qu’on est capable d’écrire un document d’allure professionnel, dans un ensemble cohérent. Ça, c’est la théorie et surtout, quand on fait tout notre document avec. Mais quand on a déjà un document de base et qu’on se doit de respecter la charte graphique de ce document, et qu’en plus ce document est un docx, c’est une autre paire de manche.

Voici donc une liste non exhaustive des emmerdes sur lesquelles on peut perdre plus d’une journée, les petits rappels pratique et autres astuces de mise en page.

Évidemment, les astuces proposées sont celles que j’ai utilisée et ne représente pas systématiquement la solution optimale, ça fonctionne juste. Si vous avez des solutions plus élégante, ou simplement d’autre manière de faire, n’hésitez pas à me les faire parvenir par mail (voir la page de contact) ou dans les commentaires à la fin de l’article.

Les packages de base

Les documents que j’écris sont en général en français et donc, il faut le dire, histoire d’avoir les en-têtes françaises, les règles de typographie française, la gestion des accents. En plus, en bon GNU/Linuxien, tous mes documents textes sont systématiquement en UTF-8, et donc, pareil, il faut le dire à LaTeX pour pas se retrouver avec des signes cabalistiques à la place des accents (parce que, oui, en français, il y a souvent des accents et des caractères spéciaux).

\usepackage[french]{babel}          % On passe LaTeX en français
\usepackage[T1]{fontenc}            % Gestion des accents sur le document de sortie
\usepackage[utf8]{inputenc}         % Le fichier d’entrée est en UTF-8
%\usepackage[latin1]{inputenc}      % Si votre fichier est un iso8859-1 (je vous le donne quand même)

En plus de ces trois packages, il y en a un autre que j’utilise quasiment systématiquement. Par défaut, les marges sont énormes (enfin, je les trouve énormes). Et donc soit on joue avec les variables globales du document pour ajuster les marges à la main, soit on utilise le package fullpage.

\usepackage{fullpage}

Les parties et la table des matières

Le système de numérotation des sections, même s’il est très bien comme il est, ne correspond pas toujours au modèle. Les sections sont numérotés avec des chiffres romains, il faut un . pour séparer les différents niveaux, etc…

Heureusement, il existe des commandes en LaTeX pour personnaliser tout ça.

% Pour la numérotation

% Les sections sont numérotés avec des chiffres romains majuscule, séparer du titre par un .
\renewcommand \thesection{\Roman{section}.}

% Les sous-sections sont numérotés avec des chiffres arabes, avec un rappel du numéro
% de section en chiffres romains majuscule, séparé par un -
\renewcommand \thesubsection{\Roman{section} - \arabic{subsection}

% Il y a aussi la commande \roman{<level>} pour avoir des chiffres romains minuscule

Un plus du format de la numérotation, on peut aussi redéfinir le format du titre à proprement parler. Par contre, il faut connaitre les commandes de format de bloc à la TeX, plus qu’à la LaTeX. Pour se faire, on utilise le package sectsty.

J’ai fait des tests avec le package titlesec et la commande titleformat mais dès que j’ai voulu souligné un texte, la génération du document s’est très mal passé. Curieusement, le même format avec le package sectsty et les commandes *sectionfont, tout se passe bien.

\usepackage{sectsty}
\sectionfont{\center\underline}         % pour avoir des titres de section centré et souligné
\subsectionfont{\tiny}                  % les titres de sous-section sont tout petit petit

En parlant de titre souligné, il y a une autre solution possible mais qui a un inconvénient majeur : on peut définir nos titre directement en \underline au moment de le déclarer. Mais, ils seront aussi soulignés dans la table des matières. So bad!

Pour la table des matières, par défaut, LaTeX y met tous les titres jusqu’aux sous-sous-sections. On aimerait bien la limiter pour gagner en clarté en ne conservant que deux niveaux. Et hop, c’est possible avec la petite commande suivante :

\setcounter{tocdepth}{2}

En bonus : je veux pouvoir ajouter un titre fantôme, qui n’apparait que dans la table des matières. Et encore c’est possible ! (vous noterez quand même comme c’est fou que tout soit possible, c’est bien fait)

\addcontentsline{toc}{<level>}{<titre>}
% où <level> est la profondeur à laquelle on veux ajouter notre entrée
% (comprendre section, subsection, subsubsection, etc…)
% et <titre> est le titre qui va apparaître dans la table.

Évidemment, cette ligne est à mettre dans le corps du document sur la page qui doit être référencée par la table des matières.

Les polices

J’ai toujours aimé la police par défaut de LaTeX. Je la trouve particulièrement lisible. Par contre, ce n’est pas forcément adapté à tous les usages. Quand notre document de base à un corps dans une police avec serif mais une page de titre dans une police sans serif, il faut pouvoir changer la police à la volée.

Alors là, je ne suis pas satisfait de ma solution mais bon, ça a marché alors bon, je le note ici, ça peut servir à d’autre. Je vous laisse consulter le catalogue des polices disponibles sous LaTeX ici pour connaitre la bonne abréviation à utiliser.

J’utilise deux façons de changer la police. La première change le texte normal et la seconde change les textes en gras. Si je ne mets pas les deux, seulement une partie du texte a pris la nouvelle police et du coup, le résultat n’est pas top. Le scope de ces commandes se limite au bloc courant donc on peut aisément changer la police pour une seule page ou un seul paragraphe, il suffit de délimiter correctement son bloc.

% Pour le texte normal
\fontfamily{<abbreviation>}
\selectfont

% Pour le texte un peu plus formatté
\renewcommand{\rmdefault}{<abbreviation>}
\renewcommand{\sfdefault}{<abbreviation>}
\renewcommand{\ttdefault}{<abbreviation>}

Les tableaux

Faire un tableau, en LaTeX, c’est simple.

Faire un tableau avec des bordures, en LaTeX, c’est simple.

Faire un tableau avec des cases qui s’étende sur plusieurs colonnes ou sur plusieurs ligne, c’est déjà moins simple.

Si en plus, on veut des bordures dans ce tableau, ça peut engendrer une bonne prise de tête.

Ajouter de la couleur dans le fond, secouez bien, et là, vous aurez le combo de la mort qui tue.

Procédons par étape.

Les tableaux simples

Commençons par la base. Un tableau, c’est un environnement tabular avec des descripteurs de colonnes, des & et des \\. Et donc, pour faire le tableau suivant :

Tableau simple

On utilise ce code très simple :

\begin{tabular}{lcr}
    première & 2      & 3        \\
    4        & milieu & 6        \\
    7        & 8      & dernière \\
\end{tabular}

Pour ajouter des bordures partout, ce n’est pas beaucoup plus compliqué.

\begin{tabular}{|l|c|r|}
    \hline
    première & 2      & 3        \\
    \hline
    4        & milieu & 6        \\
    \hline
    7        & 8      & dernière \\
    \hline
\end{tabular}

Il suffit de rajouter des | dans la description des colonnes pour ajouter une ligne vertical sur toute la hauteur du tableau (on peut même les doubler, tripler, etc…) et des \hline sur chaque ligne pour tracer une ligne horizontale sur toute la largeur du tableau, au dessus de la ligne courante.

Les tableaux avec des cases multiples

On continue crescendo dans la difficulté. On va fusionner toutes les lignes de la colonne centrale pour en faire une seule et même cellule qui contiendra le texte milieu, en gardant les bordures. Mais attention, des bordures uniquement autour des vraies cellule de notre tableau, donc on ne veux pas que la colonne du milieu soit entrecoupé par des bordures. Comme ça :

multirow et cline

Pour commencer, fusionnons les cellules. On ne met rien au milieu sur les deux premières lignes, tout se passera sur la troisième. On va alors utiliser la commande \multirow qui prend trois paramètres :

  1. le nombre de ligne sur lesquelles la cellule doit s’étirer. Ce nombre peut être négatif ou positif en fonction de si on souhaite s’étirer vers le haut (négatif) ou vers le bas (positif). Si vous avez suivi, dans mon exemple, j’utiliserai $-3$.
  2. la largeur de la cellule. On peut y mettre une valeur littérale comme 15cm par exemple, on peut utiliser des variables globale comme \linewidth (utile quand la largeur de notre colonne est fixée — définie avec p{<taille>}), ou tout simplement le token * qui indique que la case peut être aussi large que nécessaire.
  3. le contenu de la cellule.

Ensuite, on veux mettre correctement nos bordures.

Vous vous souvenez quand je vous ai dit que \hline traçait une ligne sur toute la largeur du tableau ? Et voilà, il est là le problème. On veut bien une bordure mais elle doit être coupé par notre grosse cellule.

C’est à ce moment là qu’intervient \cline qui permet de tracer des morceaux de ligne. Elle s’utilise avec un paramètre de la forme x-y pour indiquer à LaTeX de tracer une ligne allant du début de la colonne x pour s’arrêter à la fin de la colonne y. On peut bien sûr mettre plusieurs \cline sur une même ligne.

Le suspens est à présent terminé, voici ce que ça donne en vrai :

\usepackage{multirow} % Ce package est nécessaire

\begin{tabular}{|l|c|r|}
    \hline
    première &                          & 3        \\
    \cline{1-1} \cline{3-3}
    4        &                          & 6        \\
    \cline{1-1} \cline{3-3}
    7        & \multirow{-3}{*}{milieu} & dernière \\
    \hline
\end{tabular}

Comme on est joueur, on veut faire la même mais sur des colonnes maintenant.

On commence par mettre une seule et belle grosse cellule sur la ligne du milieu avec la commande \multicolumn (on se serait presque douté du nom de la commande) Comme \multirow, elle prend trois paramètres mais il sont un poil différents :

  1. le nombre de colonnes sur laquelle la cellule va s’étendre. Attention, ce nombre ne peut être que positif. Re-attention, les colonnes déjà utilisé par multicolumn ne doivent pas être délimitée par & dans la suite de la ligne. Ainsi, si on s’étend sur deux colonnes, il y aura un & de moins sur cette ligne par rapport aux autres.
  2. le format de notre nouvelle colonne. Il s’agit du même type de donnée que ce que l’on trouve en argument de la définition de notre environnement tabular. Ça peut être c si on veut centrer sur toutes les colonnes, l ou r pour aligner à gauche ou à droite, etc…
  3. le contenu de la cellule.

Vous vous souvenez que je vous avait dit qu’un | dans les définition de colonnes permettait de tracer une ligne vertical sur toute la hauteur du tableau ? Et ben c’était pas vrai. Si un \multicolumn croise le chemin de la bordure, elle saute la cellule et reprend après. Mais comme tout n’est pas rose, ce comportement est le même qu’on soit au milieu de la cellule (ce qui est cool) ou sur une des extrémités de la cellule (ce qui est beaucoup moins cool). Et donc, si on ne fait pas attention, on se retrouve avec des tableaux ridicules de ce style là :

Erreur de bordure sur un multicolumn

La solution se trouve dans le deuxième argument de multicolumn. On y définit le format de sa colonne et donc |c| est parfaitement acceptable. Ceci va nous tracer une bordure de chaque côté de notre cellule. Et le tour est joué. Voilà donc le résultat :

Multicolumn
\usepackage{multirow} % C’est aussi dans multirow que se trouve multicolumn

\begin{tabular}{|l|c|r|}
    \hline
    première & 2 & 3             \\
    \hline
    \multicolumn{3}{|c|}{milieu} \\
    \hline
    7        & 8 & dernière       \\
    \hline
\end{tabular}

Le combo

Le but maintenant, est d’ajouter de la couleur à l’ensemble (en fait ce sera du gris parce que c’est facile) pour aboutir à un tableau comme ça :

combo

Alors sans les couleurs, maintenant, vous devriez vous en sortir et écrire quelque chose du genre :

\usepackage{multirow}

\begin{tabular}{|c|c|c|c|}
    \hline
    \multicolumn{2}{|c|}{column} & 3  & 4                     \\
    \hline
    5             &            6 & 7  &                       \\
    \cline{1-3}
    9             & 10           & 11 & \multirow{-2}{*}{row} \\
    \hline
\end{tabular}

On va maintenant ajouter de la couleur sur les deux dernière colonnes. Pour ce faire, on a besoin de deux packages supplémentaire : color pour pouvoir définir nos couleurs, et colortbl pour appliquer des couleurs sur un tableau.

Pour mettre de la couleur sur une colonne, il suffit de modifier le descripteur de cette colonne. Ainsi, les deux derniers c deviendront :

>{\columncolor[gray]{.7}}c

Vous avez compris, il suffit de préfixer la définition de la colonne par >{\columncolor###}### est la définition de la couleur. Pour la définition de la couleur, j’ai utilisée la notation [gray]{.7} mais j’aurais très bien pu utilisée une définition de couleur personnelle de cette manière :

\definecolor{NAME}{rgb}{1,.3,.3}

\begin{tabular}{|>{\columncolor{NAME}}c|}
...

Attaquons nous maintenant aux lignes. La syntaxe est encore plus simple. Il suffit d’ajouter l’appel à la commande \rowcolor en début de ligne pour colorer toute la ligne. Et donc, notre tableau coloré ressemble à ça :

\usepackage{multirow}

\begin{tabular}{|c|c|>{\columncolor[gray]{.7}}c|>{\columncolor[gray]{.7}}c|}
    \hline
    \multicolumn{2}{|c|}{column} & 3  & 4                     \\
    \hline
    \rowcolor[gray]{.9}
    5             &            6 & 7  &                       \\
    \cline{1-3}
    \rowcolor[gray]{.9}
    9             & 10           & 11 & \multirow{-2}{*}{row} \\
    \hline
\end{tabular}

Facile ? Et ben non… C’est pas bon. Parce que si on regarde bien le résultat, on se rend compte que ma \cline a un peu disparue :

combo

Le problème vient du fait que les couleurs des lignes sont appliqués après les cline et donc recouvre les lignes. cline est donc prohibé dès qu’on met de la couleur. C’est bien dommage parce que c’était bien pratique comme petite commande. On va donc se rabattre vers quelque chose de plus trapu : la commande hhline. Elle permet d’être extrêmement précis dans ce qu’on veut tracer. Alors, je suppose qu’il y a plein de chose que hhline peut faire, j’ai pas franchement lu la documentation, j’ai lu ce qu’il me fallait pour mon besoin et donc ce que je vais dire maintenant n’est absolument pas exhaustif.

hhline prend donc un argument qui est le format de la bordure que l’on veut tracer. Dans le format, on y trouve trois caractères différents : |, - et ~.

  • | permet de tracer LE pixel d’une bordure verticale (gné ?!? 1 pixel quoi !).
  • - permet de tracer la bordure horizontale d’une cellule.
  • ~ permet de ne pas tracer la bordure horizontale d’une cellule. Attention par contre, ne pas tracer veut dire que la place de la bordure est réservée mais que rien n’est tracé. Au final, vous aurez une belle ligne blanche…

En plus de ces 3 caractères, on peut définir des spécificateurs de couleur grace à la commande \arrayrulecolor qui s’utilise de la même manière que \columncolor.

Ainsi, la bordure de notre tableau est basiquement |-|-|-|~|. On peut raisonnablement « oublier » les trois premiers | du format. J’ai pas encore bien compris pourquoi mais il semblerait que s’il est omis, le - qui précède s’en charge. Et pour le premier, de toute façon, la bordure générale du tableau le dessine.

Ceci nous amène donc au format ---~|. Or, comme je vous ai dit plus tôt, ~ fini par nous faire un ligne blanche au milieu de notre cellule fusionnée, ce qui n’est pas franchement esthétique. On va donc appliquer de la couleur et notre format devient :

--->{\arrayrulecolor[gray]{.9}}-|

C’est presque bon. Avec ce format là, on se rend compte que le dernier pixel sur la bordure est gris aussi alors qu’il devrait être noir. Il faut donc appliquer la couleur noire au dernier | de la même manière que pour le gris. On obtient alors le code suivant, qui nous produit le tableau de nos rêves les plus fous :

\usepackage{multirow}
\usepackage{color}
\usepackage{colortbl}
\usepackage{hhline}

\begin{tabular}{|c|c|>{\columncolor[gray]{.7}}c|>{\columncolor[gray]{.7}}c|}
    \hline
    \multicolumn{2}{|c|}{column} & 3  & 4                     \\
    \hline
    \rowcolor[gray]{.9}
    5             &            6 & 7  &                       \\
    \hhline{--->{\arrayrulecolor[gray]{.9}}->{\arrayrulecolor[gray]{0}}|}
    \rowcolor[gray]{.9}
    9             & 10           & 11 & \multirow{-2}{*}{row} \\
    \hline
\end{tabular}

Le mot de la fin

Avant de vous quitter, je voulais vous dire que même si je râle beaucoup, ça fait plutôt plaisir de se remettre un petit coup dans du LaTeX et à aboutir à un document de qualité (que je n’aurais jamais su faire avec un éditeur à la Libreoffice ou à la Word). Bref, tout ça pour dire que LaTeX fait des choses merveilleuse si tant est qu’on s’y intéresse un peu. Du coup, la prochaine fois, avant d’ouvrir un Word, pensez aux alternatives qui font beaucoup de choses pour vous.

En bonus

Un petit bonus, parce que j’en use et j’en abuse que j’ai un tableau, un texte ou une image qui ne rentre pas sur ma page mais presque, l’environnement adjustwidth est magique. Il est disponible dans le package changepage et je vous laisse consulter sa documentation.

Pour voir les commentaires, cliquez ici

Hosting
Serveur

Comme j’avais écrit un petit guide pour mon frère pour installer Redmine facilement sur une Debian toute fraîche, je vous le livre ici.

Installation des dépendances

On va commencer par installer les dépendances nécessaires à notre affaire. Il nous faut une base de donnée (MySql), imagemagick pour la gestion des images via l’extension RMagick, curl pour télécharger facilement la suite via la ligne de commande et vim (enfin, un éditeur de texte, mais vim est tellement bien).

$ sudo apt-get install vim curl mysql-server mysql-client libmysqlclient-dev imagemagick libmagickwand-dev

On n’oublie pas de sécuriser sa base de donnée en exécutant le petit script suivant :

$ sudo mysql_secure_installation

RVM, Ruby, gem et compagnie

On commence par récupérer la clé publique des développeurs de RVM puis on va télécharger l’installeur.

$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ curl -O https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer
$ curl -O https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer.asc

Évidemment, on vérifie que le téléchargement s’est bien passé en vérifiant la signature.

$ gpg --verify rvm-installer.asc

Enfin, on fini par installer RVM, on s’ajoute au groupe des utilisateurs de RVM et à ce stade, le plus simple est de rebooter (sinon, il faut se relogger et sourcer le fichier /etc/profile.d/rvm.sh).

$ bash rvm-installer stable
$ gpasswd -a $USER rvm # Add user into rvm group
$ source /etc/profile.d/rvm.sh # Login out and relogin and source /etc/profile.d/rvm.sh (or reboot)

On a donc un RVM tout neuf qui va nous servir à installer et gérer nos instances de Ruby avec tous les gems qui vont avec.

$ rvm install ruby-2.2.1
$ rvm use ruby-2.2.1
$ rvm gemset create redmine

Installation de Redmine

On se dirige dans le dossier où on veut installer notre instance de Redmine. J’ai choisi de le mettre dans /srv/http/, une vieille habitude d’Archlinuxien.

$ sudo mkdir -p /srv/http
$ sudo chown $USER -Rf /srv/http/
$ cd /srv/http/

On télécharge le dernier Redmine stable. Au moment où j’écrit ces lignes, il s’agit de la version 3.0.1, n’hésitez pas à consulter le site https://redmine.org pour savoir si une version plus récente est sortie et si les instructions d’installation sont différentes.

$ curl -O http://www.redmine.org/releases/redmine-3.0.1.tar.gz
$ md5sum -c - <<HERE
bf63ceef4fde0d38d17d94969478d422  redmine-3.0.1.tar.gz
HERE
$ tar xzf redmine-3.0.1.tar.gz
$ cd redmine-3.0.1

À partir de maintenant nos sources sont là, on n’a plus qu‘à configurer et lancer le tout. On commence par mettre en place la base de donnée.

$ mysql -u root -p <<HERE
CREATE DATABASE redmine CHARACTER SET utf8;
GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost' IDENTIFIED BY 'my_password';
HERE

Puis on configure cette base dans Redmine en utilisant les paramètres choisis sur la ligne précédente.

$ cp config/database.yml.example config/database.yml
$ vim config/database.yml

On doit avoir un bloc avec cette tête là :

# Set production database link
production:
  adapter: mysql
  database: redmine
  host: localhost
  username: redmine
  password: my_password

Une fois que la base est configurée, on peut installer les gems nécessaires à Redmine.

$ gem install bundler
$ bundle install --without development test

Note : je ne l’ai pas dit avant, mais toutes ces commande sont à exécuter dans le même terminal. Si jamais vous devez changer de terminal, il faut recharger l’environnement RVM qu’on a mis en place avec la commande rvm use ruby-2.2.1@redmine.

On initialise notre nouvelle instance :

$ bundle exec rake generate_secret_token
$ RAILS_ENV=production bundle exec rake db:migrate
$ RAILS_ENV=production REDMINE_LANG=fr bundle exec rake redmine:load_default_data

Et on arrange les permissions pour que tout se passe bien :

$ mkdir -p tmp tmp/pdf public/plugin_assets
$ chown redmine:redmine -Rf redmine-3.0.1
$ chmod -R 755 files log tmp public/plugin_assets

On termine par tester le server pour voir si tout va bien :

$ bundle exec ruby bin/rails server webrick -e production

À partir de maintenant, on a une instance de Redmine qui tourne et qui devrait fonctionner comme un charme. Par contre, comme webrick n’est pas prévu pour tourner en production, la suite de l’article évoque quelques étapes nécessaires à la mise en production de votre nouveau serveur.

Et pour la production

Afin d’avoir quelque chose de plus stable, on va utiliser le gem Unicorn pour notre serveur. Il s’installe facilement comme un Gem classique et sa configuration est plutôt simple.

$ gem install unicorn-rails unicorn
$ cd /srv/http/
$ cat > unicorn.rb <<HERE
APP_PATH = "/srv/http/redmine-3.0.1/"

worker_processes 1
working_directory APP_PATH

preload_app true
timeout 45

listen APP_PATH + "/tmp/unicorn.sock", :backlog => 64
pid APP_PATH + "/tmp/unicorn.pid"

stderr_path APP_PATH + "/log/redmine.error.log"
stdout_path APP_PATH + "/log/redmine.access.log"


before_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
    worker.user('redmine', 'redmine') if Process.euid == 0
end
HERE

Il nous manque encore un petit script de démarrage comme celui-ci qu’il faudra lancer en tant que service au démarrage de la machine.

#!/bin/bash --login

VERSION=2.2.1       # Version du Ruby utilisé
GEMSET=redmine      # Ensemble de Gem pour notre environnement
REDMINE_PATH=/srv/http/redmine-3.0.1 # Chemin vers notre installation de Redmine

# On charge RVM avec le bon l’environnement
rvm use ruby-${VERSION}@${GEMSET}
# On démarre réellement notre instance
$(which unicorn_rails) -c "$REDMINE_PATH/../unicorn.rb" -E production -D

Et voilà, il ne vous reste plus qu’à configurer votre serveur web en reverse proxy pour qu’il aille chercher les informations sur la socket dans /srv/http/redmine-3.0.1/tmp/unicorn.sock. Si vous utilisez Nginx, une configuration de ce style devrait aller~:

upstream unicorn_redmine_server {
    server unix:/srv/http/redmine-3.0.1/tmp/unicorn.sock;
}

server {
    listen 80; ## listen for ipv4; this line is default and implied
    listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    client_max_body_size 4G;
    keepalive_timeout 5;

    root /srv/http/redmine-3.0.1/public;
    try_files $uri/index.html $uri.html $uri @app;

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        proxy_pass http://unicorn_redmine_server;
    }
}

Et le backup

Bien évidemment, on n’oublie pas de configurer un backup. Il suffit pour cela de ces deux petites lignes :

# Database
$ /usr/bin/mysqldump -u <username> -p<password> <redmine_database> | gzip > /path/to/backup/db/redmine_$(date +%y_%m_%d).gz
# Attachments
$ rsync -a /path/to/redmine/files /path/to/backup/files

Bonne chance et à bientôt. N’hésitez pas à me faire vos remarque s’il manque quelque chose à ce guide.

image

Pour voir les commentaires, cliquez ici

Scripting
Git

Aujourd’hui, comme je suis en train de remettre de l’ordre dans mes projets persos, je passe mon temps à faire des commits dans des dépôts Git d’un côté, et de faire des updates de dépôts Git de l’autre.

Comme c’est toujours les mêmes commandes, j’ai décidé d’automatiser un petit peu le process et de mettre à jour tous les dépôts Git d’un dossier à partir d’une seule et même commande.

C’est simple, ça va récupérer tous les dossier contentant un .git, puis dans chacun de ces dossiers, il récupère toutes les branches de tous les remote paramétrés avec un git fetch <remote> <branch>, puis, si la branche qu’on viens de récupérer correspond à la branche courante, on la merge avec un simple git merge <remote> <branch>.

Contrètement, ça donne les 28 lignes de shell suivante :

#!/bin/sh

OLDIFS=$IFS
IFS=$'\n'

update()
{
    echo "Update $(basename $PWD)"
    # Get all remote branch
    refs=$(git branch -r | grep -v "\->")
    for ref in $refs; do
        remote=$(echo $ref | cut -d'/' -f 1 | sed 's| ||g')
        branch=$(echo $ref | cut -d'/' -f 2 | sed 's| ||g')

        git fetch $remote $branch
        localbranch=$(git name-rev --name-only --always HEAD)
        if [ $localbranch = $branch ]; then
            echo "Remote fetched branch is same as local branch. Merge it."
            git merge $remote $branch
        fi
    done
}

for gitdir in $(find . -name ".git"); do
    (cd $(dirname "$gitdir") && update)
done

IFS=$OLDIFS

Je sais pas si ça vous servira (ni si ça me servira longtemps), mais dans le doute, je partage.

image

Pour voir les commentaires, cliquez ici

Hosting
Serveur

Ça faisait une éternité que je n’avais pas posté un billet ici. Surtout quand je vois le dernier post affiché joyeusement bonne année à tous, je me dis qu’il faut remédier à ça (même en France, on ne souhaite plus la bonne année fin mars…).

Une fois n’est pas coutume, je vous avais déjà parlé de Redmine ici, et voici donc de nouvelles aventures !

La mise à jour

Au début de l’année, une nouvelle version toute neuve de Redmine est sortie en version stable : la version 3 et donc, depuis ce moment là, je me dit qu’il faudrait que je fasse la mise à jour vers cette nouvelle version. Le problème avec la nouvelle version, quand elle est toute fraîche, les plugins que vous utilisiez avant ne sont pas systématiquement compatibles (surtout quand on change de majeur). Et donc après plusieurs tentatives de migrer avec les 3 « petits » plugins que j’utilisais, échec sur échec sur échec.

Finalement, hier, après une conversation avec mon frère qui me demandait si je connaissais Ruby et Redmine et s’il était capable de faire du suivi de temps, je suis allé faire un tour dans les paramêtres d’un projet pour activer le time-tracking. Et là, sans vraiment rien n’y comprendre :

Erreur 500: internal error

Arghhhhh…

Sur ce (je vous passe le florilège d’insulte que j’ai pu balancer à ce moment là), je me dit que c’est vraiment une bonne occasion de repartir du bon pied et de migrer le tout.

  • Première étape: abandon des plugins non compatible avec la version 3.x. Le premier project removal, installé et utilisé une fois pour nettoyer des vieux projets, je me suis dit « s’pas grave… ». Le second wiking qui permettait d’ajouter des macros au wiki. Comme il y a plein d’autre plugin pour ça, je verrais plus tard pour le remplacer par autre chose. Et finalement, l’intégration de git. Celui-là, je m’en sert énormément puisque c’est lui qui permet, entre autre, de gérer les clés SSH utilisés sur mes dépôts Git. J’utilisais jusque là le plugin redmine_gitolite qui n’a pas été mis à jour depuis 2 ans.
  • Deuxième étape: la recherche de remplaçant. Comme je l’ai dit précédemment mise à part l’intégration de Git, les autres plugins sont secondaires. C’est là que je suis tombé sur le plugin redmine_git_hosting. Seul problème pour l’installer, il faut que je perde les clés publics mémorisés par l’ancien plugins. Tant pis, je supprime tout et l’installation se passe à merveille.
  • Troisième étable: mise à jour. En suivant les étapes du wiki de Redmine sur la mise à jour, tout se porte comme un charme avec un Ruby en 2.2.1. On ajoute à ça la documentation du plugin redmine_git_hosting et c’est vraiment la fête. J’en ai profité également pour nettoyer mon installation de gitolite histoire de repartir sur des bases propres.

Final

Au final, j’ai un nouveau Redmine qui fonctionne, une intégration de Git meilleur qu’avant ce qui est plutôt sympa. Le seul point noir et la perte des clés publics de tous les utilisateurs (mais comme je suis globalement le seul à utiliser cette instance de Redmine… ça va. J’aurais peut-être cherché une autre solution si j’avais eu plein d’utilisateurs très actifs). Les dépôts git sont encore un petit peu en dérangement mais ça devrait rentrer dans l’ordre sous peu. J’en profite aussi pour mirrorer un peu mieux les différents dépôt sur Github avec des descriptions qui vont bien.

À bientôt.

image

Pour voir les commentaires, cliquez ici

misc
Tags : Blog General

C’est maintenant la fin de l’année et l’heure est au bilan. L’année 2014 fut riche de nouvelles découvertes et de nouveaux défis, tant sur le plan personnel que professionnel…

Le serveur aussi a bien profité de cette année 2014 avec une migration qui s’est étalé sur près de 5 mois, des nouveaux services plus complets (mais ça, vous ne les verrez pas), une architecture plus cohérente, plus propre et un ensemble plus sécurisé.

J’ai encore plein de projets pour l’année à venir et j’espère pouvoir les mener à bien.

En ce qui concerne le blog, mine de rien, il y a de plus en plus de monde qui le consulte et ça, ça me fais bien plaisir ! Au moins, je me dis que ce que j’écris peut être utile aux autres. À compter aussi deux articles avec Farnell, chose que je n’aurais jamais cru possible lorsque j’ai commencé l’aventure du blog.

Pour être complètement transparent, voici les statistiques de l’année :

Statistiques

Il ne me reste plus qu’à vous souhaiter une très bonne année 2015 à tous.

Pour voir les commentaires, cliquez ici

Hosting
Serveur

Ah là là, Redmine… Autant, j’aime bien utiliser ce logiciel, autant à chaque fois que j’essaye de l’administrer, de le mettre à jour, de le migrer, je suis à deux doigts de tout foutre en l’air !

Amis rubyiste, désolé, mais cet article ne va pas forcément vous plaire.

La pierre angulaire du problème

À mon sens, le principale problème de Redmine, c’est Ruby. Parce que oui, Redmine est développé en Ruby, et le gros problème de Ruby, c’est ces innombrables versions, pas forcément compatibles bien bien entre elles.

Alors, la première fois, quand on connait pas bien Ruby, on l’installe via son gestionnaire de paquets préféré et on se lance dans l’aventure. Et là, pan ! Première Groβe Boulette (avec un grand G, un grand B et un eszett, carrément).

Ensuite, ben vous faites le checkout du projet Ruby en question. Avec un peu de chance, ça arrive à fonctionner (mais il faut faire gaffe avec la chance, parce qu’elle tourne vite). Je vous passe les détails sur la mise en ligne de l’application avec Apache et Rails, c’est pas le pire…

Et puis, comme vous êtes quelqu’un de sérieux, qui fait correctement ses mises à jour, il se trouve que votre Ruby monte de version, et là : deuxième Groβe Boulette. Parce que quand vous lisez mise à jour de Ruby 1.8 à Ruby 1.9, vous vous dites : « Boh… une mise à jour d’un mineur, ça va bien se passer c’est cool «. Et on arrive sur la Groβe Boulette numéro 3. Ne jamais au grand jamais, mais alors au grand jamais croire que Ruby est un poil rétro compatible sans avoir essayé avant !

La solution (enfin une ébauche pour que ça se passe mieux)

Abandonnez votre gestionnaire de paquets pour tout ce qui touche à Ruby et commencez par installer RVM. Ensuite, installez le Ruby utilisé par votre projet, et configurer votre shell pour utiliser ce Ruby là. Dans l’exemple suivant, la première commande sert à installer Ruby 2.1.5 et la deuxième configure votre shell pour utiliser Ruby 2.1.5. Cette deuxième commande est à faire à chaque fois que vous faites quelque chose avec Ruby :

$ rvm install 2.1.5
$ rvm use 2.1.5

Ensuite, tant que votre projet n’utilise pas un autre Ruby, que vous n’avez pas testé un autre Ruby, ou tant que vous n’avez pas une attestation signée des développeurs du projet qui vous autorise à utilisée une autre version de Ruby, vous ne changez JAMAIS la version du rvm use avant vos opérations !

Ensuite, on passe les étapes classique à coup de bundle install et tout et tout, et hop, ça fonctionne. Enfin, normalement… Faut quand même pas oublier un cierge, une incantation vaudou ou je ne sais pas quoi d’autre.

Deuxième problème : Rails

Je vous ai dit tout à l’heure que Rails avec Apache, ça se faisait plutôt bien, mais comme j’aime jouer, je n’ai pas d’Apache, je suis passé à Nginx, Nginx est vraiment bien pour faire du reverse-proxy et passer toutes les requêtes d’un sous-domaine vers un serveur en cours d’exécution. Il faut donc lancer le serveur, en daemon, au démarrage de la machine. Sous SysV Init, c’est facile… Un petit script et hop, tout va bien. Par contre, mon système (comme de plus en plus de système) utilise SystemD et donc, c’est un poil plus compliqué qu’un simple script. Après quelques recherche, je vous livre ma solution complète pour démarrer une application Ruby/Rails, en utilisant la (ou le, je sais pas comment on dit) gem unicorn, le tout derrière Nginx sur un système à base de SystemD. L’exemple qui suit est spécifique à Redmine mais il s’adapte très bien à d’autres application et même à d’autres langage et d’autres frameworks.

Configuration de Unicorn

# unicorn.rb
APP_PATH = "<path to application root dir>"

worker_processes 1
working_directory APP_PATH

preload_app true
timeout 45

listen "<path to socket>", :backlog => 64
pid "<path to PID path>"

stderr_path "<error log path>"
stdout_path "<access log path>"

before_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
    worker.user('http', 'http') if Process.euid == 0
end

N’oubliez pas que l’utilisateur http (ou celui que vous avez spécifié) doit avoir les droits d’écriture sur tous les chemins donnés dans la configuration (<path to socket>, <path to PID path>, les chemins vers des logs). Garder bien en tête le chemin vers la socket, on va s’en resservir après.

Configuration de SystemD

On commence par un petit script qui démarre notre application, à mettre dans starter.sh.

#!/bin/bash --login

VERSION=2.1.5 # ou n’importe quelle version de ruby
APP_PATH="<path to application root dir>"

# Load RVM functions
source "$HOME/.rvm/script/rvm"
# Load given ruby version
rvm use $VERSION
# Start application
$HOME/.rvm/gems/ruby-$VERSION/bin/unicorn_rails -c "<path to unicorn.rb>" -E production -D

Pour tester tout ça, un tant qu’utilisateur http, lancer le script. L’application doit démarrer. Si tout se passe bien, on passe à la suite : la définition du service SystemD à mettre dans /etc/systemd/system/<application>.service

[Unit]
Description=<application description>
After=syslog.target
After=network.target

[Service]
Type=forking
User=http
Group=http
ExecStart=<path to starter.sh>

TimeoutSec=300

[Install]
WantedBy=multi-user.target

On test avec un petit coup de systemctl start <application>. Si ça marche c’est que tout va bien, si on ne sort pas, il faut changer le type en simple. (Dans le cas de unicorn, le fork marche bien parce que uincorn se fork à la fin)

Si tout se passe bien, on active le daemon avec systemctl enable <application> et notre application se lancera toute seule au boot de la machine.

Le binding avec Nginx

Et finalement, dans la configuration de Nginx [1] :

upstream unicorn_server {
    server unix:<path to socket>;
}

server {
    listen 80;
    server_name <server name>;

    root <public application path>;

    try_files $uri/index.html $uri.html $uri @app;
    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_set_header Host $http_host;
        proxy_redirect off;

        proxy_pass http://unicorn_server;
    }
}

# je vous laisse faire la configuration pour https, c’est pareil

Un petit restart du serveur et tout se passe bien. Enfin, normalement.

Bref, pour voir comment ça marche au final, direction redmine.

Et en bonus

Je vous ai dit que cette configuration s’adaptait bien à d’autres applications, d’autres langages et d’autres frameworks. Voilà ma configuration pour une application python Isso dont j’avais déjà parlé .

starter.sh

#!/bin/bash

# Create virtualenv only once with this command:
#/usr/bin/virtualenv --python=/usr/bin/python2 "<path_to_isso>"

cd "<path_to_isso>"
source ./bin/activate
uwsgi <path_to_isso>/uwsgi.ini

uwsgi.ini

[uwsgi]
http = :8080
master = true
processes = 4
cache2 = name=hash,items=10240,blocksize=32
spooler = %d/mail
module = isso.run
virtualenv = %d
env = ISSO_SETTINGS=/etc/isso.conf

isso.service

[Unit]
Description=Ich Schrei Sonst server
After=syslog.target
After=network.target

[Service]
Type=simple
User=http
Group=http
ExecStart=starter.sh

TimeoutSec=300

[Install]
WantedBy=multi-user.target

nginx

server {
    listen  80;
    server_name <server name>;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

image

[1]en vrai, je dis « d’Nginx » mais je trouve pas ça beau à écrire.

Pour voir les commentaires, cliquez ici

Hosting
Serveur

Le DNSSEC, kézako ?

Pour faire court, le DNSSEC est la version securisé du DNS que tout le monde utilise. Chaque enregistrement DNS est signé cryptographiquement et permet donc de valider le contenu de l’enregistrement. Pour plus d’informations dessus, je vous renvoie à l’article de Wikipedia sur le sujet.

La mise en place

Cet article va être très court, car je n’ai pas grand chose à dire dessus ! En fait, toutes les étapes sont décrites ailleurs… Il vous suffit de suivre les différentes étapes de ce guide. Le guide vient d’OVH donc la partie enregistrement DS dans la zone mère est spécifique à OVH mais je suis sûr que ça doit être similaire chez les autres registrar…

La vérification

Pour vérifier que tout se passe bien, j’utilise 2 sites différents :

Et voilà pour aujourd’hui, c’était plutôt court. Le seul problème que j’ai rencontré pour la mise en place du DNSSEC, c’est les temps d’attentes, le temps que le DNS slave se mette à jour, le temps que la zone mère enregistrement ma clé… Il ne faut juste pas se décourager.

image

Pour voir les commentaires, cliquez ici