Construction de modules pour Dynacase

Dans cette page, je vais présenter les éléments constitutifs d'un module Dynacase et mettre en oeuvre ces éléments pour construire un module d'exemple qu'on nommera freedom-foo.

Pour bien suivre cette présentation, il est souhaitable d'avoir bien en tête les notions d'Applications et d'Actions de Dynacase et du fonctionnement général de ceux-ci.

[A détailler]

Présentation

Vous avez surement déjà manipulé des Applications et des Actions dans Dynacase…

[A détailler]

Dans les exemples ci-dessous, nous allons détailler la construction d'un module freedom-foo qui fournira une Application Dynacase nommé FOO, avec un ensemble d'actions associés.

Les fichiers nécessaires

Fichier ''FOO.app''

Fichier ''FOO_init.php''

Fichier ''info.xml''

Le fichier info.xml permet de décrire le module Dynacase en fournissant en particulier la version du module, une description, des dépendances avec d'autres modules Dynacase, un ensemble de paramètres, un descriptif des évolutions (changelog), et un ensemble d'action de pre-install, post-install, etc.

Exemple de fichier de info.xml

<?xml version="1.0"?>
<module name="freedom-foo" version="1.2.3" release="1" [basecomponent="no"]>
 
  <description lang="en">Freedom foo</description>
  [<description lang="fr">Freedom toto</description>]
 
  <requires>
    [<installer version="1.0.0" comp="ge" />]
    <module name="freedom-bar" />
    <module name="freedom-baz" version="1.0.0" comp="ge" />
    [...]
  </requires>
 
  <parameters>
    <param name="foo_dir" label="Directory of FOO" type="text"
      default="/var/foo" needed="yes" />
    <param name="foo_color" label="Color of FOO" type="enum"
      values="red|green|blue" default="green" needed="no" />
  </parameters>
 
  <changelog>
    <version number="1.1.1" date="2009-01-01">
      <change title='First change' url='http://dev.dynacase.org/issues/111'>
	Comment for first change.
      </change>
      <change title='Second change'>
	Comment for second change.
      </change>
      <change title='Third change'>
      </change>
    </version>
    <version number="1.1.0" date="2008-12-15"/>
  </changelog>
 
  <pre-install>
    <check type="syscommand" command="zip" />
    <check type="phpfunction" function="pg_connect">
      <help>You might need to install a php-pg package.</help>
    </check>
    <check type="file" file="/var/foo" predicate="is_dir" />
  </pre-install>
 
  <post-install>
    <process command="programs/app_post FOO I" />
    <process command="programs/record_application FOO" />
    <process command="programs/app_post FOO U" />
    <process command="programs/update_catalog" />
  </post-install>
 
  <post-upgrade>
    <process command="programs/pre_migration FOO" />
    <process command="programs/app_post FOO U" />
    <process command="programs/record_application FOO" />
    <process command="programs/post_migration FOO" />
    <process command="programs/update_catalog" />
  </post-upgrade>
 
  <post-param>
  </post-param>
 
</module>

Description d'un module

Préambule Module

La racine du document info.xml est un tag <module> avec les attributs suivants :

  • name : le nom du module
  • version : la version du module (sous la forme N.N.N)
  • release : le numéro de release de la version
  • basecomponent : yes ou no, permet de spécifier si le module est un module de base, obligatoire a toute installation de Dynacase (optionnel, par défaut la valeur est no)
  • author : l'auteur du module (ex. John Doe john.doe@example.net)(optionnel)
  • licence : licence du module (optionnel)
<?xml version="1.0"?>
<module name="freedom-foo" version="1.2.3" release="rc1"
  author="John Doe <john.doe@example.net>" licence="GPLV2">
  [...]
</module>

Description

Le module peut fournir une description textuelle pour expliciter le rôle du module. On pourra fournir des descriptions localisés en utilisant l'attribut lang.

Exemple :

  <description lang="fr">Ce module permet à Dynacase de se connecter à FOO</description>
  <description lang="en">This module allows Dynacase to connect to FOO</description>

Dépendances

Les dépendances permettent d'exprimer qu'un module requiert d'autres modules Dynacase avec eventuellement une contrainte sur la version de ceux-ci.

Le tag <requires> est composés d'éléments <module> qui ont les attributs suivants :

  • name : le nom du module Dynacase requis
  • version : la version que le module requis doit avoir
  • comp : gt ou ge, opérateur de comparaison de version

