Vous cherchez à publier les mises à jour de votre application de façon transparente et automatisée. Dans cet article, nous analyserons plusieurs méthodes et nous répondrons aux questions que vous pouvez éventuellement vous poser sur la méthode choisie. Commentez

- Titre : Gestionnaire de mises à jour

- Auteurs : Neckara, Laurent Alexandre, Thibaut Cuvelier, Claude Leloup, Jacques THERY

- Parution : 9 juin 2012

- Mise à jour : 16 avril 2013

- Public visé :

- Licence : Copyright © 2013 Neckara. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

Sommaire

- I. Introduction

- II. Différentes méthodes possibles

- II-A. Désinstallation puis installation

- II-B. Un exécutable pour chaque MàJ

- II-C. Archive contenant tous les éléments

- II-D. Méthode Diff et Patch

- II-E. Détermination des ''modifications'' côté client

- II-F. Mises à jour successives

- II-G. Mise à jour unique

- II-H. Résumé des méthodes

- III. Réalisation : astuces, questions et réponses

- III-A. Fonctionnalités

- III-A-1. Comment faire une installation ?

- III-A-2. Comment faire une désinstallation ?

- III-A-2-a. Méthode bourrin

- III-A-2-b. Méthode prudente

- III-A-3. Comment mettre à jour le gestionnaire de mise à jour ?

- III-A-3-a. Le problème

- III-A-3-b. La solution

- III-A-4. Comment permettre l'abandon d'une mise à jour en cours d'exécution ?

- III-A-5. Comment afficher des news ?

- III-B. Fichiers

- III-B-1. Comment garantir l'intégrité des autres fichiers de l'utilisateur ?

- III-B-2. Comment gérer la modification des fichiers par l'utilisateur ?

- III-B-3. Quand vérifier la présence des fichiers ?

- III-B-4. Comment déterminer la version du client ?

- III-B-5. Gérer différentes versions des fichiers

- III-C. Serveur

- III-C-1. Quel serveur choisir ?

- III-C-2. Comment réduire les flux ?

- III-C-3. Comment enregistrer le contenu des différentes versions sur le serveur ?

- III-C-3-a. Problématique

- III-C-3-b. Informations nécessaires

- III-C-3-c. Table BDD

- III-C-4. Quelles instructions le gestionnaire de mise à jour doit-il reconnaître ?

- III-C-5. Comment déterminer ces instructions ?

- III-C-6. Comment administrer les versions ?

- III-D. Proposition de fonctionnement du gestionnaire

- IV. Conclusion

- V. Remerciements

I - Introduction

Un gestionnaire de mises à jour sert, comme son nom l'indique, à la mise à jour d'un logiciel. Parfois, il peut remplir d'autres fonctions importantes comme l'installation ou la désinstallation du logiciel mais aussi des tâches plus secondaires comme l'affichage de news.

Nous allons donc nous pencher sur différentes méthodes possibles.
Il n'existe pas de « meilleure méthode », il est important de choisir une méthode en fonction des objectifs et des contraintes.

Dans un second temps, je choisirai arbitrairement une méthode afin de pouvoir l'approfondir.
Mais les explications présentées seront aussi valables pour les autres méthodes.

Dans le but de rester succinct et généraliste, je ne proposerai que des codes SQL ainsi que l'accès au code source de la méthode choisie.

Dans la suite de ce tutoriel, « mise à jour » sera abrégée en « MàJ ».

II - Différentes méthodes possibles

La mise à jour permet à l'utilisateur d'obtenir la dernière version du logiciel lorsqu'il possède une version antérieure. Il existe plusieurs méthodes de mises à jour, je vais donc vous en présenter quelques-unes. D'autres méthodes sont sûrement envisageables, mais nous ne les aborderons pas ici.

II-A - Désinstallation puis installation

Une désinstallation suivie d'une installation est certainement la méthode la plus simple.

Pour peu que vous utilisiez un programme spécifique pour l'installation (setup.exe) et un programme spécifique pour la désinstallation (uninstall.exe) votre gestionnaire de MàJ ne sera composé que d'un appel à uninstall.exe suivi d'un téléchargement de ressources (si le setup.exe ne le fait pas lui-même) et enfin d'un appel à setup.exe.

Mais il est inutile et coûteux de supprimer et de retélécharger les fichiers qui n'auraient pas été modifiés. Imaginez que votre projet soit assez volumineux (plus de 600 Mo) et que la mise à jour ne porte que sur un petit fichier de quatre ko…

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-B - Un exécutable pour chaque MàJ

Une autre méthode consiste à faire télécharger par le client un exécutable spécifique à chaque MàJ qui se chargera d'actualiser le logiciel. Le rôle du gestionnaire de mises à jour sera donc de télécharger cet exécutable puis de l'exécuter.

Les ressources nécessaires pourront soit être téléchargées par le gestionnaire de mises à jour en même temps que l'exécutable, soit être téléchargées par celui-ci.
Rien n'empêche de télécharger certaines ressources par la première méthode et les autres par la seconde.

Souvent quelle que soit la version, on téléchargera le même exécutable, ce sera donc à lui, en fonction de la version du client d'exécuter la séquence d'instructions correspondantes.

Pour plus d'efficacité, on peut faire télécharger le même exécutable pour un « groupe de versions » voire pour chacune des versions.

Nous pouvons remarquer que les exécutables téléchargés pour les différentes MàJ contiendront tous une base commune et qu'à chaque MàJ, nous retéléchargerons cette base.

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

La MàJ hors ligne est possible mais elle est incompatible avec une bonne flexibilité face aux modifications apportées par l'utilisateur.

II-C - Archive contenant tous les éléments

L'un des problèmes de la méthode précédente est le téléchargement d'un exécutable très similaire d'une mise à jour sur l'autre.

Nous pouvons donc intégrer au gestionnaire de mises à jour la base commune à tous ces exécutables et remplacer l'exécutable par un simple fichier contenant toutes les instructions à effectuer. Le gestionnaire devra donc interpréter les instructions (principalement : déplacements et suppressions) et les exécuter.

