Des DTD pour décrire et archiver les plugins

, par _Eric_, Committo, Ergo Sum

Un Plugin SPIP nécessite d’être décrit pour être mise en œuvre avec fiabilité et signalé comme disponible sur un site Web de dépôt. Jusqu’à présent, cette description était donnée pour chaque Plugin par un fichier nommé plugin.xml, leur concaténation fournissant l’essentiel du fichier archives.xml donnant la liste des Plugins disponibles sur le dépôt.

Malheureusement ces fichiers sont trop peu souvent conformes à XML. Leur spécification conduit à des fichiers inutilement verbeux et parfois erronés sans que SPIP s’en aperçoive toujours, faute d’utiliser plus à fond les possibilités de ce formalisme et de ses outils standards.

On propose ici deux DTD précisant les informations attendues dans les deux fichiers XML et permettant leur contrôle complet par simple application du validateur XML intégré à SPIP.
Afin d’assurer la compatibilité, le nouveau fichier se nommera paquet.xml et il aura priorité sur le fichier plugin.xml qui ne sera alors plus nécessaire.
En plus des DTD, on énoncera une interface de programmation résolvant certains problèmes récurrents, notamment celui de la traduction des présentations de Plugin auxquelles les traducteurs n’ont pas facilement accès.

Pour ceux qui ne sont pas familiers avec le formalisme des DTD, rappelons que la directive ELEMENT déclare le nom d’une balise et de quoi elle est composée (éventuellement de rien, avec le mot-clé EMPTY : seuls les attributs en justifient l’existence). La directive ATTLIST déclare les attributs de cette balise sous forme de trio nom, type, présence ; un attribut de type ID a une valeur ne pouvant être utilisée deux fois. La directive ENTITY déclare juste une abréviation (mais son nom est souvent porteur d’informations informelles). Pour plus de précisions se reporter à la
définition officielle de XML.

Le fichier de description d’un Plugin

Le fichier de description doit indiquer le nom du Plugin et donner des informations techniques sur sa mise en œuvre dans SPIP. Un même fichier peut décrire plusieurs mises en œuvre si différentes versions de SPIP exigent une interface différente (par exemple si la liste des points d’entrée a changé) ; en revanche un tel fichier ne décrit qu’une seule version d’un Plugin, un changement de version majeur devant entraîner la création d’une nouvelle branche sur le site de développement. Ce fichier sert également à la production d’une archive (ou paquet) sur un site de dépôt, avec un nom indiquant clairement un unique numéro de version pour ce Plugin.

Ce rôle de base suggère d’avoir une balise racine donnant les informations nécessaires à toutes les mises en œuvre, et ayant éventuellement plusieurs sous-balises indiquant dans un attribut une ou plusieurs versions de SPIP pour lesquelles certaines de ces informations sont remplacées par d’autres. Afin de faciliter la lecture de la DTD, on utilisera le mécanisme d’abréviation ENTITY pour faire clairement apparaître que ces informations portent le même nom, qu’elles soient employées au premier ou au deuxième niveau. Chacune de ces informations sont du texte brut, l’imbrication des balises est donc limité à 3 ce qui est heureux. Par ailleurs, il est préférable d’employer autant que possible des attributs afin d’avoir des balises auto-fermantes, plus concises à écrire. Enfin, on a encore utilisé le mécanisme ENTITY cette fois pour typer implicitement les attributs, qui pourront facilement être analysés par des RegExp appropriés.

