J'ai écrit une page web qui fait des calculs en JavaScript (il s'agit toujours d'animations de E8 mais peu importe), calculs que je voudrais faire exécuter hors du cadre d'un navigateur (en l'occurrence pour faire une nouvelle vidéo à mettre sur YouTube), si possible sans réécrire complètement le code en autre chose que JavaScript[#]. Bref, exporter les résultats de ces calculs, les sauvegarder dans un fichier (sous un format à peu près quelconque, typiquement un dump texte des résultats, que je saurai ensuite convertir assez facilement).
Je cherche donc la chose suivante : un environnement JavaScript « standalone », c'est-à-dire hors d'un navigateur (mais à la limite ce n'est pas bien grave si je dois lancer un navigateur) avec une simple fonction pour écrire un fichier (dans lequel je pourrai sauvegarder le résultat de mes calculs ; enfin, il me faudra ouvrir plusieurs fichiers différents parce que les résultats sont un peu longs, je voudrais faire un fichier par image d'une animation).
Pour résumer, je veux juste écrire du texte dans un fichier depuis JavaScript. Ça n'a pas l'air de demander beaucoup, n'est-ce pas ? C'est pourtant la porte d'entrée d'un labyrinthe cauchemardesque de presque-solutions toutes aussi décevantes les unes que les autres. Faisons un peu le tour.
- Firefox fournit une version standalone de son moteur
JavaScript SpiderMonkey, et une autre de son
moteur Rhino (et tous deux sont packagés par Debian),
sous les noms
smjs
etrhino
respectivement. Mais aucune API ne semble disponible pour ouvrir un fichier (il y a eu un truc dans ce sens, mais il fallait l'activer spécialement et de toute façon il est marqué commeobsolète
sans aucune indication de ce qui le remplace, merci bien). - Il y avait un projet appelé JSlibs, qui semblait faire exactement ce que je voulais (=fournir une interface JavaScript pour un certain nombre de bibliothèques usuelles), mais ce projet a l'air mort et a probablement bitroté. Inutile donc d'essayer de comprendre comment on est censé l'installer.
- Il y a un projet appelé CommonJS qui prétend définir un standard sur la manière d'appeler différentes bibliothèques depuis JavaScript, et qui a certainement ce que je veux. Mais bon, c'est un standard, pas une implémentation, donc ça ne m'aide pas tant que ça. Il prétend avoir un grand nombre d'implémentations, mais quand je regarde la plupart d'entre elles, soit je ne comprends rien, soit le projet est mort, soit il a l'air abominable à installer, soit la partie implémentée est juste un module particulier et pas celui qui permet d'ouvrir un fichier, bref, je ne vois rien qui me convienne. Sauf peut-être :
- Node.js, dont j'entends énormément parler, est un cadre général pour écrire des serveurs Web en JavaScript : ils ont forcément de quoi ouvrir un bête fichier et écrire du texte dedans. Mais d'après ce que je comprends çà et là, Node.js utilise un mécanisme d'entrées-sorties asynchrones, basées sur des événements, quelque chose de probablement approprié pour écrire un serveur Web, mais complètement inadapté pour simplement écrire du texte dans un fichier. Si je mets le doigt dedans, je vais sans doute souffrir.
- On me souffle qu'il est possible d'utiliser le moteur JavaScript V8 de Google depuis du code C++, et certainement de donner au code JavaScript de quoi communiquer avec le C++ pour y faire ce que je veux. Bon, mais C++ est le langage de programmation dont je ne connais rien du tout et dont je ne veux surtout rien connaître. Dommage.
- On me souffle aussi que mon problème serait très simple sous Windows. Bon, mais je n'ai pas accès à un Windows (sauf un vieux XP dans une machine virtuelle, je doute que ça convienne vraiment).
- Sinon, le projet Gnome est
réputé exporter toutes ses API (dont certainement ce
qu'il faut pour écrire un fichier…) sous une forme telle qu'elles
soient utilisables dans un grand nombre de langages de programmation.
Il y a même un cadre général pour faire ça de façon
automatisée : GObjectIntrospection.
Et il y a non pas un mais deux interpréteurs JavaScript
(subtilement différents et confusants) qui font plus ou moins partie
du projet Gnome : l'un
s'appelle
gjs
, l'autre s'appelle Seed. C'est très certainement ce que je veux : pour programmer des petites choses simples en JavaScript qui interagissent avec mon environnement graphique ou mon système d'exploitation, des bindings Gnome semblent idoines. Le problème est l'absence complète de documentation de l'utilisation des API dans le cadre de ces deux projets : je trouve vaguement un exemple utilisantgjs
(pour ouvrir une fenêtre), je trouve cette page de doc dont je ne sais même pas d'où elle sort, mais inexplicablement il n'y a aucune méthode contenant le motfile
(et si j'essaie d'utiliserGLib.io_channel_new_file()
comme il semble logique d'après l'API C, ça n'existe pas), les exemples Seed que je trouve ici semblent avoir essentiellement disparu, les traces que j'en retrouve néanmoins par exemple là ne marchent pas.
Bon, après des heures et des heures à naviguer à tâtons dans ce
labyrinthe, je crois avoir trouvé que ceci fonctionne avec Seed, pour
écrire foobar
dans le fichier monfichier
,
mais je ne comprends vraiment pas d'où vient cette API ni
comment j'étais censé la deviner : var Gio = imports.gi.Gio; var
file = Gio.file_new_for_path("monfichier"); var fstream =
file.replace(); var dstream = new Gio.DataOutputStream.c_new(fstream);
dstream.put_string("foobar"); fstream.close();
; l'ennui c'est
que je ne comprends rien à ce que je fais, je ne sais pas pourquoi ça
ne marche que sous Seed et pas sous gjs
alors qu'ils sont
censés utiliser la même API, je ne sais pas ce que c'est
que Gio et pourquoi il faut chercher imports.gi.Gio
alors
que cette
page précédemment citée évoque imports.gi.GLib
, bref,
je ne comprends rien à ce que je fais. Qu'est-ce que c'est que cette
fonction Gio.file_new_for_path
et quel est son rapport
avec ce
qui est ici,
ou ce
qui est là ? Je suis vraiment perdu dans un labyrinthe.
[Ajout : Sous gjs
, apparemment, il
faut faire : var Gio = imports.gi.Gio; var file =
Gio.file_new_for_path("monfichier"); var fstream = file.replace(null,
false, 0, null); var dstream = new Gio.DataOutputStream.new(fstream);
dstream.put_string("foobar", null); fstream.close(null);
; par
ailleurs, la raison de ma confusion sur les API est qu'il
existe à la fois
une API IOChannel
dans la GLib et aussi
une API GIO,
qui n'a rien à voir sauf qu'elle fait à peu près les mêmes choses de
façon gratuitement et stupidement différentes, juste pour emmerder le
programmeur. Et apparemment on ne peut pas utiliser les fonctions de
manipulation de fichiers de la GLib
depuis gjs
/Seed, ou en tout cas je n'ai pas réussi, par
exemple GLib.open()
n'existe pas alors que logiquement il
devrait. Tout ceci est incompréhensible.]
C'est un peu le problème des projets en logiciel libre où tout ce qui se fait un jour est rendu obsolète le jour suivant parce qu'ils ont décidé que ce n'était plus la bonne façon de faire, donc toutes les docs qu'on trouve sont obsolètes et on ne sait jamais ce qui a remplacé quoi. Quel chaos !
[#] Pas que JavaScript soit le langage le plus adapté du monde pour ce que j'ai à faire — loin de là — mais maintenant que le code est écrit, je n'ai pas envie de le réécrire complètement en Perl/Python/quidlibet.