Le téléchargement ne pourra donc plus se faire via l'exécutable, les ressources seront donc téléchargées en même temps que le fichier contenant les instructions.

Afin de limiter le travail du serveur, on peut préparer des archives, afin de limiter le nombre d'archives, nous pouvons aussi ne faire qu'une archive pour un groupe de versions.

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-D - Méthode Diff et Patch

Cette méthode utilise très peu de bande passante.
Au lieu de remplacer entièrement un fichier lorsqu'une modification a été faite sur celui-ci, on va regarder les octets qui ont changé entre deux fichiers de versions (commande diff sous Linux).

Le client va donc télécharger le fichier produit puis ne va changer que les octets qui ont été modifiés (commande patch sous Linux).

En cas de modification du fichier par l'utilisateur, la mise à jour ne sera pas correcte.
Il est possible de comparer le fichier du client au fichier attendu (avec un hash par exemple).
Et dans le cas où il aurait été modifié, il faudra soit recomparer les deux fichiers, soit retélécharger l'original.

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-E - Détermination des ''modifications'' côté client

Cette méthode consiste à envoyer toutes les informations nécessaires sur la nouvelle MàJ au client. C'est-à-dire envoyer au minimum l'arborescence, les liens de téléchargement des fichiers ainsi qu'un moyen de comparer les versions des fichiers :

- comparer les contenus des fichiers : on doit alors télécharger la dernière version du fichier, à ce niveau-là, la méthode d'installation-désinstallation est tout aussi efficace ;

- comparer les hash des différents fichiers ce qui permet une bonne flexibilité ;

- avoir côté client un fichier contenant la version de chaque fichier. Mais il ne correspondra pas forcément à la réalité car à chaque modification ou suppression de fichier du logiciel par l'utilisateur, il ne sera pas mis à jour.

Le gestionnaire de MàJ devra donc, en fonction des fichiers présents du côté du client déterminer toutes les instructions ainsi que les fichiers à télécharger pour effectuer la mise à jour.

L'un des avantages de cette méthode est de pouvoir mettre à jour des versions non officielles (non reconnues par le serveur).

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-F - Mises à jour successives

Cette méthode est très utile si on souhaite conserver toutes (ou certaines) les (des) versions du logiciel.

On considère qu'on ne sait que passer de la version X à la version X+1, on va donc enchaîner les mises à jour jusqu'à ce qu'on atteigne la dernière version.

N.B. On peut aussi faire des mises à jour par paliers, c'est-à-dire que pour chaque version on sait comment obtenir une version palier plus récente. Et à partir de cette version palier, on peut obtenir une autre version palier encore plus récente jusqu'à obtenir la dernière version.

Mais si un fichier a été modifié cinq fois entre la dernière version et la version X, il faudra le télécharger cinq fois. Si on souhaite conserver toutes les versions du logiciel, il faudra gérer différentes versions côté serveur afin de pouvoir télécharger d'anciennes versions de fichiers.

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-G - Mise à jour unique

Le client envoie sa version (X) au serveur qui lui retourne une liste d'instructions permettant de passer de la version X à la version Y.

Le gestionnaire va donc exécuter ces instructions et va télécharger uniquement les fichiers dont il a besoin, soit un par un, soit en demandant au serveur de préparer une archive avec tous les fichiers nécessaires.

Dans cette méthode, il est nécessaire de pouvoir déterminer à chaque version, les instructions exactes à effectuer. Bien sûr, il ne faudra pas écrire toutes ces instructions à la main, nous allons donc devoir essayer d'automatiser la génération des instructions nécessaires.

Grâce à cette méthode, il sera donc possible de revenir à une version antérieure très facilement soit par souhait du développeur soit par souhait du client (nécessite alors une gestion des versions des fichiers côté serveur).

C'est la méthode qu'on détaillera par la suite.

Simplicité

Flexibilité

Flux

Temps

MàJ hors ligne

II-H - Résumé des méthodes

désinstallation-installation

exécutable

Archive

Diff & Patch

Détermination
côté client

MàJ
successives

MàJ unique

Simplicité

Flexibilité

Flux

Temps

MàJ
hors ligne

Ce tableau a pour but d'essayer de récapituler les points forts et les points faibles de chaque méthode, mais il convient de choisir une méthode selon vos propres besoins, limitations et objectifs.

III - Réalisation : astuces, questions et réponses

Nous allons donc nous pencher sur la dernière méthode (détermination des instructions côté serveur et choix des téléchargements côté client) et surtout sur les difficultés que vous pourriez rencontrer.

III-A - Fonctionnalités

III-A-1 - Comment faire une installation ?

L'installation permet à l'utilisateur d'installer la dernière version de votre logiciel. En effet, il est inutile d'installer une version antérieure pour ensuite devoir effectuer une MàJ.

L'installation peut être gérée par un programme spécifique (souvent setup.exe).

Dans ce cas-là, on peut soit demander à l'utilisateur de lancer lui-même ce programme, soit d'offrir la possibilité à l'utilisateur d'installer le logiciel via le gestionnaire de MàJ qui lancera lui-même l'installateur.

Trois méthodes s'offrent alors à vous :

- soit vous intégrez toutes les ressources dans le setup ce qui permettra une installation hors ligne mais en contrepartie, le setup.exe sera lourd et vous n'installerez pas forcément le dernier logiciel ;

- soit le setup va rechercher les ressources sur Internet, nous serons alors sûrs d'obtenir la dernière version du logiciel, le setup sera plus léger mais vous ne pourrez pas faire d'installation hors ligne ;

- soit vous faites un mixte des deux, en mettant tout ou partie des ressources dans le setup puis en téléchargeant les ressources manquantes tout en mettant à jour certains fichiers (la méthode diff et patch est très appropriée dans cette situation). Dans ce cas-là, on préférera souvent mettre dans le setup les fichiers stables ainsi que les fichiers indispensables à l'utilisation hors ligne du logiciel et on téléchargera les fichiers instables ou non indispensables au fonctionnement hors ligne du logiciel.

