Je suis développeur web freelance et propose des formations à Symfony2 ! Contactez-moi pour en discuter.

I’m using Markdown as a markup syntax for many things: the syntax is indeed really simple to use, it lets me focus on the content I need to write, and it can later be converted to HTML for « real life » display once I’m done. In the open-source community, it has become largely spread, and many developpers use it, like me, for non code-related stuff, like keeping notes or writing their journal. Lire la suite »

La semaine dernière, j’ai eu un problème avec un exécutable, celui de wkhtmltopdf qui n’arrivait pas à générer de PDF et le log n’était pas clair. D’après certaines indications sur StackOverflow, ca pouvait être du à un problème de version de la librairie libjpeg. On peut le vérifier avec strace, c’est un utilitaire qui intercepte et loggue tous les appels systèmes, ce qui permet de voir ce qui se passe en fouillant dans les logs. Je ne connaissais pas cet outil, c’était une bonne occasion de découvrir.

La commande à inspecter est la suivante :

1
$ ./wkhtmltopdf-amd64 in.html out.pdf

On prend un fichier html en entrée, et on chercher à générer à en faire un fichier pdf.

Pour inspecter la trace d’exécution avec strace, on fait comme ça :

1
$ strace -f -o trace.log ./wkhtmltopdf-amd64 in.html out.pdf

L’option -f permet d’enregistrer égalements les appels systèmes des processus fils, -o indique un fichier dans lequel stocker les logs.

On peut ensuite chercher à voir quels sont les appels au chargement de libjpeg.so. On trouve vite ce qu’on cherche :

1
2
$ cat trace.log |grep libjpeg
18590 open("/usr/lib/x86_64-linux-gnu/libjpeg.so.8", O_RDONLY|O_CLOEXEC) = 3

On voit donc que l’exécutable cherche à charger libjpeg dans sa version 8 dans un répertoire particulier. En cherchant les installations de libjpeg ($ locate libjpeg), j’ai pu voir que la version installée sur la machine en question est libjpeg.so.62, ce n’est donc pas la bonne version, un problème résolu avec un

1
apt-get install libjpeg8

. Bref, un problème pas banal mais qui m’a permis d’apprendre plein de choses 🙂

Il est facile d’ajouter des fichiers invalides dans un système de contrôle de version si on ne fait pas attention. Un des moyens d’éviter ça, c’est d’utiliser les hooks de git.

On peut « s’accrocher » à un événement, et exécuter du code à ce moment. Git permet de le faire à peu près n’importe quand : avant un commit, avant un push, après un checkout… La liste complète des possibilités est dans la doc.
Pour cela, il suffit d’ajouter un script shell dans le répertoire .git/hooks d’un dépôt git. On peut d’ailleurs y trouver quelques exemples (inactifs, il faut les renommer pour les « activer »).

Pour éviter de soumettre des fichiers à la syntaxe invalide, on peut donc écrire un hook pre-commit en creant le fichier pre-commit dans ce répertoire. Ce script s’exécutera avant que le commit soit réalisé lorsque l’on exécute la commande commit.

Voici son code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh
# On récupère la liste des fichiers modifiés
modifiedFiles=`git diff --cached --name-only --diff-filter=ACM`;
error=false;

for file in $modifiedFiles; do
# On vérifie la syntaxe des fichiers PHP avec php -l
   if [[ $file =~ .*\.php ]]; then
      result=`php -l $file 2>&1`;
      if [[ $result =~ .*'Parse error'.* ]];
      then
         echo $file;
         echo $result;
         error=true;
      fi;
   fi;
done

if [ $error != false ]; then
   # En cas d'erreur on empêche le commit
   echo "Erreur de syntaxe dans l'un des fichiers";
   exit 1;
fi;

Le code est simple et commenté, le comprendre ne devrait pas poser de problème (l’écrire a demandé quelques coups de main à google ceci-dit. bash, quelle galère…). La vérification de syntaxe se fait avec php -l, le linter de PHP, en parsant le texte de sortie car il n’y a pas de code de retour qui permette de déduire une erreur de syntaxe. En cas d’erreur, on interrompt le commit et on affiche les fichiers à corriger. Simple et efficace.

