Browse Source

Refonte de l'empaqueteur pour effectivement supporter plusieurs methodes de repository, parmi donc svn, gitsvn et git

master
cedric@yterium.com 1 year ago
parent
commit
748886a0c0
  1. 2
      empaqueteur.php
  2. 63
      inc_empaqueteur.php
  3. 295
      inc_outils.php

2
empaqueteur.php

@ -21,7 +21,7 @@ if (!isset($argv[1]) OR !$argv[1]){
date_default_timezone_set('Europe/Paris');
define('_TRACE',true);
define('_SLEEP_BETWEEN',200000);
define('_SLEEP_BETWEEN',0);
// on force une mise a jour de tous les paquets une fois pas jour,
// entre minuit et 1H
define('_FORCE_UPDATE',date('H')<1);

63
inc_empaqueteur.php

@ -100,18 +100,13 @@ function empaqueteur_archives($url, $dir_repo, $dir_paq, $src, $nom_vcs, $dtd_pr
// Definition des deux sous-repertoires temporaires et definitifs des paquets
$dir_tmp = $dir_paq.'tmp/';
$dir_paq .= $dir_repo;
$dirs_changed = null;
// Test pour savoir si le gestionnaire de version est bien installe sur le serveur
if (!function_exists($vcs = 'vcs_exec_' . $nom_vcs)) {
echo_trace("VCS non disponible: '$nom_vcs'");
$vcs = 'explode'; // i.e. ne fait rien de ses arguments.
}
// 1. Creation des repertoires de travail et import initial
if (!file_exists($dir_repo)){
preparer_chemin(dirname(rtrim($dir_repo,'/')));
if ($url) $vcs("checkout", "$url $dir_repo");
// TODO : refaire
die("$dir_repo non initialise avec $nom_vcs");
//preparer_chemin(dirname(rtrim($dir_repo,'/')));
//if ($url) $vcs("checkout", "$url $dir_repo");
}
if (!file_exists($dir_paq))
preparer_chemin($dir_paq);
@ -122,33 +117,16 @@ function empaqueteur_archives($url, $dir_repo, $dir_paq, $src, $nom_vcs, $dtd_pr
// Si le repo est en file:// on fait un svnsync dessus,
// le up est fait par un hook post-commit sur ce qui a change uniquement
// sauf une fois par jour
if (preg_match(',^file://,',$url)) {
// supprimer le fichier qui trace les dossiers modifies avant sync ou up
$fc = rtrim($dir_repo,'/')."/dirs-changed.txt";
$vcs("sync", $url);
if (_FORCE_UPDATE){
$vcs("up",rtrim($dir_repo,'/'));
}
else {
$dirs_changed = (file_exists($fc)?file($fc):array());
$dirs_changed = array_map("trim",$dirs_changed);
$dirs_changed = array_map("dirname",$dirs_changed);
$dirs_changed = array_unique($dirs_changed);
$dirs_changed = array_filter($dirs_changed);
$d = rtrim($dir_repo,'/')."/";
foreach($dirs_changed as $k=>$v){
$dirs_changed[$k] = $d . ($v=="."?"":$v);
}
if (vcs_smart_update($nom_vcs, $dir_repo, _FORCE_UPDATE)
and !_FORCE_UPDATE) {
// fichiers modifies depuis la derniere heure
$dirs_changed = dirschanged_read($dir_repo, time()-3600);
if ($dirs_changed) {
echo_trace("Dossiers modifies : ".implode(", ",$dirs_changed));
}
// renommer le fichier dirs-changed.txt car on a traite ces modifs d'une facon ou d'une autre
// d'ici le prochain passage le fichier sera possiblement recree par un svnsync pour les _externals_
rename($fc, $fc . '.last');
}
elseif ($url) {
// le up est fait si archivelist modifie sinon une fois par jour
if (_FORCE_UPDATE)
$vcs("up", rtrim($dir_repo,'/'));
else {
$dirs_changed = null;
}
// 3. Lecture de la liste des archives a creer et des informations sur le depot
@ -158,7 +136,7 @@ function empaqueteur_archives($url, $dir_repo, $dir_paq, $src, $nom_vcs, $dtd_pr
$zips = $logos = $xmls = array();
foreach($paquets as $_paquet){
if ($_paquet['revision']=='HEAD'
AND list($infos, $logo, $xml) = creer_paquet($_paquet, $dir_repo, $dir_paq, $dir_tmp, $vcs, $dtd_prio, $dirs_changed)) {
AND list($infos, $logo, $xml) = creer_paquet($_paquet, $dir_repo, $dir_paq, $dir_tmp, $nom_vcs, $dtd_prio, $dirs_changed)) {
$zips[$_paquet['nom'] .".zip"] = $infos;
if ($logo) $logos[] = $logo;
if ($xml) $xmls[] = $xml;
@ -232,7 +210,7 @@ function lister_paquets($src) {
// $dir_repo : repertoire racine des sources extraits du repository
// $dir_paq : repertoire de depot des paquets crees
// $dir_tmp : repertoire temporaire de depot des archives crees
// $vcs : fonction d'interface du vcs utilise (ex: vcs_exec_svn)
// $nom_vcs : methode vcs (git, gitsvn, svn)
// $dtd_prio : DTD a utiliser en priorite (plugin ou paquet)
// $dirs_changed : repertoires modifies depuis le dernier passage
//
@ -248,7 +226,7 @@ function lister_paquets($src) {
// 7 : dtd utilisee
// 1 : logo cree (fichier)
// 2 : xml recopie (fichier)
function creer_paquet($paquet, $dir_repo, $dir_paq, $dir_tmp, $vcs, $dtd_prio, $dirs_changed=null) {
function creer_paquet($paquet, $dir_repo, $dir_paq, $dir_tmp, $nom_vcs, $dtd_prio, $dirs_changed=null) {
// Verifier le repertoire source du paquet a creer
$dsource = $dir_repo. $paquet['source'];
if (!file_exists($dsource)){
@ -276,12 +254,11 @@ function creer_paquet($paquet, $dir_repo, $dir_paq, $dir_tmp, $vcs, $dtd_prio, $
// Creation de l'archive
// -- Ajouter le fichier svn.revision dans les fichiers de l'archive pour les besoins de SPIP
$rev = $dsource . "/svn.revision";
$vcs("info", "$dsource > $rev");
$info = renseigner_revision_paquet($rev);
$date_commit = $info[1];
$file_rev = $dsource . "/svn.revision";
$last_commit = renseigner_revision_paquet($nom_vcs, $dir_repo, $paquet['source'], $file_rev);
$date_commit = $last_commit[1];
// -- zipper les sources incluant le fichier svn.revision
if (!archiver($dsource, $zip, $zippath, $paquet['nom_dossier'], $info, $dir_tmp))
if (!archiver($dsource, $zip, $zippath, $paquet['nom_dossier'], $last_commit, $dir_tmp))
return false;
// -- Traiter le cas de SPIP :
// copier le svn.revision de stable/spip.zip qui permet de connaitre la derniere version stable
@ -289,10 +266,10 @@ function creer_paquet($paquet, $dir_repo, $dir_paq, $dir_tmp, $vcs, $dtd_prio, $
// necessaire de remettre le fichier a la date actuelle
// car il a la date du dernier commit sur ce paquet
# touch($dsource."/svn.revision");
copie_update($rev, $dir_paq.dirname($zip)."/svn.revision");
copie_update($file_rev, $dir_paq.dirname($zip)."/svn.revision");
}
// -- supprimer le fichier info revision cree ci-dessus
@unlink($rev);
@unlink($file_rev);
// Determination de la dtd a utiliser
$dtd = '';

295
inc_outils.php

@ -2,6 +2,202 @@
// ---------------------------------------- INTERFACE VCS ------------------------------------------
function vcs_read_current_rev($nom_vcs, $dir_repo) {
switch ($nom_vcs) {
case 'git':
case 'gitsvn':
$vcs = "vcs_exec_git";
if ($out = $vcs('rev-parse', 'HEAD', $dir_repo)){
$rev = substr(trim(end($out)), 0, 9);
return $rev;
}
break;
case 'svn':
$vcs = "vcs_exec_svn";
if ($out = $vcs('info', $dir_repo)){
$out = implode("\n",$out);
// Revision
// Revision: 18763
if (preg_match(",^R..?vision[^:\w]*:\s+(\d+)$,Uims",$out,$m)) {
$rev = $m[1];
return $rev;
}
}
break;
default:
break;
}
return false;
}
function vcs_clean_dirs_changed_list($dir_repo, $files_changed) {
$dirs_changed = array_map("trim",$files_changed);
$dirs_changed = array_map("dirname",$dirs_changed);
$dirs_changed = array_unique($dirs_changed);
$dirs_changed = array_filter($dirs_changed);
$d = rtrim($dir_repo,'/')."/";
foreach($dirs_changed as $k=>$v){
$dirs_changed[$k] = $d . ($v=="."?"":$v);
}
return $dirs_changed;
}
function vcs_info_last_commit($nom_vcs, $dir_repo, $sub_dir) {
static $origins = [];
if (!is_dir($dir_repo)) {
return false;
}
$dir_repo = rtrim($dir_repo,'/') . "/";
$props = array(
'revision' => '',
'origin' => '',
'date' => '',
);
$infos = array();
switch ($nom_vcs) {
case 'git':
$vcs = "vcs_exec_git";
if ($out = $vcs('rev-parse','HEAD', $dir_repo)) {
$rev = $props['revision'] = substr(trim(end($out)), 0, 9);
if ($out = $vcs('show', "$rev -s --format='%ci'", $dir_repo)) {
$props['date'] = trim(end($out));
}
}
if (empty($origins[$dir_repo])) {
$out = $vcs('remote','-v', $dir_repo);
foreach ($out as $line) {
if (strpos($line, "origin ") === 0) {
$url = trim(substr($line,7));
$url = explode(' ', $url);
$origins[$dir_repo] = reset($url);
break;
}
}
}
$props['origin'] = $origins[$dir_repo];
break;
case 'gitsvn':
$vcs = "vcs_exec_git";
$infos = $vcs("svn", "info $sub_dir", $dir_repo);
// et on continue comme en svn pour parser les infos
case 'svn':
default:
if (!$infos) {
// Test pour savoir si le gestionnaire de version est bien installe sur le serveur
if (!function_exists($vcs = 'vcs_exec_' . $nom_vcs)) {
echo_trace("VCS non disponible: '$nom_vcs'");
$vcs = 'explode'; // i.e. ne fait rien de ses arguments.
}
$dsource = $dir_repo . $sub_dir;
$infos = $vcs("info", "$dsource");
}
foreach($infos as $line) {
$line = str_replace(chr(160)," ",$line);
if (preg_match('/^(Last Changed Rev|R.vision de la derni.re modification)\s*: (?<revision>\d*)$/',$line,$matches))
$props['revision'] = $matches['revision'];
if (preg_match('/^URL\s*: (?<url>.*)$/',$line,$matches))
$props['origin'] = $matches['url'];
if (preg_match('/^(Last Changed Date|Date de la derni.re modification\s*): (?<date_commit>[^(]*)($|\()/',$line,$matches))
$props['date'] = $matches['date_commit'];
}
break;
}
return $props;
}
function vcs_smart_update($nom_vcs, $dir_repo, $url, $force_update = false) {
if (!is_dir($dir_repo)) {
return false;
}
$rev_before = vcs_read_current_rev($nom_vcs, $dir_repo);
if (!$rev_before) {
echo_trace("Impossible de lire la revision courante de $dir_repo");
return false;
}
switch ($nom_vcs) {
case 'git':
case 'gitsvn':
$vcs = "vcs_exec_git";
if ($nom_vcs === 'git') {
$vcs("pull", "--rebase", $dir_repo);
}
else {
$vcs("svn", "fetch", $dir_repo);
$vcs("svn", "rebase", $dir_repo);
}
$rev_after = vcs_read_current_rev($nom_vcs, $dir_repo);
// recuperer la liste des fichiers modifies
$changed = $vcs("diff-tree", "--no-commit-id --name-only -r {$rev_before}..{$rev_after}", $dir_repo);
$dirs_changed = vcs_clean_dirs_changed_list($dir_repo, $changed);
dirschanged_append($dir_repo, $dirs_changed);
return true;
break;
case 'svn':
default:
// Test pour savoir si le gestionnaire de version est bien installe sur le serveur
if (!function_exists($vcs = 'vcs_exec_' . $nom_vcs)) {
echo_trace("VCS non disponible: '$nom_vcs'");
$vcs = 'explode'; // i.e. ne fait rien de ses arguments.
}
// Si le repo est en file:// on fait un svnsync dessus,
// le up est fait par un hook post-commit sur ce qui a change uniquement
// sauf une fois par jour
if (preg_match(',^file://,',$url)) {
// supprimer le fichier qui trace les dossiers modifies avant sync ou up
$fc = rtrim($dir_repo,'/')."/dirs-changed.txt";
$vcs("sync", $url, $dir_repo);
if ($force_update){
$vcs("up",rtrim($dir_repo,'/'), $dir_repo);
}
if (file_exists($fc)) {
$changed = file($fc);
$dirs_changed = vcs_clean_dirs_changed_list($dir_repo, $changed);
dirschanged_append($dir_repo, $dirs_changed);
// renommer le fichier dirs-changed.txt car on a memorise son contenu
rename($fc, $fc . '.last');
}
return true;
}
else {
// le up est fait uniquement si force
if ($force_update) {
$vcs("up", rtrim($dir_repo,'/'), $dir_repo);
return true;
}
return false;
}
break;
}
return false;
}
// Interface de commande du gestionnaire de version Subversion (GIT)
//
// $cmd : commande git
// $args : liste des arguments (ligne de commande)
//
// return : le resultat de la commande
function vcs_exec_git($cmd, $args, $dir_repo)
{
$dir = getcwd();
chdir($dir_repo);
$bin = 'git';
$out = exec_trace("$bin $cmd $args", true);
chdir ($dir);
return $out;
}
// Interface de commande du gestionnaire de version Subversion (SVN)
//
// $cmd : commande svn
@ -11,7 +207,7 @@
function vcs_exec_svn($cmd, $args)
{
$bin = ($cmd == 'sync') ? 'svnsync' : 'svn';
return exec_trace("$bin $cmd $args");
return exec_trace("$bin $cmd $args", true);
}
@ -21,7 +217,7 @@ function vcs_exec_svn($cmd, $args)
// $commande : commande a executer
//
// return : le resultat de la commande
function exec_trace($commande){
function exec_trace($commande, $full = false){
$output = array();
echo_trace($commande);
$out = exec("$commande 2>&1", $output);
@ -30,7 +226,47 @@ function exec_trace($commande){
}
if (strlen(trim($out)))
array_map('echo_trace',$output);
return $out;
return ($full ? $output : $out);
}
// -------------------------------------- dirs-changed.txt -----------------------------------------
function dirschanged_filename($dir_repo) {
$file_changed = rtrim($dir_repo,'/')."/last-changed.json";
return $file_changed;
}
function dirschanged_read($dir_repo, $since = null) {
$file = dirschanged_filename($dir_repo);
if (!$changed = file_get_contents($file)
or !$dirs_changed = json_decode($changed, true)) {
$dirs_changed = array();
}
if (!is_null($since) and $dirs_changed) {
foreach ($dirs_changed as $dir => $time) {
if ($time < $since) {
unset($dirs_changed[$dir]);
}
}
}
return $dirs_changed;
}
function dirschanged_append($dir_repo, $new_dirs_changed) {
$keep_duration = 24 * 3600; // on garde les modifs des dernieres 24h
$now = time();
$dirs_changed = dirschanged_read($dir_repo, $now - $keep_duration);
foreach ($new_dirs_changed as $dir) {
$dirs_changed[$dir] = $now;
}
$file = dirschanged_filename($dir_repo);
file_put_contents($file, json_encode($dirs_changed));
return $dirs_changed;
}
@ -133,46 +369,43 @@ function copie_update($source, $dest){
// a l'aide de la fonction version_svn_courante()
// http://doc.spip.org/@version_svn_courante
//
// $file : fichier revision.svn du paquet en cours de creation
// $nom_vcs : methode VCS utilisee
// $dir_repo : repertoire directory
// $sub_dir : repertoire paquet
// $file_rev : fichier dans lequel on export les infos revision/origin et date de dernier commit
//
// return : tableau des infos lues dans revision.svn
// 0 : numero de revision
// 1 : date du dernier commit
function renseigner_revision_paquet($file){
$revision = $date_commit = 0;
$infos = @file($file);
if (!$infos) return array('', 0);
$xml_props = $txt_props = array();
foreach($infos as $line) {
$line = str_replace(chr(160)," ",$line);
if (preg_match('/^(Last Changed Rev|R.vision de la derni.re modification)\s*: (?<revision>\d*)$/',$line,$matches))
$xml_props['revision'] = $txt_props['Revision'] = $matches['revision'];
if (preg_match('/^URL\s*: (?<url>.*)$/',$line,$matches))
$xml_props['origine'] = $txt_props['Origine'] = $matches['url'];
if (preg_match('/^(Last Changed Date|Date de la derni.re modification\s*): (?<date_commit>[^(]*)($|\()/',$line,$matches))
$xml_props['commit'] = $txt_props['Dernier commit'] = $matches['date_commit'];
}
function renseigner_revision_paquet($nom_vcs, $dir_repo, $sub_dir, $file_rev){
$props = vcs_info_last_commit($nom_vcs, $dir_repo, $sub_dir);
if (!$props) return array('', 0);
$xml_props = [
'revision' => $props['revision'],
'origine' => $props['origin'],
'commit' => $props['date'],
];
$txt_props = [
'Revision' => $props['revision'],
'Origine' => $props['origin'],
'Dernier commit' => $props['date'],
];
$svn_revision = "<svn_revision>\n<text_version>";
foreach($txt_props as $prop => $val) $svn_revision .= "\n$prop: $val";
$svn_revision .= "\n</text_version>";
foreach($xml_props as $prop => $val) $svn_revision .= "\n<$prop>$val</$prop>";
$svn_revision .= "\n</svn_revision>";
if ($fp = @fopen($file,"w")) {
fwrite($fp, $svn_revision);
@fclose($fp);
}
else echo_trace("Erreur: impossible d'ecrire dans $file");
file_put_contents($file_rev, $svn_revision);
// mettre la date du fichier a celle du dernier commit
// pour ne pas fausser la date du paquet (qui est celle du plus recent fichier)
touch($file,strtotime($xml_props['commit']));
$date_commit = date('Y-m-d H:i:s',strtotime($xml_props['commit']));
touch($file_rev,strtotime($xml_props['commit']));
return array($xml_props['revision'], $date_commit);
$date_commit = date('Y-m-d H:i:s',strtotime($props['date']));
return array($props['revision'], $date_commit);
}

Loading…
Cancel
Save