Mais l'installation peut aussi se faire directement par le gestionnaire, une installation peut alors être considérée comme une mise à jour d'une version 0 (version vide) à la version actuelle.

III-A-2 - Comment faire une désinstallation ?

La désinstallation permet à l'utilisateur de supprimer toute trace de votre logiciel.
L'utilisateur peut être amené à y recourir s'il n'est pas satisfait de votre création, s'il n'en a plus l'utilité ou s'il ne compte plus utiliser ce logiciel sur un ordinateur particulier.

III-A-2-a - Méthode bourrin

La première méthode consiste à supprimer tout le contenu du répertoire contenant le logiciel, ce que je déconseille fortement.

On ne sait jamais où l'utilisateur va installer votre logiciel ni même ce qu'il va mettre dans ce dossier.

Petite anecdote personnelle : j'ai installé un programme de création de jeux sur mon bureau pour voir les ressources. N'ayant pas obtenu ce que je voulais, je l'ai désinstallé et tous les fichiers de mon bureau ont alors été supprimés.

III-A-2-b - Méthode prudente

Je vous conseille donc une désinstallation intelligente, en connaissant la version du client, on connaît les fichiers à supprimer ainsi que leur localisation.

Si on réfléchit bien, c'est comme passer de la version X du client à la version 0 (vide), une sorte de « mise à jour à l'envers ».

Comme les fichiers à supprimer sont connus même en hors ligne, on va utiliser un fichier qui contiendra les instructions pour la désinstallation ce qui permettra de désinstaller sans être forcément connecté à internet.

III-A-3 - Comment mettre à jour le gestionnaire de mise à jour ?

III-A-3-a - Le problème

C'est un peu ironique, mais le gestionnaire, tout comme votre logiciel pourra faire l'objet de modifications.
On ne peut pas demander à l'utilisateur de réinstaller à chaque mise à jour du gestionnaire.

Il faudrait donc créer un gestionnaire de MàJ pour le gestionnaire de MàJ. Mais ce nouveau gestionnaire de MàJ qui mettra à jour le gestionnaire de MàJ sera lui aussi soumis à des mises à jour, il faudrait donc un gestionnaire de MàJ pour le gestionnaire de MàJ qui met à jour le gestionnaire de MàJ, c'est une chaîne sans fin.

Il faut donc que le gestionnaire de MàJ se mette lui-même à jour, c'est le même principe que la mise à jour du logiciel à la différence près que très souvent, on ne peut pas supprimer, remplacer ou déplacer un fichier en cours d'utilisation. Alors comment mettre à jour l'image de fond du gestionnaire de MàJ ou même l'exécutable du gestionnaire de MàJ lui-même ?

III-A-3-b - La solution

Nous pouvons déjà télécharger les nouveaux éléments et rajouter '_bis' à leur extension ou les enregistrer dans un dossier temporaire comme /tmp (Linux) ou C:\Windows\Temp\ (Windows), nous pouvons même créer notre propre dossier temporaire qu'on supprimera une fois que tous les remplacements auront été effectués.

Après, il faut remplacer les fichiers normaux par les fichiers _bis, mais ce ne sont pas les seules actions à effectuer.

Pour réaliser ces actions, on va fermer le gestionnaire et juste avant sa fermeture, on fait appel à un petit programme (on le nommera P). Comme le gestionnaire est fermé, il est donc à nouveau possible d'effectuer des actions sur les fichiers du gestionnaire, c'est donc P qui se chargera du reste.

Pour que P sache ce qu'il faut faire, on lui transmettra toutes les instructions à son lancement par arguments.

il faut bien s'assurer que le gestionnaire se soit fermé avant de commencer à traiter les instructions. Une simple attente d'une seconde avant de commencer les traitements semble suffisante pour cela. On pourrait proposer de lancer à chaque fois le gestionnaire de mises à jour via P qui attendrait que le gestionnaire ait fini de s'exécuter pour effectuer les instructions qu'il pourrait recevoir via un tube ou un fichier écrit par le gestionnaire... Mais de ce cas-là, il sera impossible de mettre à jour P !

III-A-4 - Comment permettre l'abandon d'une mise à jour en cours d'exécution ?

Pour permettre l'abandon d'une MàJ en cours d'exécution, il nous faut deux threads : l'un pour la lecture des événements clavier et l'un pour la MàJ.

Mais en cas d'arrêt de la MàJ, nous aurons une version « hybride » une version qui sera entre la version du client (X) et la version actuelle (Y) et qui ne sera ni X, ni Y.

Il faut donc s'assurer qu'au prochain redémarrage du gestionnaire, que la MàJ se poursuive ou au pire, que la MàJ permette l'acquisition d'une version Y complète.

Lorsque la MàJ est interrompue par l'utilisateur (ou par un événement externe), nous pouvons toujours enregistrer le numéro de version X, le numéro de version Y ainsi que le n° de la dernière instruction traitée afin de reprendre la MàJ où elle s'était arrêtée. Mais le plus important est de faire en sorte de modifier le numéro de version du client telle qu'elle est perçue par le gestionnaire uniquement à la toute fin de la mise à jour.

Ordinogramme représentant une MàJ : afin d'éviter d'interrompre brutalement la MàJ (ce qui laissera l'arborescence des fichiers dans un état indéterminé) on attendra la fin de chaque instruction pour traiter l'abandon de la MàJ

III-A-5 - Comment afficher des news ?

Souvent, les gestionnaires de MàJ de jeux affichent des news.

On peut intégrer un navigateur internet ouvrant une page spécifique dans un cadre du gestionnaire mais l'intégration d'un navigateur internet est très lourde, on préférera donc très souvent télécharger des fichiers dédiés aux news et à leur affichage (format XML, TXT…).

On peut aussi télécharger une ou plusieurs images qu'on affichera ensuite directement.

III-B - Fichiers

III-B-1 - Comment garantir l'intégrité des autres fichiers de l'utilisateur ?

Le gestionnaire peut supprimer/regarder/modifier n'importe quels fichiers sur le disque du client.
Pour éviter cela, avant chaque action, on regardera si le chemin ne contient pas './' et qu'il ne commence ni par '/', ni par '~' (ni par ''?:\'' pour Windows) pour éviter qu'on puisse toucher aux fichiers qui ne seraient pas dans le dossier du logiciel.

