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
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 $base_dir= getcwd();
52 }
54 $currdir=getcwd();
55 if ($folder){
56 chdir("$folder");
57 }
59 $dh = opendir(".");
60 while(false !== ($file = readdir($dh))){
62 if (preg_match("/.*\.svn.*/", $file) ||
63 preg_match("/.*smarty.*/i",$file) ||
64 preg_match("/.*\.tpl.*/",$file) ||
65 ($file==".") ||($file =="..")){
66 continue;
67 }
69 /* Recurse through all "common" directories */
70 if (is_dir($file)){
71 get_classes($file);
72 continue;
73 }
75 /* Only take care about .inc and .php files... */
76 if (!(preg_match('/\.php$/', $file) || preg_match('/\.inc$/', $file))){
77 continue;
78 }
80 /* Include existing class_ files */
81 $contents= file($file);
82 foreach($contents as $line){
83 $line= chop($line);
84 if (preg_match('/^\s*class\s*\w.*$/', $line)){
85 $class= preg_replace('/^\s*class\s*(\w+).*$/', '\1', $line);
86 $result[$class]= preg_replace("%$base_dir/%", "", "$currdir/$folder/$file");
87 }
88 }
89 }
91 closedir($dh);
92 chdir($currdir);
94 return ($result);
95 }
98 function rescan_classes()
99 {
100 echo "Updating class cache...\n";
101 $class_mapping= get_classes();
102 $filename= GOSA_HOME."/include/class_location.inc";
104 /* Sanity checks */
105 if (!file_exists($filename) || is_writable($filename)) {
107 if (!$handle= fopen($filename, 'w')) {
108 echo "Cannot open file \"$filename\" - aborted\n";
109 exit (1);
110 }
112 } else {
113 echo "File \"$filename\" is not writable - aborted\n";
114 exit (2);
115 }
117 fwrite ($handle, "<?php\n\$class_mapping= array(\n");
118 foreach ($class_mapping as $key => $value){
119 fwrite ($handle, " \"$key\" => \"$value\",\n");
120 }
121 fwrite ($handle, " );\n");
123 fclose($handle);
124 }
127 function rescan_i18n()
128 {
129 echo "Updating internationalization...\n";
130 $languages= array();
131 $size= strlen(LOCALE_DIR);
133 /* Get all available messages.po files, sort them for languages */
134 $dir= new RecursiveDirectoryIterator(LOCALE_DIR);
135 $all= new RecursiveIteratorIterator($dir);
136 foreach ( $all as $element ){
137 if ($element->isFile() && preg_match('/\/LC_MESSAGES\/messages.po$/', $element->getPathname())){
138 $lang= preg_replace('/^.*\/([^\/]+)\/LC_MESSAGES\/.*$/', '\1', $element);
139 if (!isset($languages[$lang])){
140 $languages[$lang]= array();
141 }
142 $languages[$lang][]= substr($element->getPathName(), $size+1);
143 }
144 }
146 /* For each language, merge the target .mo to the compiled directory. */
147 foreach ($languages as $language => $po_files){
148 if (!is_dir(LOCALE_DIR."/compiled/${language}/LC_MESSAGES")){
149 if (!mkdir (LOCALE_DIR."/compiled/${language}/LC_MESSAGES", 0755, TRUE)){
150 echo "Failed to create '".LOCALE_DIR."/compiled/${language}/LC_MESSAGES'- aborted";
151 exit (3);
152 }
153 }
155 /* Cat all these po files into one single file */
156 system ("(cd ".LOCALE_DIR." && msgcat ".implode(" ", $po_files)." > compiled/${language}/LC_MESSAGES/messages.po)", $val);
157 if ($val != 0){
158 echo "Merging of message files failed - aborted";
159 exit (4);
160 }
161 system ("(cd ".LOCALE_DIR."/compiled/${language}/LC_MESSAGES && msgfmt -o messages.mo messages.po && rm messages.po)", $val);
162 if ($val != 0){
163 echo "Compiling of message files failed - aborted";
164 exit (5);
165 }
166 }
167 }
170 function parse_ini($file)
171 {
172 global $description, $provides, $depends, $versions, $conflicts;
174 $res= "";
175 if (file_exists($file)){
176 $tmp= parse_ini_file($file, TRUE);
178 if (isset($tmp['gosa-plugin'])){
179 $plugin= &$tmp['gosa-plugin'];
180 if (isset($plugin['name'])&& isset($plugin['description'])){
181 $res= $plugin['name'];
182 $provides[$res]= $plugin[$res];
183 $description[$res]= $plugin['description'];
184 $versions[$res]= $plugin['version'];
185 if (isset($plugin['depends'])){
186 $depends[$res]= explode(',', preg_replace('/\s+/', '', $plugin['depends']));
187 }
188 if (isset($plugin['conflicts'])){
189 $conflicts[$res]= explode(',', preg_replace('/\s+/', '', $plugin['conflicts']));
190 }
191 }
192 }
193 }
195 return $res;
196 }
199 function dependency_check()
200 {
201 global $description, $provides, $depends;
203 foreach ($depends as $name => $pl_depends){
204 foreach ($pl_depends as $pl){
205 if (!in_array($pl, $provides)){
206 echo "! Error: plugin '$name' depends on '$pl' which is not provided by any plugin\n\n";
207 exit (1);
208 }
209 }
210 }
211 }
214 function load_plugins()
215 {
216 if (!is_dir(PLUGSTATE_DIR)){
217 if (!mkdir (PLUGSTATE_DIR, 0755, TRUE)){
218 echo "Cannot create plugstate dir '".PLUGSTATE_DIR."' - aborted\n";
219 exit (2);
220 }
221 }
222 $dir= new DirectoryIterator(PLUGSTATE_DIR);
223 foreach ($dir as $entry){
224 if ($dir->isDir() && !preg_match('/^\./', $dir->__toString())){
225 $file= $dir->getPathName()."/plugin.dsc";
226 if (parse_ini($file) == ""){
227 echo "! Warning: plugin ".$dir->getPathName()." is missing declarations\n";
228 }
229 }
230 }
231 }
234 function list_plugins()
235 {
236 global $description, $versions;
237 $count= 0;
239 /* Load plugin list */
240 load_plugins();
242 /* Show plugins */
243 foreach ($description as $name => $dsc){
244 if ($count == 0){
245 echo "Plugin\t\t|Version |Description\n";
246 echo "----------------------------------------------------------------------------\n";
247 }
248 $ver= $versions[$name];
249 echo "$name\t\t|$ver\t |$dsc\n";
250 $count++;
251 }
253 /* Yell about non existing plugins... */
254 if ($count == 0){
255 echo "No plugins found...\n\n";
256 } else {
257 # Check for dependencies
258 dependency_check();
259 echo "\n";
260 }
261 }
264 function install_plugin($file)
265 {
266 global $description, $provides, $depends, $conflicts;
268 /* Load plugin list */
269 load_plugins();
271 /* Load .dsc file */
272 if (file_exists($file)){
273 $tmp= parse_ini_file($file, TRUE);
275 if (isset($tmp['gosa-plugin'])){
276 $plugin= &$tmp['gosa-plugin'];
277 if (isset($plugin['name'])&& isset($plugin['description'])){
278 $name= $plugin['name'];
279 $description= $plugin['description'];
280 $depends= array();
281 if (isset($plugin['depends'])){
282 $depends= explode(',', preg_replace('/\s+/', '', $plugin['depends']));
283 }
285 /* Already installed? */
286 if (isset($provides[$name])){
287 echo "! Error: plugin already installed\n\n";
288 exit (3);
289 }
291 /* Check if dependencies are fullfilled */
292 foreach ($depends as $dep){
293 $found= false;
294 foreach ($provides as $provide => $dummy){
295 if ($dep == $provide){
296 $found= true;
297 break;
298 }
299 }
300 if (!$found){
301 echo "! Error: plugin depends on '$dep', but this is not installed\n\n";
302 exit (3);
303 }
304 }
306 /* Check for conflicts */
307 foreach ($conflicts as $conf){
308 if (!in_array($conf, $provides)){
309 echo "! Warning: plugin conflicts with '$conf'\n\n";
310 }
311 }
313 /* Create plugstate directory and touch plugin.lst */
314 if (!mkdir (PLUGSTATE_DIR."/$name", 0755, TRUE)){
315 echo "Failed to create '".PLUGSTATE_DIR."/$name - aborted";
316 exit (3);
317 }
318 if (!$handle= fopen(PLUGSTATE_DIR."/$name/plugin.lst", 'w')) {
319 echo "Cannot open file '$filename' - aborted\n";
320 exit (1);
321 }
323 echo "Installing plugin '$name'...\n";
325 /* Copy and fill plugin.lst */
326 $path= dirname($file);
327 $dir= new RecursiveDirectoryIterator($path);
328 $all= new RecursiveIteratorIterator($dir);
329 foreach ( $all as $entry ){
330 $source= $path."/".substr($entry->getPathName(), strlen($path) + 1);
332 /* Skip description - it belongs to the state dir */
333 if (preg_match('/\/plugin.dsc$/', $source)){
334 copy ($source, PLUGSTATE_DIR."/$name/plugin.dsc");
335 continue;
336 }
338 /* Skip well known directories */
339 if (preg_match('/^\.+$/', $source) || preg_match('/\/\.svn\//', $source)) {
340 continue;
341 }
343 /* Calculate destination */
344 if (preg_match("%^.*locale/%", $source)){
345 $dest= GOSA_HOME."/locale/plugin/$name/".preg_replace("%^.*locale/%", "", $source);
346 } else {
347 $dest= GOSA_HOME."/plugins/".substr($entry->getPathName(), strlen($path) + 1);
348 }
350 /* Destination exists in case of directories? */
351 if ($entry->isDir()){
352 if (!is_dir($dest)){
353 mkdir($dest, 0755, TRUE);
354 fwrite ($handle, "$dest\n");
355 }
356 } else {
357 if (!is_dir(dirname($dest))){
358 mkdir(dirname($dest), 0755, TRUE);
359 fwrite ($handle, dirname($dest)."\n");
360 }
361 }
363 /* Copy files */
364 if ($entry->isFile()){
365 copy ($source, $dest);
366 }
368 /* Note what we did... */
369 fwrite ($handle, "$dest\n");
370 }
372 fclose($handle);
373 }
374 }
375 }
377 /* Update caches */
378 rescan_classes();
379 rescan_i18n();
380 }
383 function remove_plugin($name)
384 {
385 global $description, $depends;
387 /* Load plugin list */
388 load_plugins();
390 /* Present? */
391 if (!isset($description[$name])){
392 echo "! Error: cannot find a plugin named '$name'\n\n";
393 exit (1);
394 }
396 /* Depends? */
397 foreach ($depends as $sname => $pl_depends){
398 if (in_array($name, $pl_depends)){
399 echo "! Error: plugin '$sname' depends on '$name' - cannot remove it\n\n";
400 exit (1);
401 }
402 }
404 /* Load information */
405 if (!file_exists(PLUGSTATE_DIR."/$name/plugin.lst")){
406 echo "! Error: cannot remove plugin '$name' - no install history found\n\n";
407 exit (1);
408 }
410 echo "Removing plugin '$name'...\n";
411 $contents= file(PLUGSTATE_DIR."/$name/plugin.lst");
412 $cnv= array();
413 foreach($contents as $line){
414 $entry= chop($line);
415 $cnv[strlen($entry).":$entry"]= $entry;
416 }
417 krsort($cnv);
419 /* Remove files first */
420 clearstatcache();
421 foreach ($cnv as $entry){
422 if (is_dir($entry)){
423 rmdir($entry);
424 continue;
425 }
426 if (file_exists($entry)){
427 unlink($entry);
428 }
429 }
431 /* Remove state directory for plugin */
432 rmdirRecursive(PLUGSTATE_DIR."/$name");
434 /* Update caches */
435 rescan_classes();
436 rescan_i18n();
437 }
441 /* Fill global values */
442 $description= $provides= $depends= $versions= $conflicts= array();
444 /* Action specified? */
445 if ($argc < 2){
446 rescan_classes();
447 rescan_i18n();
448 exit (0);
449 }
451 switch ($argv[1]){
452 case 'install':
453 if (isset($argv[2])){
454 install_plugin($argv[2]);
455 } else {
456 echo "Usage: update-gosa install dsc-file\n\n";
457 exit (1);
458 }
459 break;
460 case 'list':
461 list_plugins();
462 break;
463 case 'remove':
464 if (isset($argv[2])){
465 remove_plugin($argv[2]);
466 } else {
467 echo "Usage: update-gosa remove plugin-name\n\n";
468 exit (1);
469 }
470 break;
471 case 'rescan-i18n':
472 rescan_i18n();
473 break;
474 case 'rescan-classes':
475 rescan_classes();
476 break;
477 default:
478 echo "Error: Supplied command not known\n\n";
479 print_usage();
480 break;
481 }
484 ?>