Certaines informations présentes dans les fichiers de description actuels plugin.xml sont absentes dans la nouvelle description,
étant retrouvées grâce à une interface de programmation plus rigoureuse et plus fiable :

  • le nom du fichier devant être systématiquement chargé (actuelle balise options) : un nom mal choisi pouvant perturber le fonctionnement de SPIP (à travers sa fonction de recherche find_in_path) il a toujours été recommandé de placer ce fichier à la racine du répertoire du Plugin, sous le nom ${prefixe_du_plugin}_options. Nous proposons de rendre cette règle obligatoire, ce qui rend superflue sa description. Ce fichier pouvant contenir des directives importantes (définition de constantes générales etc), il est souvent nécessaire de le consulter pour vérifier qu’il est compatible avec d’autres usages, il est donc opportun qu’un utilisateur puisse accéder à son contenu rapidement, sans avoir à transiter par le fichier de description pour connaître son nom.
  • le nom du fichier devant être systématiquement chargé avant une compilation (actuelle balise fonctions) : les mêmes remarques s’appliquent sur ce fichier, nous proposons donc là aussi de convenir que ce fichier se nommera toujours ${prefixe_du_plugin}_fonctions à la racine du répertoire du Plugin.
  • le nom du fichier devant être systématiquement chargé à l’installation ou à la mise à jour : bien qu’aucune recommandation n’ait été émise sur ce fichier, les mêmes problèmes se posent et nous proposons donc là encore de nommer systématiquement ce fichier ${prefixe_du_plugin}_installations à la racine du répertoire du Plugin.
  • la description des fonctionnalités du Plugin : elle est donnée sous forme de textes en différentes langues repérées par la construction multi spécifique à SPIP. Malheureusement leur présence dans ce fichier les exclut du processus de demande de traduction. Nous proposons donc que ces textes migrent dans le répertoire lang du Plugin (plus précisément les fichiers de ce répertoire dont les noms sont formés du préfixe du Plugin suivi du nom de la langue), sous des appellations conventionnelles permettant de les retrouver automatiquement à la fabrication de la liste des Plugins disponibles. On profitera de l’occasion pour avoir deux chaînes de langues, l’une (${prefixe_du_plugin}_slogan) qualifiant brièvement le Plugin, l’autre (${prefixe_du_plugin}_description) donnant une description plus détaillée, notamment les nouveautés lors d’un changement de version. La présence de ces deux chaînes de langues dans un fichier de langue équivaut à la disponibilité du Plugin dans cette langue. Nous reviendrons sur ces textes à propos du fichier de dépôt, car ils posent encore d’autres problèmes.

Ces remarques nous conduisent à proposer la DTD ci-dessous pour décrire les fichiers paquet.xml. Les différences par rapport aux fichiers existants sont essentiellement les suivantes :

  • la balise paquet remplace la balise plugin. Les sous-balises de plugin qui ne devaient pas être répétées deviennent des attributs pour alléger l’écriture et typer cette information. Font exception nom et licence, car il s’agit de textes pouvant utiliser apostrophes et guillemets. Le nom et la licence ne sont pas destinés à être traduits. On remarquera que nom, licence et auteur (celle-ci en nombre quelconque) doivent apparaître dans cet ordre et avant toute autre sous-balise. La balise lien devient elle aussi un attribut bien qu’elle pouvait être répétée (sur les 801 fichiers plugin.xml examinés, seuls 5 utilisent cette possibilité) et sa valeur doit être une URL ou un raccourci SPIP à titre implicite [->raccourci] (sur les 801 fichiers, 52 utilisent ce raccourci autrement, et même 21 si on exclut les standards documentation, site etc ; nous reviendrons sur les 21 restants) ;
  • la balise necessite avait en fait plusieurs utilisations qui sont à présent réparties sur quatre balises distinctes :
    • la balise racine paquet dont l’attribut compatible indique la ou les versions de SPIP pour lesquelles s’appliquent les informations données par les sous-balises ;
    • la balise spip ayant le même attribut compatible et qui donne des informations ayant priorité sur les précédentes pour d’autres versions SPIP, cette hiérarchie éliminant toute répétition d’informations ;
    • la balise lib avec deux attributs nom et src pour utiliser une bibliothèque externe ;
    • et une balise necessite limitée à l’utilisation de Plugins et qui, ainsi que la balise utilise, voit son attribut id (contre-indiqué ici en XML) renommé en prefix (puisque c’est le préfixe du Plugin qu’il faut donner) ;
  • les balises bouton, onglet, pipeline, chemin conservent leur nom mais leurs sous-balises sont transformées en attributs, en harmonisant leur nom.
