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 if (!in_array($dep, $provides)){
294 echo "! Error: plugin depends on '$dep', but this is not installed\n\n";
295 exit (3);
296 }
297 }
299 /* Check for conflicts */
300 foreach ($conflicts as $conf){
301 if (!in_array($conf, $provides)){
302 echo "! Warning: plugin conflicts with '$conf'\n\n";
303 }
304 }
306 /* Create plugstate directory and touch plugin.lst */
307 if (!mkdir (PLUGSTATE_DIR."/$name", 0755, TRUE)){
308 echo "Failed to create '".PLUGSTATE_DIR."/$name - aborted";
309 exit (3);
310 }
311 if (!$handle= fopen(PLUGSTATE_DIR."/$name/plugin.lst", 'w')) {
312 echo "Cannot open file '$filename' - aborted\n";
313 exit (1);
314 }
316 echo "Installing plugin '$name'...\n";
318 /* Copy and fill plugin.lst */
319 $path= dirname($file);
320 $dir= new RecursiveDirectoryIterator($path);
321 $all= new RecursiveIteratorIterator($dir);
322 foreach ( $all as $entry ){
323 $source= $path."/".substr($entry->getPathName(), strlen($path) + 1);
325 /* Skip description - it belongs to the state dir */
326 if (preg_match('/\/plugin.dsc$/', $source)){
327 copy ($source, PLUGSTATE_DIR."/$name/plugin.dsc");
328 continue;
329 }
331 /* Skip well known directories */
332 if (preg_match('/^\.+$/', $source) || preg_match('/\/\.svn\//', $source)) {
333 continue;
334 }
336 /* Calculate destination */
337 if (preg_match("%^.*locale/%", $source)){
338 $dest= GOSA_HOME."/locale/plugin/$name/".preg_replace("%^.*locale/%", "", $source);
339 } else {
340 $dest= GOSA_HOME."/plugins/".substr($entry->getPathName(), strlen($path) + 1);
341 }
343 /* Destination exists in case of directories? */
344 if ($entry->isDir()){
345 if (!is_dir($dest)){
346 mkdir($dest, 0755, TRUE);
347 fwrite ($handle, "$dest\n");
348 }
349 } else {
350 if (!is_dir(dirname($dest))){
351 mkdir(dirname($dest), 0755, TRUE);
352 fwrite ($handle, dirname($dest)."\n");
353 }
354 }
356 /* Copy files */
357 if ($entry->isFile()){
358 copy ($source, $dest);
359 }
361 /* Note what we did... */
362 fwrite ($handle, "$dest\n");
363 }
365 fclose($handle);
366 }
367 }
368 }
370 /* Update caches */
371 rescan_classes();
372 rescan_i18n();
373 }
376 function remove_plugin($name)
377 {
378 global $description;
380 /* Load plugin list */
381 load_plugins();
383 /* Present? */
384 if (!isset($description[$name])){
385 echo "! Error: cannot find a plugin named '$name'\n\n";
386 exit (1);
387 }
389 /* Load information */
390 if (!file_exists(PLUGSTATE_DIR."/$name/plugin.lst")){
391 echo "! Error: cannot remove plugin '$name' - no install history found\n\n";
392 exit (1);
393 }
395 echo "Removing plugin '$name'...\n";
396 $contents= file(PLUGSTATE_DIR."/$name/plugin.lst");
397 $cnv= array();
398 foreach($contents as $line){
399 $entry= chop($line);
400 $cnv[strlen($entry).":$entry"]= $entry;
401 }
402 krsort($cnv);
404 /* Remove files first */
405 clearstatcache();
406 foreach ($cnv as $entry){
407 if (is_dir($entry)){
408 rmdir($entry);
409 continue;
410 }
411 if (file_exists($entry)){
412 unlink($entry);
413 }
414 }
416 /* Remove state directory for plugin */
417 rmdirRecursive(PLUGSTATE_DIR."/$name");
419 /* Update caches */
420 rescan_classes();
421 rescan_i18n();
422 }
426 /* Fill global values */
427 $description= $provides= $depends= $versions= $conflicts= array();
429 /* Action specified? */
430 if ($argc < 2){
431 rescan_classes();
432 rescan_i18n();
433 exit (0);
434 }
436 switch ($argv[1]){
437 case 'install':
438 if (isset($argv[2])){
439 install_plugin($argv[2]);
440 } else {
441 echo "Usage: update-gosa install dsc-file\n\n";
442 exit (1);
443 }
444 break;
445 case 'list':
446 list_plugins();
447 break;
448 case 'remove':
449 if (isset($argv[2])){
450 remove_plugin($argv[2]);
451 } else {
452 echo "Usage: update-gosa remove plugin-name\n\n";
453 exit (1);
454 }
455 break;
456 case 'rescan-i18n':
457 rescan_i18n();
458 break;
459 case 'rescan-classes':
460 rescan_classes();
461 break;
462 default:
463 echo "Error: Supplied command not known\n\n";
464 print_usage();
465 break;
466 }
469 ?>