1#************************************************************************* 2# 3# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4# 5# Copyright 2000, 2010 Oracle and/or its affiliates. 6# 7# OpenOffice.org - a multi-platform office productivity suite 8# 9# This file is part of OpenOffice.org. 10# 11# OpenOffice.org is free software: you can redistribute it and/or modify 12# it under the terms of the GNU Lesser General Public License version 3 13# only, as published by the Free Software Foundation. 14# 15# OpenOffice.org is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU Lesser General Public License version 3 for more details 19# (a copy is included in the LICENSE file that accompanied this code). 20# 21# You should have received a copy of the GNU Lesser General Public License 22# version 3 along with OpenOffice.org. If not, see 23# <http://www.openoffice.org/license.html> 24# for a copy of the LGPLv3 License. 25# 26#************************************************************************* 27 28#************************************************************************* 29# 30# SourceConfig - Perl extension for parsing general info databases 31# 32# usage: see below 33# 34#************************************************************************* 35 36package SourceConfig; 37 38use strict; 39 40use constant SOURCE_CONFIG_FILE_NAME => 'source_config'; 41use constant SOURCE_CONFIG_VERSION => 3; 42 43use Carp; 44use Cwd; 45use RepositoryHelper; 46use File::Basename; 47use File::Temp qw(tmpnam); 48 49my $debug = 0; 50 51##### profiling ##### 52 53##### ctor ##### 54 55sub new { 56 my $proto = shift; 57 my $class = ref($proto) || $proto; 58 my $source_root = shift; 59 my @additional_repositories = @_; 60 61 my $self = {}; 62 $self->{USER_SOURCE_ROOT} = undef; 63 $self->{SOURCE_CONFIG_FILE} = undef; 64 if (defined $source_root) { 65 $source_root = Cwd::realpath($source_root); 66 $source_root =~ s/\\|\/$//; 67 if (-f $source_root) { 68 # We have path to source_config 69 if (File::Basename::basename($source_root) eq 'source_config') { 70 # We have path to source_config 71 $self->{SOURCE_CONFIG_FILE} = $source_root; 72 $source_root = File::Basename::dirname($source_root); 73 } else { 74 croak("$source_root is not a source_config file"); 75 }; 76 } else { 77 $self->{USER_SOURCE_ROOT} = $source_root; 78 $source_root .= '/..'; 79 } 80 } else { 81 $source_root = $ENV{SOURCE_ROOT_DIR}; 82 }; 83 $source_root = Cwd::realpath($source_root); 84 $self->{SOURCE_ROOT} = $source_root; 85 $self->{DEBUG} = 0; 86 $self->{VERBOSE} = 0; 87 $self->{REPOSITORIES} = {}; 88 $self->{ACTIVATED_REPOSITORIES} = {}; 89 $self->{MODULE_PATHS} = {}; 90 $self->{MODULE_BUILD_LIST_PATHS} = {}; 91 $self->{ACTIVATED_MODULES} = {}; 92 $self->{MODULE_REPOSITORY} = {}; 93 $self->{REAL_MODULES} = {}; 94 $self->{NEW_MODULES} = []; 95 $self->{REMOVE_MODULES} = {}; 96 $self->{REMOVE_REPOSITORIES} = {}; 97 $self->{NEW_REPOSITORIES} = []; 98 $self->{WARNINGS} = []; 99 $self->{REPORT_MESSAGES} = []; 100 $self->{CONFIG_FILE_CONTENT} = []; 101 if (defined $self->{USER_SOURCE_ROOT}) { 102 ${$self->{REPOSITORIES}}{File::Basename::basename($self->{USER_SOURCE_ROOT})} = $self->{USER_SOURCE_ROOT}; 103 }; 104 $self->{SOURCE_CONFIG_FILE} = get_config_file($self->{SOURCE_ROOT}) if (!defined $self->{SOURCE_CONFIG_FILE}); 105 $self->{SOURCE_CONFIG_DEFAULT} = $self->{SOURCE_ROOT} .'/'.SOURCE_CONFIG_FILE_NAME; 106 if (defined $self->{USER_SOURCE_ROOT}) { 107 ${$self->{REPOSITORIES}}{File::Basename::basename($self->{USER_SOURCE_ROOT})} = $self->{USER_SOURCE_ROOT}; 108 }; 109 foreach my $additional_repository (@additional_repositories) 110 { 111 ${$self->{REPOSITORIES}}{File::Basename::basename($additional_repository)} = $additional_repository; 112 } 113 114 read_config_file($self); 115 get_module_paths($self); 116 bless($self, $class); 117 return $self; 118} 119 120##### methods ##### 121 122sub get_version { 123 return SOURCE_CONFIG_VERSION; 124}; 125 126sub get_repositories 127{ 128 my $self = shift; 129 return sort keys %{$self->{REPOSITORIES}}; 130} 131 132sub add_repository 133{ 134 my $self = shift; 135 my $new_rep_path = shift; 136 $new_rep_path = Cwd::realpath($new_rep_path); 137 my $new_rep_name = File::Basename::basename($new_rep_path); 138 if (defined ${$self->{REPOSITORIES}}{$new_rep_name}) { 139 croak("Repository $new_rep_name is already defined!!"); 140 }; 141 ${$self->{REPOSITORIES}}{$new_rep_name} = $new_rep_path; 142 $self -> get_repository_module_paths($new_rep_name); 143} 144 145sub get_config_file_default_path { 146 my $self = shift; 147 return $self->{SOURCE_CONFIG_DEFAULT}; 148} 149 150sub get_config_file_path { 151 my $self = shift; 152 return $self->{SOURCE_CONFIG_FILE}; 153} 154 155sub get_module_repository { 156 my $self = shift; 157 my $module = shift; 158 if (defined ${$self->{MODULE_REPOSITORY}}{$module}) { 159 return ${$self->{MODULE_REPOSITORY}}{$module}; 160 } else { 161 Carp::cluck("No such module $module in active repositories!!\n"); 162 return undef; 163 }; 164} 165 166sub get_module_path { 167 my $self = shift; 168 my $module = shift; 169 if (defined ${$self->{MODULE_PATHS}}{$module}) { 170 return ${$self->{MODULE_PATHS}}{$module}; 171 } else { 172 Carp::cluck("No path for module $module in active repositories!!\n") if ($debug); 173 return undef; 174 }; 175} 176 177sub get_module_build_list { 178 my $self = shift; 179 my $module = shift; 180 if (defined ${$self->{MODULE_BUILD_LIST_PATHS}}{$module}) { 181 return ${$self->{MODULE_BUILD_LIST_PATHS}}{$module}; 182 } else { 183 my @possible_build_lists = ('build.lst', 'build.xlist'); # build lists names 184 foreach (@possible_build_lists) { 185 my $possible_path = ${$self->{MODULE_PATHS}}{$module} . "/prj/$_"; 186 if (-e $possible_path) { 187 ${$self->{MODULE_BUILD_LIST_PATHS}}{$module} = $possible_path; 188 return $possible_path; 189 }; 190 }; 191 Carp::cluck("No build list in module $module found!!\n") if ($self->{DEBUG}); 192 return undef; 193 }; 194} 195 196sub get_all_modules 197{ 198 my $self = shift; 199 my $module = shift; 200 return sort keys %{$self->{MODULE_PATHS}}; 201}; 202 203sub get_active_modules 204{ 205 my $self = shift; 206 if (scalar keys %{$self->{ACTIVATED_MODULES}}) { 207 return sort keys %{$self->{ACTIVATED_MODULES}}; 208 } 209 return sort keys %{$self->{REAL_MODULES}}; 210} 211 212sub is_active 213{ 214 my $self = shift; 215 my $module = shift; 216 if (scalar keys %{$self->{ACTIVATED_MODULES}}) { 217 return exists ($self->{ACTIVATED_MODULES}{$module}); 218 } 219 return exists ($self->{REAL_MODULES}{$module}); 220} 221 222##### private methods ##### 223 224sub get_repository_module_paths { 225 my $self = shift; 226 my $repository = shift; 227 my $repository_path = ${$self->{REPOSITORIES}}{$repository}; 228 if (opendir DIRHANDLE, $repository_path) { 229 foreach my $module (readdir(DIRHANDLE)) { 230 next if (($module =~ /^\.+/) || (!-d "$repository_path/$module")); 231 my $module_entry = $module; 232 if (($module !~ s/\.lnk$//) && ($module !~ s/\.link$//)) { 233 $self->{REAL_MODULES}{$module}++; 234 } 235 my $possible_path = "$repository_path/$module_entry"; 236 if (-d $possible_path) { 237 if (defined ${$self->{MODULE_PATHS}}{$module}) { 238 close DIRHANDLE; 239 croak("Ambiguous paths for module $module: $possible_path and " . ${$self->{MODULE_PATHS}}{$module}); 240 }; 241 ${$self->{MODULE_PATHS}}{$module} = $possible_path; 242 ${$self->{MODULE_REPOSITORY}}{$module} = $repository; 243 } 244 }; 245 close DIRHANDLE; 246 } else { 247 croak("Cannot read $repository_path repository content"); 248 }; 249}; 250 251sub get_module_paths { 252 my $self = shift; 253 foreach my $repository (keys %{$self->{REPOSITORIES}}) { 254 get_repository_module_paths($self, $repository); 255 }; 256 my @false_actives = (); 257 foreach (keys %{$self->{ACTIVATED_MODULES}}) { 258 push(@false_actives, $_) if (!defined ${$self->{MODULE_PATHS}}{$_}); 259 }; 260 croak("Error!! Activated module(s): @false_actives\nnot found in the active repositories!! Please check your " . $self->{SOURCE_CONFIG_FILE} . "\n") if (scalar @false_actives); 261 croak("No modules found!") if (!scalar keys %{$self->{MODULE_PATHS}}); 262}; 263 264sub get_config_file { 265 my $source_root = shift; 266 my $possible_path = $source_root . '/' . SOURCE_CONFIG_FILE_NAME; 267 return $possible_path if (-f $possible_path); 268 return ''; 269}; 270 271# 272# Fallback - fallback repository is based on RepositoryHelper educated guess 273# 274sub get_fallback_repository { 275 my $self = shift; 276 my $repository_root = RepositoryHelper->new()->get_repository_root(); 277 ${$self->{REPOSITORIES}}{File::Basename::basename($repository_root)} = $repository_root; 278}; 279 280sub read_config_file { 281 my $self = shift; 282 if (!$self->{SOURCE_CONFIG_FILE}) { 283 if (!defined $self->{USER_SOURCE_ROOT}) { 284 get_fallback_repository($self); 285 }; 286 return; 287 }; 288 my $repository_section = 0; 289 my $module_section = 0; 290 my $line = 0; 291 my @file_content = (); 292 293 if (open(SOURCE_CONFIG_FILE, $self->{SOURCE_CONFIG_FILE})) { 294 foreach (<SOURCE_CONFIG_FILE>) { 295 push (@{$self->{CONFIG_FILE_CONTENT}}, $_); 296 $line++; 297 chomp; 298 next if (!/^\S+/); 299 next if (/^\s*#+/); 300 s/\r\n//; 301 if (/^\[repositories\]\s*(\s+#)*/) { 302 $module_section = 0; 303 $repository_section = 1; 304 next; 305 }; 306 if (/^\[modules\]\s*(\s+#)*/) { 307 $module_section = 1; 308 $repository_section = 0; 309 next; 310 }; 311 next if (!$repository_section && !$module_section); 312 if (/\s*(\S+)=active\s*(\s+#)*/) { 313 if ($repository_section) { 314 my $repository_source_path = $self->{SOURCE_ROOT} . "/$1"; 315 if (defined $ENV{UPDMINOREXT}) { 316 $repository_source_path .= $ENV{UPDMINOREXT}; 317 if (defined ${$self->{REPOSITORIES}}{$1.$ENV{UPDMINOREXT}}) { 318 delete ${$self->{REPOSITORIES}}{$1.$ENV{UPDMINOREXT}}; 319 }; 320 }; 321 ${$self->{REPOSITORIES}}{$1} = $repository_source_path; 322 ${$self->{ACTIVATED_REPOSITORIES}}{$1}++; 323 next; 324 } 325 if ($module_section) { 326 ${$self->{ACTIVATED_MODULES}}{$1}++; 327 next; 328 }; 329 }; 330 croak("Line $line in " . $self->{SOURCE_CONFIG_FILE} . ' violates format. Please make your checks!'); 331 }; 332 close SOURCE_CONFIG_FILE; 333 if (!scalar keys %{$self->{REPOSITORIES}}) { 334 get_fallback_repository($self); 335 }; 336 } else { 337 croak('Cannot open ' . $self->{SOURCE_CONFIG_FILE} . ' for reading'); 338 }; 339}; 340 341sub remove_all_activated_repositories { 342 my $self = shift; 343 $self->remove_activated_repositories([keys %{$self->{ACTIVATED_REPOSITORIES}}]); 344}; 345 346sub remove_activated_repositories { 347 my $self = shift; 348 my $new_repositories_ref = shift; 349 push(@{$self->{WARNINGS}}, "\nWARNING: Empty repository list passed for removing from source_config\n") if (!scalar @$new_repositories_ref); 350 $self->{VERBOSE} = shift; 351 $self->{REMOVE_REPOSITORIES} = {}; 352 foreach (@$new_repositories_ref) { 353 if (!defined ${$self->{ACTIVATED_REPOSITORIES}}{$_}) { 354 push (@{$self->{WARNINGS}}, "\nWARNING: repository $_ is not activated in ". $self->get_config_file_default_path()."\n"); 355 } else { 356 ${$self->{REMOVE_REPOSITORIES}}{$_}++; 357 delete ${$self->{ACTIVATED_REPOSITORIES}}{$_}; 358 }; 359 }; 360 generate_config_file($self); 361}; 362 363sub remove_all_activated_modules { 364 my $self = shift; 365 $self->remove_activated_modules([keys %{$self->{ACTIVATED_MODULES}}]); 366}; 367 368sub remove_activated_modules { 369 my $self = shift; 370 my $new_modules_ref = shift; 371 push(@{$self->{WARNINGS}}, "\nWARNING: Empty module list passed for removing from source_config\n") if (!scalar @$new_modules_ref); 372 $self->{VERBOSE} = shift; 373 $self->{REMOVE_MODULES} = {}; 374 foreach (@$new_modules_ref) { 375 if (!defined ${$self->{ACTIVATED_MODULES}}{$_}) { 376 push (@{$self->{WARNINGS}}, "\nWARNING: module $_ is not activated in ". $self->get_config_file_default_path()."\n"); 377 } else { 378 ${$self->{REMOVE_MODULES}}{$_}++; 379 delete ${$self->{ACTIVATED_MODULES}}{$_}; 380 }; 381 }; 382 generate_config_file($self); 383}; 384 385sub add_active_repositories { 386 my $self = shift; 387 $self->{NEW_REPOSITORIES} = shift; 388 croak('Empty repository list passed for addition to source_config') if (!scalar @{$self->{NEW_REPOSITORIES}}); 389 $self->{VERBOSE} = shift; 390 foreach (@{$self->{NEW_REPOSITORIES}}) { 391 $self->add_repository($_); 392 }; 393 generate_config_file($self); 394}; 395 396sub add_active_modules { 397 my $self = shift; 398 my $module_list_ref = shift; 399 my $ignored_modules_string = ''; 400 my @real_modules = (); 401 foreach my $module (sort @$module_list_ref) { 402 if ($self->get_module_path($module)) { 403 push(@real_modules, $module); 404 } else { 405 $ignored_modules_string .= " $module"; 406 }; 407 }; 408 push (@{$self->{WARNINGS}}, "\nWARNING: following modules are not found in active repositories, and have not been added to the " . $self->get_config_file_default_path() . ":$ignored_modules_string\n") if ($ignored_modules_string); 409 $self->{NEW_MODULES} = \@real_modules; 410 croak('Empty module list passed for addition to source_config') if (!scalar @{$self->{NEW_MODULES}}); 411 $self->{VERBOSE} = shift; 412 generate_config_file($self); 413}; 414 415sub add_content { 416 my $self = shift; 417 my $content = shift; 418 my $entries_to_add = shift; 419 return if (!scalar @$entries_to_add); 420 my $message; 421 my $message_part1; 422 my $warning_message; 423 my $activated_entries; 424 425 if ($entries_to_add == $self->{NEW_MODULES}) { 426 $self->{NEW_MODULES} = []; 427 $message_part1 = "Module(s):\n"; 428 $activated_entries = $self->{ACTIVATED_MODULES}; 429 } elsif ($entries_to_add == $self->{NEW_REPOSITORIES}) { 430 $self->{NEW_REPOSITORIES} = []; 431 $message_part1 = "Repositories:\n"; 432 $activated_entries = $self->{ACTIVATED_REPOSITORIES}; 433 }; 434 foreach my $entry (@$entries_to_add) { 435 if (defined $$activated_entries{$entry}) { 436 $warning_message .= "$entry " 437 } else { 438 push(@$content, "$entry=active\n"); 439 ${$activated_entries}{$entry}++; 440 $message .= "$entry " 441 }; 442 }; 443 444 push(@{$self->{REPORT_MESSAGES}}, "\n$message_part1 $message\nhave been added to the ". $self->get_config_file_default_path()."\n") if ($message); 445 push (@{$self->{WARNINGS}}, "\nWARNING: $message_part1 $warning_message\nare already added to the ". $self->get_config_file_default_path()."\n") if ($warning_message); 446}; 447 448sub generate_config_file { 449 my $self = shift; 450 my @config_content_new = (); 451 my ($module_section, $repository_section); 452 my %removed_modules = (); 453 my %removed_repositories = (); 454 foreach (@{$self->{CONFIG_FILE_CONTENT}}) { 455 if (/^\[repositories\]\s*(\s+#)*/) { 456 if ($module_section) { 457 $self->add_content(\@config_content_new, $self->{NEW_MODULES}); 458 }; 459 $module_section = 0; 460 $repository_section = 1; 461 }; 462 if (/^\[modules\]\s*(\s+#)*/) { 463 if ($repository_section) { 464 $self->add_content(\@config_content_new, $self->{NEW_REPOSITORIES}); 465 }; 466 $module_section = 1; 467 $repository_section = 0; 468 }; 469 if ($module_section && /\s*(\S+)=active\s*(\s+#)*/) { 470 if (defined ${$self->{REMOVE_MODULES}}{$1}) { 471 $removed_modules{$1}++; 472 next; 473 }; 474 } 475 if ($repository_section && /\s*(\S+)=active\s*(\s+#)*/) { 476 if (defined ${$self->{REMOVE_REPOSITORIES}}{$1}) { 477 $removed_repositories{$1}++; 478 next; 479 }; 480 } 481 push(@config_content_new, $_); 482 }; 483 if (scalar @{$self->{NEW_MODULES}}) { 484 push(@config_content_new, "[modules]\n") if (!$module_section); 485 $self->add_content(\@config_content_new, $self->{NEW_MODULES}); 486 }; 487 if (scalar @{$self->{NEW_REPOSITORIES}}) { 488 push(@config_content_new, "[repositories]\n") if (!$repository_section); 489 $self->add_content(\@config_content_new, $self->{NEW_REPOSITORIES}); 490 }; 491 if (scalar keys %removed_modules) { 492 my @deleted_modules = keys %removed_modules; 493 push(@{$self->{REPORT_MESSAGES}}, "\nModules: @deleted_modules\nhave been removed from the ". $self->get_config_file_default_path()."\n"); 494 495 }; 496 if (scalar keys %removed_repositories) { 497 my @deleted_repositories = keys %removed_repositories; 498 push(@{$self->{REPORT_MESSAGES}}, "\nRepositories: @deleted_repositories\nhave been removed from the ". $self->get_config_file_default_path()."\n"); 499 500 }; 501 502 # Writing file, printing warnings and reports 503 504 #check if we need to write a new file 505 my $write_needed = 0; 506 if ((scalar @{$self->{CONFIG_FILE_CONTENT}}) != (scalar @config_content_new)) { 507 $write_needed++; 508 } else { 509 foreach my $i (0 .. $#{$self->{CONFIG_FILE_CONTENT}}) { 510 if (${$self->{CONFIG_FILE_CONTENT}}[$i] ne $config_content_new[$i]) { 511 $write_needed++; 512 last; 513 }; 514 }; 515 }; 516 if ($write_needed) { 517 my $temp_config_file = File::Temp::tmpnam($ENV{TMP}); 518 die("Cannot open $temp_config_file") if (!open(NEW_CONFIG, ">$temp_config_file")); 519 print NEW_CONFIG $_ foreach (@config_content_new); 520 close NEW_CONFIG; 521 rename($temp_config_file, $self->get_config_file_default_path()) or system("mv", $temp_config_file, $self->get_config_file_default_path()); 522 if (-e $temp_config_file) { 523 system("rm -rf $temp_config_file") if (!unlink $temp_config_file); 524 }; 525 $self->{CONFIG_FILE_CONTENT} = \@config_content_new; 526 }; 527 if ($self->{VERBOSE}) { 528 print $_ foreach (@{$self->{WARNINGS}}); 529 $self->{VERBOSE} = 0; 530 }; 531 $self->{WARNINGS} = []; 532 print $_ foreach (@{$self->{REPORT_MESSAGES}}); 533 $self->{REPORT_MESSAGES} = []; 534}; 535 536##### finish ##### 537 5381; # needed by use or require 539 540__END__ 541 542=head1 NAME 543 544SourceConfig - Perl extension for parsing general info databases 545 546=head1 SYNOPSIS 547 548 # example that will read source_config file and return the active repositories 549 550 use SourceConfig; 551 552 # Create a new instance of the parser: 553 $a = SourceConfig->new(); 554 555 # Get repositories for the actual workspace: 556 $a->get_repositories(); 557 558 # Add a repository new_repository for the actual workspace (via full path): 559 $a->add_repository(/DEV300/new_repository); 560 561=head1 DESCRIPTION 562 563SourceConfig is a perl extension to load and parse General Info Databses. 564It uses a simple object oriented interface to retrieve the information stored 565in the database. 566 567Methods: 568 569SourceConfig::new() 570 571Creates a new instance of SourceConfig. Can be initialized by: path to the default repository, path to the source_config, default - empty, the source_config will be taken from the environment 572 573 574SourceConfig::get_version() 575 576Returns version number of the module. Can't fail. 577 578 579SourceConfig::get_repositories() 580 581Returns sorted list of active repositories for the actual workspace 582 583 584SourceConfig::add_repository(REPOSITORY_PATH) 585 586Adds a repository to the list of active repositories 587 588 589SourceConfig::get_active_modules() 590 591Returns a sorted list of active modules 592 593SourceConfig::get_all_modules() 594 595Returns sorted list of all modules in active repositories. 596 597SourceConfig::get_module_path($module) 598 599Returns absolute module path 600 601SourceConfig::get_module_build_list($module) 602 603Returns absolute module build list path 604 605SourceConfig::get_module_repository($module) 606 607Returns the module's repository 608 609SourceConfig::get_config_file_path() 610 611Returns absolute module to the source configuration file 612 613SourceConfig::get_config_file_default_path() 614 615Returns default path for source configuration file 616 617SourceConfig::is_active() 618 619Returns 1 (TRUE) if a module is active 620Returns 0 (FALSE) if a module is not active 621 622SourceConfig::add_active_modules($module_array_ref) 623 624Adds modules from the @$module_array_ref as active to the source_config file 625 626SourceConfig::add_active_repositories($repository_array_ref) 627 628Adds repositories from the @$repository_array_ref as active to the source_config file 629 630SourceConfig::remove_activated_modules($module_array_ref) 631 632Removes modules from the @$module_array_ref from the source_config file 633 634SourceConfig::remove_all_activated_modules() 635 636Removes all activated modules from the source_config file 637 638SourceConfig::remove_activated_repositories($repository_array_ref) 639 640Removes repositories from the @$repository_array_ref from the source_config file 641 642SourceConfig::remove_all_activated_repositories() 643 644Removes all activated repositories from the source_config file 645 646 647=head2 EXPORT 648 649SourceConfig::new() 650SourceConfig::get_version() 651SourceConfig::get_repositories() 652SourceConfig::add_repository() 653SourceConfig::get_active_modules() 654SourceConfig::get_all_modules() 655SourceConfig::get_module_path($module) 656SourceConfig::get_module_build_list($module) 657SourceConfig::get_module_repository($module) 658SourceConfig::get_config_file_path() 659SourceConfig::get_config_file_default_path() 660SourceConfig::is_active($module) 661SourceConfig::add_active_modules($module_array_ref) 662SourceConfig::add_active_repositories($repository_array_ref) 663SourceConfig::remove_activated_modules($module_array_ref) 664SourceConfig::remove_all_activated_modules() 665SourceConfig::remove_activated_repositories($repository_array_ref) 666SourceConfig::remove_all_activated_repositories() 667 668=head1 AUTHOR 669 670Vladimir Glazunov, vg@openoffice.org 671 672=head1 SEE ALSO 673 674perl(1). 675 676=cut 677