III-B-2 - Comment gérer la modification des fichiers par l'utilisateur ?

Il peut arriver que l'utilisateur supprime ou modifie des fichiers.

Pour résoudre le problème des fichiers supprimés, il faudra, pendant la mise à jour, voire à chaque exécution du gestionnaire, vérifier que tous les fichiers nécessaires existent.

Le problème des fichiers modifiés est un peu plus complexe.

On peut tester chaque fichier et remplacer ceux qui ont été modifiés, mais comment savoir si le client souhaite ou non que sa modification soit annulée ?
On peut décider que le client n'a pas à modifier ces fichiers (éventuellement à l'exception de certains fichiers).

Mais il faut bien être conscient que le gestionnaire ne peut vous garantir que les fichiers seront intacts lors de leur utilisation. Pour cela, il vous faudra lancer un logiciel qui vérifiera l'état de vos fichiers en même temps que s'exécutera votre programme.

Nous pouvons aussi considérer que les modifications ne posent pas de problème et que l'utilisateur est responsable de ses actes. Si la modification pose problème, on laissera l'utilisateur supprimer le fichier afin qu'il puisse être retéléchargé au prochain lancement du gestionnaire.

III-B-3 - Quand vérifier la présence des fichiers ?

Afin de résoudre le problème lié à la suppression des fichiers par l'utilisateur, il faut vérifier la présence de ces fichiers. Tant qu'il n'y a pas de MàJ, on ne se pose pas vraiment la question, mais dans le cas contraire, quand faut-il faire cette vérification ?

- Avant la MàJ ? Mais dans ce cas-là, on risque de rétablir des fichiers qui seront supprimés pendant la MàJ.

- Après la MàJ ? On va devoir alors vérifier la présence de tous les fichiers, même ceux qui viennent juste d'être téléchargés. De plus, la suppression d'un dossier risque de poser problème, en effet, certaines opérations comme l'ajout de fichiers dans ces dossiers risquent d'être compromises.

La meilleure solution est d'intégrer les vérifications à la MàJ, on vérifiera donc la présence de tous les fichiers inchangés ainsi que d'autres fichiers dont l'absence pourrait poser problème lors de la MàJ. On préférera donc vérifier la présence d'un fichier juste avant sa première utilisation par le gestionnaire.

Lorsqu'aucune MàJ ne sera disponible nous ferons donc une « miniMàJ » dans le but de restaurer tous les fichiers supprimés.

III-B-4 - Comment déterminer la version du client ?

Nous avons vu que nous avons besoin de connaître la version du client pour effectuer une MàJ, mais comment connaître la version X du client ?

On peut décider de stocker la version du client dans votre logiciel, on récupérerait alors la version en l'appelant avec un argument spécial et il nous écrira la version sur sa sortie standard. Il est ainsi plus difficile de changer artificiellement la version perçue par le gestionnaire mais ceci implique de devoir mettre à jour l'exécutable à chaque MàJ. Ceci peut devenir très lourd surtout si la MàJ ne touche que des petits fichiers et que l'exécutable est assez volumineux.

Il est aussi possible d'enregistrer la version du client dans un fichier. Mais si l'utilisateur supprime ce fichier, on considérera qu'il possède une version 0, il provoquera donc une réinstallation du logiciel. Mais s'il écrit dedans, il risquera d'avoir des fichiers non mis à jour.

On peut aussi mettre la version dans le nom de l'exécutable (ex. : mon_programme_v0.15.exe) mais ceci nécessitera de mettre tous les raccourcis vers cet exécutable à jour. Or si l'utilisateur a créé ses propres raccourcis, il sera forcé de les modifier un à un.

Certaines personnes vont essayer de déterminer la version du client grâce au poids des fichiers et de leurs dates de création. Bien que cette méthode marche assez souvent, elle n'est pas très fiable (on ne sait jamais ce que l'utilisateur va faire) et est plus lente que d'autres méthodes plus simples.

Dans le cas du stockage de la version dans un fichier, l'utilisateur modifie la ''perception'' de la version du client par le gestionnaire en toute conscience, on le juge donc responsable de ses actes sur un tel fichier. Tandis qu'avec la méthode précédente, si l'utilisateur effectue une modification quelconque, il ne sera pas conscient de modifier la version perçue.

On utilisera de préférence la version du fichier

III-B-5 - Gérer différentes versions des fichiers

Dans certains cas, il est nécessaire de conserver plusieurs versions des fichiers voire du logiciel, pour permettre à l'utilisateur de continuer à utiliser une ancienne version de votre logiciel si jamais la nouvelle version ne fonctionne pas chez lui.

On peut alors soit conserver toutes les versions côté client ou conserver des versions spécifiques (toutes les X.0 versions par exemple), dans ce cas-là, il faudra mettre en place côté serveur une gestion des différentes versions des fichiers.

On peut aussi décider de conserver uniquement les versions que l'utilisateur a utilisées et dans ce cas-là, il est inutile de conserver d'anciennes versions des fichiers côté serveur.

Mais dans les deux cas, il faudra, côté client, conserver différentes versions d'un même fichier.

Pour ceci un simple dossier portant le nom de la version et contenant tous les fichiers ayant été modifiés ou ajoutés par cette version. C'est-à-dire qu'une version d'un fichier (à ne pas confondre avec la version du logiciel) ne sera stockée qu'une seule fois dans le dossier de la version où il est apparu pour la première fois. L'exécutable de la version X va donc rechercher dans le dossier X les éléments nécessaires et s'il ne les trouve pas, il ira rechercher dans une version antérieure, jusqu'à les trouver.

III-C - Serveur

Il faut que le gestionnaire puisse aller rechercher sur internet les informations et les fichiers qui lui sont nécessaires pour cela un serveur est nécessaire.