On pourrait bien sûr faire d’autre vérifications : validation de la syntaxe des fichiers JavaScript avec jslint, assurer le bon respect des règles de codage avec PHPCS

Plus d’informations sur les hooks dans la documentation.

Il y a quelques temps, j’ai du filmer un écran pendant un long moment, plusieurs heures; comme il n’allait rien s’y passer pendant la majeure partie du temps, utiliser une application qui allait prendre plusieurs images par seconde n’était pas envisageable, car le fichier de sortie aurait rapidement atteint une taille trop grosse. De plus, j’avais juste besoin de voir en gros les moments où il y aurait de l’activité donc je n’avais pas besoin d’une telle précision. Une précision de l’ordre de la seconde suffisait largement.

J’ai donc opté pour un script shell, qui faisait une capture d’image par seconde, que j’ai ensuite assemblée, à une vitesse supérieure (plusieurs images par secondes). On appelle ce genre de vidéo un timelapse.

Divers articles m’ont aidé, mais c’est finalement celui-ci que j’ai mis en oeuvre car il est simple. Le processus est assez facile à reproduire sur une Ubuntu.

On commence récupérer les deux packages que l’on va utiliser, pour faire les captures puis l’assemblage :

1
$ apt-get install scrot mplayer

Pour faire les captures d’écran, on écrit le script shell suivant, qu’on lance et qu’on laisse tourner :

1
2
#!/bin/sh
while [ 1 ]; do scrot -q 100 $(date +%Y%m%d%H%M%S).jpg; sleep 1; done

Ce script prend une capture toute les secondes, et sauvegarde dans un fichier JPEG dont le nom correspond à la date formattée.

Une fois la capture terminée, on arrête le script et on liste les fichiers images dans un fichier, du plus récent au plus ancien :

1
$ ls -1tr *.jpg > files.txt

C’est l’occasion de découvrir de nouveaux paramètres pour ls !

    -1 permet d’avoir un nom de fichier par ligne (attention, c’est le chiffre « un », pas la lettre « l »)
    -t trie les fichiers par date de modification
    -r inverse l’ordre des fichiers

On assemble enfin les images avec mencoder, à raison de 20 images par secondes. Vous pouvez ou non ajouter un fichier mp3 directement pendant l’assemblage :

1
$ mencoder -ovc x264 -oac mp3lame -audiofile basket_case.mp3 -mf w=1400:h=900:fps=20:type=jpg 'mf://@files.txt' -o screenlapse.avi

Et voila. Prochaine utilisation de ce script lors de ma participation à une future Ludum Dare, peut être la 32ème ? Les timelapse de participants y sont monnaie courante.

Quelques astuces testées sur le terrain pour débugguer une application angularJS sans quitter le navigateur.

Dans chrome, on ouvre la console avec F12 ou ctrl+maj+j. Couplé au fait que l’on peut modifier le code et le faire rejouer directement depuis les outils pour développeurs, cela permet de débugger/corriger rapidement son code sans avoir à recharger la page systématiquement, ce qui est parfois très pratique.

Récupérer un service

Des fois un service en cours de développement ne marche pas comme il faut et c’est pas toujours marrant de devoir recharger la page à chaque modification pour déclencher à nouveau l’appel en question et le débugger. Par contre, on peut récupérer le service avec la méthode ci-dessous, modifier en direct la méthode depuis l’onglet « sources » de chrome dev tools, et lancer l’exécution à la main de la méthode réticente.

1
2
var service = angular.element('body').injector().get('myService');
service.maMethodeARelancer("plop");

A mettre entre toutes les mains. Depuis que j’ai découvert ça, je ne peux plus m’en passer.

Récupérer un scope local

Des fois on a besoin de récupérer le scope sous un contrôleur, que ce soit pour voir le contenu d’une variable à un instant particulier. Pour ce cas d’usage, la plupart du temps le débuggueur est plus pratique.
Par contre, quand on veut appeler une action de controlleur présente dans le scope, c’est très pratique.

