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

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

smart_paquets. Etre en mesure de recopier le logo d'un plugin sous son nom canonique dans le repertoire des Zip pour SVP.

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