III-C-1 - Quel serveur choisir ?

Un simple serveur Web suffit, il faudra juste une interface en PHP ainsi qu'une base de données, ce qui reste relativement assez facile à trouver gratuitement.
Dans ce cas-là, on utilisera l'interface PHP pour administrer nos versions et le gestionnaire lira une page Web qui transmettra les instructions à effectuer. Il ne faut en aucun cas que ce soit le gestionnaire qui se connecte directement à la BDD à moins de créer et d'utiliser un compte « public » où seule la lecture est autorisée.
La page PHP peut déterminer elle-même les instructions à effectuer lors de la MàJ, mais on peut aussi décider qu'à chaque nouvelle MàJ, on détermine puis on enregistre toutes les séquences d'instructions pour chaque version. La page PHP devra alors juste afficher le contenu du fichier approprié.

Il est aussi possible d'utiliser un serveur dédié, on s'orientera alors souvent vers un programme côté serveur en C ou C++ voire en Java ce qui permettra d'être plus rapide.
Il y a alors deux solutions, soit on établit des sockets, soit on utilise des fichiers cgi.

Héberger les données en P2P semble plutôt intéressant car ceci permet de décharger son serveur de multiples téléchargements ainsi qu'aux utilisateurs de télécharger plus rapidement nos fichiers.

Il existe trois réseaux en P2P :

- centralisé : un serveur unique, il ne représente donc aucun intérêt ici ;

- distribué : chaque utilisateur donne de sa bande passante et joue le rôle de serveur mais il faut que chaque utilisateur de votre logiciel accepte de donner une partie de sa bande passante. De plus nous sommes en plus confrontés à des problèmes de sécurité surtout si vous distribuez votre logiciel en open source. En effet, rien n'empêchera un utilisateur de distribuer une version corrompue de votre logiciel. Les autres utilisateurs l'installeront automatiquement en mettant à jour leurs versions sans se douter de rien.

- hybride : il y a plusieurs serveurs et un utilisateur peut devenir serveur s'il le souhaite et sous certaines conditions. Mais ce système n'est pas simple à mettre en place et ne résout pas les problèmes de versions corrompues.

En conclusion, le P2P est une ''fausse bonne idée'' car il est peu fiable pour cette utilisation.

Il est possible de régler le problème des versions corrompues en proposant un serveur qui donnera pour chaque fichier, ainsi que sa version, son hash afin de pouvoir vérifier chaque fichier téléchargé.

Dans la suite du tutoriel, nous donnerons surtout des instructions SQL afin de rester le plus général possible.

III-C-2 - Comment réduire les flux ?

Pour réduire les flux entre le serveur et le client, il n'y a pas beaucoup de solutions.

Il faut déjà essayer de supprimer tous les flux inutiles comme l'envoi d'un fichier que le client possède déjà.

Ensuite, on peut compresser au maximum les archives envoyées au client, mais ceci nécessite de devoir les décompresser côté client.

Certains pourront penser à utiliser des sockets UDP pour télécharger les fichiers, mais nous n'aurons alors aucune garantie que nos fichiers arrivent intacts et dans l'ordre à destination.

III-C-3 - Comment enregistrer le contenu des différentes versions sur le serveur ?

III-C-3-a - Problématique

Le serveur doit savoir comment passer d'une version à une autre et ceci automatiquement.
Il doit donc connaître le contenu des différentes versions ainsi que les modifications qui ont été effectuées.

Deux méthodes sont alors possibles :

- on enregistre toutes les modifications d'une MàJ sur l'autre dans un fichier, mais ceci ne facilite pas du tout les traitements et plus la version cliente sera vieille, plus il lui faudra du temps pour déterminer les instructions à effectuer ;

- nous pouvons aussi voir les versions comme une arborescence ou plutôt un arbre :
les feuilles correspondent soit à des fichiers, soit à des dossiers vides,
les nœuds correspondent aux dossiers.

Trouver les instructions pour effectuer la mise à jour reviendra donc à trouver comment passer d'un arbre à l'autre.

III-C-3-b - Informations nécessaires

Dans un fichier ou dans un dossier, ce qui nous intéresse, c'est :