Il faut connaitre le sélecteur DOM de l’élément du DOM dans lequel se trouve le scope auquel ou souhaite accéder.

1
var scope = angular.element('[ui-view=panel-communication]').scope()

Ensuite, on peut accéder aux propriétés accessibles dans ce scope, et appeler les méthodes que l’on souhaite.

1
2
scope.unMethodeARelancer("pouet")
scope.UnAttributQueJePeuxRegarderPlusFacilementDansLeDebuggueur

Débugger les directives

Il est parfois d’accéder au scope local à la directive, qui ont un don assez fou pour ne pas contenir les valeurs que l’on croit, les rendant particulièrement pénibles à débugger.

1
var localScope = angular.element('[ui-view=panel-communication]').localScope()

Certains directives ont un contrôleur, auquel on peut accéder, ce qui est un luxe qui peut vous faire gagner pas mal de temps et vous économiser nombre de dolipranes.

1
var controller = angular.element('[ui-view=panel-communication]').controller()

Bon courage !

terminatorIl y a quelques semaines, mon collègue tilap écrivait un article sur l’utilisation de screen partager un terminal en plusieurs.

Screen est plus largement répandu, et permet de partager un terminal sans installation préalable lors d’une connection SSH. Par contre au quotidien je préfère utiliser terminator, qui est quand même plus simple et convivial. Voici donc un petit guide de survie.

Installation

L’installation sur Ubuntu 14.04 se fait via :

1
apt-get install terminator

Les raccourcis essentiels

4 raccourcis servent à faire la plupart des choses :

  • ctrl+maj+o = ouvre un terminal dans le répertoire actuel, une barre horizontale sépare alors les 2 terminaux
  • ctrl+maj+e = ouvre un terminal dans le répertoire actuel, une barre verticale sépare alors les 2 terminaux
  • ctrl+maj+w = ferme le terminal sélectionné
  • ctrl+maj+x = fait disparaitre les autres terminaux, en ouvrant le terminal sélectionné en grand. ctrl+maj+x permet de revenir aux autres écrans

Pour ceux qui aiment naviguer au clavier, on peut se déplacer entre les terminaux rapidement assez rapidement avec quelques
ctrl+tab permet de naviguer vers le terminal suivant (ctrl+maj+tab pour obtenir le précédent)
ctrl+maj+gauche/droite/haut/bas permet déplacer les séparateurs entre les différents terminaux

La configuration de terminator est stockée dans ~/.config/terminator/config. Voici quelques paramètres que je trouve bien pour donner à terminator l’apparence d’un gnome shell :

1
2
3
4
5
6
7
8
9
[global_config]
  suppress_multiple_term_dialog = True
[profiles]
  [[default]]
    background_image = None
    background_color = "#2c001e"
    split_to_group = True
    show_titlebar = False
    foreground_color = "#ffffff"

Cela permet d’avoir la couleur de fond d’ubuntu et masque les titres ajoutés par terminator, donnant ainsi aux terminaux le même aspect qu’un gnome-terminal, mais en ayant plus de possibilités.

I wrote this article a while ago. Instead of letting it sink on my hard drive, the release of docker 1.0 is a good opportunity to let people know how easy getting started is. There might be some better solutions for many things, since stuff have evolved a lot in the last months, but you can see this article as an introduction to what docker is and how it works.

A few months ago, I talked about how to use Vagrant in order to deploy virtual machines on DigitalOcean. More recently, I’ve been playing with Docker, which is a kind of git for virtual machines.

With this tool, one can create virtual machines. The philosophy is not to ease machine creation (stuff that you would find with Vagrant + Puppet or Chef). The magic idea is that after every modification on the system (setup, file creation, script execution…), it is possible to save the state of the machine. This is so similar to ‘git commit’ that the command is… ‘docker commit’.
With such a philosophy, it is possible to navigate between the states, publish a machine like you would publish a repository on github, update a set of already-running machines efficiently, and so on.

