|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Commande d'execution …
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace autodoc\Helpers;
|
|
|
|
|
|
|
|
|
|
use Symfony\Component\Console\Input\InputInterface;
|
|
|
|
|
use Symfony\Component\Console\Input\StringInput;
|
|
|
|
|
use Symfony\Component\Console\Input\ArgvInput;
|
|
|
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
|
|
|
use autodoc\Application as Autodoc;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exécuter l'application…
|
|
|
|
|
*/
|
|
|
|
|
class Generator
|
|
|
|
|
{
|
|
|
|
|
private $input;
|
|
|
|
|
private $output;
|
|
|
|
|
private $autoloader;
|
|
|
|
|
|
|
|
|
|
private $dirs = array();
|
|
|
|
|
private $files = array();
|
|
|
|
|
private $svn = array(); // informations sur le dépot SVN
|
|
|
|
|
private $options = array('dirs' => array()); // forcer des répertoires en dehors des options de ligne de commande
|
|
|
|
|
private $commands = array(); // forcer des commandes spécifiques à phpdocumentor
|
|
|
|
|
|
|
|
|
|
// les infos de plugins sont enregistrées dedans pour l'index.html de la commande generateFromFile()
|
|
|
|
|
private $infos_plugins = array();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Description de la documentation à générer
|
|
|
|
|
* @var string $description */
|
|
|
|
|
private $description = "";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Présentation de la documentation à générer
|
|
|
|
|
* @var string $presentation */
|
|
|
|
|
private $presentation = "";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructeur
|
|
|
|
|
*
|
|
|
|
|
* @param InputInterface $input
|
|
|
|
|
* @param OutputInterface $output
|
|
|
|
|
**/
|
|
|
|
|
public function __construct(InputInterface $input, OutputInterface $output, $autoloader = null)
|
|
|
|
|
{
|
|
|
|
|
$this->input = $input;
|
|
|
|
|
$this->output = $output;
|
|
|
|
|
$this->autoloader = $autoloader;
|
|
|
|
|
|
|
|
|
|
$this->setApplicationDirectories();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Obtient le chemin d'un executable sur le serveur.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* ```
|
|
|
|
|
* $cmd = $this->obtenir_commande_serveur('svn');
|
|
|
|
|
* if ($cmd)
|
|
|
|
|
* exec("$cmd ... ... ");
|
|
|
|
|
* }
|
|
|
|
|
* ```
|
|
|
|
|
* @param string $command
|
|
|
|
|
* Nom de la commande
|
|
|
|
|
* @return string
|
|
|
|
|
* Chemin de la commande
|
|
|
|
|
**/
|
|
|
|
|
public function obtenir_commande_serveur($command) {
|
|
|
|
|
static $commands = array();
|
|
|
|
|
if (array_key_exists($command, $commands)) {
|
|
|
|
|
return $commands[$command];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exec("command -v $command", $output, $err);
|
|
|
|
|
if (!$err and count($output) and $cmd = trim($output[0])) {
|
|
|
|
|
return $commands[$command] = $cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->output->writeln("<error>Commande '$command' introuvable sur ce serveur…</error>");
|
|
|
|
|
return $commands[$command] = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer la documentation à partir du SVN de SPIP
|
|
|
|
|
*
|
|
|
|
|
* Retrouve le nom de la version utilisée et s'en sert de titre.
|
|
|
|
|
*
|
|
|
|
|
* @param string $chemin Chemin dans le svn
|
|
|
|
|
**/
|
|
|
|
|
public function generateFromSpip($chemin) {
|
|
|
|
|
$core = "svn://trac.rezo.net/spip/$chemin";
|
|
|
|
|
|
|
|
|
|
$prefixe = $this->input->getOption('prefixe');
|
|
|
|
|
$ok = $this->createDirectories($prefixe)
|
|
|
|
|
&& $this->getSvnSource($core);
|
|
|
|
|
|
|
|
|
|
if (!$ok) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$titre = "";
|
|
|
|
|
if ($this->input->hasOption('titre')) {
|
|
|
|
|
$titre = $this->input->getOption('titre');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retrouver la version de SPIP
|
|
|
|
|
if (!$titre and file_exists($inc_version = $this->dirs['input'] . '/ecrire/inc_version.php')) {
|
|
|
|
|
$inc_version = file_get_contents($inc_version);
|
|
|
|
|
if (preg_match('/spip_version_branche = "([^"]+)";/', $inc_version, $res)) {
|
|
|
|
|
$titre = "SPIP " . $res[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($titre) {
|
|
|
|
|
$this->setCommand('title', $titre);
|
|
|
|
|
$this->setOption('titre', $titre);
|
|
|
|
|
$this->setOption('description', "Documentation du code PHP de " . $titre);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->generateFromDirectory($this->dirs['input'], true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer la documentation à partir du SVN de la Zone de SPIP
|
|
|
|
|
*
|
|
|
|
|
* @param string $chemin Chemin dans le svn
|
|
|
|
|
**/
|
|
|
|
|
public function generateFromZone($chemin) {
|
|
|
|
|
$zone = "svn://zone.spip.org/spip-zone/$chemin";
|
|
|
|
|
return $this->generateFromSvn($zone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer la documentation à partir d'une url SVN
|
|
|
|
|
*
|
|
|
|
|
* @param string $source URL SVN
|
|
|
|
|
**/
|
|
|
|
|
public function generateFromSvn($source) {
|
|
|
|
|
$prefixe = $this->input->getOption('prefixe');
|
|
|
|
|
$ok = $this->createDirectories($prefixe)
|
|
|
|
|
&& $this->getSvnSource($source)
|
|
|
|
|
&& $this->generateFromDirectory($this->dirs['input'], true);
|
|
|
|
|
return $ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer la documentation à partir d'un répertoire indiqué
|
|
|
|
|
*
|
|
|
|
|
* @param string $dir Chemin du répertoire source
|
|
|
|
|
* @param bool $is_ready
|
|
|
|
|
* Indique si les préparatifs (création des répertoires) sont déjà faits
|
|
|
|
|
**/
|
|
|
|
|
public function generateFromDirectory($dir, $is_ready = false) {
|
|
|
|
|
$prefixe = $this->input->getOption('prefixe');
|
|
|
|
|
$ok = true;
|
|
|
|
|
|
|
|
|
|
if (!$is_ready) {
|
|
|
|
|
# forcer le chemin de la source spécifique
|
|
|
|
|
$this->options['dirs']['input'] = $dir;
|
|
|
|
|
$ok = $this->createDirectories($prefixe);
|
|
|
|
|
if (!$ok) return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->retrouverInfoPaquetXml();
|
|
|
|
|
|
|
|
|
|
$ok = $this->prepareConfigXml()
|
|
|
|
|
&& $this->clearLogs()
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
if (!$ok) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->execute();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer la documentation à partir d'un fichier listant les documentations à exécuter
|
|
|
|
|
*
|
|
|
|
|
* On duplique le fichier chez soi et on gère une rotation de ce fichier à chaque lancement
|
|
|
|
|
* afin de supprimer les documentations devenues inutiles (disparues du nouveau fichier).
|
|
|
|
|
*
|
|
|
|
|
* @param string $file Chemin du fichier ou URL SVN
|
|
|
|
|
**/
|
|
|
|
|
public function generateFromFile($file) {
|
|
|
|
|
|
|
|
|
|
$timerStart = microtime(true);
|
|
|
|
|
|
|
|
|
|
// Option boussole SPIP => topnav.
|
|
|
|
|
if ($this->getOption('avec_boussole_spip')) {
|
|
|
|
|
$this->setOption('topnav', '//boussole.spip.net/?page=spipnav.js&lang=fr');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// si un prefixe spécifique de plugin est indiqué,
|
|
|
|
|
// seul lui sera actualisé dans la liste des plugins.
|
|
|
|
|
// et on considère que le fichier autodoc.txt n'a pas bougé dans le cas.
|
|
|
|
|
$prefixe = $this->getOption('prefixe', null);
|
|
|
|
|
|
|
|
|
|
// définir les chemins et faire tourner le backup précédent
|
|
|
|
|
$this->files['autodoc.txt'] = $this->dirs['work'] . '/autodoc.txt';
|
|
|
|
|
$this->files['autodoc.txt.bak'] = $this->files['autodoc.txt'] . '.bak';
|
|
|
|
|
|
|
|
|
|
// à quel endroit sont générées les documentation des fichiers
|
|
|
|
|
$output_base = $this->input->getOption('sorties');
|
|
|
|
|
if (!$output_base) {
|
|
|
|
|
$output_base = $this->dirs['work'] . '/output';
|
|
|
|
|
}
|
|
|
|
|
$this->setOption('site', '../index.html');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($prefixe) {
|
|
|
|
|
// autodoc.txt est censé être déjà là
|
|
|
|
|
$this->output->writeln("* Lecture des informations du fichier (sans l'actualiser)");
|
|
|
|
|
$presents = $this->parseFile($this->files['autodoc.txt']);
|
|
|
|
|
// ne conserver que ce prefixe
|
|
|
|
|
$presents = array_intersect_key($presents, array($prefixe => ''));
|
|
|
|
|
} else {
|
|
|
|
|
// autodoc.txt doit être téléchargé ou mis à jour
|
|
|
|
|
$this->actualiser_liste_source($file);
|
|
|
|
|
|
|
|
|
|
$this->output->writeln("* Lecture des informations du fichier");
|
|
|
|
|
$anciens = $this->parseFile($this->files['autodoc.txt.bak'], false);
|
|
|
|
|
$presents = $this->parseFile($this->files['autodoc.txt']);
|
|
|
|
|
|
|
|
|
|
if ($anciens) {
|
|
|
|
|
$absents = array_diff_key($anciens, $presents);
|
|
|
|
|
$this->supprimer_vieux_plugins($absents);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$nb_erreur = 0;
|
|
|
|
|
$nb_update = 0;
|
|
|
|
|
|
|
|
|
|
foreach ($presents as $_prefixe => $description) {
|
|
|
|
|
$ok = $this->obtenir_fichiers_a_documenter($_prefixe, $description);
|
|
|
|
|
if ($ok) {
|
|
|
|
|
$nb_update++;
|
|
|
|
|
$this->execute();
|
|
|
|
|
} elseif ($ok === false) {
|
|
|
|
|
$nb_erreur++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->output->writeln("\n");
|
|
|
|
|
if ($nb_erreur) {
|
|
|
|
|
$this->output->writeln("<comment>$nb_erreur documentation(s) non générée(s) sur " . count($presents) . ".</comment>");
|
|
|
|
|
} else {
|
|
|
|
|
$this->output->writeln("<comment>Documentations générées : " . $nb_update . " / " . count($presents) . ".</comment>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// générer la page sommaire (si pas uniquement 1 seul prefixe actualisé
|
|
|
|
|
if (!$prefixe) {
|
|
|
|
|
$this->generer_sommaire_documentations($presents, $output_base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->output->writeln(sprintf("%-'-81s", ""));
|
|
|
|
|
$this->output->write(sprintf('%-68.68s .. ', "Temps total"));
|
|
|
|
|
$this->output->writeln(sprintf('%8.3fs', microtime(true) - $timerStart));
|
|
|
|
|
$this->output->writeln("Fin");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Télécharge ou actualise les fichiers d'une documentation
|
|
|
|
|
*
|
|
|
|
|
* Si la mise à jour ne modifie pas les fichiers,
|
|
|
|
|
* la documentation n'est pas à actualiser (retourne null).
|
|
|
|
|
*
|
|
|
|
|
* @param string $prefixe
|
|
|
|
|
* Préfixe de cette documentation
|
|
|
|
|
* @param array $description
|
|
|
|
|
* Description. La clé 'source' a l'url SVN
|
|
|
|
|
* @return bool|null
|
|
|
|
|
* - True si OK et mise à jour à faire.
|
|
|
|
|
* - null : ok, mais mise à jour inutile
|
|
|
|
|
* - False : erreur
|
|
|
|
|
**/
|
|
|
|
|
public function obtenir_fichiers_a_documenter($prefixe, $description) {
|
|
|
|
|
$this->output->writeln("\n");
|
|
|
|
|
$titre = "Générer la documentation de $prefixe";
|
|
|
|
|
$this->output->writeln("<comment>$titre</comment>");
|
|
|
|
|
$this->output->writeln("<comment>" . str_repeat("-", strlen($titre)) . "</comment>");
|
|
|
|
|
|
|
|
|
|
if (!$this->createDirectories($prefixe)) {
|
|
|
|
|
$this->output->writeln("<error>* Documentation ignorée à cause d'une erreur.</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$revision_actuelle = $this->recuperer_revision_svn();
|
|
|
|
|
if (!$this->getSvnSource($description['source'])) {
|
|
|
|
|
$this->output->writeln("<error>* Documentation ignorée à cause d'une erreur.</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ces options sont créées par retrouverInfoPaquetXml() SI elles n'existent pas.
|
|
|
|
|
// il faut les nettoyer à chaque passage !
|
|
|
|
|
$this->setOption('titre', null);
|
|
|
|
|
$this->setOption('description', null);
|
|
|
|
|
$this->setOption('presentation', null);
|
|
|
|
|
|
|
|
|
|
// Retrouver les informations de paquet.xml
|
|
|
|
|
if (!$this->retrouverInfoPaquetXml()) {
|
|
|
|
|
$this->output->writeln("<error>* Documentation ignorée : paquet.xml introuvable.</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pas besoin de mettre à jour, si l'update n'a pas augmenté la révision
|
|
|
|
|
$revision_nouvelle = $this->recuperer_revision_svn();
|
|
|
|
|
if ($revision_nouvelle <= $revision_actuelle) {
|
|
|
|
|
$this->output->writeln("* Documentation déjà à jour.");
|
|
|
|
|
// sauf si on le force explicitement
|
|
|
|
|
if (!$this->getOption('force')) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$ok = $this->prepareConfigXml() && $this->clearLogs();
|
|
|
|
|
|
|
|
|
|
if (!$ok) {
|
|
|
|
|
$this->output->writeln("<error>* Documentation ignorée à cause d'une erreur.</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Générer le sommaire des documentations réalisés à partir d'un fichier source d'url
|
|
|
|
|
*
|
|
|
|
|
* @param array $presents
|
|
|
|
|
* Liste des plugins du fichier
|
|
|
|
|
* @param string $outut_base
|
|
|
|
|
* Répertoire où on été enregistré les documentations
|
|
|
|
|
* @return
|
|
|
|
|
**/
|
|
|
|
|
public function generer_sommaire_documentations($presents, $output_base) {
|
|
|
|
|
|
|
|
|
|
// générer un sommaire de toutes ces documentations
|
|
|
|
|
$this->output->writeln("Création du sommaire des documentations");
|
|
|
|
|
|
|
|
|
|
// ajouter les dépendances du fichier html
|
|
|
|
|
if (!is_dir($data = $output_base . '/__data')) {
|
|
|
|
|
mkdir($data);
|
|
|
|
|
$template = $this->dirs['template'];
|
|
|
|
|
foreach (array('bootstrap', 'images', 'css', 'js') as $dir) {
|
|
|
|
|
exec("cp -r '$template/$dir' '$data/$dir'");
|
|
|
|
|
}
|
|
|
|
|
copy("$template/favicon.png", "$output_base/favicon.png");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (file_exists($index = "$output_base/index.html")) {
|
|
|
|
|
unlink($index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtenir les description des plugins
|
|
|
|
|
$plugins = array();
|
|
|
|
|
foreach ($presents as $prefixe => $present) {
|
|
|
|
|
if (isset($this->infos_plugins[$prefixe])) {
|
|
|
|
|
$plugins[$prefixe] = $this->infos_plugins[$prefixe];
|
|
|
|
|
} else {
|
|
|
|
|
// ce n'était pas un plugin ou erreur
|
|
|
|
|
$plugins[$prefixe] = array(
|
|
|
|
|
'prefixe' => $prefixe,
|
|
|
|
|
'nom' => $prefixe,
|
|
|
|
|
'slogan' => '',
|
|
|
|
|
'description' => '',
|
|
|
|
|
'annuaire' => '',
|
|
|
|
|
'documentation' => '',
|
|
|
|
|
'developpement' => '',
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
usort($plugins, function($a, $b) {
|
|
|
|
|
return ($a['nom'] < $b['nom']) ? -1 : 1;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// charger Twig, générer la page et l'enregitrer
|
|
|
|
|
$loader = new \Twig_Loader_Filesystem( $this->dirs['helper'] . '/Template' );
|
|
|
|
|
$twig = new \Twig_Environment($loader);
|
|
|
|
|
|
|
|
|
|
$topnav = $this->getOption('topnav', '');
|
|
|
|
|
|
|
|
|
|
$content = $twig->render('index.html', array(
|
|
|
|
|
'titre' => 'Documentation automatique des plugins SPIP',
|
|
|
|
|
'plugins' => $plugins,
|
|
|
|
|
'topnav' => $topnav,
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
file_put_contents($index, $content);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Télécharge la source de liste des documentations à faire dans autodoc.txt
|
|
|
|
|
* et fait une rotation avec l'ancienne liste
|
|
|
|
|
*
|
|
|
|
|
* @param strig $file
|
|
|
|
|
* URL du fichier source (svn) de la liste des docémentations à générer
|
|
|
|
|
* @return bool True si ok.
|
|
|
|
|
**/
|
|
|
|
|
public function actualiser_liste_source($file) {
|
|
|
|
|
// supprimer l'ancienne rotation
|
|
|
|
|
if (file_exists( $this->files['autodoc.txt.bak'] )) {
|
|
|
|
|
unlink($this->files['autodoc.txt.bak']);
|
|
|
|
|
}
|
|
|
|
|
// rotation
|
|
|
|
|
if (file_exists( $this->files['autodoc.txt'] )) {
|
|
|
|
|
copy($this->files['autodoc.txt'], $this->files['autodoc.txt.bak']);
|
|
|
|
|
unlink($this->files['autodoc.txt']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// copier le fichier de liste chez soi
|
|
|
|
|
if (0 === strpos($file, 'svn://')) {
|
|
|
|
|
$this->output->write("* Obtenir <info>$file</info> ");
|
|
|
|
|
|
|
|
|
|
// si c'est en svn, on l'exporte simplement.
|
|
|
|
|
if ($res = $this->makeSvnCommand("export $file autodoc.txt", true, $this->dirs['work'])) {
|
|
|
|
|
$this->output->writeln("[<info>OK</info>]");
|
|
|
|
|
} else {
|
|
|
|
|
$this->output->writeln("[<info>Error</info>]");
|
|
|
|
|
throw new \Exception("Impossible de récupérer le fichier SVN : $file");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (file_exists($file)) {
|
|
|
|
|
copy($file, $this->files['autodoc.txt']);
|
|
|
|
|
} else {
|
|
|
|
|
throw new \Exception("Impossible de trouver le fichier : $file");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Effacte une ou plusieurs documentations qui ne sont plus listés
|
|
|
|
|
* dans la description du fichier autodoc.txt
|
|
|
|
|
*
|
|
|
|
|
* @param array $absents
|
|
|
|
|
* Liste [ prefixe => url ]
|
|
|
|
|
* @return bool
|
|
|
|
|
* True si au moins une documentation, et ses caches, ont été effacés.
|
|
|
|
|
**/
|
|
|
|
|
public function supprimer_vieux_plugins($absents) {
|
|
|
|
|
if ($absents) {
|
|
|
|
|
$this->output->writeln("<comment>Certaines documentations ne sont plus à générer.</comment>");
|
|
|
|
|
foreach ($absents as $prefixe=>$absent) {
|
|
|
|
|
$this->output->writeln("<comment>- Effacement de $prefixe.</comment>");
|
|
|
|
|
$this->deleteDirectoryContent($output_base . '/$prefixe', true);
|
|
|
|
|
$this->deleteDirectoryContent($this->dirs['work'] . 'log/$prefixe', true);
|
|
|
|
|
$this->deleteDirectoryContent($this->dirs['work'] . 'input/$prefixe', true);
|
|
|
|
|
$this->deleteDirectoryContent($this->dirs['work'] . 'cache/$prefixe', true);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Analyse un fichier listant les documentations à générer.
|
|
|
|
|
*
|
|
|
|
|
* @param string $file Chemin du fichier
|
|
|
|
|
* @param bool $write_errors Ecrire les erreurs dans la console ?
|
|
|
|
|
* @return array|bool
|
|
|
|
|
* - false si echec,
|
|
|
|
|
* - couples (prefixe => array) sinon. Le tableau de description a les clés suivantes :
|
|
|
|
|
* - ligne : numéro de ligne
|
|
|
|
|
* - type : 'svn'
|
|
|
|
|
* - source : url du svn
|
|
|
|
|
**/
|
|
|
|
|
private function parseFile($file, $write_errors = true) {
|
|
|
|
|
if (!file_exists($file)) return false;
|
|
|
|
|
if (!$lines = file($file)) return false;
|
|
|
|
|
|
|
|
|
|
$liste = array();
|
|
|
|
|
foreach ($lines as $lineno => $line) {
|
|
|
|
|
if (!$line) continue;
|
|
|
|
|
$line = trim($line);
|
|
|
|
|
if (!$line OR $line[0] == '#') continue;
|
|
|
|
|
$couples = explode(';', $line);
|
|
|
|
|
$lineno++;
|
|
|
|
|
if (count($couples) != 2) {
|
|
|
|
|
if (count($couples) == 1) {
|
|
|
|
|
$this->output->writeln("<error>Ligne $lineno omise. Le préfixe ne semble pas défini. Contenu : $line</error>");
|
|
|
|
|
} else {
|
|
|
|
|
$this->output->writeln("<error>Ligne $lineno omise. Trop de paramètres indiqués. Contenu : $line</error>");
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list ($url, $prefixe) = $couples;
|
|
|
|
|
if (!$url) {
|
|
|
|
|
$this->output->writeln("<error>Ligne $lineno omise. L'URL ne semble pas définie. Contenu : $line</error>");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!$prefixe) {
|
|
|
|
|
$this->output->writeln("<error>Ligne $lineno omise. Le préfixe ne semble pas défini. Contenu : $line</error>");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (isset($liste[$prefixe])) {
|
|
|
|
|
$this->output->writeln("<error>Ligne $lineno omise. Le prefixe $prefixe est déjà déclaré ligne : " . $liste[$prefixe]['ligne'] . "</error>");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pas d'erreur !
|
|
|
|
|
$liste[$prefixe] = array(
|
|
|
|
|
'type' => 'svn',
|
|
|
|
|
'ligne' => $lineno,
|
|
|
|
|
'source' => $url
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return $liste;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Effacer le contenu du répertoire log.
|
|
|
|
|
*
|
|
|
|
|
* On ne gardera du coup que les logs de la prochaine exécution.
|
|
|
|
|
*
|
|
|
|
|
* @return bool true si réussi
|
|
|
|
|
**/
|
|
|
|
|
private function clearLogs() {
|
|
|
|
|
return $this->deleteDirectoryContent($this->dirs['log']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Définit les répertoires utiles à l'application
|
|
|
|
|
**/
|
|
|
|
|
private function setApplicationDirectories() {
|
|
|
|
|
# ce répertoire
|
|
|
|
|
$this->dirs['helper'] = realpath(__DIR__);
|
|
|
|
|
|
|
|
|
|
# executable php de l'application autodoc (extension de l'application phpdocumentor)
|
|
|
|
|
$this->dirs['bin'] = realpath( $this->dirs['helper'] . '/../../../bin');
|
|
|
|
|
|
|
|
|
|
# répertoire racine (celui depuis lequel on execute ce script).
|
|
|
|
|
exec('pwd', $output);
|
|
|
|
|
$this->dirs['root'] = $output[0];
|
|
|
|
|
|
|
|
|
|
# répertoire de travail (celui où on écrira tout).
|
|
|
|
|
$this->dirs['work'] = $this->dirs['root'] . '/work';
|
|
|
|
|
|
|
|
|
|
# répertoire du template zora
|
|
|
|
|
$this->dirs['template'] = realpath( $this->dirs['helper'] . '/../../../templates/zora');
|
|
|
|
|
|
|
|
|
|
# fichier de config xml pour phpdocumentor
|
|
|
|
|
$this->files['phpdoc.xml'] = $this->dirs['work'] . '/phpdoc.xml';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Définit et crée les répertoires nécessaires au fonctionnement de ce programme
|
|
|
|
|
*
|
|
|
|
|
* @param string $prefixe Préfixe utilisé pour cette génération
|
|
|
|
|
* @return bool true si réussi
|
|
|
|
|
**/
|
|
|
|
|
private function createDirectories($prefixe) {
|
|
|
|
|
$_work = $this->dirs['work'];
|
|
|
|
|
$this->output->writeln("* Vérifier/créer les répertoires de travail dans <info>$_work</info>");
|
|
|
|
|
|
|
|
|
|
# si un répertoire pour toutes les sorties est indiqué, forcer son utilisation.
|
|
|
|
|
if ($this->input->hasOption('sorties') and $dir_output = $this->input->getOption('sorties')) {
|
|
|
|
|
$this->setOption('dirs/output', $dir_output . "/$prefixe");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# si un répertoire de sortie est indiqué, forcer son utilisation.
|
|
|
|
|
if ($this->input->hasOption('sortie') and $dir_output = $this->input->getOption('sortie')) {
|
|
|
|
|
$this->setOption('dirs/output', $dir_output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (array('output', 'input', 'log', 'cache') as $dir) {
|
|
|
|
|
// valeur par défaut, en fonction du préfixe
|
|
|
|
|
$this->dirs[$dir] = "$_work/$dir/$prefixe";
|
|
|
|
|
|
|
|
|
|
// valeur forcée dans certains cas
|
|
|
|
|
if ($path = $this->getOption("dirs/$dir")) {
|
|
|
|
|
$this->dirs[$dir] = $path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (array('output', 'input', 'log', 'cache') as $dir) {
|
|
|
|
|
if (!$this->createDirectory( $this->dirs[$dir] )) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Créer un des répertoires d'utilisation
|
|
|
|
|
*
|
|
|
|
|
* Vérifie également que le répertoire est utilisable en écriture.
|
|
|
|
|
*
|
|
|
|
|
* @param string $chemin Répertoire à créer
|
|
|
|
|
* @return bool true si réussi
|
|
|
|
|
**/
|
|
|
|
|
private function createDirectory($dir) {
|
|
|
|
|
if (!is_dir($dir)) {
|
|
|
|
|
$this->output->writeln(" - Création du répertoire <info>$dir</info>");
|
|
|
|
|
|
|
|
|
|
if (!@mkdir($dir, 0755, true)) {
|
|
|
|
|
$this->output->writeln("<error>Impossible de créer le répertoire : $dir</error>");
|
|
|
|
|
$error = error_get_last();
|
|
|
|
|
$this->output->writeln($error['message']);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (!is_writable($dir)) {
|
|
|
|
|
$this->output->writeln("<error>Le répertoire $dir n'est pas accessible en écriture</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Télécharge ou met à jour la source SVN indiquée
|
|
|
|
|
*
|
|
|
|
|
* @param string $source URL de la source SVN
|
|
|
|
|
* @return bool true si réussi
|
|
|
|
|
**/
|
|
|
|
|
private function getSvnSource($source) {
|
|
|
|
|
$this->output->writeln("* Obtenir <info>$source</info>");
|
|
|
|
|
|
|
|
|
|
$this->svn = array();
|
|
|
|
|
|
|
|
|
|
// si c'est en svn et le bon, on fait svn up simplement.
|
|
|
|
|
if ($res = $this->makeSvnCommand('info --xml')) {
|
|
|
|
|
// nous avons un svn… verifions que c'est le bon !
|
|
|
|
|
$xml = simplexml_load_string(implode("", $res));
|
|
|
|
|
$source_actuelle = (string)$xml->entry->url;
|
|
|
|
|
|
|
|
|
|
if ($source_actuelle == $source) {
|
|
|
|
|
#$this->output->write("<comment> - Update </comment>");
|
|
|
|
|
|
|
|
|
|
if (!$res = $this->makeSvnCommand("update")) {
|
|
|
|
|
$this->output->writeln("<error>[Echec Update]</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$last = array_pop($res);
|
|
|
|
|
# $this->output->writeln("[<info>OK</info>] ($last)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// erreur, donc pas un dossier svn ou pas le bon
|
|
|
|
|
else {
|
|
|
|
|
// on nettoie le contenu pour svn co
|
|
|
|
|
$this->deleteDirectoryContent($this->dirs['input']);
|
|
|
|
|
|
|
|
|
|
#$this->output->write("<comment> - Checkout </comment>");
|
|
|
|
|
|
|
|
|
|
if (!$res = $this->makeSvnCommand("checkout $source .")) {
|
|
|
|
|
$this->output->writeln("<error>[Echec Checkout]</error>");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$last = array_pop($res);
|
|
|
|
|
if ($last) $last = "($last)";
|
|
|
|
|
|
|
|
|
|
# $this->output->writeln("<info>[OK]</info> $last");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// On récupère le numéro de dernière révision, ça peut servir
|
|
|
|
|
if ($revision = $this->recuperer_revision_svn()) {
|
|
|
|
|
$this->svn['revision'] = $revision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrouver le numéro de la dernière révision du dossier de travail
|
|
|
|
|
*
|
|
|
|
|
* @return string Numéro de révision (si connu)
|
|
|
|
|
**/
|
|
|
|
|
function recuperer_revision_svn() {
|
|
|
|
|
$revision = '';
|
|
|
|
|
|
|
|
|
|
// Ici, on a les bons fichiers SVN à jour
|
|
|
|
|
// on récupère le numéro de dernière révision
|
|
|
|
|
if ($res = $this->makeSvnCommand('info --xml')) {
|
|
|
|
|
// nous avons un svn… verifions que c'est le bon !
|
|
|
|
|
$xml = simplexml_load_string(implode("", $res));
|
|
|
|
|
$revision = (string)$xml->entry->commit['revision'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $revision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exécuter la commande svn indiquée
|
|
|
|
|
*
|
|
|
|
|
* @param string $cmd Commande SVN
|
|
|
|
|
* @param bool $no_error true : Envoie les erreurs dans /dev/null
|
|
|
|
|
* @return mixed|bool false en cas d'erreur
|
|
|
|
|
**/
|
|
|
|
|
private function makeSvnCommand($cmd, $no_error = true, $dir = null) {
|
|
|
|
|
if (is_null($dir)) {
|
|
|
|
|
$dir = $this->dirs['input'];
|
|
|
|
|
}
|
|
|
|
|
if (!$svn = $this->obtenir_commande_serveur('svn')) {
|
|
|
|
|
if (!$svn = $this->obtenir_commande_serveur('svnlite')) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
$this->output->writeln("<info>Commande 'svnlite' trouvée</info>");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$no_error = $no_error ? '2> /dev/null' : '';
|
|
|
|
|
|
|
|
|
|
exec("cd $dir && $svn $cmd $no_error", $res, $error);
|
|
|
|
|
if ($error) return false;
|
|
|
|
|
return $res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Suppression du contenu d'un repertoire.
|
|
|
|
|
*
|
|
|
|
|
* @link https://www.php.net/manual/en/function.rmdir.php#92050
|
|
|
|
|
*
|
|
|
|
|
* @param string $dir Chemin du repertoire
|
|
|
|
|
* @param string $delete_me Supprimer aussi le répertoire ?
|
|
|
|
|
* @return bool Suppression reussie.
|
|
|
|
|
*/
|
|
|
|
|
function deleteDirectoryContent($dir, $delete_me = false) {
|
|
|
|
|
if (!file_exists($dir)) return true;
|
|
|
|
|
if (!is_dir($dir) || is_link($dir)) return @unlink($dir);
|
|
|
|
|
|
|
|
|
|
foreach (scandir($dir) as $item) {
|
|
|
|
|
if ($item == '.' || $item == '..') continue;
|
|
|
|
|
if (!$this->deleteDirectoryContent($dir . "/" . $item, true)) {
|
|
|
|
|
@chmod($dir . "/" . $item, 0777);
|
|
|
|
|
if (!$this->deleteDirectoryContent($dir . "/" . $item, true)) return false;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($delete_me) {
|
|
|
|
|
return @rmdir($dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Obtient une option, soit de la ligne de commande, soit forcée par le générateur
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Nom de l'option
|
|
|
|
|
* @return mixed
|
|
|
|
|
**/
|
|
|
|
|
private function getOption($name, $default = null) {
|
|
|
|
|
if (strpos($name, '/') === false) {
|
|
|
|
|
if ($this->input->hasOption($name) and $valeur = $this->input->getOption($name)) {
|
|
|
|
|
return $valeur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isset($this->options[$name]) and $this->options[$name]) {
|
|
|
|
|
return $this->options[$name];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$name = explode('/', $name);
|
|
|
|
|
$pointeur = &$this->options;
|
|
|
|
|
while (true) {
|
|
|
|
|
$n = array_shift($name);
|
|
|
|
|
if (!isset($pointeur[$n])) {
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
if (!count($name)) {
|
|
|
|
|
return $pointeur[$n];
|
|
|
|
|
}
|
|
|
|
|
if (!is_array($pointeur[$n])) {
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
$pointeur = &$pointeur[$n];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enregistre une option (forcée par le générateur)
|
|
|
|
|
*
|
|
|
|
|
* Permet d'enregistrer avec des chemins par /
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* $this->setOption('dirs/output', $dir)
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Nom de l'option
|
|
|
|
|
* @param string $value Valeur de l'option
|
|
|
|
|
**/
|
|
|
|
|
private function setOption($name, $value) {
|
|
|
|
|
$name = explode('/', $name);
|
|
|
|
|
$n = array_shift($name);
|
|
|
|
|
$pointeur = &$this->options;
|
|
|
|
|
while ($name) {
|
|
|
|
|
if (!is_array($pointeur[$n])) {
|
|
|
|
|
$pointeur[$n] = array();
|
|
|
|
|
}
|
|
|
|
|
$pointeur = &$pointeur[$n];
|
|
|
|
|
$n = array_shift($name);
|
|
|
|
|
}
|
|
|
|
|
$pointeur[$n] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Récupère une option de commande pour phpDocumentor
|
|
|
|
|
*
|
|
|
|
|
* @param string $command Nom de la commande
|
|
|
|
|
* @return mixed
|
|
|
|
|
**/
|
|
|
|
|
private function getCommand($command) {
|
|
|
|
|
if (isset($this->commands[$command])) {
|
|
|
|
|
$val = $this->commands[$command];
|
|
|
|
|
return " --$command=\"$val\"";
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enregistre une option de commande pour phpDocumentor
|
|
|
|
|
*
|
|
|
|
|
* @param string $command Nom de la commande
|
|
|
|
|
* @param string $value Valeur de la commande
|
|
|
|
|
**/
|
|
|
|
|
private function setCommand($command, $value) {
|
|
|
|
|
$this->commands[$command] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrouver des infos du paquet.xml si on le trouve
|
|
|
|
|
*
|
|
|
|
|
* Définir avec le titre, et une présentation (si ce n'est déjà fait).
|
|
|
|
|
*
|
|
|
|
|
* @return bool true si on a trouvé un paquet.xml
|
|
|
|
|
**/
|
|
|
|
|
private function retrouverInfoPaquetXml() {
|
|
|
|
|
$source = $this->dirs['input'];
|
|
|
|
|
$is_spip = false;
|
|
|
|
|
|
|
|
|
|
if (!file_exists($paquet = $source . '/paquet.xml')) {
|
|