source: spip-zone/_outils_/smart_paquets/inc_empaqueteur.php @ 41878

Last change on this file since 41878 was 41878, checked in by cedric@…, 9 years ago

ne pas supprimer le fichier archive.xml avant de le produire, sinon on va generer des 404

File size: 11.4 KB
Line 
1<?php
2
3define('_TRACE',true);
4define('_SLEEP_BETWEEN',200000);
5// on force une mise a jour de tous les paquets une fois pas jour,
6// entre minuit et 1H
7define('_FORCE_UPDATE',date('H')<1);
8#error_reporting(E_ALL);
9
10// Fonction creant le fichier archives.xml final.
11// Ne pas le reecrire si rien de neuf, c'est + efficace et ca permet
12// au detecteur de nouvelle version d'utiliser If-Modified-Since.
13// Attention, file_put_contents fait ce qu'il veut de certaines lignes vides
14// http://fr2.php.net/manual/fr/function.file-put-contents.php
15
16function empaqueteur_xml_archives($zips, $dir_paq, $dir_repo, $srcname)
17{
18        $xml = '';
19        $re = ",<"."\?xml[^>]*\?".">,Uims";
20        foreach($zips as $zip => $res) {
21                list($size, $time, $source) = $res;
22#               if (file_exists($dir_repo . $source . '/lang'))
23#                 echo_trace("$source a des chaines de langues");
24                // Recuperer le xml qui decrit le plugin
25                $f = $dir_repo . $source . '/' . $srcname ;
26                if (file_exists($f))
27                        $desc = trim(preg_replace($re,'',file_get_contents($f)));
28                else {
29                        echo_trace("(info) Paquet $zip sans plugin.xml");
30                        $desc = '';
31                }
32
33                $xml .= "<archive id=\"$zip\">
34<file>$zip</file>
35<size>$size</size>
36<date>$time</date>
37<source>$source</source>
38$desc
39</archive>\n\n";
40        }
41        if ($xml) {
42                $all = "<archives>
43$xml
44</archives>";
45                $xml = strlen($all);
46                $f = $dir_paq . $dir_repo . 'archives.xml';
47                $old = (file_exists($f)) ? trim(file_get_contents($f)) : '';
48                if ($old != $all) {
49                        echo_trace("Nouveau $f de taille $xml");
50                        file_put_contents($f, $all);
51                        return;
52                }
53        }
54        echo_trace("$f intact (taille: $xml)");
55}
56
57function empaqueteur($url, $dir_repo, $dir_paq, $src, $dest, $xml, $nom_vcs, $mail_to, $mail_from)
58{
59        global $erreurs;
60
61        $erreurs = array();
62        $url = trim($url);
63        $dir_repo = rtrim($dir_repo ? $dir_repo : basename($url),'/') .'/';
64        $dir_paq = rtrim($dir_paq ? $dir_paq : '.','/') .'/';
65       
66        $zips = empaqueteur_zips($url, $dir_repo, $dir_paq, $src, $nom_vcs);
67        if (!$erreurs) {
68                // ne pas nettoyer le fichier archives.xml !
69                $old = array_keys($zips);
70                foreach(is_array($dest) ? $dest : array($dest) as $nom_dest)
71                        $old[] = $nom_dest . 'xml';
72                nettoyer_vieux_paquets($old, $dir_paq . $dir_repo, $dir_tmp);
73        } elseif ($mail_to) empaqueteur_mail($erreurs, $mail_to, $mail_from);
74
75        foreach(is_array($dest) ? $dest : array($dest) as $nom_dest) {
76                if (!function_exists($dest = 'empaqueteur_xml_' . $nom_dest)) {
77                        echo_trace("Producteur xml inconnu: '$nom_dest'");
78                } else $dest($zips, $dir_paq, $dir_repo, $xml);
79        }
80}
81
82function empaqueteur_zips($url, $dir_repo, $dir_paq, $src, $nom_vcs)
83{
84        $dir_tmp = $dir_paq.'tmp/';
85        $dir_paq .= $dir_repo;
86        $zips = array();
87
88        if (!function_exists($vcs = 'empaqueteur_exec_' . $nom_vcs)) {
89                echo_trace("VCS non disponible: '$nom_vcs'");
90                $vcs = 'explode'; // i.e. ne fait rien de ses arguments.
91        }
92
93        // Creation des repertoires de travail et import initial
94
95        if (!file_exists($dir_repo)){
96                preparer_chemin(dirname(rtrim($dir_repo,'/')));
97                if ($url) $vcs("checkout", "$url $dir_repo");
98        }
99        if (!file_exists($dir_paq))
100                preparer_chemin($dir_paq);
101        if (!file_exists($dir_tmp))
102                preparer_chemin($dir_tmp);
103
104        // si le repo est en file:// on fait un svnsync dessus,
105        // le up est fait par un hook post-commit sur ce qui a change uniquement
106        // sauf une fois par jour
107        if (preg_match(',^file://,',$url)) {
108                $vcs("sync", $url);
109                if (_FORCE_UPDATE)
110                        $vcs("up",rtrim($dir_repo,'/'));
111        }
112        elseif ($url) {
113                $vcs("up", rtrim($dir_repo,'/'));
114        }
115
116        foreach(liste_paquets($dir_repo . $src) as $paquet){
117                if ($paquet['revision']=='HEAD') {
118                        $source = rtrim($paquet['source'],'/');
119                        $dsource = $dir_repo.$source;
120                        if (!file_exists($dsource)){
121                                echo_trace("Erreur : $dsource inexistant");
122                        } else {
123                                // ajouter le fichier svn.revision
124                                $rev = $dsource . "/svn.revision";
125                                $vcs("info", "$dsource > $rev");
126                                $info = renseigner_revision_paquet($rev);
127                                $zip = $paquet['nom'] .".zip";
128                                $zippath = $dir_paq.$zip;
129                                $res = paqueter($dsource, $zip, $zippath, $paquet['nom_dossier'], $info, $dir_tmp);
130                                // copier le svn.revision de stable/spip.zip qui permet de connaitre la derniere version stable
131                                if ($zip=="stable/spip.zip") {
132                        // necessaire de remettre le fichier a la date actuelle
133                        // car il a la date du dernier commit sur ce paquet
134                        # touch($dsource."/svn.revision");
135                                        copie_update($rev,$dir_paq.dirname($zip)."/svn.revision");
136                                }
137                        // supprimer le fichier info revision cree ci-dessus
138                                @unlink($rev);
139                                $zips[$zip] = array(
140                                                    filesize($zippath),
141                                                    filemtime($zippath),
142                                                    $source);
143                        }
144                        if (intval(_SLEEP_BETWEEN)) usleep(_SLEEP_BETWEEN);
145                }
146        }
147        echo_trace(count($zips) . " trouves");
148        return $zips;
149}
150       
151function empaqueteur_mail($erreurs, $mail_to, $mail_from)
152{
153        $headers =
154                "From: ".($mail_from ?$mail_from : $mail_to)."\r\n"
155                ."Reply-To: ".($mail_from ?$mail_from : $mail_to)."\r\n";
156        mail($mail_to,"empaqueteur",implode("",$erreurs),$headers);
157}
158
159
160/**
161 * Echo avec un horodatage
162 */
163function echo_trace($out){
164        $outh = @date("[Y-m-d H:i:s] ",time()).$out."\n";
165        if (_TRACE) echo $outh;
166
167        if (strncmp($out,"Erreur :",8)==0)
168                $GLOBALS['erreurs'][]=$outh;
169
170        return $outh;
171}
172
173/**
174 * exec avec une trace de la commande et de son resultat
175 */
176function exec_trace($commande){
177        $output = array();
178        echo_trace($commande);
179        $out = exec("$commande 2>&1", $output);
180        if ($output!==null) {
181                $out = end($output);
182        }
183        if (strlen(trim($out)))
184                array_map('echo_trace',$output);
185        return $out;
186}
187
188/**
189 * exec de Subversion
190 */
191
192function empaqueteur_exec_svn($cmd, $args)
193{
194        $bin = ($cmd == 'sync') ? 'svnsync' : 'svn';
195        return exec_trace("$bin $cmd $args");
196}
197
198/**
199 * preparer une arborescence/vide/vers/un/nom/de/dossier
200 */
201function preparer_chemin($dir){
202        if (strlen($dir)){
203                if ($parent = dirname($dir) AND !is_dir($parent))
204                        preparer_chemin($parent);
205                if (!is_dir($dir))
206                        mkdir($dir);
207        }
208}
209
210/**
211 * supprimer une arborescence/vide/vers/un/nom/de/dossier
212 * a partir d'un repertoire $base que l'on conserve
213 */
214function supprimer_chemin($base,$dir){
215        if (strlen($dir) AND $dir!='.'){
216                if (file_exists($base .$dir))
217                        rmdir($base .$dir);
218                supprimer_chemin($base,dirname($dir));
219        }
220}
221
222/**
223 * Copier le paquet si il a change
224 */
225function copie_update($source,$dest){
226        if (file_exists($source)){
227                $ts = filemtime($source);
228                if (file_exists($dest))
229                        unlink($dest);
230                else {
231                        // si l'archive doit etre mise dans un sous repertoire
232                        // creer l'arbo la premiere fois
233                        preparer_chemin(dirname($dest));
234                }
235                rename($source,$dest);
236                touch($dest,$ts);
237        }
238        else
239                echo_trace("Erreur : fichier $source non trouve");
240}
241
242function renseigner_revision_paquet($file){
243        $revision = $date_commit = 0;
244        /*
245                Creation du fichier svn.revision
246                Ce fichier est utilise par SPIP pour afficher son numero de version dans l'interface privee
247                a l'aide de la fonction version_svn_courante()
248                http://doc.spip.org/@version_svn_courante
249        */
250               
251
252        $infos = @file($file);
253        if (!$infos) return array('', 0);
254        $xml_props = $txt_props = array();
255        foreach($infos as $line) {
256                if (preg_match('/^(Last Changed Rev|R.vision de la derni.re modification)\s*: (?<revision>\d*)$/',$line,$matches))
257                        $xml_props['revision'] = $txt_props['Revision'] = $matches['revision'];
258                if (preg_match('/^URL\s*: (?<url>.*)$/',$line,$matches))
259                        $xml_props['origine'] = $txt_props['Origine'] = $matches['url'];
260                if (preg_match('/^(Last Changed Date|Date de la derni.re modification\s*): (?<date_commit>[^(]*)($|\()/',$line,$matches))
261                        $xml_props['commit'] = $txt_props['Dernier commit'] = $matches['date_commit'];
262        }
263       
264        $svn_revision = "<svn_revision>\n<text_version>";
265        foreach($txt_props as $prop => $val) $svn_revision .= "\n$prop: $val";
266        $svn_revision .= "\n</text_version>";
267        foreach($xml_props as $prop => $val) $svn_revision .= "\n<$prop>$val</$prop>";
268        $svn_revision .= "\n</svn_revision>";
269       
270        if ($fp = @fopen($file,"w")) {
271                fwrite($fp, $svn_revision);
272                @fclose($fp);
273        } else echo_trace("Erreur: impossible d'ecrire dans $file");
274        // mettre la date du fichier a celle du dernier commit
275        // pour ne pas fausser la date du paquet (qui est celle du plus recent fichier)
276        touch($file,strtotime($xml_props['commit']));
277
278        $date_commit = date('Y-m-d H:i:s',strtotime($xml_props['commit']));
279        //echo_trace("$file, Revision $revision, dernier commit : $date_commit");
280        return array($xml_props['revision'],$date_commit);
281}
282
283/**
284 * Creer un paquet a partir du
285 * $source : sous repertoire de $dir
286 * $zip : nom du fichier zip (avec l'extension)
287 * $nom_dossier : arborescence dans le zip qui sera cree lors du dezippage
288 *
289 */
290function paqueter($source, $zip, $zippath, $nom_dossier, $rev, $dir_tmp){
291        $zipfile = basename($zip);
292        list($revision,$date_commit) = $rev;
293        $date_paquet = file_exists($zippath) ? filemtime($zippath) : 0;
294        // tester si le paquet est a jour
295        if (strtotime($date_commit)<$date_paquet AND !_FORCE_UPDATE) {
296                echo_trace("$zip OK : du ".date('Y-m-d H:i:s',$date_paquet)." / dernier commit du $date_commit");
297        }
298        else {
299                preparer_chemin($dir_tmp.$nom_dossier);
300                if (!rename($source,$dir_tmp.$nom_dossier)) {
301                        echo_trace("Erreur: impossible de renommer $source");
302                } else {
303                        $d = getcwd();
304                        chdir($dir_tmp);
305                        $base_dir = reset(explode('/',$nom_dossier));
306                        // zipper en prenant la date du fichier le plus recent
307                        // comme date du paquet
308                        exec_trace("zip -roq $zipfile $base_dir -x \*/.svn\*");
309                        chdir($d);
310
311                        $date_paquet = filemtime($dir_tmp.$zipfile);
312                        // cas ou le dernier commit consiste en la suppression de fichiers
313                        // du coup le zip est plus ancien que le dernier commit
314                        // on corrige manuellement
315                        if ($date_paquet<strtotime($date_commit)) {
316                                touch($dir_tmp.$zipfile,strtotime($date_commit)+1);
317                        }
318
319                        rename($dir_tmp.$nom_dossier,$source);
320                }
321                supprimer_chemin($dir_tmp,$nom_dossier);
322                copie_update($dir_tmp.$zipfile,$zippath);
323        }
324}
325
326/**
327 * Supprimer les vieux paquets obsoletes
328 * @param <type> $paquets_a_jour
329 */
330function nettoyer_vieux_paquets($paquets_a_jour, $dir_paq, $dir_tmp){
331        $maxfiles = 10000; // securite
332        if (@is_dir($dir_paq) AND is_readable($dir_paq) AND $d = @opendir($dir_paq)) {
333                while (($f = readdir($d)) !== false && ($nbfiles<$maxfiles)) {
334                        if ($f[0] != '.' # ignorer . .. .svn etc
335                        AND $f != 'CVS'
336                        AND $f != 'remove.txt'
337                        AND is_readable($g = $dir_paq.$f)) {
338                                if (is_file($g)) {
339                                        if (!in_array($f,$paquets_a_jour)){
340                                                echo_trace("Suppression du vieux paquet $f");
341                                                unlink($g);
342                                                @unlink($dir_tmp.$f); // securite, on vire aussi le vieux paquet tmp eventuel
343                                        }
344                                }
345                        }
346                }
347                closedir($d);
348        }
349}
350
351
352/**
353 * Lister les paquets demandes dans le fichier archivelist a la racine
354 * @param <type> $archivelist
355 * @return <type>
356 */
357function liste_paquets($archivelist){
358        echo_trace("chargement de $archivelist");
359        if (!$archivefile=file($archivelist)){
360                echo_trace("Erreur : Impossible de lire $archivelist");
361                return array();
362        }
363
364        $paquets = array();
365        foreach($archivefile as $ligne=>$lignepaquet){
366                $lignepaquet=rtrim($lignepaquet);//on vire le retour ligne de la fin
367                if (substr($lignepaquet,0,1)!="#" AND strlen($lignepaquet)){
368                        //on separe les parametres
369                        // et on fixe ceux manquants
370                        $a = explode(";",$lignepaquet);
371                        $b = preg_split("/:/",$a[0]);
372                        $source = $b[0];
373                        $svn_version = empty($b[1]) ?'HEAD' : $b[1];           
374                        $nom_paquet = empty($a[1]) ? basename($source) : $a[1];
375                        $nom_dossier = empty($a[2]) ? $nom_paquet : $a[2];
376
377                        $paquets[] = array('source'=>$source,'nom'=>$nom_paquet,'nom_dossier'=>$nom_dossier,'revision'=>$svn_version);
378                }
379        }
380
381        echo_trace(count($paquets)." paquets definis");
382        return $paquets;
383}
384
385?>
Note: See TracBrowser for help on using the repository browser.