I’ll get through the first steps to create a small machine that can be used in order to execute sandboxed php code : the php code will run inside the machine, and we’ll get the result. This could be used for a PaaS (Platform as a Service), like jsbin or codepen, but for languages whose functionnalities could pose security threats if it was executed on the main machine (php, python, ruby…).

Installing docker

I won’t get much into the details about how to install docker actually, everything you need is up to date in the <a href= »http://docs.docker.io/en/latest/ »>documentation</a>. There are some requirements about the version of your kernel, so if you can’t install, a solution is to run it inside a vagrant virtual machine. The source code contains a Vagrantfile already setup, so nothing could be easier :

Now that we have our new toy, we can start creating an image.

Open a terminal and start an instance using the base image :

1
sudo docker run -i -t base /bin/bash

This will launch you into a shell inside the machine. We can now start customizing the image. We won’t do much in this tutorial, we will simply install php, but of course you can do everything you would do with any virtual machine.

Installing php

Inside the shell, run :

1
2
apt-get update
apt-get install php5

Saving of a machine

Now that we have a machine with PHP installed, we want to save it, in order to be able to reuse it afterwards. We have made modifications on the system but if we exit the shell right now, since they have not been saved, we’ll have to install php again the next time we run our image.

Leave the current terminal open, and open another terminal. In order to save our image we need its identifier, so run :

1
 sudo docker ps

It will show the ID of the running container in the other terminal. We can save our image with the name ‘clem/php’ by running the commit command :

1
sudo docker commit clem/php

The name looks like the conventions on github (user/repository). Even though here there are no obligations, it’s good to keep good habits.

If all went well, your images ‘clem/php’ will appear in the list of available images :

1
sudo docker images

Images are similar to git branches of the base image. The next time you want to create a machine, if you want to install php and mysql, you can :

  • run the base image, install php and mysql
  • run the clem/php, and install mysql

Our basic jsbin like for PHP

Remember, we want to do something similar to jsbin, but for executing php in a sandbox. Our image clem/php will be the sandbox, because we don’t want to restrict the functionnalities of the language, what if someone executed some shell code from PHP in order to erase the whole system. We can use docker to start a machine, execute any phpcode, return us the result, and quit. Since we won’t save the machine, every execution will provide us with a brand new machine. If someone destroys it in anyway, we couldn’t care less.

We need to create a file on the host, that will be executed in docker. Create test.php, and write something like :

1
<?php echo 'Hello World !'.PHP_EOL;

Run some code inside your new sandbox
The first idea I came up with was this one :

1
cat test.php | sudo docker run -i clem/php /bin/bash -c "cat &gt; test.php; php test.php"

Basically, to manually copy the content of the file thanks to cat inside docker. Then we run it thanks to bash, with a 2 command script : « cat > test.php; php test.php », or ‘dump the content to test.php then run test.php’.

There is a better solution : using a mounting point. We can share a folder on the host machine to docker.
/home/vagrant/test.php will be the file on the host machine
/home/docker.php is the file we want to have on the docker machine.
the ‘-v’ option tells docker to create a mounting point between the two files.
This time, instead of running bash, we can directly run PHP.

1
docker run -v /home/vagrant/test.php:/home/docker.php php /home/docker.php

Awesome, huh ?

Même si les bases de données NoSQL ont la côte en ce moment, les bases de données SQL ont encore de beaux jours à vivre devant eux. En effet, dans beaucoup de situations, il est assez facile de sortir des statistiques avec quelques lignes de SQL. Voici quelques astuces que j’ai découvert il y a quelques temps, et qui sont très pratiques pour sortir des chiffres.

Assez rapidement, lorsqu’on fait du SQL, on a besoin de récupérer le nombre d’éléments dans la base qui correspondent à un certain critère. Pour faire des statistiques, comme par exemple extraire le nombre d’utilisateurs enregistrés dans la base par exemple. La réponse est classique :

1
2
3
4
SELECT
    COUNT(u.id) AS total
FROM
    users u

Ok, c’était facile. Et si on veut le nombre d’utilisateurs qui ont été créés chaque mois ?

On peut utiliser un « group by date_trunc »

