site
est un script bash permettant de gérer un site web statique multi-auteurs depuis un répertoire partagé. C’est un logiciel libre, distribué sous licence GPL v3.
J’ai développé site
lorsque j’administrais un site pour les PTSI du lycée Jules Ferry de Versailles, hébergé par les pages personnelles du FAI FREE. Ce site sert à partager des ressources pédagogiques avec nos élèves. Les besoins que nous avons sont :
Initialement écrit en SPIP 3.0.5 avec une base de données MYSQL, nous avions à peu près tous nos critères de remplis, bien qu’à l’usage (intensif), nous avons constaté :
Ces points étaient assez limitants mais nous nous en sommes accommodés jusqu’à ce que notre site, ou plus exactement la base de données MYSQL de notre site, ait été attaquée à deux reprises avec le remplacement du contenu des rubriques par un « iframe » affichant un message d’une stupidité confondante. C’est à l’issue de cette deuxième attaque que j’ai développé ce qui fût les prémices de site
.
Pour remettre en ligne rapidement la plupart des contenus que nous avions sur le site, j’ai créé un site statique en HTML avec des feuilles de style CSS. Dès la première version, la rapidité d’accès aux pages était édifiante par rapport au site avec SPIP. Par contre, je me suis retrouvé très vite à centraliser les demandes de mes collègues et il est devenu impératif de concevoir :
Malgré une attention particulière portée aux outils libres, je n’en ai pas trouvé qui permette de faire ce genre de choses. En effet :
=> NON !
site
mais seul pelican
(en python) existait « à l’époque ». Malgré tout, une veille curieuse ne ma pas amené à changer d’outils tant ils ne sont soit pas très adaptés aux « utilisateurs classiques » ou à nos besoins spécifiques de dépôts de documents.=> NON !
Ce sont donc les besoins et le cahier des charges spécifiques à un site de classe préparatoire qui ont conduit à la création de site
. C’est un outil très bien adapté à ce besoin, mais il est probable, voire certain, qu’il ne sera pas pour d’autres.
Tout d’abord pour mettre au point un système multi-utilisateur, il faut une plateforme d’échange de fichiers. Pour le site des PTSI du lycée Jules Ferry de Versailles, nous avons choisi de partager un répertoire dropbox (appelé DistDir
par la suite) qui contient un répertoire squelette
et un répertoire web
.
Dans le répertoire squelette
sont stockés des fichiers textes décrivant la structure des pages du site et leur contenu, il doit contenir au minium :
squelette
|-- footer.txt
|-- header.txt
`-- index.py
Dans le cas de la démo, il contient :
squelette
|-- filiere.py
|-- footer.txt
|-- header.txt
|-- index.py
|-- Informatique.py
|-- Maths.py
|-- Physique.py
|-- PTSI1.py
|-- PTSI2.py
|-- SII.py
`-- site.py
Pour un choix de commodité d’édition en UTF-8 avec les fins de lignes UNIX (line feed \n
), les fichiers sont édités avec l’éditeur de pyzo d’où leur extension .py
.
Le répertoire web
reproduit l’arborescence des répertoires du site web réel et permet aux auteurs de déposer directement dans « le bon répertoire » les fichiers qu’ils veulent mettre sur le site, il doit contenir au minium :
web
|-- img
|-- password
`-- style
`-- vignettes
Dans le cas de la démo, il contient :
web
|-- files
|-- img
|-- password
`-- style
`-- vignettes
C’est à partir du répertoire partagé DistDir
qu’est mis à jour le répertoire local, appelé LocalDir
.
site.config
)Le fichier de configuration site.config
est un fichier texte formaté JSON qui sert « à sourcer » le script site
. Il permet de renseigner les variables suivantes :
title
Titre du site, affiché en haut de toutes les pages ;
subtitle
Sous-titre du site, affiché sous le titre de toutes les pages ;
footer
Titulaire des droits du site, par exemple « Équipe de CPGE, du lycée XXX, XXX » ;
LocalDir
Chemin complet du répertoire local (~/..somewhere..
)
DistDir
Chemin complet du répertoire partagé (~/Dropbox/somewhere
)
pagesDir
Nom du répertoire du squelette (squelette
)
pages
Liste de listes du type ["nomPage.html", "NOM de la page"]
comprenant en premier élément le nom du fichier HTML de la page à synchroniser (sans espace) et son nom affiché dans le menu en haut de toutes les pages. L’ordre des pages correspond à celui du menu.
dirsDir
Nom du répertoire dont le répertoire distant sera l’image (web
)
dirs
Liste des noms des répertoires locaux de dirsDir
à synchroniser pour voir les nouveaux fichiers ajoutés ou mis à jour ;
FTPserver
URL du serveur hébergeur
FTPuser
Identifiant de l’utilisateur FTP
FTPpwd
Mot de passe de l’utilisation FTP
FTPdir
Répertoire du site sur le serveur, par défaut "/"
.
Exemple de fichier de configuration pour le site de démo :
{
"title": "Filière, lycée XXX, XXX",
"subtitle": "MATHS, PHYSIQUE, ET SCIENCES DE L'INGÉNIEUR",
"footer": "Équipe de CPGE, du lycée XXX, XXX",
"LocalDir": "~/site",
"DistDir": "~/site/Dropbox-test",
"pagesDir": "squelette",
"pages": [
["filiere.html", "PTSI/PT"],
["PTSI1.html", "PTSI1"],
["PTSI2.html", "PTSI2"],
["Maths.html", "Maths"],
["Physique.html", "Physique-Chimie"],
["SII.html", "SII"],
["Informatique.html", "Info"],
["site.html", "À propos de site"]
],
"dirsDir": "web",
"dirs": [
"files"
],
"FTPserver": "ftpperso.free.fr",
"FTPuser": "",
"FTPpwd": "",
"FTPdir": "/"
}
Comme le fichier de configuration site.config
contient vos identifiants de connexion, veillez à ce que tous les utilisateurs n’y aient pas accès en tapant dans le terminal
chmod 600 site.config
– Attention –
Il est impératif d’avoir bien renseigné les chemins complets :
LocalDir
) où se situent les documents, scripts et fichiers de configuration relatifs à site
etDistDir
) où se situent les fichiers de squelette et les nouveaux documents ajoutés, par exemple un dossier Dropbox partagé pour votre site.La structure du site telle qu’elle peut s’afficher est définie par les fichiers du squelette
header.txt
(non mis à jour)Contient l’en-tête HTML commun à toutes les pages et notamment la description du site, l’appel des feuilles de style CSS et l’ordre des pages dans le menu.
footer.txt
(non mis à jour)Contient le pied de page HTML commun à toutes les pages du site, faisant pointer sur la licence CC et les validateurs HTML et CSS de la W3C.
index.py
(non mis à jour)C’est la page chargée par défaut. Elle sert de porte d’entrée du site. Pour cette page on peut désactiver l’affichage classique avec
no_title
no_update
no_navigation
et définir le sien en HTML en le spécifiant entre 2 balises <html>
et </html>
.
title
Permet d’afficher un nom en haut de la page
no_title
Préciser de ne pas afficher de nom en haut de la page
no_update
Préciser de ne pas afficher la date de mise à jour en haut de la page
no_navigation
Par défaut, un mini-menu permet de pointer vers les rubriques de la page. Cette option désactive son affichage.
docdir
Précise le répertoire du dossier web
dans lequel trouver les documents.
Une page classique, par exemple physique.py
, commence par :
title("Physique-chimie")
docdir("physique")
Une page peut être structurée sous la forme :
rubrique
|-- section
| |-- subsection
rubrique(nom, open)
Crée une nouvelle rubrique. L’affichage est paramétré avec la classe rubrique
. Par défaut, on a l’option open=True
et le contenu est visible. Si open=False
, le contenu n’est pas visible et il faut cliquer sur le titre pour le voir.
section(nom, open)
Crée une nouvelle section. L’affichage est paramétré avec la classe container-item-phys
. Par défaut, on a l’option open=False
et le contenu n’est pas visible et il faut cliquer sur le titre pour le voir. Si open=True
, le contenu est visible.
section_open(nom)
Crée une nouvelle section. Par défaut, le contenu est visible.
Fonction obsolète, à remplacer par section(nom, True)
.
section_CI(nom)
Crée une nouvelle section, affichage tiers de page sur grand écran. L’affichage est paramétré avec la classe container-item
.
section_TP(nom)
Crée une nouvelle section, affichage avec tableau pour TP. L’affichage est paramétré avec la classe container-item
+ tableau avec la classe TP
.
subsection(nom)
Crée une nouvelle sous-section. L’affichage est paramétré avec un <h2>
pour le titre et un petit séparateur de la classe floatreset
.
subsection_CI(nom)
Crée une nouvelle sous-section, affichage tiers de page sur grand écran. L’affichage est paramétré avec la classe sub-container-item
.
nav_rubrique()
Affiche les liens vers les sections de la rubrique en cours. À placer sous la définition d’une rubrique.
Les sections avec une étoile *
avant la parenthèse, du genre
section*(nom)
section_open*(nom)
section_CI*(nom)
section_TP*(nom)
ne sont pas liées (comme en LaTeX).
web
)Le répertoire dirsDir
(aka web
) reproduit l’arborescence des répertoires du site web réel.
style
C’est le répertoire qui contient les feuilles de style CSS des pages HTML et les images ou icones utilisées de façon standard sur le site.
password
Ce répertoire contient le fichier .htpasswd
des couples (identifiant, mot de passe) des utilisateurs du site (voir la rubrique sécurité).
img
Ce répertoire peut être considéré comme public. L’accès à tous ses éléments peut se faire sans mot de passe. Il permet de stocker des fichiers auxquels n’importe quel utilisateur peut avoir accès.
Pour créer un répertoire et ses parents en même temps, taper :
mkdir -p $dirsDir/sii/ptsi1
Les outils développés sont :
site
Script bash permettant de mettre à jour le site à partir des contenus ajoutés ou modifiés dans le répertoire partagé DistDir
(dropbox).
MakePage.py
Script python (plutôt version 3) permettant d’interpréter les pages textes du squelette pour générer les pages HTML du site. Il est appelé par le script site
.
Pour utiliser les outils développés, il est nécessaire d’avoir :
head
, tail
, cp
, cut
, grep
, sed
, stat
, tar
, md5sum
, … et j’en oublie).La dernière version est la 0.1.6 (23/09/2019).
Archive : site-0.1.6.tar.gz
sudo apt install lftp rsync
télécharger site
:
wget http://nmesnier.free.fr/files/site-0.1.6.tar.gz
décompresser l’archive
tar -xzf site-0.1.6.tar.gz
renommer le dossier site-0.1.6
comme vous voulez puis
mv site-0.1.6 NomDeVotreSite
Dans la suite on appelle localDir
ce dossier. Vous y rendre
cd localDir
rendre exécutable le script :
chmod +x site
modifier le chemin du fichier de configuration de la variable configFile
, soit « à la main » en éditant la ligne
configFile=""
du fichier site
, soit en tapant :
sed -i "s@\(configFile=\"\)~\/site\(\/site.config\"\)@\1$(pwd)\2@" site
créer un lien symbolique de façon à pouvoir « exécuter site
de partout » :
ln -s $(pwd)/site ~/bin/.
Si le répertoire ~/bin
n’existe pas, le créer et l’ajouter au PATH
en éditant le fichier ~/.bashrc
avec la ligne :
PATH="$PATH:~/bin"
installer LFTP (voir si besoin cette aide pour installer lftp sur Mac OS x)
brew install lftp
installer rsync
brew install rsync
télécharger site
:
wget http://nmesnier.free.fr/files/site-0.1.6.tar.gz
décompresser l’archive
tar -xzf site-0.1.6.tar.gz
renommer le dossier site-0.1.6
comme vous voulez puis
mv site-0.1.6 NomDeVotreSite
Dans la suite on appelle localDir
ce dossier. Vous y rendre
cd localDir
Une différence dans l’implémentation de stat
impose de changer le stat -c %Y
utilisé dans site
en stat -f "%c"
sur mac OS X, soit « à la main », soit en tapant :
sed -i 's/stat -c %Y/stat -f "%c"/g' site
rendre exécutable le script :
chmod +x site
modifier le chemin du fichier de configuration de la variable configFile
, soit « à la main » en éditant la ligne
configFile=""
du fichier site
, soit en tapant :
sed -i "s@\(configFile=\"\)~\/site\(\/site.config\"\)@\1$(pwd)\2@" site
créer un lien symbolique de façon à pouvoir « exécuter site
de partout » :
ln -s $(pwd)/site ~/bin/.
Si le répertoire ~/bin
n’existe pas, le créer et l’ajouter au PATH
en éditant le fichier ~/.profile
avec la ligne :
PATH="$PATH:~/bin"
Oups !
Éditer le fichier de configuration site.config
et notamment les variables "LocalDir"
et "DistDir"
qui correspondent respectivement aux chemins absolus du dossier local et du dossier partagé.
Le chemin du dossier local "LocalDir"
est probablement celui dans lequel vous êtes placé avec votre terminal, donc la commande
sed -Ei 's@"LocalDir":.*@"LocalDir": "'$(pwd)'",@g' site.config
devrait suffire.
Pour le chemin du dossier partagé "DistDir"
, copier son adresse complète (chemin absolu) dans le fichier en n’oubliant pas la virgule après les guillemets.
Il n’est pas nécessaire de copier les dossiers squelette
et web
dans le "DistDir"
, ils le seront à la première exécution, par précaution hors ligne :
site -o
Cette commande permet de générer toutes les pages.
Les feuilles de styles CSS du site sont base.css
et mobile.css
, dont les rôles sont explicites, et situées dans le répertoire web/style
.
L’image du bandeau du haut commune à toutes les pages s’appelle bg.png
et se trouve dans le répertoire web/style
. Ses dimensions sont 849x135
.
Le logo et la photo de la page index.html
se situent dans le répertoire web/img
.
N’ayant pas (forcément) la main sur les paramètres du serveur qui héberge notre site, les seuls éléments de sécurités sont :
Pour restreindre l’accès à un répertoire de web
et à tout ce qu’il contient (fichiers, sous-répertoires), il suffit de placer à la racine (comprendre dans le répertoire que l’on veut protéger) un fichier .htaccess
(propre aux serveurs apache) contenant :
PerlSetVar AuthFile /password/.htpasswd
AuthName "Acces Restreint"
AuthType Basic
require valid-user
Le fichier .htpasswd
du répertoire password
doit contenir la liste des couples (identifiant, mot de passe) valide. Si le répertoire n’existe pas, il suffit de le créer
mkdir -p web/password
puis de créer la liste des couples (identifiant, mot de passe) :
echo "user:pass">>web/password/.htpasswd
le >>
pour ajouter au fichier, >
écrase le contenu du fichier tel qu’il ne reste que ce dernier contenu. Évidemment, il convient que le répertoire password
soit inaccessible par tous, de sorte que ces mots de passe ne soient pas {v,l,s}us. On peut le protéger avec un fichier .htaccess
contenant deny from all
généré avec :
echo "deny from all">web/password/.htaccess
Attention à ne pas mettre ce fichier dans le répertoire style
ni dans le répertoire img
que l’on gardera donc comme répertoires publics.
site
)Au quotidien, l’administration du site peut être résumée en 2 commandes :
site -c
pour voir s’il y a eu des modifications de contenu (squelette et fichiers) ;
site -u
pour appliquer les modifications.
En cas de problème sur une page, par exemple un fichier manquant ou un nom de fichier erroné, il est possible d’éditer rapidement la page avec :
site -e <page>
pour éditer la page <page>
avec l’éditeur spécifié par la commande editor
. Si besoin jouer (en admin) du
update-alternatives --config editor
ou faire un export EDITOR=xxx
avec xxx
votre éditeur préféré, voire même remplacer la ligne editor ...
avec votre éditeur préféré en mode graphique, comme gedit
sur GNU/Linux ou /Applications/TextMate.app/Contents/Resources/mate
sur Mac OS X.
site -p <page>
pour compiler la page <page>
;
site -e <page> -p
pour éditer puis compiler la page <page>
;
Les erreurs classiques sont :
site
est muni de quelques autres options qui sont parfois utiles. Dans tous les cas :
site -h
pour voir l’aide !
MakePage.py
)La génération des pages HTML est réalisée, page après page, avec le script python MakePage.py
, appelé par le script bash site
. Vous n’avez normalement pas besoin de l’utiliser directement mais si vous le souhaitez, il est nécessaire de se placer dans le répertoire localDir
et taper dans le terminal :
python3 MakePage.py <page>
ou encore plus simplement, si le fichier est exécutable,
./MakePage.py <page>
grâce au shebang #!/usr/bin/env python3
du début du fichier.
Il est aussi possible d’utiliser pyzo et de se placer le shell python dans ce même répertoire avec
import os
os.chdir(localDir)
Pour créer une nouvelle page page.html
, il faut :
site.config
;page.py
dans squelette
;page
où trouver les fichiers propres à la page ;site
après avoir supprimé tous les fichiers HTML de web
).Une page peut être structurée sous la forme :
rubrique
|-- section
| |-- subsection
rubrique(nom)
Crée une nouvelle rubrique.
section(nom)
Crée une nouvelle section.
subsection(nom)
Crée une nouvelle sous-section.
Pour faciliter la lisibilité des fichiers du squelette, on indentera autant de fois que le niveau hiérarchique, par exemple :
rubrique("PTSI1")
section("Section 1")
pdf("Nom","fichier.pdf")
section("Section 2")
subsection("Sous-section 2.1")
pdf("Nom","fichier.pdf")
Pour ajouter un document, il faut utiliser une des fonctions du tableau suivant.
Type de document | Fonction | Syntaxe |
---|---|---|
Fichier PDF | pdf |
pdf(nom, fichier) |
Présentation | pres |
pres(nom, fichier) |
Fichier texte | text |
text(nom, fichier) |
Document word | docx |
docx(nom, fichier) |
Archive | zip |
zip(nom, fichier) |
Image | image |
image(nom, fichier) |
Son | son |
son(nom, fichier) |
Vidéo | video |
video(nom, fichier) |
Code | code |
code(nom, fichier) |
Code python | pycode |
pycode(nom, fichier) |
Pour ajouter un fichier PDF, on écrira donc
pdf("Nom du document visible sur le site", "repertoire/fichier")
Bien vérifier que le document ajouté sur le fichier du squelette, figure bien dans :
web
|-- rep_page >>> voir `docdir("rep_page")`
|-- repertoire
|-- fichier
Il est possible d’écrire en HTML dans les fichiers du squelette. Pour cela, il suffit de le spécifier entre 2 balises <html>
et </html>
, chacune seule sur une ligne.
subsection("Ressources bibliographiques")
<html>
<ul>
<li><a href="http://arxiv.org/">arXiv</a></li>
<li><a href="https://hal.archives-ouvertes.fr/">HAL</a></li>
<li><a href="https://tel.archives-ouvertes.fr/">TEL</a></li>
</ul>
</html>
sep()
La fonction sep()
permet de faire une coupure propre avec une remise à zéro des flottants (icônes des fichiers et noms).
section_CI(ID, nom)
Crée une nouvelle section, affichage tiers de page sur grand écran. Pour présenter les supports associés à un centre d’intérêt
subsection("Centres d'intérêts")
section_CI("refCI","Nom et description du CI")
section_TP(ID, nom)
Crée une nouvelle section, affichage avec tableau pour TP.
SII_TP(systeme, sujet, DR="", sysML="", complement="")
Pour les sujets de TP, incluant les document ressources, modèle sysML et compléments éventuels.
SII_TP_Avenir()
Pour laisser le nom d’une série sans faire figurer de système et donc de document.
section_TP("TPxx","Série n°xx – Titre de la série")
SII_TP("Nom du système","TPxx/sujet.pdf", \
"TPxx/doc-ressources.pdf","TPxx/sysML.zip")
SII_TP("Nom du système","TPxx/sujet.pdf", \
"TPxx/doc-ressources.pdf","TPxx/sysML.zip", \
["TPxx/complement1.pdf", "TPxx/complement2.pdf"])
section_TP("TPxx","Série n°xx – Titre de la série")
SII_TP_Avenir()
planche(nom, description, sujet, complement, corrige)
Pour les sujets et corrigés de préparation à l’épreuve de planche
rubrique("Planches")
planche("Planche n°x","Titre de la planche", \
"sujet.pdf","","corrige.pdf")
planche("Planche n°x","Titre de la planche", \
"sujet.pdf","complement.pdf","corrige.pdf")
info_cours(nom, description, fichier)
Pour les cours d’informatique
rubrique("Cours")
info_cours_init()
info_cours("Nom","Description longue","fichier.pdf")
info_cours_close()
info_TP(num, sujet, complement="",corrige="")
Pour les TP d’informatique où l’on veut souvent publier le sujet avant son corrigé, avec d’éventuels compléments. Les arguments complement
(liste du type ["nom", "fichier"]
) et corrige
sont optionnels. Par exemple, on peut écrire :
rubrique("TP")
info_TP_init()
info_TP("01", "Info-TP01_sujet.pdf","","Info-TP01_corrige.pdf")
info_TP("02", "Info-TP02_sujet.pdf",\
["Complément","Info-TP02_complement.zip"],Info-TP02_corrige.pdf")
info_TP("03", "Info-TP03_sujet.pdf")
info_TP_close()