Le module peut aussi exprimer une contrainte sur la version de l'installeur lui même à l'aide de l'élément <installer>. Dans ce cas, les attributs sont :

  • version : la version de l'installeur que requiert le module
  • comp : gt ou ge, opérateur de comparaison de version

Exemple :

  <requires>
    <installer version="1.0" comp="ge" />
    <module name="freedom-bar" version="2.0" comp="ge" />
    <module name="freedom-baz" version="1.9" comp="gt" />
  <requires>

Dans cet exemple, le module requiert un installeur avec une version >= 1.0, le module freedom-bar en version >= 2.0 et le module freedom-baz en version > 1.9.

Changelog

Le changelog permet d'indiquer les évolutions produites en rapport avec les versions du module. Ces informations sont contenues dans une balise <changelog> contenant des <version>.

Les éléments <version> ont les attributs suivants :

  • number : le numero de version
  • date : la date de publication de la version

Les éléments <version> contiennent des éléments <change> qui décrivent chaque changement effectué. Les éléments <change> ont les attributs suivants :

  • title : l'intitulé du changement
  • url : une url en rapport avec le changement (dans l'interface dynacase-control, les chaines de forme issues/111/ sont reconnues et donnent comme texte du lien affiché 'issues 111' ; sinon un texte par défaut est utilisé)

La valeur de l'élément <change> constitue une description.

Exemple :

  <changelog>
    <version number="1.1.1" date="2009-01-01">
      <change title='First change' url='http://dev.dynacase.org/issues/111'>
	Comment for first change.
      </change>
      <change title='Second change'>
	Comment for second change.
      </change>
      <change title='Third change'>
      </change>
    </version>
    <version number="1.1.0" date="2008-12-15"/>
  </changelog>

Paramètres

Un module peut demander lors de son installation (ou upgrade) l'entrée de certains paramètres.

Les paramètres nécessaires au module sont renseignés avec un élément <parameters> contenant des éléments <param>.

Les élements <param> ont les attributs suivants :

  • name : le nom du paramètre
  • label : le label textuel pour présenter le paramètre
  • type : text ou enum, permet de spécifier le type de donnée attendu
  • default : la valeur par défaut présenté à l'utilisateur lors de la saisie des paramètres.
  • needed : yes ou no, permet de spécifier si la saisie du paramètre est obligatoire ou optionnelle.
  • values : lorsque type=“enum”, l'attribut values permet de spécifier une list de choix finis à partir de laquelle l'utilisateur selectionnera une valeur

Exemple :

  <parameters>
    <param name="foo_dir" label="Directory of FOO" type="text"
      default="/var/foo" needed="yes" />
    <param name="foo_color" label="Color of FOO" type="enum"
      values="red|green|blue" default="green" needed="no" />
  </parameters>

Pre/post install/upgrade/etc.

Lors de l'installation, upgrade ou suppression d'un module, un ensemble d'actions peuvent être effectués avant (pre) et après (post) l'opération suivant l'ordre suivant :

Chaque phase (pre-install, post-install, etc.) spécifie un ensemble de check ou process qui sont exécutés et qui retournent un status d'échec ou de réussite.

Une phase est validé lorsque tous ses sous-éléments check ou process ont retournés un statut de réussite.

Si une phase n'est pas validé, alors l'installation, ou l'upgrade, alors il est présenté à l'utilisateur les messages d'erreurs rencontrés, et celui-ci peut rejouer la phase après avoir eventuellement corrigé le problème, ou bien il peut choisir d'ignorer les messages d'erreurs et poursuivre l'install/ugprade.

pre-install

Les éléments de pre-install s'exécutent avant l'installation des fichiers du module sur le système de fichier.

Les actions possible peuvent être des éléments <check>.

Chaque élément <check> peut fournir un élément <help> qui sera présenté à l'utilisateur lorsque l'action échoue.

Exemple :

  <pre-install>
    <check type="phpfunction" function="pspell_new">
      <help>Il faut peut-être installer php5-pspell avec apspell et aspell-fr</help>
    </check>
    <check type="syscommand" command="convert" />
  </pre-install>

Les actions de pre-install serviront généralement à vérifier la présence de certains éléments et bloquer l'installation si ces éléments ne sont pas présents/corrects.

post-install

Les éléments de post-install s'exécutent après l'installation des fichiers du module sur le système de fichier.

Les actions possible peuvent être des éléments <process>.

Chaque élément <process> peut fournir un élément <label> qui sera présenté à l'utilisateur lorsque l'action sera exécuté.

Exemple :

  <post-install>
    <process command="programs/record_application FOO">
      <label lang="en">Record FOO application in database</label>
    </process>
    <process command="programs/update_catalog">
      <label lang="en">Generate localization catalog</label>
    </process>
  </post-install>

Les actions de post-install serviront généralement à configurer le module qui viens d'être isntallé. Une erreur dans la phase de post-install laissera les fichiers installés en place, mais le paquet sera marqué en erreur de post-install dans l'interface.

pre-upgrade

Les éléments de pre-upgrade s'exécutent avant l'installation des nouveaux fichiers du module sur le système de fichier.

Les actions possible peuvent être des éléments <check>.

Chaque élément <check> peut fournir un élément <help> qui sera présenté à l'utilisateur lorsque l'action échoue.

Exemple :

  <pre-upgrade>
    <check type="phpfunction" function="pspell_new">
      <help>Il faut peut-être installer php5-pspell avec apspell et aspell-fr</help>
    </check>
    <check type="syscommand" command="convert" />
  </pre-upgrade>

Les actions de pre-upgrade serviront généralement à vérifier la présence de certains éléments et bloquer l'upgrade si ces éléments ne sont pas présents/corrects.

post-upgrade

Les éléments de post-upgrade s'exécutent après l'installation des nouveaux fichiers du module sur le système de fichier.

Les actions possible peuvent être des éléments <process>.

Chaque élément <process> peut fournir un élément <label> qui sera présenté à l'utilisateur lorsque l'action sera exécuté.

Exemple :

  <post-upgrade>
    <process command="programs/pre_migration FOO">
      <label lang="en">Pre-migration scripts</label>
    </process>
    <process command="programs/record_application FOO">
      <label lang="en">Update application record in database</label>
    </process>
    <process command="programs/post_migration FOO">
      <label lang="en">Post-migration scripts</label>
    </process>
    <process command="programs/update_catalog">
      <label lang="en">Re-generate localization catalog</label>
    </process>
  </post-install>

Les actions de post-upgrade serviront généralement à configurer le module qui viens d'être isntallé, lancer les scripts de migration, etc. Une erreur dans la phase de post-upgrade laissera les fichiers installés en place, mais le paquet sera marqué en erreur de post-upgrade dans l'interface.

pre-remove

post-remove

Les checks

Les éléments check permettent d'executer des actions pour vérifier la présence de certains éléments.

phpfunction

Le check de type phpfunction permet de vérifier la présence d'une fonction PHP.

Le nom de la fonction testé est spécifié avec l'attribut function.

Exemple :

  <check type="phpfunction" function="pg_connect" />

syscommand

Le check de type syscommand permet de vérifier la présence d'une commande disponible sur le système.

Le nom de la command testé est spécifié avec l'attribut command

Exemple :

  <check type="syscommand" command="convert" />

phpclass

Le check de type phpclass permet de vérifier la présence d'une classe objet PHP.

Le nom de la classe PHP est fournis avec les attributs suivants :

  • include : le nom du fichier pour inclure la définition de la classe
  • class : le nom de la classe

Exemple :

  <check type="phpclass" include="Net/SMTP.php" class="Net_SMTP" />

apachemodule

LE check de type apachemodule permet de vérifier qu'un module Apache particulier est activé et chargé par celui-ci.

Le nom du module est spécifié par l'attribut module.

Exemple :

  <check type="apachemodule" module="mod_expires" />

Les process

Les éléments process servent à exécuter les actions permettant d'effectuer les opérations nécessaires au fonctionnement du module suite à son installation.

programs/app_post

Prototype :

  • programs/app_post <APPNAME> I|U

Utilisable dans les phases :

  • post-install
  • post-upgrade

Conditions d'utilisation :

  • Dans la phase post-install, le programme doit être exécuté avec le programme record_application
  • Dans la phase post-upgrade, le programme doit être exécuté après pre_migration et avant le programme record_application

Le programme app_post permet de lancer un script _post pour initialiser une application Dynacase.

Les arguments sont :

  • Le nom de l'application (le script exécuté sera alors <APPNAME>_post)
  • I | U : Le nom de la phase d'initialisation a exécuter (I pour install, U pour upgrade)

Exemple :

  <post-install>
    <process command="programs/post_app WEBDESK I" />
    [...]
  </post-install>
 
  <post-upgrade>
    [...]
    <process command="programs/post_app WEBDESK U" />
    [...]
  </post-upgrade>

programs/record_application

Prototype :

  • programs/record_application <APPNAME>

Utilisable dans les phases :

  • post-install
  • post-upgrade

Conditions d'utilisation :

  • Le programme doit être exécuté après le programme app_post

Le programme record_application est utilisé pour enregistrer, ou mettre à jour, la définition de l'application en base de données.

La ligne de commande est spécifié par l'attribut command.

record_application prend en argument le nom de l'application à enregistrer.

Exemple :

  <process command="programs/record_application FOO" />

programs/update_catalog

Prototype :

  • programs/update_catalog

Utilisable dans les phases :

  • post-install
  • post-upgrade

Conditions d'utilisation :

  • Le programme doit être exécuté à la fin de la phase

Le programme update_catalog est utilisé pour ré-générer le catalogue des messages de localisation.

Exemple :

  <process command="programs/update_catalog" />

programs/pre_migation

Prototype :

  • programs/pre_migration

Utilisable dans les phases :

  • post-upgrade

Conditions d'utilisation :

  • Le programme doit être exécuté au début de la phase, avant le programme app_post

Le programme pre_migration est utilisé pour exécuter les scripts de pre-migration d'un module lors de sa mise-à-jour.

Exemple :

  <process command="programs/pre_migration" />

programs/post_migation

Prototype :

  • programs/post_migration

Utilisable dans les phases :

  • post-upgrade

Conditions d'utilisation :

  • Le programme doit être exécuté après le programme record_application, et avant le update_catalog

Le programme post_migration est utilisé pour exécuter les scripts de post-migration d'un module lors de sa mise-à-jour.

Exemple :

  <process command="programs/post_migration" />

./wsh.php

Prototype :

  • ./wsh.php

Utilisable dans les phases :

  • post-install
  • post-upgrade

Conditions d'utilisation :

  • Le programme peut être utilisé à n'importe quel moment en fonction des besoins

Le programme ./wsh.php est utilisé pour exécuter des méthodes sur des classes documentaires et exécuter des API Dynacase.

Exemple :

  <process command="./wsh.php --api=freedom_refresh --method=postModify --famid=FOO" />

Programmes personnalisés

Vous avez la possibilité d'écrire vos propres programmes de post-install, post-upgrade, etc. afin d'effectuer des opérations spécifiques à votre module.

Ces programmes seront généralement développés soit en shell Bash soit en PHP. Ils seront disponible après la phase de décompression de votre paquet, dans le répertoire que vous aurez spécifié à l'empaquetage.

Le programme est exécuté dans le répertoire racine de l'installeur DYNACASE-CONTROL, et les variables d'environnement suivantes sont accessible depuis le script :

  • WIFF_ROOT : Le chemin du répertoire ou est installé DYNACASE-CONTROL (c'est donc aussi le répertoire courant ($CWD) dans lequel sera exécuté votre programmes)
  • WIFF_CONTEXT_ROOT : Le chemin du répertoire du contexte sur lequel est effectué l'opération.
  • WIFF_CONTEXT_NAME : Le nom du contexte sur lequel est effectué l'opération.

Ecrire un programme personnalisé en shell Bash

Exemple :

#!/bin/bash
 
set -e
 
# -- Récupérer la valeur du paramètre `foo_dir' spécifié par l'utilisateur
PARAM_FOO_DIR=`"$WIFF_ROOT"/wiff --getValue=foo_dir`
 
# -- Créer le répertoire s'il n'existe pas
if [ ! -d "$PARAM_FOO_DIR" ];
  mkdir "$PARAM_FOO_DIR"
fi
 
# -- Ajouter le nom de ce répertoire dans le fichier
# -- `foo_dir.list' dans le sous-répertoire de mon module `FOO'
echo "$PARAM_FOO_DIR" >> "$WIFF_CONTEXT_ROOT"/FOO/foo_dir.list

Ecrire un programme personnalisé en PHP

Note : Le programme PHP a aussi accès aux variables d'environnement, comme le script Bash, mais le chemin d'include doit être construit en fonction de vos besoins.

Exemple :

#!/usr/bin/env php
<?php
 
$WIFF_ROOT=getenv('WIFF_ROOT');
if( $WIFF_ROOT === false ) {
  print "WIFF_ROOT environment variable is not set!";
  exit( 1 );
}
 
$WIFF_CONTEXT_ROOT=getenv('WIFF_CONTEXT_ROOT');
if( $WIFF_CONTEXT_ROOT === false ) {
  print "WIFF_CONTEXT_ROOT environment variable is not set!";
  exit( 1 );
}
 
 
# -- Si je dois accéder aux fichier d'include de Dynacase
# -- j'ajoute les répertoire d'include de Dynacase
# -- dans mon include_path PHP
set_include_path( get_include_path().PATH_SEPARATOR."$WIFF_ROOT/include".PATH_SEPARATOR$WIFF_CONTEXT_ROOT );
 
set_include_path(join(PATH_SEPARATOR, array(
  get_include_path(),
  "$WIFF_ROOT/include",
  "$WIFF_CONTEXT_ROOT"
)));
 
# -- A présent, je peux inclure les librairies de l'installeur
require("lib/Lib.Cli.php");
# -- ... et les librairies Dynacase
require("WHAT/Lib.Common.php");
 
$param_foo_dir = wiff_getParamValue('foo_dir');
if( ! is_dir($param_foo_dir) ) {
  $ret = mkdir($param_foo_dir);
  if( $ret === false ) {
    print sprintf("Error: could not create directory '%s'!", $param_foo_dir);
    exit( 1 );
  }
}
 
?>
 
[A compléter]

Générer le fichier .webinst

Pour fabriquer votre fichier webinst il faut disposer d'un fichier configure.in d'un fichier Makefile.in comme ceux-ci.

Le configure.in

#   Autoconf script for libphp
#
#
AC_REVISION($Id: configure.in $)
dnl
dnl Process this file with autoconf to produce a configure script.
dnl
AC_PREREQ(2.13)
AC_INIT(./Makefile.in)
AC_SUBST(VERSION)
VERSION=`cat VERSION`
AC_SUBST(RELEASE)
RELEASE=`cat RELEASE`
AC_SUBST(PACKAGE)
PACKAGE=freedom-myapplication
AC_SUBST(APPNAME)
APPNAME=MYAPP

ac_default_prefix=/usr/share/what
AC_SUBST(PUBRULE)
PUBRULE=
AC_ARG_WITH(pubrule, [  --with-pubrule=dir	Path to PubRule], PUBRULE=$withval)
if test "x$PUBRULE" != "x"; then
  PUBRULEDIR=$PUBRULE
else
  if test "x$PUBRULEDIR" == "x"; then
     AC_CHECK_FILE($HOME/anakeen/devtools/PubRule, PUBRULEDIR=$HOME/anakeen/devtools/)
     if test "x$PUBRULEDIR" = "x"; then
          PUBRULEDIR=`pwd`
     fi
  fi
fi
AC_CHECK_FILE($PUBRULEDIR/PubRule, PUBRULE=$PUBRULEDIR)
if test "x$PUBRULE" = "x"; then
  AC_MSG_ERROR([Could not find PubRule])
fi
AC_MSG_NOTICE([PubRule located at $PUBRULE])



AC_OUTPUT(Makefile  info.xml )

Le Makefile :

# ============================================
# $Id: Makefile.in $
# ============================================
PACKAGE = @PACKAGE@
VERSION = @VERSION@
RELEASE = @RELEASE@
utildir=@PUBRULE@
pubdir = @prefix@
appname = offline
srcdir = @srcdir@
SUBDIR= Action

TOP_MODULES =

TAR = gtar
GZIP_ENV = --best

export targetdir PACKAGE

pages_not_xml = info.xml

include $(utildir)/PubRule

DISTFILES += $(SUBDIR) \
            RELEASE VERSION 

le makefile inclut le fichier Pubrule. Il contient un ensemble de règles pour publier le code et fabriquer les paquets.

Vous devez inclure ce fichier dans le répertoire de vos sources. Ensuite vous tapez :

autoconf
./configure
make webinst

cela va générer le fichier webinst correspondant à votre module.

freedom_3/install/dev/addmodule.txt · Dernière modification: 06/07/2011 10:55 par charles