Lftp ou comment mettre à jour un site web statique en une seule commande

Posté le 2015-09-03, dans : GNU+Linux

Cet un vieil article qui n'est plus d'actualité concernant ce site, mais que je laisse car toujours utile

Commençons par le début : un site web statique est un site ne contenant que des pages HTML (aucun script PHP ou autres). Pourquoi lftp ? Parce qu'il est possible de faire des scripts contenant des commandes à effectuer comme avec votre shell (bash,dash,csh...) , de la même manière que vous le faites déjà peut être avec MySQL et sa commande source. Aussi lftp est bien plus puissant que ftp : il gère plusieurs protocoles de tranfert, a de nombreuses commandes que ftp n'a pas etc. Le site que nous allons mettre à jour, c'est celui où vous êtes actuellement.

Sommaire

Pré-requis

Pour suivre ce howto, il faut :

Deux solutions possibles

Le concept des modules

Dans les deux cas, on utilise un système de "modules" qui divise le site en plusieurs parties. Ici par exemple j'ai : howtos,tkhtmltidy,tkhtmltidyfr, bugs,css,ban. Les deux solutions développées ici sont traitées indépendamment, vous pouvez ne lire qu'une solution et pas l'autre, vous arriverez quand même à quelque chose.

Solution 1 : Ecrire un script par module (la plus simple)

Cela veut dire que l'on va créer un script par module que vous pourrez ré-utiliser ultérieurement.

Avantages : c'est trés simple à mettre en oeuvre, vous n'avez pas besoin de coder quelque chose.

Inconvénients : Le manque de souplesse. Au delà de 2-3 modules, c'est ingérable, même pour ici ce serait la galère. De plus si vous distribuez des logiciels avec des versions qui changent tout le temps, il faut changer vos scripts à chaque fois.

Solution 2 : Ecrire un programme qui génère un script global

Cela veut dire que l'on va créer un seul script qui correspond aux modules à mettre à jour à partir d'un programme. C'est exactement ce que vous faites pour compiler un programme : ./configure génère Makefile qui va vous permettre de le compiler. Souvent ces scripts générés ne servent qu'une fois.

Avantages : Trés souple, efficace quand vous avez des régles de mises à jours complexes ou qui vous oblige à aller au quatre coins de votre arborescence (c'est le cas ici ;), ou des noms de fichiers changeants (logiciels etc.)

Inconvénients : Il faut créer le générateur de script, car chacun a des besoins différents donc cela prend un peu plus de temps initialement mais le gain de temps est énorme par la suite.

Solution 1 : Ecrire un script par modules (la plus simple)

Il va falloir écrire un script pour chaque module. Dans mon cas je les stocke dans mon $HOME. Voici 3 scripts sur les 6 (il serait inutile de tous les mettre ici ) :

Ecriture des scripts

Les scripts utilisables avec lftp sont trés simples : une commande par ligne !

/home/francois/tkhtmltidy

cd /
put /mnt/hdb2/perso/index.php
cd tkhtmltidy/
put /mnt/hdb2/perso/tkhtmltidy/tkhtmltidy-0.41.tar.gz
put /mnt/hdb2/perso/tkhtmltidy/index.php
cd /

/home/francois/tkhtmltidyfr

cd /
put /mnt/hdb2/perso/index.php
cd tkhtmltidy/fr
put /mnt/hdb2/perso/tkhtmltidy/fr/tkhtmltidy-0.41-fr.tar.gz
put /mnt/hdb2/perso/tkhtmltidy/fr/index.php
cd /

/home/francois/howto

cd /
put /mnt/hdb2/perso/index.php
cd howtos
put /mnt/hdb2/perso/howtos/ftpd.html
put /mnt/hdb2/perso/howtos/index.php
cd /

Execution des scripts

Nos scripts écrits, il n'y a plus qu'a les exécuter. C'est ce que l'on va voir ici :

Pour lancer lftp, faites de cette manière :

lftp -u <nom d'utilisateur> serveur_ftp

Une fois connecté, vous pouvez lancer vos scripts avec la commande source suivi du nom de fichier du script. Voila ce que ca doit donner :

~$ lftp -u anonymous 127.0.0.1
Mot de passe: 
lftp anonymous@127.0.0.1:~> source tkhtmltidyfr
cd ok, cwd=/pub                
cd ok, cwd=/pub/tkhtmltidy/fr
18528 octets transférés                                              
7290 octets transférés                                
3202 octets transférés                                                          
lftp anonymous@127.0.0.1:/pub> source tkhtmltidy
cd ok, cwd=/pub/tkhtmltidy
17983 octets transférés                                                                                
7077 octets transférés                                                                     
3202 octets transférés

Vous remarquerez que dans mes scripts j'upload toujours l'index : là j'ai donc uploadé 2 fois le même fichier (l'index du site). Il vous faut donc à tout prix diviser un maximum les tâches à effectuer. De plus, il me faudrait modifier les scripts à chaque nouvelle version pour TkHTMLtidy et changer le nom de fichier à chaque howto. Bref pas pratique tout ça, c'est pour ça que la deuxième solution s'avère plus complexe à mettre en oeuvre mais après c'est automagique :)

Solution 2 : Ecrire un programme qui génère un script global

Il n'y a ici pas de solution parfaite : chacun à ses régles d'upload. Je ne peux donc que vous donner un exemple commenté, celui que j'utilise pour ce site, écrit en Perl. NB : le module Net::FTP ne marche pas sur le serveur FTP de free, par contre il marche chez moi ! Vu que la page aurait été trop lourde à mon goût en utilisant perltidy -html il est là tel quel (avec quelques bugs possibles):


#!/usr/bin/perl -w