<!ENTITY % MAIL "CDATA"> <!-- adresse mail -->
<!ENTITY % NAME "CDATA"> <!-- identificateur (notamment nom de fonction) -->
<!ENTITY % ITEM "CDATA"> <!-- chaine de langue -->
<!ENTITY % NUMBER "CDATA"> <!-- nombre entier naturel -->
<!ENTITY % PATH "CDATA"> <!-- chemin d'acces a un fichier ou repertoire -->
<!ENTITY % QUERY_STRING "CDATA"> <!-- couples x=y separes par esperluete -->
<!ENTITY % URI "CDATA"> <!-- lien sur le Web -->
<!ENTITY % VNUM "CDATA"> <!-- 3 entiers naturels separes par un point: x.y.z -->
<!ENTITY % INTERVAL "CDATA"> <!-- 2 VNUM entre crochets ou parentheses -->

<!ENTITY % STATUS "(experimental|dev|test|stable)">

<!ENTITY % CATEGORY "(auteur|communication|date|divers|edition|maintenance|multimedia|navigation|outil|performance|squelette|statistique|theme)">

<!ENTITY % CONTENT "(bouton|chemin|credits|copyright|lib|necessite|onglet|pipeline|utilise)*" >

<!ELEMENT paquet nom licence? auteur* %CONTENT; spip* >
<!ATTLIST paquet
          categorie %CATEGORY; #REQUIRED
          compatible %INTERVAL; #IMPLIED
          etat %STATUS; #REQUIRED
          lien %URI;  #IMPLIED
          logo %PATH; #IMPLIED
          meta %NAME; #IMPLIED
          prefix ID #REQUIRED
          version %VNUM; #REQUIRED
          version_base %NUMBER; #IMPLIED
>