- la version de création (savoir s'il faudra le créer) ;

- la version de destruction (savoir s'il faudra le supprimer, le prendre en compte ou non) ;

- la version de dernière mise à jour (savoir s'il faut le mettre à jour).

Les différents localisations et noms pour les différentes versions, c'est-à-dire le dossier qui contient le fichier ou le dossier (non renseigné s'il est à la racine). On n'a pas besoin de connaître la position à chaque version, mais juste de savoir quand sa position a changé ainsi que sa nouvelle position.

Ainsi pour un fichier donné, il suffira de regarder sa position 'cliente' et sa position future pour le déplacer, nous ne tiendrons donc pas compte des déplacements antérieurs

Il faudra aussi rajouter un attribut « version prochaine MàJ » pour pouvoir enregistrer l'état d'une version en cours de création (version non activée) de création et ainsi éviter d'écrire sur la version de dernière mise à jour ce qui aurait pour effet d'empêcher le client de mettre à jour certains fichiers tant que la version en cours de création n'est pas finie.

Nous aurons donc :

- des fichiers et des dossiers ;

- des versions ;

- ainsi que des positions de fichiers (ou de dossiers) qui seront fonction d'une version et d'un fichier (ou d'un dossier), par exemple, en connaissant un fichier et une version, nous avons une ou zéro position.
Un fichier ou un dossier devra avoir au moins une position (position initiale) ainsi qu'une version de création.

Une position doit donc avoir :

- l'identifiant du fichier (ou du dossier) ;

- l'identifiant de la version ;

- le nouveau nom du fichier (ou du dossier) ;

- la position du fichier (ou dossier).

Mais en sachant qu'un fichier (ou un dossier) est dans un dossier et en connaissant la position du dossier, nous pouvons savoir à chaque fois où il se trouvera. Et nous n'aurons pas à changer la position à chaque fois que des dossiers sont déplacés.

Exemple :

position originelle : /d1/d2/d3/fichier ;
déplacement de d3 dans d1 ;
nouvelle position : /d1/d3/fichier.

Vous remarquerez que fichier est toujours dans le dossier d3, seul le dossier contenant d3 a été changé. Déplacer un fichier se résumera donc à une seule modification au lieu de X modifications si le dossier contient X fichiers/dossier (récursivement).

III-C-3-c - Table BDD

Pour plus de rapidité dans les traitements, nous rajouterons aussi un attribut Etat qui prendra ces valeurs :

- N : n'est pas la dernière position du fichier ;

- O : dernière position du fichier ;

- T : prochaine position du fichier lorsque la prochaine version en cours sera finie ;

- P : ne sera plus la dernière position du fichier lorsque la prochaine version en cours sera finie.

Requêtes SQL pour la création des tables :

Création des tables

/* on supprime les tables si elles existent déjà */
DROP TABLE POSITION ;
DROP TABLE FICHIER;
DROP TABLE VERSION;

/* on crée les tables en ajoutant des contraintes de colonnes et de tables afin d'être sûr de garder une table valide quoi qu'il se passe. */
CREATE TABLE VERSION (id MEDIUMINT PRIMARY KEY AUTO_INCREMENT, Version VARCHAR(20) NOT NULL, Active CHAR(1) NOT NULL CHECK Active IN ('O', 'N'), CHECK(Version <> '0')) ;

CREATE TABLE FICHIER (id MEDIUMINT PRIMARY KEY AUTO_INCREMENT, Version_creation MEDIUMINT NOT NULL REFERENCES VERSION.id, Version_suppression MEDIUMINT REFERENCES VERSION.id, Version_maj MEDIUMINT REFERENCES VERSION.id, Version_futur_maj MEDIUMINT REFERENCES VERSION.id, Source  VARCHAR(200), CHECK(Version_suppression IS NULL OR Version_suppression > Version_creation), CHECK((Version_suppression IS NOT NULL AND Version_maj IS NULL) OR Version_suppression IS NULL), CHECK (Version_maj IS NULL OR Version_maj > Version_creation), CHECK((Source IS NULL AND Version_maj IS NULL AND Version_futur_maj IS NULL) OR Source IS NOT NULL)) ;

CREATE TABLE POSITION (id_Fichier MEDIUMINT NOT NULL REFERENCES FICHIER.id, id_Version MEDIUMINT NOT NULL REFERENCES VERSION.id, Nom VARCHAR(100) NOT NULL, id_dossier MEDIUMINT REFERENCES FICHIER.id, Derniere_position CHAR(1) NOT NULL CHECK Derniere_position IN ('O', 'N', 'T', 'P'), PRIMARY KEY(id_Fichier, id_Version), CHECK(id_Fichier <> id_dossier));

/* on crée la version 0 (version vide) */
INSERT INTO VERSION VALUES('', '0', 'O');

Il ne faut pas oublier de créer la version 0.

III-C-4 - Quelles instructions le gestionnaire de mise à jour doit-il reconnaître ?

Pour passer d'une version à une autre, le gestionnaire va devoir effectuer des actions en fonction des instructions qui lui sont données, voici une liste de différentes instructions possibles :

- supprimer un fichier ;

- supprimer un fichier du gestionnaire ;

- supprimer un dossier vide ;

- supprimer un dossier vide du gestionnaire ;

- créer un dossier ;

- créer/mettre à jour un fichier * ;

- mettre à jour un fichier du gestionnaire * ;

- déplacer/renommer un fichier ou un dossier ° ;

- déplacer/renommer un fichier ou un dossier du gestionnaire ° ;

- vérifier la présence d'un fichier *.

Tous nécessitent de connaître le chemin des fichiers du client.

* nécessite de connaître le chemin de la ressource à télécharger.

° nécessitent de connaître le chemin de destination.

Pour mieux comprendre ce que devra faire chacune de ces fonctions, voici un ordinogramme donnant les différentes actions exécutées lors du traitement d'une instruction :

III-C-5 - Comment déterminer ces instructions ?

Maintenant que nous connaissons quelques instructions, il faut encore déterminer une séquence d'instructions correcte afin d'éviter toute erreur lors de la MàJ comme l'ajout d'un fichier dans un dossier pas encore créé.

Les dossiers se distinguent des fichiers par un attribut source NULL

Soit X l'identifiant de la version de l'utilisateur et Y celui de la nouvelle version.

L'algorithme reste assez simple à comprendre, j'ai mis le code SQL nécessaire à l'acquisition des informations nécessaires à l'écriture des instructions.

En utilisant les noms des fichiers de la version X :

- on supprime tous les fichiers où la version de suppression > X et dont la version de création < X :

Suppressions des fichiers

/* sélection du nom et de l'identifiant du dossier contenant le(s) fichier(s) à supprimer. */
SELECT nom, id_dossier FROM POSITION WHERE Derniere_position = 'O' AND id_Fichier IN(SELECT id FROM FICHIER WHERE Version_suppression IS NOT NULL AND Version_suppression > Y AND Version_creation < X Source IS NOT NULL)

- on crée tous les dossiers où la version de création > X et dont la version de suppression n'est pas renseignée :

Création des dossiers

/* sélection du nom et de l'identifiant du dossier contenant le(s) dossier(s) à créer. */
SELECT nom, id_dossier FROM POSITION WHERE id_Fichier IN(SELECT id FROM FICHIER WHERE Version_creation > Y AND Version_suppression IS NULL AND Source IS NULL);

Attention à l'ordre de création des dossiers, pour éviter tout problème, on préférera souvent établir temporairement un arbre contenant tous les nouveaux dossiers ainsi que leurs dossiers parents.
À chaque ajout d'un dossier à cet arbre, on testera sa présence si elle n'est pas évidente.
Ensuite, il suffira d'ajouter les dossiers en faisant un parcours en profondeur de l'arbre.

On utilisait jusqu'à présent les anciens noms des dossiers, on va désormais utiliser les deux.

- On déplace/renomme tous les dossiers où la version de dernière position > X et dont la version de suppression n'est pas renseignée en triant les dossiers par id décroissant :

Déplacements de dossiers

/* sélection du nom, de l'identifiant et de l'identifiant du dossier qui contiendra le(s) dossier(s) à déplacer. */
SELECT nom, id_dossier, id_Fichier FROM POSITION WHERE id_Version > X AND Etat = 'O' AND id_Fichier NOT IN (SELECT id FROM FICHIERS WHERE Version_suppression > X AND source IS NULL) ORDER BY id_Fichier ASC;

Lorsqu'on recherchera le chemin de ce dossier, on utilisera l'ancien nom de dossier si l'id du dossier est > à l'id du dossier en cours sinon, on utilisera le nom de la version Y.

Lorsqu'on déterminera le chemin source ainsi que le chemin de destination, il ne faut pas oublier d'ajouter tous les dossiers qui ne sont pas encore dans notre arbre temporaire et aussi de déplacer les dossiers au sein de notre arbre au fur et à mesure qu'on déplace nos propres dossiers.

Maintenant, on n'utilise que les noms de la version Y.

- On déplace/renomme tous les fichiers de version de dernière position > X et dont la suppression n'est pas renseignée :

Déplacements des fichiers

/* sélection du nom, de l'identifiant et de l'identifiant du dossier qui contiendra le(s) dossier(s) à déplacer. */
SELECT nom, id_dossier, id_Fichier FROM POSITION WHERE id_Version > X AND Etat = 'O' AND id_Fichier NOT IN (SELECT id FROM FICHIERS WHERE Version_suppression > X AND source IS NOT NULL);

Nous inclurons aussi ces fichiers dans notre arbre temporaire.

- On supprime les dossiers dont la version de suppression est > X :

Suppression des dossiers

SELECT nom, id_dossier FROM POSITION WHERE Derniere_position = 'O' AND id_Fichier IN(SELECT id FROM FICHIER WHERE Version_suppression IS NOT NULL AND Version_suppression > X AND Source IS NULL)

- On crée les fichiers dont la version de suppression est > X et dont la version de suppression n'est pas renseignée :

Créations des fichiers

/* sélection du nom, de la source et de l'identifiant du dossier contenant le(s) fichier(s) à créer. */
SELECT POSITION.nom, POSITION.id_dossier, FICHIER.source FROM POSITION, FICHIER WHERE POSITION.id_Fichier = FICHIER.id AND FICHIER.Version_creation X AND FICHIER.Source IS NOT NULL AND FICHIER.Version_suppression IS NULL AND Etat = 'O';

- Et enfin, on parcourt en profondeur notre arbre temporaire en même temps que l'arborescence de la version Y et on rajoute tous les fichiers manquants.

Comme vous pouvez le voir, ces instructions ne sont pas évidentes, d'où l'importance du précalcul. Plutôt que de tout recalculer dès qu'un client veut mettre à jour son logiciel, on va , lors de la création d'une version, enregistrer pour chaque version, les instructions à effectuer.

III-C-6 - Comment administrer les versions ?

Maintenant que nous savons comment déterminer une séquence d'instructions pour mettre à jour une version donnée de votre logiciel, il nous manque encore à ajouter de nouvelles versions au serveur.

L'administration des versions sera similaire à ceci :

L'Administrateur (admin sur le schéma) utilisera une interface pour générer des fichiers d'instructions à partir des informations stockées dans la BDD (Base De Données). Les fichiers d'instructions devront aussi connaître l'URL des fichiers sources à télécharger par le client.

Là encore, il y a plusieurs méthodes comme de comparer une archive comprenant l'ensemble des fichiers de la nouvelle version du logiciel avec l'archive de la version précédente afin de déterminer les modifications qui ont été ajoutées. Mais cette méthode ne fera pas de lien entre deux versions différentes d'un fichier. Il faudra aussi comparer tous les fichiers de la version précédente avec ceux de la nouvelle version pour détecter les déplacements. De plus il n'est pas toujours évident qu'il puisse détecter correctement les déplacements de dossier.

Soit X le nombre de fichiers de la version précédente et Y celui de la nouvelle version, il faudra faire X*Y comparaisons.

Je préfère plutôt permettre au développeur de partir de la version précédente puis de modifier lui-même cette version pour donner la version actuelle. C'est certes plus long mais ceci permettra de pouvoir observer l'évolution de chaque fichier et de voir lesquels sont plutôt instables et lesquels sont plutôt stables.

Il faudra donc que le développeur puisse :

- créer une nouvelle version : cette version devra être inactivée afin de ne pas mettre à jour avec une version incomplète les clients qui lanceraient leur gestionnaire pendant que nous finissons cette version :

Nouvelle version

INSERT INTO VERSION VALUES(NULL, $nom_version, 'N')

- voir l'arborescence de la nouvelle version : de base, elle sera identique à celle de la version précédente, il faudra donc que le développeur modifie cette arborescence pour créer la nouvelle version, on utilisera alors une fonction récursive pour l'affichage :

Afficher

/* sélection des informations fichiers sur les éléments présents à la racine de l'arborescence */
SELECT * FROM FICHIER, POSITION WHERE FICHIER.Version_suppression IS NULL AND POSITION.Derniere_position IN ('O', 'P') AND POSITION.id_Fichier = FICHIER.id AND POSITION.id_dossier IS NULL;
/* sélection des informations fichiers sur les éléments contenus dans le dossier d'identifiant $id_dossier */
SELECT * FROM FICHIER, POSITION WHERE FICHIER.Version_suppression IS NULL AND POSITION.Derniere_position IN ('O', 'P') AND POSITION.id_Fichier = FICHIER.id AND POSITION.id_dossier = $id_dossier;

- construire une nouvelle version à partir de cette dernière version (création, suppression, déplacement, MàJ) :

Modification de la version

/* Ajouter un fichier : vérification de l’existence du fichier */
SELECT FICHIER.id, POSITION.nom, POSITION.id_dossier FROM FICHIER, POSITION WHERE FICHIER.id = $id_fichier AND POSITION.id_Fichier = FICHIER.id AND POSITION.id_Version IN (SELECT MAX(id_Version) FROM POSITION WHERE id_Fichier = $id_fichier;
/* Ajouter un fichier : */
INSERT INTO FICHIER VALUES(NULL, $num_version, NULL, NULL, NULL, $source);
INSERT INTO POSITION VALUES($num_fichier, $num_version, $nom, $id_dossier, 'T');
/* Ajouter un dossier : */
INSERT INTO FICHIER VALUES(NULL, $num_version, NULL, NULL, NULL, NULL);
INSERT INTO POSITION VALUES($num_dossier, $num_version, $nom, $id_dossier, 'T');
/* MàJ fichier : */
UPDATE FICHIER SET Version_future_maj = $version WHERE id = $id_fichier;

/* Suppression fichier/dossier : */
UPDATE FICHIER SET Version_suppression = $new_version WHERE id = $id_fichier;
DELETE POSITION WHERE id_Version = $new_version AND id_Fichier = $id_fichier;
UPDATE POSITION SET Etat = 'O' WHERE id_Fichier = $id_fichier AND Etat = 'P';
/* Déplacer/Renommer fichier/dossier : */
INSERT INTO POSITION VALUES ($id_fichier, $new_version, $nom, $id_dossier, 'T');
/* si le fichier a déjà été déplacé, on modifie la position du fichier dans la nouvelle version */
UPDATE POSITION SET nom = $nom, id_dossier = $id_dossier WHERE id_Fichier = $id_fichier AND id_Version = $new_version;

- supprimer une « nouvelle version » non active : si jamais, vous voulez reprendre la version depuis le début ou si vous vous êtes trompé lors de sa création :

Supprimer version

/* suppression des positions de la version à supprimer */
DELETE FROM POSITION WHERE id_Version = $id_version;
/* suppression des fichiers créés lors de la version à supprimer */
DELETE FROM FICHIER WHERE Version_creation = $id_version;
/* on modifie certaines informations pour garder une table cohérente */
UPDATE POSITION SET Derniere_position = 'O' WHERE Derniere_position = 'P';
UPDATE FICHIER SET Version_suppression = NULL WHERE Version_suppression = $id_version;
UPDATE FICHIER SET Version_futur_maj = NULL WHERE Version_futur_maj = $id_version;
/* on supprime la version */
DELETE FROM VERSION WHERE id = $id_version;

- sauvegarder une « nouvelle version » sans l'activer : c'est dans ce but que nous avons rajouté Version_futur_maj dans FICHIER ainsi que Etat dans POSITION, ceci permettant de ne pas interférer avec les MàJ des clients qui se feront pendant ce temps-là ;

- modifier la source d'un fichier : il peut arriver qu'on souhaite changer la position d'un fichier dans le serveur :

Changement de la source

UPDATE FICHIER SET source =$nouvelle_source WHERE id = $id_fichier;

- activer la « nouvelle version » : maintenant que la version est finie, il faut l'activer pour que les clients puissent se mettre à jour :

Activation

/* on met à jour les dates de MàJ. */
UPDATE  FICHIER SET Version_maj = Version_futur_maj, Version_futur_maj = NULL WHERE Version_futur_maj IS NOT NULL;
/* on met à jour les Etats des positions */
UPDATE POSITION SET Derniere_position = 'N' WHERE Derniere_position = 'P';
UPDATE POSITION SET Derniere_position = 'O' WHERE Derniere_position = 'T';
/* on active officiellement la version */
UPDATE VERSION SET Active = 'O' WHERE id = 1;

III-D - Proposition de fonctionnement du gestionnaire

En tout premier lieu, je vous propose de télécharger des images de news et de les conserver pour éviter de les retélécharger à chaque lancement du gestionnaire.

Ensuite, le gestionnaire se connecte au serveur de MàJ du gestionnaire. Si une MàJ est disponible, nous l'appliquons automatiquement, nous lançons le petit programme que nous avons nommé P, puis nous arrêtons le gestionnaire. P va donc effectuer tout ce qu'il a à faire et juste avant de se fermer, il lancera le gestionnaire.

Si aucune MàJ n'est disponible, on se connecte au serveur de MàJ de votre logiciel (peut être le même ou différent du serveur de MàJ du gestionnaire). Si le serveur est disponible, on va regarder la version du client et vérifier la présence de MàJ, s'il y a une mise à jour, on l'applique sinon on vérifie la présence des fichiers de votre logiciel.

Si le logiciel est à la version 0 (non installé), on l'installera ce qui correspondra à une MàJ ordinaire.

Une fois cela fait, on va proposer au client trois choix :

- quitter ;

- désinstaller le logiciel (une fois le logiciel désinstallé, on ne pourra plus que quitter le gestionnaire) ;

- lancer votre logiciel (fermera le gestionnaire).

Ci-dessous, un ordinogramme résumant le fonctionnement du gestionnaire :

IV - Conclusion

Voilà maintenant vous connaissez la théorie, la réalisation d'un gestionnaire de MàJ ne devrait plus vous poser de problèmes.

Il ne vous reste donc plus qu'à créer votre propre gestionnaire, votre propre interface pour administrer et vos versions.

S'il vous reste encore des zones d'ombre, je peux vous proposer l'implémentation de la méthode expliquée ici en C++ côté client et PHP côté serveur.

Source Release : [Non disponible].

Source Github : [Non disponible].

Documentation Doxygen : [Non disponible].

Contactez-moi par MP pour toute remarque sur ce tutoriel.

V - Remerciements

Merci à LittleWhite de m'avoir proposé de faire ce tutoriel sur Developpez avant de m'apporter une aide et un soutien sans faille pendant toute la rédaction de ce tutoriel.

Merci à dourouc05 pour ses suggestions.

Merci à ClaudeLELOUP ainsi qu'à jacques_jean pour leur relecture orthographique.

Gestionnaire de mises à jour

Analyse et conseils

Auteurs

| Neckara | Laurent Alexandre | Thibaut Cuvelier | Claude Leloup | Jacques THERY |