use strict;
use Term::Complete;    #pour la completion des commandes
my $local_dir  = "/mnt/hdb2/perso/";    #la racine du site chez moi
my $remote_dir = "/";                   #la racine du site sur le serveur
my $command    = "";                    #la commande que j'ai tapé

# 0 == pas de howto encore uploadé donc ajouter l'index des howtos
my $howto = 0;

#les commandes disponibles
my @commands = [
"tkhtmltidy", "tkhtmltidyfr", "howto", "bugs",
"write",      "exit",         "ban",   "css",
"raw"
];

#le contenu du script
my @to_write;

#A chaque upload, l'index principal doit être uploadé (pour les news)
&update_index;

#ici c'est le début du shell me permettant de lancer mes commandes
#comme sous n'importe quel shell.
while ( $command !~ /(write|exit)/i ) {
print "\n";

#entrée de la commande avec la completion
$command = Complete( $0 . "\$ ", @commands );

#suivant les resultats de la commande :

# tkhtmltidy : tkhtmltidy <version>
if ( $command =~ /tkhtmltidy\s([0-9]\.[0-9]{1,3})/i ) {
    if ( -e $local_dir . "tkhtmltidy/tkhtmltidy-" . $1 . ".tar.gz" ) {
        push( @to_write, "cd tkhtmltidy/" );
        &put( $local_dir . "tkhtmltidy/tkhtmltidy-" . $1 . ".tar.gz" );
        &put( $local_dir . "tkhtmltidy/index.php" );
        push( @to_write, "cd " . $remote_dir );
        print "tkhtmltidy $1 => OK";
    }
    else {
        print "tkhtmltidy $1 => Erreur : l'archive n'existe pas";
    }
}

# tkhtmltidyfr : tkhtmltidyfr <version>
elsif ( $command =~ /tkhtmltidyfr\s([0-9]\.[0-9]{1,3})/i ) {
    if ( -e $local_dir . "tkhtmltidy/fr/tkhtmltidy-" . $1 . "-fr.tar.gz" ) {
        push( @to_write, "cd tkhtmltidy/fr" );
        &put(
            $local_dir . "tkhtmltidy/fr/tkhtmltidy-" . $1 . "-fr.tar.gz" );
        &put( $local_dir . "tkhtmltidy/fr/index.php" );
        push( @to_write, "cd " . $remote_dir );
        print "tkhtmltidyfr $1 => OK";
    }
    else {
        print "tkhtmltidyfr $1 => Erreur : l'archive n'existe pas";
    }
}

#howto : howto <nom de fichier du howto sans .html>
elsif ( $command =~ /howto\s(.+)/i ) {
    if ( -e $local_dir . "howtos/" . $1 . ".html" ) {
        push( @to_write, "cd howtos" );
        &put( $local_dir . "howtos/" . $1 . ".html" );
        &put( $local_dir . "howtos/index.php" ) unless ( $howto == 1 );
        push( @to_write, "cd " . $remote_dir );
        print "howto $1 OK";
        $howto = 1;
    }
    else {
        print "howto $1 => Erreur : le howto n'existe pas";
    }
}

#bugs : uploade la page de bugs de TkHTMLtidy. Tel quel.
elsif ( $command =~ /bugs/i ) {
    push( @to_write, "cd tkhtmltidy" );
    &put( $local_dir . "tkhtmltidy/bugs.html" );
    push( @to_write, "cd " . $remote_dir );
    print "bugs OK";
}

#ban : ajoute la banière. S'utilise tel quel.
elsif ( $command =~ /ban/i ) {
    &put( $local_dir . "linux_909.jpg" );
    push( @to_write, "cd " . $remote_dir );
    print "ban OK";
}

#css : ajoute la feuille de style. S'utilise tel quel.
elsif ( $command =~ /css/i ) {
    &put( $local_dir . "style.css" );
    push( @to_write, "cd " . $remote_dir );
    print "css OK";
}

#la commande n'existe pas
else {
    print "Mauvaise commande" if ( $command !~ /(write|exit)/i );
}
}

#on génère le script ~/rules qu'on utilisera avec lftp
if ( $command =~ /write/i ) {
open( RULES, "> /home/francois/rules" ) || die( "\n" . $0 . " : " . $! );
foreach my $line (@to_write) {
    print RULES $line . "\n";
}
close RULES;
}

#créée une ligne put <fichier>
sub put {
push( @to_write, "put " . $_[0] );
}

#mise à jour de l'index de la page d'accueil
sub update_index {
push( @to_write, "cd " . $remote_dir );
push( @to_write, "put " . $local_dir . "index.html" );
push( @to_write, "cd " . $remote_dir );
}

En pratique...

Comparé à la première solution, c'est bien plus simple :

On décide de ce qu'il faut uploader

~$ ./update_perso 
./update_perso$ tkhtmltidy 0.41
tkhtmltidy 0.41 => OK
./update_perso$ tkhtmltidyfr 0.41
tkhtmltidyfr 0.41 > OK
./update_perso$ write

Cela va générer le script suivant :

~$ cat rules 
cd /
put /mnt/hdb2/perso/index.php
cd /
cd tkhtmltidy/
put /mnt/hdb2/perso/tkhtmltidy/tkhtmltidy-0.41.tar.gz
put /mnt/hdb2/perso/tkhtmltidy/index.php
cd /
cd tkhtmltidy/fr
put /mnt/hdb2/perso/tkhtmltidy/fr/tkhtmltidy-0.41-fr.tar.gz
put /mnt/hdb2/perso/tkhtmltidy/fr/index.php
cd /    

Transfert

Ensuite on transfère tout ca, en utilisant -e (==executer une commande) et en utilisant la commande source <fichier_commandes> (==lire les commandes a effectuer dans le fichier donné) :

~$ lftp -u anonymous -e "source rules" 127.0.0.1