|
|
@ -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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|