L’astuce, c’est d’utiliser date_trunc. date_trunc permet de ne conserver, dans une date, que la partie de la date qui nous intéresse. Si notre date est le 4 janvier 1981 à 17h23, lorsqu’on tronque au mois, date_trunc nous renverra le 1 janvier 1981 à 00h00. En combinant cela avec un group by, on peut obtenir le nombre d’utilisateur qui a été créé mois par mois :

1
2
3
4
5
6
7
SELECT
    COUNT(u.id) AS total,
    date_trunc ('months', u.created_at) AS considered_month
FROM
    users u
GROUP BY date_trunc ('months', u.created_at)
ORDER BY date_trunc ('months', u.created_at)

Comme vous l’avez compris, le premier paramètre de date_trunc permet de définir où tronquer. En tronquant au jour ou bien à l’heure on obtient une granularité plus fine, mais également plus de données, ce qui n’est pas toujours ce dont on a besoin.

On obtient des résultats de ce genre, en supposant que nous ayons des utilisateurs entre avril et novembre 2013 :

total considered_month
3956 « 2013-04-01 00:00:00 »
3965 « 2013-05-01 00:00:00 »
3549 « 2013-06-01 00:00:00 »
3728 « 2013-07-01 00:00:00 »
8311 « 2013-08-01 00:00:00 »
6041 « 2013-09-01 00:00:00 »
6381 « 2013-10-01 00:00:00 »
3784 « 2013-11-01 00:00:00 »

En fait, maintenant, on aimerait bien connaitre, pour chaque mois, le pourcentage d’utilisateurs qui s’est connecté au moins 3 fois, par rapport au nombre total d’utilisateurs créés durant le mois. Ok, c’est un exemple tordu, mais c’est pour expliquer comment peut faire un pourcentage sur le nombre d’éléments d’un sous-ensemble de données d’un mois concerné par rapport au nombre d’éléments de l’ensemble de départ.

La structure sum (case …)

L’idée, c’est d’utiliser une structure avec SUM (case … ) pour gérer un compteur « à la main ». Dans l’exemple ci-dessous, vous pouvez voir qu’on compte le nombre d’éléments total avec count, et qu’on compte le nombre d’utisateurs ayant 3 connections en incrémentant un compteur nous même via SUM (case … ). Enfin, à la troisième ligne du select on calcule le pourcentage correspondant.

1
2
3
4
5
6
7
8
9
10
SELECT
    COUNT(u.id) AS total,
    SUM( CASE WHEN u.nb_connection > 3 THEN 1 ELSE 0 END) AS subset_count,
    SUM( CASE WHEN u.nb_connection > 3 THEN 1 ELSE 0 END)::FLOAT * 100/ COUNT(u.id)::FLOAT AS percentage,
    date_trunc ('months', u.created_at) AS considered_month
FROM
    users u

GROUP BY date_trunc ('months', u.created_at)
ORDER BY date_trunc ('months', u.created_at)

Dans la vraie vie, au lieu de stocker un entier correspondant au nombre de connections, on stockerait plutôt la date de connection dans une table séparée, mais c’est pour simplifier.

On obtient des résultats de ce genre :

total subset_count percentage considered_month
3956 334 8.44287158746208 « 2013-04-01 00:00:00 »
3965 343 8.65069356872636 « 2013-05-01 00:00:00 »
3549 628 17.6951253874331 « 2013-06-01 00:00:00 »
3728 456 12.2317596566524 « 2013-07-01 00:00:00 »
8311 1206 14.5108891830105 « 2013-08-01 00:00:00 »
6041 842 13.938089720245 « 2013-09-01 00:00:00 »
6381 818 12.8193073186021 « 2013-10-01 00:00:00 »
3784 800 21.1416490486258 « 2013-11-01 00:00:00 »

Il est à noter qu’avec PostgreSQL, on pourrait convertir directement le résultat de « u.nb_connection > 3 » entier pour faire la somme de manière plus concise, mais pas forcément plus simple à lire. De plus, l’exemple ci-dessus montre qu’on peut mettre plusieurs conditions (avec plusieurs « when » à l’intérieur du case), ce que la conversion d’un boolean ne montre pas forcément. Néanmoins, il est possible d’écrire la ligne qui suit :