<!ELEMENT nom (#PCDATA)>
<!ELEMENT credits (#PCDATA)>
<!ELEMENT copyright (#PCDATA)>

<!ELEMENT licence (#PCDATA)>
<!ATTLIST licence
          src %URI; #IMPLIED
>

<!ELEMENT spip  %CONTENT; >
<!ATTLIST spip compatible %INTERVAL; #REQUIRED>

<!ELEMENT auteur (#PCDATA)>
<!ATTLIST auteur mail %MAIL; #IMPLIED>

<!ELEMENT chemin EMPTY>
<!ATTLIST chemin
          path %PATH; #REQUIRED
          type %NAME; #IMPLIED
>

<!ELEMENT lib EMPTY>
<!ATTLIST lib
          nom %NAME; #REQUIRED
          src %URI; #REQUIRED
>

<!ELEMENT necessite EMPTY>
<!ATTLIST necessite
          prefix %NAME; #REQUIRED
          version %VNUM; #REQUIRED
>

<!ELEMENT utilise EMPTY>
<!ATTLIST utilise
          prefix %NAME; #REQUIRED
          version %VNUM; #REQUIRED
>

<!ELEMENT pipeline EMPTY>
<!ATTLIST pipeline
          action %NAME; #IMPLIED
          nom %NAME; #REQUIRED
          path %PATH; #IMPLIED
>

<!ELEMENT bouton EMPTY>
<!ATTLIST bouton
          nom %NAME; #REQUIRED
          parent %NAME; #REQUIRED
          action %NAME;  #REQUIRED
          args %QUERY_STRING; #IMPLIED
          icone %PATH; #IMPLIED
          titre %ITEM; #REQUIRED
>

<!ELEMENT onglet EMPTY>
<!ATTLIST onglet
          nom %NAME; #REQUIRED
          parent %NAME; #REQUIRED
          action %NAME;  #REQUIRED
          args %QUERY_STRING; #IMPLIED
          icone %PATH; #IMPLIED
          titre %ITEM; #REQUIRED
>

Le fichier de description d’un dépôt

Ce fichier, nommé actuellement archives.xml(mais ce n’est pas une obligation) est une concaténation des fichiers de spécifications précédents indiqués par la liste des paquets,
auxquels des informations sont ajoutées par le script
smart-paquets. Ce fichier est exploité ensuite par les fonctions du squelette page-paquets du site
file.spip.org qui présente les paquets.

Suite aux modifications ci-dessus, il ne faut pas oublier de rajouter dans ce fichier les textes
que nous avons fait migrer dans les fichiers de langues, car ils sont attendus par les
squelettes du plugin SVP. Il est temps de reparler de ces textes, ainsi que du libellé présent dans de rares utilisations de l’actuelle balise lien. Leur rôle est de donner une description des fonctionnalités du Plugin, et non sa mise en œuvre, et ils apparaissent dans une liste générale des Plugins (tant sur la page d’administration de SPIP que sur le site de dépôt) ; il est donc ni nécessaire ni souhaitable que des balises HTML soient utilisées dans ces textes pour imposer des mises en pages forcément hétérogènes. Il n’est pas anodin de remarquer que leur présence poserait de plus des problèmes de validation du fichier XML selon sa DTD, car cela montre bien que l’on mélangerait les buts du balisage (informatif pour le fichier XML, typographique pour les textes). On peut néanmoins tolérer quelques effets de micro-typographie, dans le respect de la contrainte de validation, ce qui revient à accepter les raccourcis SPIP construits avec les accolades et les crochets (donc en particulier les raccourcis d’URL avec titre, à présent interdits dans l’attribut lien).

A l’examen des 801 fichiers plugin.xml, les textes effectuant de complètes mises en pages avec des balises HTML décrivent en fait la mise en œuvre de Plugin, description qui a plutôt sa place dans sa page de configuration. Depuis SPIP 2.1, cette page est automatiquement produite et proposée par SPIP s’il existe
un squelette prive/exec/configurer_${prefix}.html ou un script
exec/configurer_${prefix}.php dans le répertoire du Plugin, on pourra donc facilement mettre ces textes dans l’un de ces fichiers.

La DTD du fichier d’archive devant reprendre celle du fichier de description d’un Plugin, le plus simple est d’inclure celle-ci dans celle-là. Comme il faut rajouter des informations pour chaque Plugin et qu’il n’est dans ses conditions pas possible de modifier la balise paquet, on conserve la méthode actuelle
qui l’emboîte dans une balise archive non indispensable en théorie. Cette nouvelle balise aura comme attributs les valeurs décrivant physiquement le paquet (size, date, source, zip), et comme sous-balises slogan et description donnant les informations extraites des fichiers de langues. Ces deux balises auront un attribut lang indiquant la langue des textes ainsi insérés.

Enfin, la balise englobante archives, actuellement sans attributs, est à remplacer par la balise depot afin de distinguer les deux formats. Elle aura deux attributs src et type donnant l’adresse et le type du site recueillant le dépot, et une sous-balise
nom figurant avant la liste des archives.

L’attribut maj permet de collecter la date de la dernière mise à jour du plugin, soit sous SVN la date du dernier commit.

Voici donc cette DTD :

<!ENTITY % PAQUET_DTD SYSTEM
  "-//SPIP PAQUET//FR"
  "paquet.dtd">
%PAQUET_DTD;

<!ENTITY % TREPO "(svn|git|manuel)">
<!ENTITY % LANG "CDATA"> <!-- code de langue sur deux lettres -->

<!ELEMENT depot nom archive+ >
<!ATTLIST depot
          type %TREPO; #REQUIRED
          src %URI; #IMPLIED
>

<!ELEMENT nom (#PCDATA)>

<!ELEMENT archive slogan+ description* paquet>
<!ATTLIST archive
         date %NUMBER; #REQUIRED
         size %NUMBER; #REQUIRED
          source %PATH; #REQUIRED
         zip %PATH; #REQUIRED
         maj %NUMBER; #IMPLIED
>

<!ELEMENT slogan (#PCDATA)>
<!ATTLIST slogan
         lang %LANG; #IMPLIED
>

<!ELEMENT description (#PCDATA)>
<!ATTLIST description
         lang %LANG; #IMPLIED
>

L’ensemble de ces spécifications devrait permettre une meilleure visibilité des Plugins, et faciliter la mise au point de leur déclaration par un repérage d’erreurs plus fiable. Le développement d’outils de migration de plugin.xml vers paquet.xml est envisageable, toutefois les textes d’accompagnement devront inévitablement être révisés manuellement.

Dans le portfolio vous trouverez des exemples de fichiers paquet.xml.

P.-S.

Ces spécifications ont été implémentées par un Plugin de migration nommé
Plugonet désormais opérationnel. La DTD finalement utilisée tient compte des remarques exprimées dans le forum de discussion, et est disponible ici.