root/trunk/midcom/build/packageMidCOM.php

Revision 17345, 19.5 kB (checked in by bergie, 1 month ago)

Version bump

Line 
1 <?php
2 /**
3  * Created on 10/09/2006
4  * @author tarjei huse
5  * @package midcom.admin.aegir
6  * @copyright The Midgard Project, http://www.midgard-project.org
7  * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
8  *
9  */
10 require_once "phing/Task.php";
11 /**
12  * This class
13  */
14 class packageMidCOM extends Task
15 {
16
17     /**
18      * Component name
19      */
20     protected $package = null;
21     
22     /**
23      * Package version
24      */
25     protected $version = null;
26
27     /**
28      * Package state
29      */
30     protected $state = null;
31     
32     /**
33      * MidCOM component manifest array
34      */
35     protected $manifest = null;
36     
37     /**
38      * The PEAR name of the package.
39      */
40     protected $package_name;
41     protected $channel = 'ragnaroek.pear.midgard-project.org';
42
43     protected $returnProperty; // name of property to set to return value
44
45     /**
46      * The root path to where the module is stored.
47      */
48     private $path = null;
49     /**
50      * The target directory where the packagefile should be saved.
51      */
52     protected $target_dir = null;
53     
54     function __construct()
55     {
56         ini_set('memory_limit', '-1');
57     }
58     
59     /**
60      * The setter for the attribute "message"
61      */
62     public function setTarget_dir($str)
63     {
64         $this->target_dir = $str;
65     }
66     public function setPath($str)
67     {
68         $this->path = $str;
69     }
70     public function setPackage($str)
71     {
72         $this->package = $str;
73     }
74     public function setVersion($str)
75     {
76         $this->version = $str;
77     }
78     public function setState($str)
79     {
80         $this->state = $str;
81     }
82     public function setChannel($str)
83     {
84         $this->channel = $str;
85     }
86     /** Sets property name to set with return value of function or expression.*/
87     public function setReturnProperty($r)
88     {
89         $this->returnProperty = $r;
90     }
91
92     protected $copyfiles = array ();
93
94     /**
95      * The init method: Do init steps.
96      */
97     public function init()
98     {
99         // nothing to do here
100     }
101
102     /**
103      * The main entry point method.
104      */
105     public function main()
106     {
107         $this->package_name = str_replace('.', '_', $this->package);
108         $this->package_name = str_replace('/', '', $this->package_name);
109         echo "Using package name : {$this->package_name} \n";
110         // todo add more validation
111         if ($this->target_dir === null 
112             || !is_dir($this->target_dir
113         ) {
114             throw new Exception("You must set the target attribute to a writable directory (current: {$this->target_dir})!\n");
115         }
116         // read the manifest
117         $this->readManifest();
118         $packageInfo = $this->getComponentInfo();
119         // build the filelist
120         $filelist = $this->getFileList($packageInfo);
121         // create the xml for package.xml
122         $xml = $this->createXml($packageInfo, $filelist);
123         // save package.xml.
124         file_put_contents($this->path . "/" . $this->package . "/package.xml", $xml);
125         
126         $this->execPearPackage();
127         // I planned to use the tar task to create the package, then this would be needed
128         $name = $this->package_name . "-" . $packageInfo['version'];
129         $this->project->setProperty($this->returnProperty, $name);
130         // should I delete package.xml? Hmm, todo I think.
131
132     }
133
134     protected function execPearPackage()
135     {
136         $curr_dir = getcwd();
137         chdir($this->target_dir);
138         $pear = exec('which pear');
139         if (!is_executable($pear))
140         {
141             die("Pear executable $pear is not executable!");
142         }
143         
144         $ret = exec("$pear package-validate {$this->path}/{$this->package}/package.xml", $out, $status);
145         $out = null;
146         if ($status == 0)
147         {
148             $ret = exec("$pear package {$this->path}/{$this->package}/package.xml", $out, $status);
149             foreach ($out as $line) {
150                 if (stripos($line, 'error')) {
151                     echo $line . "\n";
152                 }
153                 if (stripos($line, 'warning')) {
154                     echo $line . "\n";
155                 }
156                 
157             }
158             
159         }
160         else
161         {
162             chdir($curr_dir);
163             if (!is_null($out))
164             {
165                 echo implode($out);
166             }
167             die ("Packagefile did not validate! Exiting.");
168         }
169         chdir($curr_dir);
170         
171     }
172
173     protected function getFileList($packageInfo)
174     {
175
176         $filelist_config = array
177         (
178             'filelist' => '',
179             'package' => $packageInfo,
180             'component' => $this->package_name,
181             'path' => $this->path . "/" . $this->package,
182             'prefix' => '    ',
183             'baseinstalldir' => 'midcom/lib/' . str_replace('.', '/', $this->package),
184             'static' => false,
185         );
186         $filelist = $this->directory_list_contents($filelist_config);
187         return $filelist;
188     }
189
190     /**
191      * Generate the filelist
192      *@param array $config File listing configuration
193      * @return string File XML list
194      */
195     function directory_list_contents($config, $directory_name_override = null)
196     {
197         $directory = dir($config['path']);
198
199         if ($directory_name_override)
200         {
201             $dir_name = $directory_name_override;
202         } else
203         {
204             $dir_name = basename($config['path']);
205         }
206
207         // Add more to the prefix
208         $config['prefix'] .= '    ';
209
210         // Start the directory output
211         if ($dir_name == 'static' && $config['prefix'] != '        ')
212         {
213             // All static files are handled through Role_Web
214             $config['static'] = true;
215             $config['filelist'] .= "{$config['prefix']}<dir name=\"{$dir_name}\">\n";
216             $config['baseinstalldir'] = str_replace('_', '.', "/{$config['component']}");
217             $config['install-as-prefix'] = '';
218         } else
219         {
220             $config['filelist'] .= "{$config['prefix']}<dir name=\"{$dir_name}\">\n";
221         }
222
223         // List contents
224         while (false !== ($entry = $directory->read()))
225         {
226             if (substr($entry, 0, 1) == '.')
227             {
228                 // Ignore dotfiles
229                 continue;
230             }
231             if ($entry == 'CVS' || $entry == '.svn')
232             {
233                 // Ignore CVS directories
234                 continue;
235             }
236             if ($entry == 'package.xml')
237             {
238                 // Ignore the package file itself
239                 continue;
240             }
241
242             // Handle packaging file roles
243             elseif ($dir_name == 'config' && $entry == 'mgdschema.xml')
244             {
245                 // MgdSchemas shipped by components are placed in config/mgdschema.xml
246                 $role = 'mgdschema';
247             }
248             elseif ($dir_name == 'config' && $entry == 'mgdschema.sql')
249             {
250                 // SQL files shipped by components are placed in config/mgdschema.xml
251                 // These will be installed via the Datagard database update command
252                 $role = 'midgardsql';
253             } else
254             {
255                 // All files are by default PHP
256                 $role = 'php';
257
258                 // Check for potential other file extensions
259                 $path_parts = pathinfo($entry);
260                 switch ($path_parts['extension'])
261                 {
262                     // binary formats
263                     case 'jpg' :
264                     case 'gif' :
265                     case 'png' :
266                     case 'zip' :
267                     case 'tgz' :
268                         $role = 'data';
269                         break;
270                         // Web formats *not* in static directory
271                     case 'html' :
272                     case 'js' :
273                     case 'htc' :
274                     case 'css' :
275                         $role = 'data';
276                         break;
277                 }
278             }
279
280             if (is_dir("{$config['path']}/{$entry}"))
281             {
282                 // List the subdirectory
283                 $subconfig = $config;
284                 $subconfig['path'] = "{$config['path']}/{$entry}";
285                 $subconfig['install-as-prefix'] .= "{$entry}/";
286                 $config['filelist'] = $this->directory_list_contents($subconfig);
287             } else
288             {
289                 // List the files
290                 if ($config['static'])
291                 {
292                     $role = 'web';
293                     $config['filelist'] .= "{$config['prefix']}    <file baseinstalldir=\"{$config['baseinstalldir']}\" install-as=\"{$config['install-as-prefix']}{$entry}\" name=\"{$entry}\" role=\"{$role}\" />\n";
294                 } else
295                 {
296                     $config['filelist'] .= "{$config['prefix']}    <file baseinstalldir=\"{$config['baseinstalldir']}\" name=\"{$entry}\" role=\"{$role}\" />\n";
297                 }
298             }
299             $this->copyfiles[] = $config['path'] . "/" . $entry;
300         }
301
302         $directory->close();
303         $config['filelist'] .= "{$config['prefix']}</dir>\n";
304         return $config['filelist'];
305     }
306
307     public function getComponentInfo()
308     {
309         $component = array ();
310         $component['baseinstalldir'] = "midcom/lib";
311         $component_path_array = explode('.', $this->package);
312         foreach ($component_path_array as $directory)
313         {
314             $component['baseinstalldir'] = "{$component['baseinstalldir']}/{$directory}";
315         }
316         // PEAR packages can't have dots in their names
317         $package['name'] = $this->package_name;
318
319         // Default license to LGPL if missing
320         if (array_key_exists('license', $this->manifest['package.xml']))
321         {
322             $package['license'] = $this->manifest['package.xml']['license'];
323         } else
324         {
325             $package['license'] = 'LGPL';
326         }
327
328         // Version string is a string
329         $package['version'] = $this->manifest['version'];
330
331         // Release date is today
332         // TODO: Get latest modification date from CHANGES
333         $package['date'] = date('Y-m-d');
334         $package['time'] = date('H:i:s');
335
336         // Package state. Default to stable
337         if (array_key_exists('state', $this->manifest))
338         {
339             $package['state'] = $this->manifest['state'];
340         }
341         else
342         {
343             echo "Note: You have not set packagestate. Defaulting to devel.\n";
344             $package['state'] = 'devel';
345         }
346
347         // Load the summary
348         if (array_key_exists('summary', $this->manifest['package.xml']))
349         {
350             $package['summary'] = $this->manifest['package.xml']['summary'];
351         }
352         else
353         {
354             $package['summary'] = "MidCOM component {$this->package}";
355         }
356
357         // Load the description
358         if (array_key_exists('description', $this->manifest['package.xml']))
359         {
360             $package['description'] = $this->manifest['package.xml']['description'];
361         } else
362         {
363             $package['description'] = "MidCOM component {$this->package}";
364         }
365
366         //     Generate the maintainer list
367         $package['maintainers'] = '';
368         if (array_key_exists('maintainers', $this->manifest['package.xml']) && is_array($this->manifest['package.xml']['maintainers']))
369         {
370             foreach ($this->manifest['package.xml']['maintainers'] as $username => $person)
371             {
372                 if (!is_array($person))
373                 {
374                     $person = Array ();
375                 }
376
377                 if (!array_key_exists('name', $person))
378                 {
379                     // Maintainer must have a name
380                     continue;
381                 }
382
383                 if (!array_key_exists('role', $person))
384                 {
385                     $person['role'] = 'developer';
386                 }
387
388                 if (!array_key_exists('active', $person))
389                 {
390                     $person['active'] = 'yes';
391                 }
392
393                 $package['maintainers'] .= "
394                                                 <{$person['role']}>
395                                                     <name>{$person['name']}</name>   
396                                                     <user>{$username}</user>
397                                                     <email>{$person['email']}</email>
398                                                     <active>{$person['active']}</active>
399                                                 </{$person['role']}>
400                                                 ";
401             }
402         }
403
404         // Generate dependencies, if any
405         $package['dependencies'] = '';
406         if (array_key_exists('dependencies', $this->manifest['package.xml']) && is_array($this->manifest['package.xml']['dependencies']))
407         {
408             foreach ($this->manifest['package.xml']['dependencies'] as $requirement => $dependency)
409             {
410                 if (!is_array($dependency))
411                 {
412                     $dependency = Array ();
413                 }
414
415                 $dependency['min'] = '';
416                 if (array_key_exists('version', $dependency))
417                 {
418                     // No version specified, the dependency just needs to exist
419                     $dependency['min'] = "<min>{$dependency['version']}</min>";
420                 }
421
422                 if (!array_key_exists('type', $dependency))
423                 {
424                     // Default to depending on PEAR packages
425                     $dependency['type'] = 'package';
426                 }
427
428                 if (!array_key_exists('channel', $dependency))
429                 {
430                     // Default to depending on packages from MidCOM repository
431                     $dependency['channel'] = $this->channel;
432                 }
433
434                 if (strstr($requirement, '.'))
435                 {
436                     // Convert dots in component names to underscores used in PEAR packages
437                     $requirement = str_replace('.', '_', $requirement);
438                 }
439
440                 $package['dependencies'] .= "
441                                                     <{$dependency['type']}>
442                                                         <name>{$requirement}</name>
443                                                         <channel>{$dependency['channel']}</channel>
444                                                         {$dependency['min']}
445                                                     </{$dependency['type']}>           
446                                                 ";
447             }
448         }
449         return $package;
450     }
451     /**
452      * Reads the manifest file and redies it for parsing.
453      */
454     protected function readManifest()
455     {
456         $file = sprintf("%s/%s/config/manifest.inc", $this->path, $this->package);
457         $manifest = array ();
458         if (!file_exists($file))
459         {
460             die("Missing componentfile $file. Cannot package {$this->package}\n");
461         }
462         eval ('$manifest = Array(' . file_get_contents($file) . ');');
463
464         $this->manifest =& $manifest;
465         
466         // Update manifest if needed
467         if (   !empty($this->version)
468             && $manifest['version'] != $this->version)
469         {
470             echo "Updating manifest to version {$this->version}\n";
471             $manifest['version'] = $this->version;
472             $this->writeManifest();
473         }
474         if (   !empty($this->state)
475             && $manifest['state'] != $this->state)
476         {
477             echo "Updating manifest to state {$this->state}\n";
478             $manifest['state'] = $this->state;
479             $this->writeManifest();
480         }
481         
482         // Require PEAR information
483         if (!array_key_exists('package.xml', $this->manifest) || !is_array($this->manifest['package.xml']))
484         {
485             die("PEAR packaging information missing from component manifest {$component['manifest_file']}.\n");
486         }
487     }
488     
489     protected function writeManifest()
490     {
491         $file = sprintf("%s/%s/config/manifest.inc", $this->path, $this->package);
492         if (!is_array($this->manifest))
493         {
494             die("Manifest is not an array, aborting write");
495         }
496         file_put_contents($file, $this->drawArray($this->manifest));
497     }
498
499     protected function drawArray($array, $prefix = '')
500     {
501         $data = '';
502         foreach ($array as $key => $val)
503         {
504             $data .= $prefix;
505             if (!is_numeric($key))
506             {
507                 $data .= "'{$key}' => ";
508             }
509             
510             switch(gettype($val))
511             {
512                 case 'boolean':
513                     $data .= ($val)?'true':'false';
514                     break;
515                 case 'array':
516                     if (empty($val))
517                     {
518                         $data .= 'array()';
519                     }
520                     else
521                     {
522                         $data .= "array\n{$prefix}(\n" . $this->drawArray($val, "{$prefix}    ") . "{$prefix})";
523                     }
524                     break;
525
526                 default:
527                     if (is_numeric($val))
528                     {
529                         $data .=