Code

Updated Systems management
[gosa.git] / gosa-core / update-gosa
1 #!/usr/bin/php5
2 <?php
4 define ("GOSA_HOME", dirname(__FILE__));
5 define ("LOCALE_DIR", GOSA_HOME."/locale");
6 define ("PLUGSTATE_DIR", GOSA_HOME."/state");
8 function print_usage()
9 {
10         ?>
11 update-gosa - class cache updated and plugin manager for GOsa
12 Usage: update-gosa install dsc     Install the plugin using the dsc information
13                                    placed in the plugin source directory.
15        update-gosa remove plugin   Remove the plugin named "plugin" from
16                                    the current configuration.
18        update-gosa lists           Lists installed plugins
20        update-gosa rescan-i18n     Rebuilds the translations
22        update-gosa rescan-classes  Rebuilds the class list
23        
24        update-gosa                 Shortcut for rescan-classes and rescan-i18n
25 <?php
26         exit (1);
27 }
30 function rmdirRecursive($path, $followLinks=false) {
31   $dir= opendir($path);
32   while($entry= readdir($dir)) {
33     if(is_file($path."/".$entry) || ((!$followLinks) && is_link($path."/".$entry))) {
34       unlink($path."/".$entry);
35     } elseif (is_dir($path."/".$entry) && $entry!='.' && $entry!='..') {
36       rmdirRecursive($path."/".$entry);
37     }
38   }
39   closedir($dir);
40   return rmdir($path);
41 }
44 /* Function to include all class_ files starting at a given directory base */
45 function get_classes($folder= ".")
46 {
47   static $base_dir= "";
48   static $result= array();
50   if ($base_dir == ""){
51     if ($folder == "."){
52       $base_dir= getcwd();
53     } else {
54       $base_dir= $folder;
55     }
56   }
58   $currdir=getcwd();
59   if ($folder){
60     chdir("$folder");
61   }
63   $dh = opendir(".");
64   while(false !== ($file = readdir($dh))){
66     if (preg_match("/.*\.svn.*/", $file) ||
67         preg_match("/.*smarty.*/i",$file) ||
68         preg_match("/.*\.tpl.*/",$file) ||
69         ($file==".") ||($file =="..")){
70       continue;
71     }
73     /* Recurse through all "common" directories */
74     if (is_dir($file)){
75       get_classes($file);
76       continue;
77     }
79     /* Only take care about .inc and .php files... */
80     if (!(preg_match('/\.php$/', $file) || preg_match('/\.inc$/', $file))){
81       continue;
82     }
84     /* Include existing class_ files */
85     $contents= file($file);
86     foreach($contents as $line){
87       $line= chop($line);
88       if (preg_match('/^\s*class\s*\w.*$/', $line)){
89         $class= preg_replace('/^\s*class\s*(\w+).*$/', '\1', $line);
90         $result[$class]= preg_replace("%$base_dir/%", "", "$currdir/$folder/$file");
91       }
92     }
93   }
95   closedir($dh);
96   chdir($currdir);
98   return ($result);
99 }
102 function rescan_classes()
104         echo "Updating class cache...\n";
105         $class_mapping= get_classes();
106         $filename= GOSA_HOME."/include/class_location.inc";
108         /* Sanity checks */
109         if (!file_exists($filename) || is_writable($filename)) {
111             if (!$handle= fopen($filename, 'w')) {
112                  echo "Cannot open file \"$filename\" - aborted\n";
113                  exit (1);
114             }
116         } else {
117             echo "File \"$filename\" is not writable - aborted\n";
118             exit (2);
119         }
121         fwrite ($handle, "<?php\n\$class_mapping= array(\n");
122         foreach ($class_mapping as $key => $value){
123           fwrite ($handle, "                \"$key\" => \"$value\",\n");
124         }
125         fwrite ($handle, " );\n");
127         fclose($handle);
131 function rescan_i18n()
133         echo "Updating internationalization...\n";
134         $languages= array();
135         $size= strlen(LOCALE_DIR);
137         /* Get all available messages.po files, sort them for languages */
138         $dir= new RecursiveDirectoryIterator(LOCALE_DIR);
139         $all= new RecursiveIteratorIterator($dir);
140         foreach ( $all as $element ){
141                 if ($element->isFile() && preg_match('/\/LC_MESSAGES\/messages.po$/', $element->getPathname())){
142                         $lang= preg_replace('/^.*\/([^\/]+)\/LC_MESSAGES\/.*$/', '\1', $element);
143                         if (!isset($languages[$lang])){
144                                 $languages[$lang]= array();
145                         }
146                         $languages[$lang][]= substr($element->getPathName(), $size+1);
147                 }
148         }
150         /* For each language, merge the target .mo to the compiled directory. */
151         foreach ($languages as $language => $po_files){
152                 if (!is_dir(LOCALE_DIR."/compiled/${language}/LC_MESSAGES")){
153                         if (!mkdir (LOCALE_DIR."/compiled/${language}/LC_MESSAGES", 0755, TRUE)){
154                                 echo "Failed to create '".LOCALE_DIR."/compiled/${language}/LC_MESSAGES'- aborted";
155                                 exit (3);
156                         }
157                 }
159                 /* Cat all these po files into one single file */
160                 system ("(cd ".LOCALE_DIR." && msgcat ".implode(" ", $po_files)." > compiled/${language}/LC_MESSAGES/messages.po)", $val);
161                 if ($val != 0){
162                         echo "Merging of message files failed - aborted";
163                         exit (4);
164                 }
165                 system ("(cd ".LOCALE_DIR."/compiled/${language}/LC_MESSAGES && msgfmt -o messages.mo messages.po && rm messages.po)", $val);
166                 if ($val != 0){
167                         echo "Compiling of message files failed - aborted";
168                         exit (5);
169                 }
170         }
174 function parse_ini($file)
176         global $description, $provides, $depends, $versions, $conflicts;
178         $res= "";
179         if (file_exists($file)){
180                 $tmp= parse_ini_file($file, TRUE);
182                 if (isset($tmp['gosa-plugin'])){
183                         $plugin= &$tmp['gosa-plugin'];
184                         if (isset($plugin['name'])&& isset($plugin['description'])){
185                                 $res= $plugin['name'];
186                                 $provides[$res]= $plugin[$res];
187                                 $description[$res]= $plugin['description'];
188                                 $versions[$res]= $plugin['version'];
189                                 if (isset($plugin['depends'])){
190                                         $depends[$res]= explode(',', preg_replace('/\s+/', '', $plugin['depends']));
191                                 }
192                                 if (isset($plugin['conflicts'])){
193                                         $conflicts[$res]= explode(',', preg_replace('/\s+/', '', $plugin['conflicts']));
194                                 }
195                         }
196                 }
197         }
199         return $res;
203 function dependency_check()
205         global $description, $provides, $depends;
207         foreach ($depends as $name => $pl_depends){
208                 foreach ($pl_depends as $pl){
209                         if (!in_array($pl, $provides)){
210                                 echo "! Error: plugin '$name' depends on '$pl' which is not provided by any plugin\n\n";
211                                 exit (1);
212                         }
213                 }
214         }
218 function load_plugins()
220         if (!is_dir(PLUGSTATE_DIR)){
221                 if (!mkdir (PLUGSTATE_DIR, 0755, TRUE)){
222                         echo "Cannot create plugstate dir '".PLUGSTATE_DIR."' - aborted\n";
223                         exit (2);
224                 }
225         }
226         $dir= new DirectoryIterator(PLUGSTATE_DIR);
227         foreach ($dir as $entry){
228                 if ($dir->isDir() && !preg_match('/^\./', $dir->__toString())){
229                         $file= $dir->getPathName()."/plugin.dsc";
230                         if (parse_ini($file) == ""){
231                                 echo "! Warning: plugin ".$dir->getPathName()." is missing declarations\n";
232                         }
233                 }
234         }
238 function list_plugins()
240         global $description, $versions;
241         $count= 0;
243         /* Load plugin list */
244         load_plugins();
246         /* Show plugins */
247         foreach ($description as $name => $dsc){
248                 if ($count == 0){
249                         echo "Plugin\t\t|Version |Description\n";
250                         echo "----------------------------------------------------------------------------\n";
251                 }
252                 $ver= $versions[$name];
253                 echo "$name\t\t|$ver\t |$dsc\n";
254                 $count++;
255         }
257         /* Yell about non existing plugins... */
258         if ($count == 0){
259                 echo "No plugins found...\n\n";
260         } else {
261                 # Check for dependencies
262                 dependency_check();
263                 echo "\n";
264         }
268 function install_plugin($file)
270         global $description, $provides, $depends, $conflicts;
272         /* Load plugin list */
273         load_plugins();
275         /* Load .dsc file */
276         if (file_exists($file)){
277                 $tmp= parse_ini_file($file, TRUE);
279                 if (isset($tmp['gosa-plugin'])){
280                         $plugin= &$tmp['gosa-plugin'];
281                         if (isset($plugin['name'])&& isset($plugin['description'])){
282                                 $name= $plugin['name'];
283                                 $description= $plugin['description'];
284                                 $depends= array();
285                                 if (isset($plugin['depends'])){
286                                         $depends= explode(',', preg_replace('/\s+/', '', $plugin['depends']));
287                                 }
289                                 /* Already installed? */
290                                 if (isset($provides[$name])){
291                                         echo "! Error: plugin already installed\n\n";
292                                         exit (3);
293                                 }
295                                 /* Check if dependencies are fullfilled */
296                                 foreach ($depends as $dep){
297                                         $found= false;
298                                         foreach ($provides as $provide => $dummy){
299                                                 if ($dep == $provide){
300                                                         $found= true;
301                                                         break;
302                                                 }
303                                         }
304                                         if (!$found){
305                                                 echo "! Error: plugin depends on '$dep', but this is not installed\n\n";
306                                                 exit (3);
307                                         }
308                                 }
310                                 /* Check for conflicts */
311                                 foreach ($conflicts as $conf){
312                                         if (!in_array($conf, $provides)){
313                                                 echo "! Warning: plugin conflicts with '$conf'\n\n";
314                                         }
315                                 }
317                                 /* Create plugstate directory and touch plugin.lst */
318                                 if (!mkdir (PLUGSTATE_DIR."/$name", 0755, TRUE)){
319                                         echo "Failed to create '".PLUGSTATE_DIR."/$name - aborted";
320                                         exit (3);
321                                 }
322                                 if (!$handle= fopen(PLUGSTATE_DIR."/$name/plugin.lst", 'w')) {
323                                         echo "Cannot open file '$filename' - aborted\n";
324                                         exit (1);
325                                 }
327                                 echo "Installing plugin '$name'...\n";
329                                 /* Copy and fill plugin.lst */
330                                 $path= dirname($file);
331                                 $dir= new RecursiveDirectoryIterator($path);
332                                 $all= new RecursiveIteratorIterator($dir);
333                                 foreach ( $all as $entry ){
334                                         $source= $path."/".substr($entry->getPathName(), strlen($path) + 1);
336                                         /* Skip description - it belongs to the state dir */
337                                         if (preg_match('/\/plugin.dsc$/', $source)){
338                                                 copy ($source, PLUGSTATE_DIR."/$name/plugin.dsc");
339                                                 continue;
340                                         }
342                                         /* Skip well known directories */
343                                         if (preg_match('/^\.+$/', $source) || preg_match('/\/\.svn\//', $source)) {
344                                                 continue;
345                                         }
347                                         /* Calculate destination */
348                                         if (preg_match("%^.*locale/%", $source)){
349                                                 $dest= GOSA_HOME."/locale/plugin/$name/".preg_replace("%^.*locale/%", "", $source);
350                                         } else {
351                                                 $dest= GOSA_HOME."/plugins/".substr($entry->getPathName(), strlen($path) + 1);
352                                         }
354                                         /* Destination exists in case of directories? */
355                                         if ($entry->isDir()){
356                                                 if (!is_dir($dest)){
357                                                         mkdir($dest, 0755, TRUE);
358                                                         fwrite ($handle, "$dest\n");
359                                                 }
360                                         } else {
361                                                 if (!is_dir(dirname($dest))){
362                                                         mkdir(dirname($dest), 0755, TRUE);
363                                                         fwrite ($handle, dirname($dest)."\n");
364                                                 }
365                                         }
367                                         /* Copy files */
368                                         if ($entry->isFile()){
369                                                 copy ($source, $dest);
370                                         }
372                                         /* Note what we did... */
373                                         fwrite ($handle, "$dest\n");
374                                 }
376                                 fclose($handle);
377                         }
378                 }
379         }
380         
381         /* Update caches */
382         rescan_classes();
383         rescan_i18n();
387 function remove_plugin($name)
389         global $description, $depends;
391         /* Load plugin list */
392         load_plugins();
394         /* Present? */
395         if (!isset($description[$name])){
396                 echo "! Error: cannot find a plugin named '$name'\n\n";
397                 exit (1);
398         }
400         /* Depends? */
401         foreach ($depends as $sname => $pl_depends){
402                 if (in_array($name, $pl_depends)){
403                         echo "! Error: plugin '$sname' depends on '$name' - cannot remove it\n\n";
404                         exit (1);
405                 }
406         }
408         /* Load information */
409         if (!file_exists(PLUGSTATE_DIR."/$name/plugin.lst")){
410                 echo "! Error: cannot remove plugin '$name' - no install history found\n\n";
411                 exit (1);
412         }
414         echo "Removing plugin '$name'...\n";
415         $contents= file(PLUGSTATE_DIR."/$name/plugin.lst");
416         $cnv= array();
417         foreach($contents as $line){
418                 $entry= chop($line);
419                 $cnv[strlen($entry).":$entry"]= $entry;
420         }
421         krsort($cnv);
423         /* Remove files first */
424         clearstatcache();
425         foreach ($cnv as $entry){
426                 if (is_dir($entry)){
427                         rmdir($entry);
428                         continue;
429                 }
430                 if (file_exists($entry)){
431                         unlink($entry);
432                 }
433         }
435         /* Remove state directory for plugin */
436         rmdirRecursive(PLUGSTATE_DIR."/$name");
438         /* Update caches */
439         rescan_classes();
440         rescan_i18n();
445 /* Fill global values */
446 $description= $provides= $depends= $versions= $conflicts= array();
448 /* Action specified? */
449 if ($argc < 2){
450         rescan_classes();
451         rescan_i18n();
452         exit (0);
455 switch ($argv[1]){
456         case 'install':
457                 if (isset($argv[2])){
458                         install_plugin($argv[2]);
459                 } else {
460                         echo "Usage: update-gosa install dsc-file\n\n";
461                         exit (1);
462                 }
463                 break;
464         case 'list':
465                 list_plugins();
466                 break;
467         case 'remove':
468                 if (isset($argv[2])){
469                         remove_plugin($argv[2]);
470                 } else {
471                         echo "Usage: update-gosa remove plugin-name\n\n";
472                         exit (1);
473                 }
474                 break;
475         case 'rescan-i18n':
476                 rescan_i18n();
477                 break;
478         case 'rescan-classes':
479                 rescan_classes();
480                 break;
481         default:
482                 echo "Error: Supplied command not known\n\n";
483                 print_usage();
484                 break;
488 ?>