1
2
3
4
SELECT
    COUNT(u.id) AS total,
    SUM( (u.nb_connection > 3)::INTEGER ) AS subset_count,
    ...

Bref, on a vu dans cet articles 2 structures pratiques pour extraire des chiffres à partir de votre base, en utilisant group by date_trunc et sum (case …). Ca a l’air de rien car les sommes et les moyennes sont des outils simples, mais ce sont également des outils très pratiques pour étudier l’évolution d’un business, ou anticiper les évolutions de structure à prévoir.

Bien que j’utilise git depuis un bon moment, j’ai longtemps été effrayé par l’usage de git stash, par peur de perdre du travail. A tort, car elle se révèle finalement très simple d’utilisation, et très pratique. Cette commande (to stash = réserver) permet de mettre de côté toutes les modifications en cours sans les commiter, pour pouvoir les reprendre plus tard.

Dans ma manière de travailler, c’est utile quand je travaille seul comme quand je travaille avec des collègues. Voici deux cas d’utilisation récents :

  • Je travaille sur une fonctionnalité avec un collègue. Il a besoin d’un correctif sur un bout de code que j’ai écrit avant pour pouvoir continuer à travailler. Je travaille sur une branche ‘feature’, et doit donc revenir sur la branche ‘dev’, dernière version stable de ma branche de développement, pour y apporter un correctif. Dans ma branche ‘feature’ actuelle, je suis en plein milieu d’un développement, je ne peux absolument pas lui fournir ce nouveau code à moitié terminé, ni faire un commit du code au milieu de son développement pour changer de branche. Je dois donc mettre le code sur lequel je travaille actuellement de côté, pour le reprendre par la suite.
  • Je travaille sur une fonctionnalité seul, en javascript par exemple. Lors de mon développement, je me rends compte qu’avant de pouvoir finir ce que j’ai commencé, je dois changer quelque chose ailleurs dans le code (sur la partie PHP qui va exposer une API par exemple). Comme j’aime avoir des commits unitaires et fonctionnellement séparés, je préfère avoir les modifications de l’API en PHP dans un commit, et celles du JS qui l’utilise ensuite. Comme j’ai déjà commencé à travailler sur le JS, je dois mettre mon code de côté.

Ce que j’ai longtemps fait dans ces situations, c’est de faire un commit temporaire. J’ajoutais mes fichiers modifiés, et je laissais un commentaire du type « temporary commit, edit later ». Plus tard, lorsque je revenais sur le code en question, et que le travail terminé, j’éditais mon commit via git commit –amend. Cette commande permet d’éditer le dernier commit en ajoutant/supprimer des fichiers, et en changeant le message de commit. Attention, c’est à utiliser avec soin si vous pushez/pullez du code souvent.

Plutôt que de committer du code temporaire (qui a finalement tendance à pourir l’historique avec des commits que j’oublie de nettoyer), la solution préconisée par git pour ce genre de choses, c’est git stash.

Cette commande permet de mettre de côté ses modifications pour les récupérer ultérieurement. Une fois exécutée, on peut ensuite changer de branche, faire ses modifications dans la nouvelle branche et revenir, ou bien faire ses modifications directement dans la branche où l’on a réservé les modifications, cela n’est pas un problème.

Avec un exemple d’utilisation, vous allez voir qu’il est très simple de s’en servir. Le point de départ : vous êtes en train de travailler, vous avez ajouté certains fichiers, modifiés d’autres… en vous devez mettre les modifications de côté. C’est parti, on stash.

1
2
3
git stash
Saved working directory and index state WIP on feature_branch: d9e2bb5 merged v5.3.4
HEAD is now at d9e2bb5 merged v5.3.4

Une fois que c’est fait, votre git status est vide.

1
2
3
4
5
6
[clem@clem:~/dev/currProject] git status -s
## feature_branch
# -> rien, les modifications se sont ajoutées à la pile de la réserve
[clem@clem:~/dev/currProject] git stash list
# Sur un écran à part, on peut voir que la pile
# de la réserve contient un élément: nos modifications

