CAW1 2017 Projet de Quentin de LONGRAYE et Victor LE

De Ensiwiki
Aller à : navigation, rechercher

Compilio est un service de compilation en ligne permettant de compiler des fichiers en lignes de commandes. La compilation peut être faite depuis le site par Drag & Drop ou depuis une machine source. Le processus de compilation est exécuté sur un serveur distant puis le résultat est retourné sur la machine source ou sur le site.

Project schedule.png
Titre du projet Compilio
Cadre Appli web

Équipe Victor Le Quentin de Longraye
Encadrants Sebastien Viardot


Présentation du projet

Voir également les fichiers README.md pour chaque projet sur GitHub.

Organisation du projet

Le site est développé en agilité, avec des déploiements fréquents sur un RaspberryPi (sous l'OS Raspbian).

Technologies utilisées

Le site est développé avec Django 1.11 (Python 3.5). Il utilise également NodeJS 6 avec Webpack pour la gestion des assets (compilation SCSS, ES6, ...) et VueJS pour certaines parties dynamiques du site. Nous avons créé notre propre API en utilisant Sanic.

Fonctionnalités attendues

  • ✔ Compiler des fichiers en ligne de commandes ou par drag & drop
  • ✔ Se créer un compte: Compilio gère l'inscription
  • ✔ Se connecter: Compilio gère l'authentification
  • ✔ Suivre ses tâches de compilation en cours: L'utilisateur peut suivre ses tâches de compilation en cours et passées s'il possède un compte
  • ✔ Proposer plusieurs rôles pour les utilisateurs (pour une utilisation avancée de la sécurité): Deux modes de sécurité existent pour les utilisateurs s'ils sont anonymes (tâches publiques sauvegardées pendant la session courange) ou connectés (tâches privées liées à l'utilisateur connecté)
  • ✔ Mise en place d'un flux RSS pour le suivi des tâches de compilation: Les utilisateurs peuvent s'abonner aux tâches de compilation exécutées sur le site

Besoins techniques :

  • ✔ Pouvoir utiliser le site sur toutes les tailles d'écran
  • ✔ Tests unitaires
  • ✔ Tests fonctionnels
  • ✔ Utilisation de webservices (compilio-runner)
  • ✔ Utilisation d'un framework frontend : VueJS

Cas d'utilisation

Les fichiers *.feature dans le dossier ./functional/features spécifient déjà une partie des fonctionnalités de l'application. Voir la section Tests ci-dessous.

En plus de la connexion, de l'inscription et de la navigation "basique", les utilisateurs doivent pouvoir compiler leurs fichiers. Pour cela, plusieurs cas classiques ont été identifiés.

  • Compilation simple

Un utilisateur doit pouvoir, en arrivant sur Compilio, ajouter un fichier et cliquer sur le compilateur de son choix qui doit alors lancer la compilation du fichier en question. Il est redirigé sur une page affichant l'état d'avancement de la compilation. Le fichier une fois compilé peut être téléchargé.