Vous changez de branche, faites ce que vous avez à faire, puis vient le moment où vous revenez sur la branche courante pour reprendre votre travail là où vous l’avez laissé. C’est le moment d’utiliser git stash pop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[clem@clem:~/dev/currProject] git stash pop
# On branch feature_branch
# You are currently rebasing branch 'bh' on 'fb7b1dc'.
#   (all conflicts fixed: run "git rebase --continue")
#
# You are currently bisecting branch 'bh'.
#   (use "git bisect reset" to get back to the original branch)
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   app/Berthe/ServiceXHR/ServiceXHRQuote.php
#   modified:   lib/Evaneos/Berthe/JsonServer.php
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (21f9583cd4159df5627307eada103e29fe165431)
[clem@clem:~/dev/currProject] git status -s
## feature_branch
 M app/Berthe/ServiceXHR/ServiceXHRQuote.php
 M lib/Evaneos/Berthe/JsonServer.php

Comme vous pouvez le voir sur les 2 commandes ci-dessus, git stash pop enlève les modifications de la pile, les met dans la branche courante, et supprime le sommet de la pile.

Le stash fonctionnant comme une pile, il peut arriver que l’on ne veuille pas récupérer ses modifications. Pour cela, on peut supprimer le dernier élément de la pile via git stash drop. Voici à quoi cela ressemble :

1
2
3
4
5
6
7
8
9
10
11
[clem@clem:~/dev/currProject] git stash
Saved working directory and index state WIP on feature_branch: d9e2bb5 merged v5.3.4
HEAD is now at d9e2bb5 merged v5.3.4
# Je sauvegarde les modifications
[clem@clem:~/dev/currProject] git stash drop
Dropped refs/stash@{0} (befd3f17f416548c30624a01118b609ebb1bc0a8)
# Je n'en ai plus besoin, je les supprime du stash.
[clem@clem:~/dev/currProject] git status -s
## feature_branch
# Ma branche courante est vide. Dans cet exemple, c'est comme
# si j'avais fait git reset HEAD --hard.

Et voila, non seulement c’est plus élégant que des commit temporaires, mais c’est aussi très simple d’utilisation.

La semaine dernière, j’ai réécrit pour Sublime Text 3 l’extension FormatSQL, qui me servait régulièrement dans la version 2, mais qui n’est plus compatible. L’objectif : prendre une chaine SQL mal formatée, et la formater de manière lisible. Le code final de mon petit plugin est sur Github.

J’ai eu étonnamment beaucoup de mal à comprendre comment démarrer. La plupart des bouts de code que j’ai trouvé sur les net, y compris sur le site officiel, ne fonctionnent que sous Sublime Text 2, et n’étaient pas compatibles.

Démarrer

Pour démarrer, c’est en fait très simple, encore faut-il le savoir : en cliquant sur Tools -> new Plugin, on obtient le code minimal d’un plugin, point de départ que je ne trouvais pas.

1
2
3
4
5
import sublime, sublime_plugin

class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")

C’est du python, ST3 embarque la version 3.3, d’où l’origine de conflits pour de nombreux packages, qui utilisent des librairies qui ne fonctionnent plus en python 3.3.

Exécuter le plugin

Quand on enregistre ce fichier, on est déjà positionné dans le bon répertoire (chez moi : ~/.config/sublime-text-3/Packages/User). On sauvegarde example.py, et sans redémarrer, on peut utiliser le nouveau plugin, de 2 manières :

Depuis la console :
on l’ouvre avec ctrl+`, et on tape view.run_command(‘example’). Le plugin s’exécute !
Depuis un nouveau binding :
On crée un nouveau raccourci, en allant dans Preferences -> Key bindings – User, où l’on ajoute :

1
{ "keys": ["ctrl+alt+f"], "command": "example" }

Maintenant, à chaque fois que l’on appuiera sur ctrl+alt+f, notre plugin s’executera.

Et maintenant, à vous de jouer !

Bon courage !