L'utilisateur peut également, après avoir installé compilio-cli (pip install compilio-cli), lancer une compilation, par exemple compilio -- pdflatex fichier.tex. Un lien lui est donné pour qu'il puisse également voir la tâche sur le site (et verrouiller l'accès). À la fin de la compilation, le fichier compilé est immédiatement téléchargé sur son ordinateur.

  • Sauvegarder ses tâches de compilation

Un utilisateur doit pouvoir sauvegarder ses tâches de compilation. Pour cela, deux cas de figure sont possibles.

Si l'utilisateur n'est pas connecté, ses tâches sont sauvegardées uniquement pour la session courante et ne seront plus listés dans sa liste de tâches s'il quitte son navigateur et revient ultérieurement. Ces tâches ne sont donc pas liées à un utilisateur particulier et il est possible de partager leur lien. Tout utilisateur non connecté peut visualiser la tâche. Si un utilisateur connecté affiche la tâche, alors celle-ci est associé à cet utilisateur et la tâche devient privée ; seul cet utilisateur pourra la voir désormais.

Si l'utilisateur est connecté, la tâche est immédiatement associée à son compte et aucun utilisateur autre que lui ne pourra la visionner.

  • Supprimer ses tâches

Frontend

Le frontend est fourni par l'application Django (les vues sont générées par le système de templating traditionnel). Certaines parties fortement dynamique côté client sont construite à l'aide du framework VueJS, comme par exemple la zone de drag & drop ou l'affichage de la trace d'exécution des tâches en cours.

Le frontend est construit avec la grille bootstrap (individuelle) ainsi que Normalize.css pour s'assurer d'un rendu uniforme sur tous les navigateurs.

Organisation des templates

Les templates principaux sont stockés dans le dossier ./compilio/templates. On retrouve la structure de base des pages ainsi que la définition du header et du footer. Différents blocs sont définis et utilisés, on retiendra principalement le bloc intro contenant le texte d'introduction des pages du site, et le bloc content du contenu principal de la page.

Ce template de base est ensuite étendu, par exemple dans ./compilio/compiler/templates avec la page d'accueil du site dans index.html. Les différents blocs sont utilisés ou étendus par héritage de templates.

Utilisation de modules NodeJS

Le frontend est, en dehors des templates classiques compilées par Django, géré par NodeJS qui se charge d'appeler des modules en charge de compiler le code scss (Sass) et le code Javascript écrit en suivant le standard ES6 (afin de le rendre compatible avec les navigateurs actuels qui ne supportent pas pleinement ce standard) en utilisant BabelJS.

Les modules NodeJS utilisés sont décrits dans le fichier package.json à la racine.

Pour pouvoir afficher correctement le contenu du site, il est nécessaire de lancer au choix :

  • Le webpack-dev-server (via la commande npm run server qui se chargera de compiler les fichiers à la volée lors de leur modification (et de recharger automatiquement le code concerné sur la page courante) et de les exposer via un serveur web simple. Il n'est utilisé qu'en développement.
  • webpack (via la commande npm run compile) permet de compiler les fichiers et de les stocker dans le dossier ./compilio/static/assets.

En production, le fichier ./compilio/settings.py est modifié (STATIC_URL) pour que les fichiers statiques soient récupérés dans ce dossier et non sur le webpack-dev-server.

Webpack va automatiquement récupérer le contenu du fichier webpack.config.babel.js qui décrit son mode de fonctionnement (et en particulier les chargeurs qui doivent être utilisés en fonction du type de fichier, et la destination de la compilation).

L'application dispose de trois points d'entrés dans ./compilio/static/js : main, drop et task. Ces deux derniers seront décrits dans la section suivante.

main est en charge de gérer tout le code javascript et css nécessaire au bon fonctionnement de l'ensemble des pages. En particulier, il va charger le fichier global.scss qui est le point d'entrée du code Sass. Le main charge également la grille Bootstrap (uniquement ; le reste des fonctionnalités de Bootstrap n'est pas utilisé), Font Awesome ainsi que normalize.css qui permet de normaliser l'affichage sur tous les navigateurs en supprimant les marges par défaut, l'espacement entre les lignes, ...

Utilisation de VueJS

L'application utilise également VueJS pour la gestion du comportement du formulaire présent sur la page d'accueil (drag & drop) ainsi que l'affichage dynamique de la trace de compilation, actualisée en Ajax (en utilisant la bibliothèque Javascript Axios) toutes les trois secondes.

Pour la gestion du drag & drop, un deuxième point d'entrée drop a été créé dans le fichier drop.js. Ce point d'entrée a pour responsabilité de charger VueJS et d'initialiser le module principal nommé Drop. Tous les modules VueJS sont stockés dans le dossier ./compilio/static/js/modules. Le module principal appelé Drop est attaché à la div de la page d'accueil ayant d'id drop-area.

Drop repose lui-même sur deux autres modules : DropArea qui gère la zone de drag & drop et CompilerList qui liste les compilateurs disponibles. Chaque compilateur est affiché en utilisant le module Compiler.

Chaque module est stocké dans un fichier .vue qui regroupe le code html nécessaire à l'affichage (certaines balises pouvant être utilisées pour appeler d'autres modules), le code javascript en charge d'effectuer certaines actions en fonction des actions de l'utilisateur et du chargement d'autres modules, et enfin de code Sass propre au module qui sera lié (scoped) au module en question.

Ceci permet d'assurer la réutilisabilité des modules, le découpage est donc important.

Le troisième module, task.js est relativement simple et ne se charge que d'actualiser la trace d'exécution.

Backend

Structure

L'application Django se divise en deux principaux modules :

  • compiler : en charge de la gestion de l'essentiel du code métier de l'application
  • user : en charge des pages permettant l'inscription et la connexion des utilisateurs

Le frontend web utilise l'API compiler du serveur Django pour l'envoi des fichiers et la sélection de la commande. L'application CLI utilise cette même API.

Le modèle de données se découpe de la manière suivante :

Modèle de données Compilio.png

Le module compiler parse la commande et détermine les fichiers à envoyer par le client. Une fois les fichiers d'entrées reçus, il envoie la tâche à éxecuter au premier runner disponible.

Diagramme séquence Compilio.png

Pour cela, les runners disposent de leur propre API leur permettant d'être appelés par Compilio. L'exécution de la tâche est ensuite programmée sur le serveur du runner, les logs sont transmis en direct au client. Une fois la tâche terminé, le module compiler récupère le résultat et le sauvegarde. L'utilisateur est ensuite notifié par la terminaison, et peut télécharger ses fichiers.

Tests

Les tests sont lancés sur Travis CI (voir le fichier .travis.yml à la racine du projet). Deux types de tests ont été mis en place.

Tests unitaires

L'application utilise les fonctionnalités de test unitaires standards de Django. Les tests unitaires sont stockés dans les fichiers ./tests.py des différents modules.

Pour lancer les tests unitaires, utiliser la commande python manage.py test.

Tests fonctionnels

L'application est également testée en utilisant Selenium (via le ChromeDriver), avec une surcouche fournie par le paquet Behave permettant d'écrire le code de test sous la forme de spécifications fonctionnelles.

La structure des tests est la suivante :

  1. Dans ./functional/features se trouvent les fichiers spécifiant l'application (dans des fichiers d'extension .feature). Ces fichiers suivent la syntaxe Gherkin présentée sur le site Cucumber.io. Cette syntaxe permet de décrire les fonctionnalités d'une application sous la forme de spécifications fonctionnelles interprétables et exécutables.
  2. Pour pouvoir exécuter les différentes étapes du fichier .feature, un fichier doit décrire le code à exécuter. Il est stocké dans ./functional/features/steps. Pour une expression donnée, le code définissant l'implémentation doit être exécuté (avec d'éventuelles assertions).
  3. Pour pouvoir utiliser Selenium convenablement, il est nécessaire de le lancer correctement. Pour cela, on utilise le fichier ./functional/features/environment.py qui définit les commandes à exécuter avant chaque scénario et l'ensemble des tests (en particulier lancer le webdriver Chrome, on pourrait aussi utiliser Gecko pour lancer les tests sous Firefox.

Pour lancer les tests fonctionnels, utiliser la commande python manage.py test functional.

Validation continue

Le projet est validé continuellement (à chaque push) par TravisCI. Voir le résultat des builds sur Travis.

Tests frontend

L'application n'est pas testée côté frontend mais le respect des bonnes pratiques est vérifié (le code doit suivre les règles décrites par StandardJS).

Deux commandes sont disponibles, elles sont définies dans le fichier package.json, dans la section script.

  • npm run lint permet de vérifier que le code Javascript respecte les règles de syntaxe du projet
  • npm run lint:fix permet de corriger automatiquement les erreurs de syntaxe trouvées

Bilan

Ce projet nous a permis d'expérimenter de nombreuses possibilités offertes aux développeurs Python, de la création d'une application web aux APIs en passant par un client publié sur PyPI et qui peut donc être installé sur n'importe quel système.

L'application mériterait désormais à s'etoffer en fonctionnalités (pour pouvoir ajouter des runners via une interface dédiée) ainsi que quelques améliorations ergonomiques et de sécurité (envoi d'emails pour valider l'identité de l'utilisateur, systèmes anti-spam, antivirus ...).