1: 2 eval 'exec perl -S $0 ${1+"$@"}' 3 if 0; 4#************************************************************** 5# 6# Licensed to the Apache Software Foundation (ASF) under one 7# or more contributor license agreements. See the NOTICE file 8# distributed with this work for additional information 9# regarding copyright ownership. The ASF licenses this file 10# to you under the Apache License, Version 2.0 (the 11# "License"); you may not use this file except in compliance 12# with the License. You may obtain a copy of the License at 13# 14# http://www.apache.org/licenses/LICENSE-2.0 15# 16# Unless required by applicable law or agreed to in writing, 17# software distributed under the License is distributed on an 18# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19# KIND, either express or implied. See the License for the 20# specific language governing permissions and limitations 21# under the License. 22# 23#************************************************************** 24 25 26# 27# build - build entire project 28# 29 use strict; 30 use Config; 31 use POSIX; 32 use Cwd qw (cwd); 33 use File::Path; 34 use File::Temp qw(tmpnam tempdir); 35 use File::Find; 36 use Socket; 37 use IO::Socket::INET; 38 use IO::Select; 39 use Fcntl; 40 use POSIX qw(:errno_h); 41 use Sys::Hostname; 42 43 use lib ("$ENV{SOLARENV}/bin/modules"); 44 use SourceConfig; 45 use RepositoryHelper; 46 use Cwd 'chdir'; 47 48 my $in_so_env = 0; 49 if (defined $ENV{COMMON_ENV_TOOLS}) { 50 unshift(@INC, "$ENV{COMMON_ENV_TOOLS}/modules"); 51 $in_so_env++; 52 }; 53 if (defined $ENV{CWS_WORK_STAMP}) { 54 require GenInfoParser; import GenInfoParser; 55 require IO::Handle; import IO::Handle; 56 }; 57 my $verbose_mode = 0; 58 if (defined $ENV{verbose} || defined $ENV{VERBOSE}) { 59 $verbose_mode = ($ENV{verbose} =~ /^t\S*$/i); 60 } 61 my $enable_multiprocessing = 1; 62 ### for XML file format 63 eval { require XMLBuildListParser; import XMLBuildListParser; }; 64 my $enable_xml = 0; 65 my @modes_array = (); 66 if (!$@) { 67 $enable_xml = 1; 68 @modes_array = split('\s' , $ENV{BUILD_TYPE}); 69 }; 70#### script id ##### 71 72 ( my $script_name = $0 ) =~ s/^.*\b(\w+)\.pl$/$1/; 73 my $id_str = ' $Revision: 275224 $ '; 74 my $script_rev = 0; 75 $id_str =~ /Revision:\s+(\S+)\s+\$/ 76 ? ($script_rev = $1) : ($script_rev = "-"); 77 78 print "$script_name -- version: $script_rev\n"; 79 80######################### 81# # 82# Globale Variablen # 83# # 84######################### 85 86 my $modules_number++; 87 my $perl = 'perl'; 88 my $remove_command = 'rm -rf'; 89 my $nul = '> /dev/null'; 90 91 my $processes_to_run = 0; 92# delete $pid when not needed 93 my %projects_deps_hash = (); # hash of projects with no dependencies, 94 # that could be built now 95 my %broken_build = (); # hash of hashes of the modules, 96 # where build was broken (error occurred) 97 my %folders_hashes = (); 98 my %running_children = (); 99 my $dependencies_hash = 0; 100 my $cmd_file = ''; 101 my $build_all_parents = 0; 102 my $show = 0; 103 my $checkparents = 0; 104 my $deliver = 0; 105 my $pre_custom_job = ''; 106 my $custom_job = ''; 107 my $post_custom_job = ''; 108 my %local_deps_hash = (); 109 my %path_hash = (); 110 my %platform_hash = (); 111 my %alive_dependencies = (); 112 my %global_deps_hash = (); # hash of dependencies of the all modules 113 my %global_deps_hash_backup = (); # backup hash of external dependencies of the all modules 114 my %module_deps_hash_backup = (); # backup hash of internal dependencies for aech module 115 my @broken_module_names = (); # array of modules, which cannot be built further 116 my @dmake_args = (); 117 my %dead_parents = (); 118 my $initial_module = ''; 119 my $all_dependent = 1; # a flag indicating if the hash has independent keys 120 my $build_from_with_branches = ''; 121 my $build_all_cont = ''; 122 my $build_since = ''; 123 my $dlv_switch = ''; 124 my $child = 0; 125 my %processes_hash = (); 126 my %module_announced = (); 127 my $prepare = ''; # prepare for following incompatible build 128 my $ignore = ''; 129 my $html = ''; 130 my @ignored_errors = (); 131 my %incompatibles = (); 132 my %skip_modules = (); 133 my %exclude_branches = (); 134 my $only_platform = ''; # the only platform to prepare 135 my $only_common = ''; # the only common output tree to delete when preparing 136 my %build_modes = (); 137 my $maximal_processes = 0; # the max number of the processes run 138 my %modules_types = (); # modules types ('mod', 'img', 'lnk') hash 139 my %platforms = (); # platforms available or being working with 140 my %platforms_to_copy = (); # copy output trees for the platforms when --prepare 141 my $tmp_dir = get_tmp_dir(); # temp directory for checkout and other actions 142# $dmake_batch = undef; # 143 my @possible_build_lists = ('build.lst', 'build.xlist'); # build lists names 144 my %build_list_paths = (); # build lists names 145 my %build_lists_hash = (); # hash of arrays $build_lists_hash{$module} = \($path, $xml_list_object) 146 my $pre_job = 'announce'; # job to add for not-single module build 147 my $post_job = ''; # -"- 148 my @warnings = (); # array of warnings to be shown at the end of the process 149 my @errors = (); # array of errors to be shown at the end of the process 150 my %html_info = (); # hash containing all necessary info for generating of html page 151 my %module_by_hash = (); # hash containing all modules names as values and correspondent hashes as keys 152 my %build_in_progress = (); # hash of modules currently being built 153 my %build_is_finished = (); # hash of already built modules 154 my %modules_with_errors = (); # hash of modules with build errors 155 my %build_in_progress_shown = (); # hash of modules being built, 156 # and shown last time (to keep order) 157 my $build_time = time; 158 my $html_last_updated = 0; 159 my %jobs_hash = (); 160 my $html_path = undef; 161 my $build_finished = 0; 162 my $html_file = ''; 163 my %had_error = (); # hack for misteriuos windows problems - try run dmake 2 times if first time there was an error 164 my $mkout = correct_path("$ENV{SOLARENV}/bin/mkout.pl"); 165 my %weights_hash = (); # hash contains info about how many modules are dependent from one module 166# %weight_stored = (); 167 my $grab_output = 1; 168 my $stop_build_on_error = 0; # for multiprocessing mode: do not build further module if there is an error 169 my $interactive = 0; # for interactive mode... (for testing purpose enabled by default) 170 my $parent_process = 1; 171 my $server_mode = 0; 172 my $setenv_string = ''; # string for configuration of the client environment 173 my $ports_string = ''; # string with possible ports for server 174 my @server_ports = (); 175 my $html_port = 0; 176 my $server_socket_obj = undef; # socket object for server 177 my $html_socket_obj = undef; # socket object for server 178 my %clients_jobs = (); 179 my %clients_times = (); 180 my $client_timeout = 0; # time for client to build (in sec)... 181 # The longest time period after that 182 # the server considered as an error/client crash 183 my %lost_client_jobs = (); # hash containing lost jobs 184 my %job_jobdir = (); # hash containing job-dir pairs 185 my $reschedule_queue = 0; 186 my %module_build_queue = (); 187 my %reversed_dependencies = (); 188 my %module_paths = (); # hash with absolute module paths 189 my %active_modules = (); 190 my $generate_config = 0; 191 my %add_to_config = (); 192 my %remove_from_config = (); 193 my $clear_config = 0; 194 my $finisched_children = 0; 195 my $debug = 0; 196 my %module_deps_hash_pids = (); 197 my @argv = @ARGV; 198 my $source_config_file; 199 my @modules_built = (); 200 my $deliver_command = $ENV{DELIVER}; 201 my %prj_platform = (); 202 my $check_error_string = ''; 203 my $dmake = ''; 204 my $dmake_args = ''; 205 my $echo = ''; 206 my $new_line = "\n"; 207 my $incompatible = 0; 208 my $local_host_ip = 'localhost'; 209### main ### 210 211 get_options(); 212 213# my $temp_html_file = correct_path($tmp_dir. '/' . $ENV{INPATH}. '.build.html'); 214 get_build_modes(); 215 my %deliver_env = (); 216 if ($prepare) { 217 get_platforms(\%platforms); 218 219 $deliver_env{'BUILD_SOSL'}++; 220 $deliver_env{'COMMON_OUTDIR'}++; 221 $deliver_env{'GUI'}++; 222 $deliver_env{'INPATH'}++; 223 $deliver_env{'OFFENV_PATH'}++; 224 $deliver_env{'OUTPATH'}++; 225 $deliver_env{'L10N_framework'}++; 226 }; 227 my $workspace_path = get_workspace_path(); # This also sets $initial_module 228 my @additional_repositories = (); 229 230 # Collect additional repository directories from the ADDITIONAL_REPOSITORIES 231 # environment variable (typically set by configure). 232 foreach my $additional_repository (split(";", $ENV{ADDITIONAL_REPOSITORIES})) 233 { 234 next if $additional_repository eq ""; 235 # The repository path is expected to be relative to the workspace_path. 236 # For support of absolute paths we need functionality to distinguish between 237 # relative and absolute paths (provided by File::Spec). 238 my $path = Cwd::realpath(correct_path($workspace_path . "/" . $additional_repository)); 239 if ( -d $path) 240 { 241 push @additional_repositories, $path; 242 } 243 } 244 245 my $source_config = SourceConfig -> new($workspace_path, @additional_repositories); 246 check_partial_gnumake_build($initial_module); 247 248 if ($html) { 249 if (defined $html_path) { 250 $html_file = correct_path($html_path . '/' . $ENV{INPATH}. '.build.html'); 251 } else { 252 my $log_directory = Cwd::realpath(correct_path($workspace_path . '/..')) . '/log'; 253 if ((!-d $log_directory) && (!mkdir($log_directory))) { 254 print_error("Cannot create $log_directory for writing html file\n"); 255 }; 256 $html_file = $log_directory . '/' . $ENV{INPATH}. '.build.html'; 257 print "\nPath to html status page: $html_file\n"; 258 }; 259 }; 260 261 if ($generate_config && ($clear_config || (scalar keys %remove_from_config)||(scalar keys %add_to_config))) { 262 generate_config_file(); 263 exit 0; 264 } 265 get_module_and_buildlist_paths(); 266 provide_consistency() if (defined $ENV{CWS_WORK_STAMP} && defined($ENV{COMMON_ENV_TOOLS})); 267 268 $deliver_command .= ' -verbose' if ($html); 269 $deliver_command .= ' '. $dlv_switch if ($dlv_switch); 270 $ENV{mk_tmp}++; 271 272 get_commands(); 273 unlink ($cmd_file); 274 if ($cmd_file) { 275 if (open (CMD_FILE, ">>$cmd_file")) { 276 select CMD_FILE; 277 $echo = 'echo '; 278 if ($ENV{GUI} ne 'UNX') { 279 $new_line = "echo.\n"; 280 print "\@$echo off\npushd\n"; 281 } else { 282 $new_line = $echo."\"\"\n"; 283 }; 284 } else { 285 print_error ("Cannot open file $cmd_file"); 286 }; 287# } elsif ($show) { 288# select STDOUT; 289 }; 290 291 print $new_line; 292 get_server_ports(); 293 start_interactive() if ($interactive); 294 295 if ($checkparents) { 296 get_parent_deps( $initial_module, \%global_deps_hash ); 297 } else { 298 build_all(); 299 } 300 if (scalar keys %broken_build) { 301 cancel_build(); 302# } elsif (!$custom_job && $post_custom_job) { 303# do_post_custom_job(correct_path($workspace_path.$initial_module)); 304 }; 305 print_warnings(); 306 if (scalar keys %active_modules) { 307 foreach (keys %dead_parents) { 308 delete $dead_parents{$_} if (!defined $active_modules{$_}); 309 }; 310 }; 311 if (scalar keys %dead_parents) { 312 print $new_line.$new_line; 313 print $echo."WARNING! Project(s):\n"; 314 foreach (keys %dead_parents) { 315 print $echo."$_\n"; 316 }; 317 print $new_line; 318 print $echo."not found and couldn't be built. dependencies on that module(s) ignored. Maybe you should correct build lists.\n"; 319 print $new_line; 320 do_exit(1) if ($checkparents); 321 }; 322 if (($ENV{GUI} ne 'UNX') && $cmd_file) { 323 print "popd\n"; 324 }; 325 $ENV{mk_tmp} = ''; 326 if ($cmd_file) { 327 close CMD_FILE; 328 print STDOUT "Script $cmd_file generated\n"; 329 }; 330 if ($ignore && scalar @ignored_errors) { 331 print STDERR "\nERROR: next directories could not be built:\n"; 332 foreach (@ignored_errors) { 333 print STDERR "\t$_\n"; 334 }; 335 print STDERR "\nERROR: please check these directories and build the corresponding module(s) anew!!\n\n"; 336 do_exit(1); 337 }; 338 do_exit(0); 339 340 341######################### 342# # 343# Procedures # 344# # 345######################### 346 347sub print_warnings { 348 if (scalar @warnings) { 349 print STDERR "\nWARNING(S):\n"; 350 print STDERR $_ foreach (@warnings); 351 }; 352}; 353 354sub rename_file { 355 my ($old_file_name, $new_file_name, $throw_error) = @_; 356 357 if(-e $old_file_name) { 358 rename($old_file_name, $new_file_name) or system("mv", $old_file_name, $new_file_name); 359 if (-e $old_file_name) { 360 system("rm -rf $old_file_name") if (!unlink $old_file_name); 361 }; 362 } elsif ($throw_error) { 363 print_error("No such file $old_file_name"); 364 }; 365}; 366 367sub generate_config_file { 368 $source_config->add_active_modules([keys %add_to_config], 1) if (scalar %add_to_config); 369 $source_config->remove_activated_modules([keys %remove_from_config], 1) if (scalar %remove_from_config); 370 $source_config->remove_all_activated_modules() if ($clear_config); 371}; 372 373 374sub start_interactive { 375 my $pid = open(HTML_PIPE, "-|"); 376 print "Pipe is open\n"; 377 378 if ($pid) { # parent 379 # make file handle non-blocking 380 my $flags = ''; 381 fcntl(HTML_PIPE, F_GETFL, $flags); 382 $flags |= O_NONBLOCK; 383 fcntl(HTML_PIPE, F_SETFL, $flags); 384 } else { # child 385 $parent_process = 0; 386 start_html_listener(); 387 }; 388}; 389 390sub start_html_listener { 391 $html_port = $server_ports[$#server_ports]; 392 do { 393 $html_port++ 394 } while (start_server_on_port($html_port, \$html_socket_obj)); 395 print "html_port:$html_port html_socket_obj: $html_socket_obj\n"; 396 my $new_socket_obj; 397 do { 398 $new_socket_obj = accept_html_connection(); 399 if (defined $new_socket_obj) { 400 my $html_message; 401 $html_message = <$new_socket_obj>; 402 chomp $html_message; 403 print $html_message . "\n"; 404 my $socket_message = ''; 405 for my $action ('rebuild', 'delete') { 406 if ($html_message =~ /$action=(\S+)/) { 407 print $new_socket_obj "Module $1 is scheduled for $action"; 408 }; 409 }; 410 close($new_socket_obj); 411 } else { 412 sleep(10); 413 }; 414 } while(1); 415}; 416 417sub start_html_message_trigger { 418 my $child_id=fork(); ### VG: for windows there is a "simulation of the "fork"", no new procs... One can use Win32::Process::Create 419 420 if ($child_id) { 421 # parent 422# print "started listener trigger\n"; 423 } else { 424 my $buffer_size = 1024; 425 my $buffer; 426 my $rv; 427 my $full_buffer = ''; 428 my %modules_to_rebuild = (); 429 my $paddr; 430 while ($rv = sysread(HTML_PIPE, $buffer, $buffer_size)) { 431 $full_buffer .= $buffer; 432 }; 433 if (length $full_buffer) { 434 print "**********Got message $full_buffer\n"; 435 socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!"; 436 if (connect(SOCKET, $paddr)) { 437 $full_buffer .= "\n"; 438 syswrite SOCKET, $full_buffer, length $full_buffer; 439# close SOCKET or die "Child close socket: $!"; 440 } else { 441 die "Child connect: $!"; 442 }; 443 } 444 _exit(0); 445 }; 446}; 447 448sub get_html_orders { 449 return if (!$interactive); 450 my $buffer_size = 1024; 451 my $buffer; 452 my $rv; 453 my $full_buffer = ''; 454 my %modules_to_rebuild = (); 455 my %modules_to_delete = (); 456 while ($rv = sysread(HTML_PIPE, $buffer, $buffer_size)) { 457 $full_buffer .= $buffer; 458 }; 459# }; 460 my @html_messages = split(/\n/, $full_buffer); 461 foreach (@html_messages) { 462 if (/^html_port:(\d+)/) { 463 $html_port = $1; 464 print "Html port is: $html_port\n"; 465 next; 466 };# GET /rebuild=officenames HTTP/1.0 467 print "Message: $_\n"; 468 chomp; 469 if (/GET\s+\/delete=(\S+)[:(\S+)]*\s*HTTP/) { 470 $modules_to_delete{$1} = $2; 471 print "$1 scheduled for removal from build for \n"; 472 } 473 if (/GET\s+\/rebuild=(\S+)[:(\S+)]*\s*HTTP/) { 474 if (defined $global_deps_hash{$1}) { 475 print "!!! /tarModule $1 has not been built. Html order ignored\n"; 476 } else { 477 $modules_to_rebuild{$1} = $2; 478 print "Scheduled $1 for rebuild\n"; 479 } 480 } 481 }; 482 if (scalar keys %modules_to_delete) { 483 $reschedule_queue++; 484 schedule_delete(\%modules_to_delete); 485 generate_html_file(); 486 }; 487 if (scalar keys %modules_to_rebuild) { 488 $reschedule_queue++; 489 schedule_rebuild(\%modules_to_rebuild); 490 generate_html_file(); 491 }; 492}; 493 494sub schedule_delete { 495 my $modules_to_delete = shift; 496 foreach (keys %$modules_to_delete) { 497 print "Schedule module $_ for delete\n"; 498 delete ($global_deps_hash{$_}); 499 delete ($global_deps_hash_backup{$_}); 500 if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) { 501 kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}; 502 handle_dead_children(0); 503 }; 504 remove_from_dependencies($_, \%global_deps_hash); 505 remove_from_dependencies($_, \%global_deps_hash_backup); 506 delete $reversed_dependencies{$_}; 507 delete $build_is_finished{$_} if defined $build_is_finished{$_}; 508 delete $modules_with_errors{$_} if defined $modules_with_errors{$_}; 509 delete $module_announced{$_} if defined $module_announced{$_}; 510 delete $html_info{$_} if defined $html_info{$_}; 511 delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_}; 512 }; 513}; 514 515sub schedule_rebuild { 516 my $modules_to_rebuild = shift; 517 foreach (keys %$modules_to_rebuild) { 518 if (defined $$modules_to_rebuild{$_}) { 519 print "Schedule directory for rebuild"; 520 } else { 521 print "Schedule complete $_ module for rebuild\n"; 522 if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) { 523 kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}; 524 handle_dead_children(0); 525 }; 526 delete $build_is_finished{$_} if defined $build_is_finished{$_}; 527 delete $modules_with_errors{$_} if defined $modules_with_errors{$_}; 528 delete $module_announced{$_}; 529 initialize_html_info($_); 530 531 foreach my $waiter (keys %{$reversed_dependencies{$_}}) { 532 # for rebuild_all_dependent - refacture "if" condition 533 ${$global_deps_hash{$waiter}}{$_}++ if (!defined $build_is_finished{$waiter}); 534 }; 535 delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_}; 536 my %single_module_dep_hash = (); 537 foreach my $module (keys %{$global_deps_hash_backup{$_}}) { 538 if (defined ${$global_deps_hash_backup{$_}}{$module} && (!defined $build_is_finished{$module})) { 539 $single_module_dep_hash{$module}++; 540 }; 541 }; 542 $global_deps_hash{$_} = \%single_module_dep_hash; 543 }; 544 }; 545}; 546 547 548# 549# procedure retrieves build list path 550# (all possibilities are taken into account) 551# 552sub get_build_list_path { 553 my $module = shift; 554 return $build_list_paths{$module} if (defined $build_list_paths{$module}); 555 my @possible_dirs = ($module, $module. '.lnk', $module. '.link'); 556 return $build_list_paths{$module} if (defined $build_list_paths{$module}); 557 foreach (@possible_dirs) { 558 my $possible_dir_path = $module_paths{$_}.'/prj/'; 559 if (-d $possible_dir_path) { 560 foreach my $build_list (@possible_build_lists) { 561 my $possible_build_list_path = correct_path($possible_dir_path . $build_list); 562 if (-f $possible_build_list_path) { 563 $build_list_paths{$module} = $possible_build_list_path; 564 return $possible_build_list_path; 565 }; 566 } 567 print_error("There's no build list for $module"); 568 }; 569 }; 570 $dead_parents{$module}++; 571 $build_list_paths{$module} = correct_path(retrieve_build_list($module)) if (!defined $build_list_paths{$module}); 572 return $build_list_paths{$module}; 573}; 574 575# 576# Get dependencies hash of the current and all parent projects 577# 578sub get_parent_deps { 579 my $prj_dir = shift; 580 my $deps_hash = shift; 581 my @unresolved_parents = ($prj_dir); 582 my %skipped_branches = (); 583 while (my $module = pop(@unresolved_parents)) { 584 next if (defined $$deps_hash{$module}); 585 my %parents_deps_hash = (); 586 foreach (get_parents_array($module)) { 587 if (defined $exclude_branches{$_}) { 588 $skipped_branches{$_}++; 589 next; 590 }; 591 $parents_deps_hash{$_}++; 592 } 593 $$deps_hash{$module} = \%parents_deps_hash; 594 foreach my $parent (keys %parents_deps_hash) { 595 if (!defined($$deps_hash{$parent}) && (!defined $exclude_branches{$module})) { 596 push (@unresolved_parents, $parent); 597 }; 598 }; 599 }; 600 check_deps_hash($deps_hash); 601 foreach (keys %skipped_branches) { 602 print $echo . "Skipping module's $_ branch\n"; 603 delete $exclude_branches{$_}; 604 }; 605 my @missing_branches = keys %exclude_branches; 606 if (scalar @missing_branches) { 607 print_error("For $prj_dir branche(s): \"@missing_branches\" not found\n"); 608 }; 609}; 610 611sub store_weights { 612 my $deps_hash = shift; 613 foreach (keys %$deps_hash) { 614 foreach my $module_deps_hash ($$deps_hash{$_}) { 615 foreach my $dependency (keys %$module_deps_hash) { 616 $weights_hash{$dependency}++; 617 }; 618 }; 619 }; 620}; 621 622# 623# This procedure builds comlete dependency for each module, ie if the deps look like: 624# mod1 -> mod2 -> mod3 -> mod4,mod5, 625# than mod1 get mod3,mod4,mod5 as eplicit list of deps, not only mod2 as earlier 626# 627sub expand_dependencies { 628 my $deps_hash = shift; 629 630 foreach my $module1 (keys %$deps_hash) { 631 foreach my $module2 (keys %$deps_hash) { 632 next if ($module1 eq $module2); 633 if (defined ${$$deps_hash{$module2}}{$module1}) { 634 ${$$deps_hash{$module2}}{$_}++ foreach (keys %{$$deps_hash{$module1}}) 635 }; 636 }; 637 }; 638}; 639 640# 641# This procedure fills the second hash with reversed dependencies, 642# ie, with info about modules "waiting" for the module 643# 644sub reverse_dependensies { 645 my ($deps_hash, $reversed) = @_; 646 foreach my $module (keys %$deps_hash) { 647 foreach (keys %{$$deps_hash{$module}}) { 648 if (defined $$reversed{$_}) { 649 ${$$reversed{$_}}{$module}++ 650 } else { 651 my %single_module_dep_hash = ($module => 1); 652 $$reversed{$_} = \%single_module_dep_hash; 653 }; 654 }; 655 }; 656}; 657 658# 659# Build everything that should be built 660# 661sub build_all { 662 if ($build_all_parents) { 663 my ($prj, $prj_dir, $orig_prj); 664 get_parent_deps( $initial_module, \%global_deps_hash); 665 if (scalar keys %active_modules) { 666 $active_modules{$initial_module}++; 667 $modules_types{$initial_module} = 'mod'; 668 }; 669 modules_classify(keys %global_deps_hash); 670 expand_dependencies (\%global_deps_hash); 671 prepare_incompatible_build(\%global_deps_hash) if ($incompatible && (!$build_from_with_branches)); 672 if ($build_from_with_branches) { 673 my %reversed_full_deps_hash = (); 674 reverse_dependensies(\%global_deps_hash, \%reversed_full_deps_hash); 675 prepare_build_from_with_branches(\%global_deps_hash, \%reversed_full_deps_hash); 676 } 677 if ($build_all_cont || $build_since) { 678 store_weights(\%global_deps_hash); 679 prepare_build_all_cont(\%global_deps_hash); 680 %weights_hash = (); 681 }; 682 if ($generate_config) { 683 %add_to_config = %global_deps_hash; 684 generate_config_file(); 685 exit 0; 686 } elsif ($incompatible) { 687 my @missing_modules = (); 688 foreach (sort keys %global_deps_hash) { 689 push(@missing_modules, $_) if (!defined $active_modules{$_}); 690 }; 691 if (scalar @missing_modules) { 692 push(@warnings, "The modules: \"@missing_modules\" should be have been built, but they are not activated and have been skipped. Be aware, that can cause compatibility problems. Maybe you should verify your $source_config_file.\n"); 693 }; 694 }; 695 foreach my $module (keys %dead_parents, keys %skip_modules) { 696 remove_from_dependencies($module, \%global_deps_hash); 697 delete ($global_deps_hash{$module}) if (defined $global_deps_hash{$module}); 698 }; 699 store_weights(\%global_deps_hash); 700 backup_deps_hash(\%global_deps_hash, \%global_deps_hash_backup); 701 reverse_dependensies(\%global_deps_hash_backup, \%reversed_dependencies); 702 $modules_number = scalar keys %global_deps_hash; 703 initialize_html_info($_) foreach (keys %global_deps_hash); 704 if ($processes_to_run) { 705 build_multiprocessing(); 706 return; 707 }; 708 if ($server_mode) { 709 run_server(); 710 }; 711 while ($prj = pick_prj_to_build(\%global_deps_hash)) { 712 if (!defined $dead_parents{$prj}) { 713 if (scalar keys %broken_build) { 714 print $echo . "Skipping project $prj because of error(s)\n"; 715 remove_from_dependencies($prj, \%global_deps_hash); 716 $build_is_finished{$prj}++; 717 next; 718 }; 719 720 $prj_dir = $module_paths{$prj}; 721 get_module_dep_hash($prj, \%local_deps_hash); 722 my $info_hash = $html_info{$prj}; 723 $$info_hash{DIRS} = check_deps_hash(\%local_deps_hash, $prj); 724 $module_by_hash{\%local_deps_hash} = $prj; 725 build_dependent(\%local_deps_hash); 726 print $check_error_string; 727 }; 728 729 remove_from_dependencies($prj, \%global_deps_hash); 730 $build_is_finished{$prj}++; 731 }; 732 } else { 733 store_build_list_content($initial_module); 734 get_module_dep_hash($initial_module, \%local_deps_hash); 735 initialize_html_info($initial_module); 736 my $info_hash = $html_info{$initial_module}; 737 $$info_hash{DIRS} = check_deps_hash(\%local_deps_hash, $initial_module); 738 $module_by_hash{\%local_deps_hash} = $initial_module; 739 if ($server_mode) { 740 run_server(); 741 } else { 742 build_dependent(\%local_deps_hash); 743 }; 744 }; 745}; 746 747sub backup_deps_hash { 748 my $source_hash = shift; 749 my $backup_hash = shift; 750 foreach my $key (keys %$source_hash) { 751 my %values_hash = %{$$source_hash{$key}}; 752 $$backup_hash{$key} = \%values_hash; 753 }; 754}; 755 756sub initialize_html_info { 757 my $module = shift; 758 return if (defined $dead_parents{$module}); 759 $html_info{$module} = { 'DIRS' => [], 760 'ERRORFUL' => [], 761 'SUCCESSFUL' => [], 762 'BUILD_TIME' => 0}; 763} 764 765# 766# Do job 767# 768sub dmake_dir { 769 my ($new_job_name, $error_code); 770 my $job_name = shift; 771 $jobs_hash{$job_name}->{START_TIME} = time(); 772 $jobs_hash{$job_name}->{STATUS} = 'building'; 773 if ($job_name =~ /(\s)/o && (!-d $job_name)) { 774 $error_code = do_custom_job($job_name, \%local_deps_hash); 775 } else { 776 html_store_job_info(\%local_deps_hash, $job_name); 777 print_error("$job_name not found!!\n") if (!-d $job_name); 778 if (!-d $job_name) { 779 $new_job_name = $job_name; 780 $new_job_name =~ s/_simple//g; 781 if ((-d $new_job_name)) { 782 print("\nTrying $new_job_name, $job_name not found!!\n"); 783 $job_name = $new_job_name; 784 } else { 785 print_error("\n$job_name not found!!\n"); 786 } 787 } 788 if ($cmd_file) { 789 print "cd $job_name\n"; 790 print $check_error_string; 791 print $echo.$job_name."\n"; 792 print "$dmake\n"; 793 print $check_error_string; 794 } else { 795 print "\n" if ( ! $show ); 796 print "Entering $job_name\n"; 797 }; 798 remove_from_dependencies($job_name, \%local_deps_hash) if (!$child); 799 return if ($cmd_file || $show); 800 $error_code = run_job($dmake, $job_name); 801 html_store_job_info(\%local_deps_hash, $job_name, $error_code) if (!$child); 802 }; 803 804 if ($error_code && $ignore) { 805 push(@ignored_errors, $job_name); 806 $error_code = 0; 807 }; 808 if ($child) { 809 my $oldfh = select STDERR; 810 $| = 1; 811 select $oldfh; 812 $| =1; 813 if ($error_code) { 814 _exit($error_code >> 8); 815 } else { 816 _exit($? >> 8) if ($? && ($? != -1)); 817 }; 818 _exit(0); 819 } elsif ($error_code && ($error_code != -1)) { 820 $broken_build{$job_name} = $error_code; 821 return $error_code; 822 }; 823}; 824 825# 826# Procedure stores information about build list (and) 827# build list object in build_lists_hash 828# 829sub store_build_list_content { 830 my $module = shift; 831 my $build_list_path = get_build_list_path($module); 832 return undef if (!defined $build_list_path); 833 return if (!$build_list_path); 834 my $xml_list = undef; 835 if ($build_list_path =~ /\.xlist$/o) { 836 print_error("XMLBuildListParser.pm couldn\'t be found, so XML format for build lists is not enabled") if (!defined $enable_xml); 837 $xml_list = XMLBuildListParser->new(); 838 if (!$xml_list->loadXMLFile($build_list_path)) { 839 print_error("Cannot use $build_list_path"); 840 }; 841 $build_lists_hash{$module} = $xml_list; 842 } else { 843 if (open (BUILD_LST, $build_list_path)) { 844 my @build_lst = <BUILD_LST>; 845 $build_lists_hash{$module} = \@build_lst; 846 close BUILD_LST; 847 return; 848 } 849 $dead_parents{$module}++; 850 }; 851} 852# 853# Get string (list) of parent projects to build 854# 855sub get_parents_array { 856 my $module = shift; 857 store_build_list_content($module); 858 my $build_list_ref = $build_lists_hash{$module}; 859 860 if (ref($build_list_ref) eq 'XMLBuildListParser') { 861 return $build_list_ref->getModuleDependencies(\@modes_array); 862 }; 863 foreach (@$build_list_ref) { 864 if ($_ =~ /#/) { 865 if ($`) { 866 $_ = $`; 867 } else { 868 next; 869 }; 870 }; 871 s/\r\n//; 872 if ($_ =~ /\:+\s+/) { 873 return pick_for_build_type($'); 874 }; 875 }; 876 return (); 877}; 878 879# 880# get folders' platform infos 881# 882sub get_prj_platform { 883 my $build_list_ref = shift; 884 my ($prj_alias, $line); 885 foreach(@$build_list_ref) { 886 s/\r\n//; 887 $line++; 888 if ($_ =~ /\snmake\s/) { 889 if ($' =~ /\s*-\s+(\w+)[,\S+]*\s+(\S+)/ ) { 890 my $platform = $1; 891 my $alias = $2; 892 print_error ("There is no correct alias set in the line $line!") if ($alias eq 'NULL'); 893 mark_platform($alias, $platform); 894 } else { 895 print_error("Misspelling in line: \n$_"); 896 }; 897 }; 898 }; 899}; 900 901# 902# Procedure populate the dependencies hash with 903# information from XML build list object 904# 905sub get_deps_from_object { 906 my ($module, $build_list_object, $dependencies_hash) = @_; 907 908 foreach my $dir ($build_list_object->getJobDirectories("make", $ENV{GUI})) { 909 $path_hash{$dir} = $module_paths{$module}; 910 $path_hash{$dir} .= $dir if ($dir ne '/'); 911 my %deps_hash = (); 912 913 foreach my $dep ($build_list_object->getJobDependencies($dir, "make", $ENV{GUI})) { 914 $deps_hash{$dep}++; 915 }; 916 $$dependencies_hash{$dir} = \%deps_hash; 917 }; 918}; 919 920# 921# this function wraps the get_module_dep_hash and backups the resultung hash 922# 923sub get_module_dep_hash { 924 my ($module, $module_dep_hash) = @_; 925 if (defined $module_deps_hash_backup{$module}) { 926 backup_deps_hash($module_deps_hash_backup{$module}, $module_dep_hash); 927 } else { 928 get_deps_hash($module, $module_dep_hash); 929 my %values_hash = (); 930 backup_deps_hash($module_dep_hash, \%values_hash); 931 $module_deps_hash_backup{$module} = \%values_hash; 932 } 933}; 934 935# 936# Getting hashes of all internal dependencies and additional 937# information for given project 938# 939sub get_deps_hash { 940 my ($dummy, $module_to_build); 941 my %dead_dependencies = (); 942 $module_to_build = shift; 943 my $dependencies_hash = shift; 944 if ($custom_job) { 945 if ($modules_types{$module_to_build} ne 'lnk') { 946 add_prerequisite_job($dependencies_hash, $module_to_build, $pre_custom_job); 947 add_prerequisite_job($dependencies_hash, $module_to_build, $pre_job); 948 add_dependent_job($dependencies_hash, $module_to_build, $custom_job); 949 add_dependent_job($dependencies_hash, $module_to_build, $post_job); 950 add_dependent_job($dependencies_hash, $module_to_build, $post_custom_job); 951 }; 952 return; 953 }; 954 if ( defined $modules_types{$module_to_build} && $modules_types{$module_to_build} ne 'mod') { 955 add_prerequisite_job($dependencies_hash, $module_to_build, $pre_job); 956 return; 957 }; 958 959 my $build_list_ref = $build_lists_hash{$module_to_build}; 960# delete $build_lists_hash{$module_to_build}; 961 if (ref($build_list_ref) eq 'XMLBuildListParser') { 962 get_deps_from_object($module_to_build, $build_list_ref, $dependencies_hash); 963 } else { 964 get_prj_platform($build_list_ref); 965 foreach (@$build_list_ref) { 966 if ($_ =~ /#/o) { 967 next if (!$`); 968 $_ = $`; 969 }; 970 s/\r\n//; 971 if ($_ =~ /\s+nmake\s+/o) { 972 my ($platform, $dependencies, $dir, $dir_alias); 973 my %deps_hash = (); 974 $dependencies = $'; 975 $dummy = $`; 976 $dummy =~ /(\S+)\s+(\S*)/o; 977 $dir = $2; 978 $dependencies =~ /(\w+)/o; 979 $platform = $1; 980 $dependencies = $'; 981 while ($dependencies =~ /,(\w+)/o) { 982 $dependencies = $'; 983 }; 984 $dependencies =~ /\s+(\S+)\s+/o; 985 $dir_alias = $1; 986 if (!check_platform($platform)) { 987 next if (defined $platform_hash{$dir_alias}); 988 $dead_dependencies{$dir_alias}++; 989 next; 990 }; 991 delete $dead_dependencies{$dir_alias} if (defined $dead_dependencies{$dir_alias}); 992 print_error("Directory alias $dir_alias is defined at least twice!! Please, correct build.lst in module $module_to_build") if (defined $$dependencies_hash{$dir_alias}); 993 $platform_hash{$dir_alias}++; 994 $dependencies = $'; 995 print_error("$module_to_build/prj/build.lst has wrongly written dependencies string:\n$_\n") if (!$dependencies); 996 $deps_hash{$_}++ foreach (get_dependency_array($dependencies)); 997 $$dependencies_hash{$dir_alias} = \%deps_hash; 998 my $local_dir = ''; 999 if ($dir =~ /(\\|\/)/o) { 1000 $local_dir = "/$'"; 1001 }; 1002 $path_hash{$dir_alias} = correct_path($module_paths{$module_to_build} . $local_dir); 1003 } elsif ($_ !~ /^\s*$/ && $_ !~ /^\w*\s/o) { 1004 chomp; 1005 push(@errors, $_); 1006 }; 1007 }; 1008 if (scalar @errors) { 1009 my $message = "$module_to_build/prj/build.lst has wrongly written string(s):\n"; 1010 $message .= "$_\n" foreach(@errors); 1011 if ($processes_to_run) { 1012 $broken_build{$module_to_build} = $message; 1013 $dependencies_hash = undef; 1014 return; 1015 } else { 1016 print_error($message); 1017 }; 1018 }; 1019 foreach my $alias (keys %dead_dependencies) { 1020 next if defined $alive_dependencies{$alias}; 1021# if (!IsHashNative($alias)) { 1022 remove_from_dependencies($alias, $dependencies_hash); 1023 delete $dead_dependencies{$alias}; 1024# }; 1025 }; 1026 }; 1027 resolve_aliases($dependencies_hash, \%path_hash); 1028 if (!$prepare) { 1029 add_prerequisite_job($dependencies_hash, $module_to_build, $pre_custom_job); 1030 add_prerequisite_job($dependencies_hash, $module_to_build, $pre_job); 1031 add_dependent_job($dependencies_hash, $module_to_build, $custom_job); 1032 add_dependent_job($dependencies_hash, $module_to_build, $post_job) if ($module_to_build ne $initial_module); 1033 add_dependent_job($dependencies_hash, $module_to_build, $post_custom_job); 1034 }; 1035 store_weights($dependencies_hash); 1036}; 1037 1038# 1039# procedure adds which is independent from anothers, but anothers are dependent from it 1040# 1041sub add_prerequisite_job { 1042 my ($dependencies_hash, $module, $job) = @_; 1043 return if (!$job); 1044 $job = "$module $job"; 1045 foreach (keys %$dependencies_hash) { 1046 my $deps_hash = $$dependencies_hash{$_}; 1047 $$deps_hash{$job}++; 1048 }; 1049 $$dependencies_hash{$job} = {}; 1050}; 1051 1052# 1053# procedure adds a job wich is dependent from all already registered jobs 1054# 1055sub add_dependent_job { 1056 # $post_job is dependent from all jobs 1057 my ($dependencies_hash, $module, $job) = @_; 1058 return if (!$job); 1059 my %deps_hash = (); 1060 $deps_hash{$_}++ foreach (keys %$dependencies_hash); 1061 $$dependencies_hash{"$module $job"} = \%deps_hash; 1062}; 1063 1064# 1065# this procedure converts aliases to absolute paths 1066# 1067sub resolve_aliases { 1068 my ($dependencies_hash, $path_hash) = @_; 1069 foreach my $dir_alias (keys %$dependencies_hash) { 1070 my $aliases_hash_ref = $$dependencies_hash{$dir_alias}; 1071 my %paths_hash = (); 1072 foreach (keys %$aliases_hash_ref) { 1073 $paths_hash{$$path_hash{$_}}++; 1074 }; 1075 delete $$dependencies_hash{$dir_alias}; 1076 $$dependencies_hash{$$path_hash{$dir_alias}} = \%paths_hash; 1077 }; 1078}; 1079 1080# 1081# mark platform in order to prove if alias has been used according to specs 1082# 1083sub mark_platform { 1084 my $prj_alias = shift; 1085 if (exists $prj_platform{$prj_alias}) { 1086 $prj_platform{$prj_alias} = 'all'; 1087 } else { 1088 $prj_platform{$prj_alias} = shift; 1089 }; 1090}; 1091 1092# 1093# Convert path from abstract (with '\' and/or '/' delimiters) 1094# to system-independent 1095# 1096sub correct_path { 1097 $_ = shift; 1098 s/\\/\//g; 1099 return $_; 1100}; 1101 1102 1103sub check_dmake { 1104#print "Checking dmake..."; 1105 if (open(DMAKEVERSION, "dmake -V |")) { 1106# if (open(DMAKEVERSION, "dmake -V |")) { 1107 my @dmake_version = <DMAKEVERSION>; 1108 close DMAKEVERSION; 1109# if ($dmake_version[0] =~ /^dmake\s\-\sCopyright\s\(c\)/) { 1110# print " Using version $1\n" if ($dmake_version[0] =~ /Version\s(\d+\.*\d*)/); 1111# }; 1112 return; 1113 }; 1114 my $error_message = 'dmake: Command not found.'; 1115 $error_message .= ' Please rerun bootstrap' if (!defined $ENV{COMMON_ENV_TOOLS}); 1116 print_error($error_message); 1117}; 1118 1119# 1120# Get platform-dependent commands 1121# 1122sub get_commands { 1123 my $arg = ''; 1124 # Setting alias for dmake 1125 $dmake = 'dmake'; 1126 check_dmake(); 1127 1128 if ($cmd_file) { 1129 if ($ENV{GUI} eq 'UNX') { 1130 $check_error_string = "if \"\$?\" != \"0\" exit\n"; 1131 } else { 1132 $check_error_string = "if \"\%?\" != \"0\" quit\n"; 1133 }; 1134 }; 1135 1136 $dmake_args = join(' ', 'dmake', @dmake_args); 1137 1138 while ($arg = pop(@dmake_args)) { 1139 $dmake .= ' '.$arg; 1140 }; 1141 $dmake .= ' verbose=true' if ($html); 1142}; 1143 1144# 1145# Procedure retrieves list of projects to be built from build.lst 1146# 1147sub get_workspace_path { 1148 if (!defined $ENV{GUI}) { 1149 $ENV{mk_tmp} = ''; 1150 die "No environment set\n"; 1151 }; 1152 my $repository_helper = RepositoryHelper->new(); 1153 my $workspace_path = $repository_helper->get_repository_root(); 1154 my $initial_dir = $repository_helper->get_initial_directory(); 1155 if ($workspace_path eq $initial_dir) { 1156 print_error('Found no project to build'); 1157 }; 1158 $initial_module = substr($initial_dir, length($workspace_path) + 1); 1159 if ($initial_module =~ /(\\|\/)/) { 1160 $initial_module = $`; 1161 }; 1162 $module_paths{$initial_module} = $workspace_path . "/$initial_module"; 1163 return $workspace_path; 1164}; 1165 1166# 1167# Picks project which can be built now from hash and then deletes it from hash 1168# 1169sub pick_prj_to_build { 1170 my $deps_hash = shift; 1171 get_html_orders(); 1172 my $prj = find_indep_prj($deps_hash); 1173 if ($prj) { 1174 delete $$deps_hash{$prj}; 1175 generate_html_file(); 1176 }; 1177 return $prj; 1178}; 1179 1180# 1181# Make a decision if the project should be built on this platform 1182# 1183sub check_platform { 1184 my $platform = shift; 1185 return 1 if ($platform eq 'all'); 1186 return 1 if (($ENV{GUI} eq 'WIN') && ($platform eq 'w')); 1187 return 1 if (($ENV{GUI} eq 'UNX') && ($platform eq 'u')); 1188 return 1 if (($ENV{GUI} eq 'OS2') && ($platform eq 'p')); 1189 return 1 if (($ENV{GUI} eq 'WNT') && 1190 (($platform eq 'w') || ($platform eq 'n'))); 1191 return 0; 1192}; 1193 1194# 1195# Remove project to build ahead from dependencies and make an array 1196# of all from given project dependent projects 1197# 1198sub remove_from_dependencies { 1199 my ($exclude_prj, $i, $prj, $dependencies); 1200 $exclude_prj = shift; 1201 my $exclude_prj_orig = ''; 1202 $exclude_prj_orig = $` if (($exclude_prj =~ /\.lnk$/o) || ($exclude_prj =~ /\.link$/o)); 1203 $dependencies = shift; 1204 foreach $prj (keys %$dependencies) { 1205 my $prj_deps_hash = $$dependencies{$prj}; 1206 delete $$prj_deps_hash{$exclude_prj} if (defined $$prj_deps_hash{$exclude_prj}); 1207 }; 1208}; 1209 1210 1211# 1212# Check the hash for consistency 1213# 1214sub check_deps_hash { 1215 my ($deps_hash_ref, $module) = @_; 1216 my @possible_order; 1217 my $module_path = $module_paths{$module} if (defined $module); 1218 return if (!scalar keys %$deps_hash_ref); 1219 my %deps_hash = (); 1220 my $consistent; 1221 backup_deps_hash($deps_hash_ref, \%deps_hash); 1222 my $string; 1223 my $log_name; 1224 my $build_number = 0; 1225 1226 do { 1227 $consistent = ''; 1228 foreach my $key (sort keys %deps_hash) { 1229 my $local_deps_ref = $deps_hash{$key}; 1230 if (!scalar keys %$local_deps_ref) { 1231 if (defined $module) { 1232 $build_number++; 1233 $string = undef; 1234 if ($key =~ /(\s)/o) { 1235 $string = $key; 1236 } else { 1237 if (length($key) == length($module_path)) { 1238 $string = './'; 1239 } else { 1240 $string = substr($key, length($module_path) + 1); 1241 $string =~ s/\\/\//go; 1242 }; 1243 }; 1244 $log_name = $string; 1245 if ($log_name eq "$module $custom_job") { 1246 $log_name = "custom_job"; 1247 }; 1248 if ($log_name eq "$module $pre_custom_job") { 1249 $log_name = "pre_custom_job"; 1250 }; 1251 if ($log_name eq "$module $post_custom_job") { 1252 $log_name = "post_custom_job"; 1253 }; 1254 $log_name =~ s/\\|\//\./g; 1255 $log_name =~ s/\s/_/g; 1256 $log_name = $module if ($log_name =~ /^\.+$/); 1257 $log_name .= '.txt'; 1258 push(@possible_order, $key); 1259 $jobs_hash{$key} = { SHORT_NAME => $string, 1260 BUILD_NUMBER => $build_number, 1261 STATUS => 'waiting', 1262 LOG_PATH => '../' . $source_config->get_module_repository($module) . "/$module/$ENV{INPATH}/misc/logs/$log_name", 1263 LONG_LOG_PATH => correct_path($module_paths{$module} . "/$ENV{INPATH}/misc/logs/$log_name"), 1264 START_TIME => 0, 1265 FINISH_TIME => 0, 1266 CLIENT => '-' 1267 }; 1268 }; 1269 remove_from_dependencies($key, \%deps_hash); 1270 delete $deps_hash{$key}; 1271 $consistent++; 1272 }; 1273 }; 1274 } while ($consistent && (scalar keys %deps_hash)); 1275 return \@possible_order if ($consistent); 1276 print STDERR "Fatal error:"; 1277 foreach (keys %deps_hash) { 1278 print STDERR "\n\t$_ depends on: "; 1279 foreach my $i (keys %{$deps_hash{$_}}) { 1280 print STDERR (' ', $i); 1281 }; 1282 }; 1283 if ($child) { 1284 my $oldfh = select STDERR; 1285 $| = 1; 1286 _do_exit(1); 1287 } else { 1288 print_error("There are dead or circular dependencies\n"); 1289 }; 1290}; 1291 1292# 1293# Find project with no dependencies left. 1294# 1295sub find_indep_prj { 1296 my ($dependencies, $i); 1297 my @candidates = (); 1298 $all_dependent = 1; 1299 handle_dead_children(0) if ($processes_to_run); 1300 my $children = children_number(); 1301 return '' if (!$server_mode && $children && ($children >= $processes_to_run)); 1302 $dependencies = shift; 1303 if (scalar keys %$dependencies) { 1304 foreach my $job (keys %$dependencies) { 1305 if (!scalar keys %{$$dependencies{$job}}) { 1306 push(@candidates, $job); 1307 last if (!$processes_to_run); 1308 }; 1309 }; 1310 if (scalar @candidates) { 1311 $all_dependent = 0; 1312 my $best_candidate = undef; 1313 my $best_weight = 0; 1314 if (scalar @candidates > 1) { 1315 foreach my $candidate (@candidates) { 1316 my $candidate_weight = get_waiters_number($candidate); 1317 if ($candidate_weight > $best_weight) { 1318 $best_candidate = $candidate; 1319 $best_weight = $candidate_weight; 1320 }; 1321 }; 1322 if (defined $best_candidate) { 1323 return $best_candidate; 1324 } 1325 } 1326 my @sorted_candidates = sort(@candidates); 1327 return $sorted_candidates[0]; 1328 }; 1329 }; 1330 return ''; 1331}; 1332 1333sub get_waiters_number { 1334 my $module = shift; 1335 if (defined $weights_hash{$module}) { 1336 return $weights_hash{$module}; 1337 }; 1338 if (defined $reversed_dependencies{$module}) { 1339 return scalar keys %{$reversed_dependencies{$module}}; 1340 }; 1341 return 0; 1342}; 1343 1344# 1345# Check if given entry is HASH-native, that is not a user-defined data 1346# 1347#sub IsHashNative { 1348# my $prj = shift; 1349# return 1 if ($prj =~ /^HASH\(0x[\d | a | b | c | d | e | f]{6,}\)/); 1350# return 0; 1351#}; 1352 1353# 1354# Getting array of dependencies from the string given 1355# 1356sub get_dependency_array { 1357 my ($dep_string, @dependencies, $parent_prj, $prj, $string); 1358 @dependencies = (); 1359 $dep_string = shift; 1360 $string = $dep_string; 1361 $prj = shift; 1362 while ($dep_string !~ /^NULL/o) { 1363 print_error("Project $prj has wrongly written dependencies string:\n $string") if (!$dep_string); 1364 $dep_string =~ /(\S+)\s*/o; 1365 $parent_prj = $1; 1366 $dep_string = $'; 1367 if ($parent_prj =~ /\.(\w+)$/o) { 1368 $parent_prj = $`; 1369 if (($prj_platform{$parent_prj} ne $1) && 1370 ($prj_platform{$parent_prj} ne 'all')) { 1371 print_error ("$parent_prj\.$1 is a wrongly dependency identifier!\nCheck if it is platform dependent"); 1372 }; 1373 $alive_dependencies{$parent_prj}++ if (check_platform($1)); 1374 push(@dependencies, $parent_prj); 1375 } else { 1376 if ((exists($prj_platform{$parent_prj})) && 1377 ($prj_platform{$parent_prj} ne 'all') ) { 1378 print_error("$parent_prj is a wrongly used dependency identifier!\nCheck if it is platform dependent"); 1379 }; 1380 push(@dependencies, $parent_prj); 1381 }; 1382 }; 1383 return @dependencies; 1384}; 1385 1386 1387# 1388# Getting current directory list 1389# 1390sub get_directory_list { 1391 my $path = shift; 1392 opendir(CurrentDirList, $path); 1393 my @directory_list = readdir(CurrentDirList); 1394 closedir(CurrentDirList); 1395 return @directory_list; 1396}; 1397 1398sub print_error { 1399 my $message = shift; 1400 my $force = shift; 1401 $modules_number -= scalar keys %global_deps_hash; 1402 $modules_number -= 1; 1403 print STDERR "\nERROR: $message\n"; 1404 $ENV{mk_tmp} = ''; 1405 if ($cmd_file) { 1406 close CMD_FILE; 1407 unlink ($cmd_file); 1408 }; 1409 if (!$child) { 1410 $ENV{mk_tmp} = ''; 1411 close CMD_FILE if ($cmd_file); 1412 unlink ($cmd_file); 1413 do_exit(1); 1414 }; 1415 do_exit(1) if (defined $force); 1416}; 1417 1418sub usage { 1419 print STDERR "\nbuild\n"; 1420 print STDERR "Syntax: build [--all|-a[:prj_name]]|[--from|-f prj_name1[:prj_name2] [prj_name3 [...]]]|[--since|-c prj_name] [--with_branches prj_name1[:prj_name2] [--skip prj_name1[:prj_name2] [prj_name3 [...]] [prj_name3 [...]|-b]|[--prepare|-p][:platform] [--deliver|-d [--dlv_switch deliver_switch]]] [-P processes|--server [--setenvstring \"string\"] [--client_timeout MIN] [--port port1[:port2:...:portN]]] [--show|-s] [--help|-h] [--file|-F] [--ignore|-i] [--version|-V] [--mode|-m OOo[,SO[,EXT]] [--html [--html_path html_file_path] [--dontgraboutput]] [--pre_job=pre_job_sring] [--job=job_string|-j] [--post_job=post_job_sring] [--stoponerror] [--genconf [--removeall|--clear|--remove|--add [module1,module2[,...,moduleN]]]] [--exclude_branch_from prj_name1[:prj_name2] [prj_name3 [...]]] [--interactive]\n"; 1421 print STDERR "Example1: build --from sfx2\n"; 1422 print STDERR " - build all projects dependent from sfx2, starting with sfx2, finishing with the current module\n"; 1423 print STDERR "Example2: build --all:sfx2\n"; 1424 print STDERR " - the same as --all, but skip all projects that have been already built when using \"--all\" switch before sfx2\n"; 1425 print STDERR "Example3: build --all --server\n"; 1426 print STDERR " - build all projects in server mode, use first available port from default range 7890-7894 (running clients required!!)\n"; 1427 print STDERR "Example4(for unixes):\n"; 1428 print STDERR " build --all --pre_job=echo\\ Starting\\ job\\ in\\ \\\$PWD --job=some_script.sh --post_job=echo\\ Job\\ in\\ \\\$PWD\\ is\\ made\n"; 1429 print STDERR " - go through all projects, echo \"Starting job in \$PWD\" in each module, execute script some_script.sh, and finally echo \"Job in \$PWD is made\"\n"; 1430 print STDERR "\nSwitches:\n"; 1431 print STDERR " --all - build all projects from very beginning till current one\n"; 1432 print STDERR " --from - build all projects dependent from the specified (including it) till current one\n"; 1433 print STDERR " --exclude_branch_from - exclude module(s) and its branch from the build\n"; 1434 print STDERR " --mode OOo - build only projects needed for OpenOffice.org\n"; 1435 print STDERR " --prepare - clear all projects for incompatible build from prj_name till current one [for platform] (cws version)\n"; 1436 print STDERR " --with_branches- the same as \"--from\" but with build all projects in neighbour branches\n"; 1437 print STDERR " --skip - do not build certain module(s)\n"; 1438 print STDERR " --since - build all projects beginning from the specified till current one (the same as \"--all:prj_name\", but skipping prj_name)\n"; 1439 print STDERR " --checkmodules - check if all required parent projects are availlable\n"; 1440 print STDERR " --show - show what is going to be built\n"; 1441 print STDERR " --file - generate command file file_name\n"; 1442 print STDERR " --deliver - only deliver, no build (usable for \'-all\' and \'-from\' keys)\n"; 1443 print STDERR " -P - start multiprocessing build, with number of processes passed\n"; 1444 print STDERR " --server - start build in server mode (clients required)\n"; 1445 print STDERR " --setenvstring - string for configuration of the client environment\n"; 1446 print STDERR " --port - set server port, default is 7890. You may pass several ports, the server will be started on the first available\n"; 1447 print STDERR " otherwise the server will be started on first available port from the default range 7890-7894\n"; 1448 print STDERR " --client_timeout - time frame after which the client/job is considered to be lost. Default is 120 min\n"; 1449 print STDERR " --dlv_switch - use deliver with the switch specified\n"; 1450 print STDERR " --help - print help info\n"; 1451 print STDERR " --ignore - force tool to ignore errors\n"; 1452 print STDERR " --html - generate html page with build status\n"; 1453 print STDERR " file named $ENV{INPATH}.build.html will be generated in $ENV{SOLARSRC}\n"; 1454 print STDERR " --html_path - set html page path\n"; 1455 print STDERR " --dontgraboutput - do not grab console output when generating html page\n"; 1456 print STDERR " --genconf - generate/modify workspace configuration file\n"; 1457 print STDERR " --add - add active module(s) to configuration file\n"; 1458 print STDERR " --remove - removeactive modules(s) from configuration file\n"; 1459 print STDERR " --removeall|--clear - remove all active modules(s) from configuration file\n"; 1460 1461 print STDERR " --stoponerror - stop build when error occurs (for mp builds)\n"; 1462 print STDERR " --interactive - start interactive build process (process can be managed via html page)\n"; 1463 print STDERR " Custom jobs:\n"; 1464 print STDERR " --job=job_string - execute custom job in (each) module. job_string is a shell script/command to be executed instead of regular dmake jobs\n"; 1465 print STDERR " --pre_job=pre_job_string - execute preliminary job in (each) module. pre_job_string is a shell script/command to be executed before regular job in the module\n"; 1466 print STDERR " --post_job=job_string - execute a postprocess job in (each) module. post_job_string is a shell script/command to be executed after regular job in the module\n"; 1467 print STDERR "Default: - build current project\n"; 1468 print STDERR "Unknown switches passed to dmake\n"; 1469}; 1470 1471# 1472# Get all options passed 1473# 1474sub get_options { 1475 my ($arg, $dont_grab_output); 1476 while ($arg = shift @ARGV) { 1477 $arg =~ /^-P$/ and $processes_to_run = shift @ARGV and next; 1478 $arg =~ /^-P(\d+)$/ and $processes_to_run = $1 and next; 1479 $arg =~ /^--all$/ and $build_all_parents = 1 and next; 1480 $arg =~ /^-a$/ and $build_all_parents = 1 and next; 1481 $arg =~ /^--show$/ and $show = 1 and next; 1482 $arg =~ /^--checkmodules$/ and $checkparents = 1 and $ignore = 1 and next; 1483 $arg =~ /^-s$/ and $show = 1 and next; 1484 $arg =~ /^--deliver$/ and $deliver = 1 and next; 1485 $arg =~ /^(--job=)/ and $custom_job = $' and next; 1486 $arg =~ /^(--pre_job=)/ and $pre_custom_job = $' and next; 1487 $arg =~ /^(--post_job=)/ and $post_custom_job = $' and next; 1488 $arg =~ /^-d$/ and $deliver = 1 and next; 1489 $arg =~ /^--dlv_switch$/ and $dlv_switch = shift @ARGV and next; 1490 $arg =~ /^--file$/ and $cmd_file = shift @ARGV and next; 1491 $arg =~ /^-F$/ and $cmd_file = shift @ARGV and next; 1492 $arg =~ /^--skip$/ and get_modules_passed(\%skip_modules) and next; 1493 1494 if ($arg =~ /^--with_branches$/ || $arg =~ /^-b$/) { 1495 $build_from_with_branches = 1; 1496 $build_all_parents = 1; 1497 get_modules_passed(\%incompatibles); 1498 next; 1499 }; 1500 $arg =~ /^--all:(\S+)$/ and $build_all_parents = 1 1501 and $build_all_cont = $1 and next; 1502 $arg =~ /^-a:(\S+)$/ and $build_all_parents = 1 1503 and $build_all_cont = $1 and next; 1504 if ($arg =~ /^--from$/ || $arg =~ /^-f$/) { 1505 $build_all_parents = 1; 1506 get_modules_passed(\%incompatibles); 1507 next; 1508 }; 1509 if ($arg =~ /^--exclude_branch_from$/) { 1510 get_modules_passed(\%exclude_branches); 1511 next; 1512 }; 1513 $arg =~ /^--prepare$/ and $prepare = 1 and next; 1514 $arg =~ /^-p$/ and $prepare = 1 and next; 1515 $arg =~ /^--prepare:/ and $prepare = 1 and $only_platform = $' and next; 1516 $arg =~ /^-p:/ and $prepare = 1 and $only_platform = $' and next; 1517 $arg =~ /^--since$/ and $build_all_parents = 1 1518 and $build_since = shift @ARGV and next; 1519 $arg =~ /^-c$/ and $build_all_parents = 1 1520 and $build_since = shift @ARGV and next; 1521 $arg =~ /^-s$/ and $build_all_parents = 1 1522 and $build_since = shift @ARGV and next; 1523 $arg =~ /^--help$/ and usage() and do_exit(0); 1524 $arg =~ /^-h$/ and usage() and do_exit(0); 1525 $arg =~ /^--ignore$/ and $ignore = 1 and next; 1526 $arg =~ /^--genconf$/ and $generate_config = 1 and next; 1527 if ($arg =~ /^--add$/) { 1528 get_list_of_modules(\%add_to_config); 1529 next; 1530 }; 1531 if ($arg =~ /^--remove$/) { 1532 get_list_of_modules(\%remove_from_config); 1533 if (!scalar %remove_from_config) { 1534 print_error('No module list supplied!!'); 1535 }; 1536 next; 1537 }; 1538 ($arg =~ /^--clear$/ || $arg =~ /^--removeall$/) and $clear_config = 1 and next; 1539 $arg =~ /^--html$/ and $html = 1 and next; 1540 $arg =~ /^--dontgraboutput$/ and $dont_grab_output = 1 and next; 1541 $arg =~ /^--html_path$/ and $html_path = shift @ARGV and next; 1542 $arg =~ /^-i$/ and $ignore = 1 and next; 1543 $arg =~ /^--server$/ and $server_mode = 1 and next; 1544 $arg =~ /^--client_timeout$/ and $client_timeout = (shift @ARGV)*60 and next; 1545 $arg =~ /^--setenvstring$/ and $setenv_string = shift @ARGV and next; 1546 $arg =~ /^--port$/ and $ports_string = shift @ARGV and next; 1547 $arg =~ /^--version$/ and do_exit(0); 1548 $arg =~ /^-V$/ and do_exit(0); 1549 $arg =~ /^-m$/ and get_modes() and next; 1550 $arg =~ /^--mode$/ and get_modes() and next; 1551 $arg =~ /^--stoponerror$/ and $stop_build_on_error = 1 and next; 1552 $arg =~ /^--interactive$/ and $interactive = 1 and next; 1553 if ($arg =~ /^--$/) { 1554 push (@dmake_args, get_dmake_args()) if (!$custom_job); 1555 next; 1556 }; 1557 push (@dmake_args, $arg); 1558 }; 1559 if (!$html) { 1560 print_error("\"--html_path\" switch is used only with \"--html\"") if ($html_path); 1561 print_error("\"--dontgraboutput\" switch is used only with \"--html\"") if ($dont_grab_output); 1562 }; 1563 if ((scalar keys %exclude_branches) && !$build_all_parents) { 1564 print_error("\"--exclude_branch_from\" is not applicable for one module builds!!"); 1565 }; 1566 $grab_output = 0 if ($dont_grab_output); 1567 print_error('Switches --with_branches and --all collision') if ($build_from_with_branches && $build_all_cont); 1568 print_error('Switch --skip is for building multiple modules only!!') if ((scalar keys %skip_modules) && (!$build_all_parents)); 1569# print_error('Please prepare the workspace on one of UNIX platforms') if ($prepare && ($ENV{GUI} ne 'UNX')); 1570 print_error('Switches --with_branches and --since collision') if ($build_from_with_branches && $build_since); 1571 if ($show) { 1572 $processes_to_run = 0; 1573 $cmd_file = ''; 1574 }; 1575 print_error('Switches --job and --deliver collision') if ($custom_job && $deliver); 1576 $custom_job = 'deliver' if $deliver; 1577 $post_job = 'deliver' if (!$custom_job); 1578 $incompatible = scalar keys %incompatibles; 1579 if ($prepare) { 1580 print_error("--prepare is for use with --from switch only!\n") if (!$incompatible); 1581 }; 1582 if ($processes_to_run) { 1583 if ($ignore && !$html) { 1584 print_error("Cannot ignore errors in multiprocessing build"); 1585 }; 1586 if (!$enable_multiprocessing) { 1587 print_error("Cannot load Win32::Process module for multiprocessing build"); 1588 }; 1589 if ($server_mode) { 1590 print_error("Switches -P and --server collision"); 1591 }; 1592 } elsif ($stop_build_on_error) { 1593 print_error("Switch --stoponerror is only for multiprocessing builds"); 1594 }; 1595 if ($server_mode) { 1596 $html++; 1597 $client_timeout = 60 * 60 * 2 if (!$client_timeout); 1598 } else { 1599 print_error("--ports switch is for server mode only!!") if ($ports_string); 1600 print_error("--setenvstring switch is for server mode only!!") if ($setenv_string); 1601 print_error("--client_timeout switch is for server mode only!!") if ($client_timeout); 1602 }; 1603 1604 if (!$generate_config) { 1605 my $error_message = ' switch(es) should be used only with "--genconf"'; 1606 print_error('"--removeall" ("--clear")' . $error_message) if ($clear_config); 1607 if ((scalar %add_to_config) || (scalar %remove_from_config)) { 1608 print_error('"--add" or/and "--remove"' . $error_message); 1609 }; 1610 } elsif ((!scalar %add_to_config) && !$clear_config && (!scalar %remove_from_config) && !$build_all_parents){ 1611 print_error('Please supply necessary switch for "--genconf" (--add|--remove|--removeall). --add can be used with --from and such'); 1612 }; 1613 1614 if ($only_platform) { 1615 $only_common = 'common'; 1616 $only_common .= '.pro' if ($only_platform =~ /\.pro$/); 1617 }; 1618 if ($interactive) { 1619 $html++; # enable html page generation... 1620 my $local_host_name = hostname(); 1621 $local_host_ip = inet_ntoa(scalar(gethostbyname($local_host_name)) || 'localhost'); 1622 } 1623 # Default build modes(for OpenOffice.org) 1624 $ENV{BUILD_TYPE} = 'OOo EXT' if (!defined $ENV{BUILD_TYPE}); 1625 @ARGV = @dmake_args; 1626 foreach $arg (@dmake_args) { 1627 $arg =~ /^verbose=(\S+)$/i and $verbose_mode = ($1 =~ /^t\S*$/i); 1628 } 1629}; 1630 1631sub get_module_and_buildlist_paths { 1632 if ($build_all_parents || $checkparents) { 1633 $source_config_file = $source_config->get_config_file_path(); 1634 $active_modules{$_}++ foreach ($source_config->get_active_modules()); 1635 my %active_modules_copy = %active_modules; 1636 foreach ($source_config->get_all_modules()) { 1637 delete $active_modules_copy{$_} if defined($active_modules_copy{$_}); 1638 next if ($_ eq $initial_module); 1639 $module_paths{$_} = $source_config->get_module_path($_); 1640 $build_list_paths{$_} = $source_config->get_module_build_list($_) 1641 } 1642 $dead_parents{$_}++ foreach (keys %active_modules_copy); 1643 }; 1644}; 1645 1646 1647sub get_dmake_args { 1648 my $arg; 1649 my @job_args = (); 1650 while ($arg = shift @ARGV) { 1651 next if ($arg =~ /^--$/); 1652 push (@job_args, $arg); 1653 }; 1654 return @job_args; 1655}; 1656 1657# 1658# get all options without '-' 1659# 1660sub get_switch_options { 1661 my $string = ''; 1662 my $option = ''; 1663 while ($option = shift @ARGV) { 1664 if (!($option =~ /^-+/)) { 1665 $string .= '-' . $option; 1666 $string .= ' '; 1667 } else { 1668 unshift(@ARGV, $option); 1669 last; 1670 }; 1671 }; 1672 $string =~ s/\s$//; 1673 return $string; 1674}; 1675 1676# 1677# cancel build when one of children has error exit code 1678# 1679sub cancel_build { 1680# close_server_socket(); 1681 my $broken_modules_number = scalar @broken_module_names; 1682 my $message_part = 'build '; 1683 if (scalar keys %incompatibles) { 1684 my @incompatible_modules = keys %incompatibles; 1685 if ($stop_build_on_error) { 1686 $message_part .= "--from @incompatible_modules:@broken_module_names\n"; 1687 } else { 1688 $message_part .= "--from @broken_module_names\n"; 1689 }; 1690 } else { 1691 if ($processes_to_run) { 1692 $message_part .= "--from "; 1693 } else { 1694 $message_part .= "--all:"; 1695 }; 1696 $message_part .= "@broken_module_names\n"; 1697 1698 }; 1699 if ($broken_modules_number && $build_all_parents) { 1700 print STDERR "\n"; 1701 print STDERR $broken_modules_number; 1702 print STDERR " module(s): "; 1703 foreach (@broken_module_names) { 1704 print STDERR "\n\t$_"; 1705 }; 1706 print STDERR "\nneed(s) to be rebuilt\n\nReason(s):\n\n"; 1707 foreach (keys %broken_build) { 1708 print STDERR "ERROR: error " . $broken_build{$_} . " occurred while making $_\n"; 1709 }; 1710 print STDERR "\nWhen you have fixed the errors in " . 1711 (length(@broken_module_names)==1 ? "that module" : "these modules") . 1712 " you can resume the build by running:\n\n\t" . $message_part; 1713 } else { 1714 while (children_number()) { 1715 handle_dead_children(1); 1716 } 1717 foreach (keys %broken_build) { 1718 print STDERR "ERROR: error " . $broken_build{$_} . " occurred while making $_\n"; 1719 }; 1720 }; 1721 print "\n"; 1722 do_exit(1); 1723}; 1724 1725# 1726# Function for storing errors in multiprocessing AllParents build 1727# 1728sub store_error { 1729 my ($pid, $error_code) = @_; 1730 return 0 if (!$error_code); 1731 my $child_nick = $processes_hash{$pid}; 1732 if ($ENV{GUI} eq 'WNT') { 1733 if (!defined $had_error{$child_nick}) { 1734 $had_error{$child_nick}++; 1735 return 1; 1736 }; 1737 }; 1738 $modules_with_errors{$folders_hashes{$child_nick}}++; 1739 $broken_build{$child_nick} = $error_code; 1740 if ($stop_build_on_error) { 1741 clear_from_child($pid); 1742 # Let all children finish their work 1743 while (children_number()) { 1744 handle_dead_children(1); 1745 }; 1746 cancel_build(); 1747 }; 1748 return 0; 1749}; 1750 1751# 1752# child handler (clears (or stores info about) the terminated child) 1753# 1754sub handle_dead_children { 1755 my $running_children = children_number(); 1756 return if (!$running_children); 1757 my $force_wait = shift; 1758 my $try_once_more = 0; 1759 do { 1760 my $pid = 0; 1761 if (children_number() >= $processes_to_run || 1762 ($force_wait && ($running_children == children_number()))) { 1763 $pid = wait(); 1764 } else { 1765 $pid = waitpid( -1, &WNOHANG); 1766 }; 1767 if ($pid > 0) { 1768 $try_once_more = store_error($pid, $?); 1769 if ($try_once_more) { 1770 give_second_chance($pid); 1771 } else { 1772 clear_from_child($pid); 1773 }; 1774 $finisched_children++; 1775 }; 1776 } while(children_number() >= $processes_to_run); 1777}; 1778 1779sub give_second_chance { 1780 my $pid = shift; 1781 # A malicious hack for misterious windows problems - try 2 times 1782 # to run dmake in the same directory if errors occurs 1783 my $child_nick = $processes_hash{$pid}; 1784 $running_children{$folders_hashes{$child_nick}}--; 1785 delete $processes_hash{$pid}; 1786 start_child($child_nick, $folders_hashes{$child_nick}); 1787}; 1788 1789sub clear_from_child { 1790 my $pid = shift; 1791 my $child_nick = $processes_hash{$pid}; 1792 my $error_code = 0; 1793 if (defined $broken_build{$child_nick}) { 1794 $error_code = $broken_build{$child_nick}; 1795 } else { 1796 remove_from_dependencies($child_nick, 1797 $folders_hashes{$child_nick}); 1798 }; 1799 foreach (keys %module_deps_hash_pids) { 1800 delete ${$module_deps_hash_pids{$_}}{$pid} if defined (${$module_deps_hash_pids{$_}}{$pid}); 1801 }; 1802 my $module = $module_by_hash{$folders_hashes{$child_nick}}; 1803 html_store_job_info($folders_hashes{$child_nick}, $child_nick, $error_code); 1804 $running_children{$folders_hashes{$child_nick}}--; 1805 delete $processes_hash{$pid}; 1806 $verbose_mode && print 'Running processes: ' . children_number() . "\n"; 1807}; 1808 1809# 1810# Build the entire project according to queue of dependencies 1811# 1812sub build_dependent { 1813 $dependencies_hash = shift; 1814 my $pid = 0; 1815 my $child_nick = ''; 1816 $running_children{$dependencies_hash} = 0 if (!defined $running_children{$dependencies_hash}); 1817 while ($child_nick = pick_prj_to_build($dependencies_hash)) { 1818 if ($processes_to_run) { 1819 do { 1820 if (defined $modules_with_errors{$dependencies_hash} && !$ignore) { 1821 return 0 if ($build_all_parents); 1822 last; 1823 }; 1824 # start current child & all 1825 # that could be started now 1826 if ($child_nick) { 1827 start_child($child_nick, $dependencies_hash); 1828 return 1 if ($build_all_parents); 1829 } else { 1830 return 0 if ($build_all_parents); 1831 if (scalar keys %$dependencies_hash) { 1832 handle_dead_children(1); 1833 }; 1834 }; 1835 $child_nick = pick_prj_to_build($dependencies_hash); 1836 } while (scalar keys %$dependencies_hash || $child_nick); 1837 while (children_number()) { 1838 handle_dead_children(1); 1839 }; 1840 1841 if (defined $modules_with_errors{$dependencies_hash}) { 1842 cancel_build(); 1843 } 1844 mp_success_exit(); 1845 } else { 1846 if (dmake_dir($child_nick)) { 1847 push(@broken_module_names, $module_by_hash{$dependencies_hash}); 1848 cancel_build(); 1849 }; 1850 }; 1851 $child_nick = ''; 1852 }; 1853}; 1854 1855sub children_number { 1856 return scalar keys %processes_hash; 1857}; 1858 1859sub start_child { 1860 my ($job_dir, $dependencies_hash) = @_; 1861 $jobs_hash{$job_dir}->{START_TIME} = time(); 1862 $jobs_hash{$job_dir}->{STATUS} = 'building'; 1863 if ($job_dir =~ /(\s)/o) { 1864 my $error_code = undef; 1865 if ($job_dir !~ /\sdeliver$/o) { 1866 $error_code = do_custom_job($job_dir, $dependencies_hash); 1867 return; 1868 } 1869 }; 1870 $build_in_progress{$module_by_hash{$dependencies_hash}}++; 1871 html_store_job_info($dependencies_hash, $job_dir); 1872 my $pid = undef; 1873 my $children_running; 1874 my $oldfh = select STDOUT; 1875 $| = 1; 1876 if ($pid = fork) { # parent 1877 select $oldfh; 1878 $processes_hash{$pid} = $job_dir; 1879 $children_running = children_number(); 1880 $verbose_mode && print 'Running processes: ', $children_running, "\n"; 1881 $maximal_processes = $children_running if ($children_running > $maximal_processes); 1882 $folders_hashes{$job_dir} = $dependencies_hash; 1883 store_pid($dependencies_hash, $pid); 1884 $running_children{$dependencies_hash}++; 1885 } elsif (defined $pid) { # child 1886 select $oldfh; 1887 $child = 1; 1888 dmake_dir($job_dir); 1889 do_exit(1); 1890 }; 1891}; 1892 1893sub store_pid { 1894 my ($deps_hash, $pid) = @_; 1895 if (!defined $module_deps_hash_pids{$deps_hash}) { 1896 my %module_hash_pids = (); 1897 $module_deps_hash_pids{$deps_hash} = \%module_hash_pids; 1898 }; 1899 ${$module_deps_hash_pids{$deps_hash}}{$pid}++; 1900}; 1901 1902# 1903# Build everything that should be built multiprocessing version 1904# 1905sub build_multiprocessing { 1906 my $prj; 1907 do { 1908 my $got_module = 0; 1909 $finisched_children = 0; 1910 while ($prj = pick_prj_to_build(\%global_deps_hash)) { 1911 if (!defined $projects_deps_hash{$prj}) { 1912 $projects_deps_hash{$prj} = {}; 1913 get_module_dep_hash($prj, $projects_deps_hash{$prj}); 1914 my $info_hash = $html_info{$prj}; 1915 $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$prj}, $prj); 1916 $module_by_hash{$projects_deps_hash{$prj}} = $prj; 1917 } 1918 $module_build_queue{$prj}++; 1919 $got_module++; 1920 }; 1921 if (!$got_module) { 1922 cancel_build() if ((!scalar keys %module_build_queue) && !children_number()); 1923 if (!$finisched_children) { 1924# print "#### 1979: Starting waiting for dead child\n"; 1925 handle_dead_children(1); 1926 }; 1927 }; 1928 build_actual_queue(\%module_build_queue); 1929 } while (scalar keys %global_deps_hash); 1930 # Let the last module be built till the end 1931 while (scalar keys %module_build_queue) { 1932 build_actual_queue(\%module_build_queue); 1933# print "#### 1988: Starting waiting for dead child\n"; 1934 handle_dead_children(1); 1935 }; 1936 # Let all children finish their work 1937 while (children_number()) { 1938 handle_dead_children(1); 1939 }; 1940 cancel_build() if (scalar keys %broken_build); 1941 mp_success_exit(); 1942}; 1943 1944sub mp_success_exit { 1945# close_server_socket(); 1946# if (!$custom_job && $post_custom_job) { 1947# do_post_custom_job(correct_path($workspace_path.$initial_module)); 1948# }; 1949 print "\nMultiprocessing build is finished\n"; 1950 print "Maximal number of processes run: $maximal_processes\n"; 1951 do_exit(0); 1952}; 1953 1954# 1955# Here the built queue is built as long as possible 1956# 1957sub build_actual_queue { 1958 my $build_queue = shift; 1959 my $finished_projects = 0; 1960 do { 1961 my @sorted_queue = sort {(scalar keys %{$projects_deps_hash{$a}}) <=> (scalar keys %{$projects_deps_hash{$b}})} keys %$build_queue; 1962 my $started_children = 0; 1963 foreach my $prj (keys %$build_queue) { 1964 get_html_orders(); 1965 if ($reschedule_queue) { 1966 $reschedule_queue = 0; 1967 foreach (keys %$build_queue) { 1968 # Remove the module from the build queue if there is a dependency emerged 1969 if ((defined $global_deps_hash{$_}) && (scalar keys %{$global_deps_hash{$_}})) { 1970 delete $$build_queue{$_}; 1971 }; 1972 delete $$build_queue{$_} if (!defined $global_deps_hash_backup{$_}) 1973 }; 1974 return; 1975 }; 1976 if (defined $modules_with_errors{$projects_deps_hash{$prj}} && !$ignore) { 1977 push (@broken_module_names, $prj); 1978 delete $$build_queue{$prj}; 1979 next; 1980 }; 1981 $started_children += build_dependent($projects_deps_hash{$prj}); 1982 if ((!scalar keys %{$projects_deps_hash{$prj}}) && 1983 !$running_children{$projects_deps_hash{$prj}}) { 1984 if (!defined $modules_with_errors{$projects_deps_hash{$prj}} || $ignore) 1985 { 1986 remove_from_dependencies($prj, \%global_deps_hash); 1987 $build_is_finished{$prj}++; 1988 delete $$build_queue{$prj}; 1989 $finished_projects++; 1990 }; 1991 }; 1992 }; 1993 # trigger wait 1994 if (!$started_children) { 1995 if ($finished_projects) { 1996 return; 1997 } else { 1998 handle_dead_children(1); 1999 }; 2000 }; 2001 } while (scalar keys %$build_queue); 2002}; 2003 2004sub run_job { 2005 my ($job, $path, $registered_name) = @_; 2006 my $job_to_do = $job; 2007 my $error_code = 0; 2008 print "$registered_name\n"; 2009 return 0 if ( $show ); 2010 $job_to_do = $deliver_command if ($job eq 'deliver'); 2011 $registered_name = $path if (!defined $registered_name); 2012 chdir $path; 2013 getcwd(); 2014 2015 if ($html) { 2016 my $log_file = $jobs_hash{$registered_name}->{LONG_LOG_PATH}; 2017 my $log_dir = File::Basename::dirname($log_file); 2018 if (!-d $log_dir) { 2019 system("$perl $mkout"); 2020 }; 2021 $error_code = system ("$job_to_do > $log_file 2>&1"); 2022 if (!$grab_output && -f $log_file) { 2023 system("cat $log_file"); 2024 }; 2025 } else { 2026 $error_code = system ("$job_to_do"); 2027 }; 2028 return $error_code; 2029}; 2030 2031sub do_custom_job { 2032 my ($module_job, $dependencies_hash) = @_; 2033 $module_job =~ /(\s)/o; 2034 my $module = $`; 2035 my $job = $'; 2036 html_store_job_info($dependencies_hash, $module_job); 2037 my $error_code = 0; 2038 if ($job eq $pre_job) { 2039 announce_module($module); 2040# html_store_job_info($dependencies_hash, $job_dir); 2041 remove_from_dependencies($module_job, $dependencies_hash); 2042 } else { 2043 $error_code = run_job($job, $module_paths{$module}, $module_job); 2044 if ($error_code) { 2045 # give windows one more chance 2046 if ($ENV{GUI} eq 'WNT') { 2047 $error_code = run_job($job, $module_paths{$module}, $module_job); 2048 }; 2049 }; 2050 if ($error_code && $ignore) { 2051 push(@ignored_errors, $module_job); 2052 $error_code = 0; 2053 }; 2054 if ($error_code) { 2055 $modules_with_errors{$dependencies_hash}++; 2056# $broken_build{$module_job} = $error_code; 2057 } else { 2058 remove_from_dependencies($module_job, $dependencies_hash); 2059 }; 2060 }; 2061 html_store_job_info($dependencies_hash, $module_job, $error_code); 2062 return $error_code; 2063}; 2064 2065# 2066# Print announcement for module just started 2067# 2068sub announce_module { 2069 my $prj = shift; 2070 $build_in_progress{$prj}++; 2071 print_announce($prj); 2072}; 2073 2074sub print_announce { 2075 my $prj = shift; 2076 return if (defined $module_announced{$prj}); 2077 my $prj_type = ''; 2078 $prj_type = $modules_types{$prj} if (defined $modules_types{$prj}); 2079 my $text; 2080 if ($prj_type eq 'lnk') { 2081 if (!defined $active_modules{$prj}) { 2082 $text = "Skipping module $prj\n"; 2083 } else { 2084 $text = "Skipping link to $prj\n"; 2085 }; 2086 $build_is_finished{$prj}++; 2087 } elsif ($prj_type eq 'img') { 2088 $text = "Skipping incomplete $prj\n"; 2089 $build_is_finished{$prj}++; 2090 } elsif ($custom_job) { 2091 $text = "Running custom job \"$custom_job\" in module $prj\n"; 2092 } else { 2093 $text = "Building module $prj\n"; 2094 }; 2095 my $announce_string = $new_line; 2096 $announce_string .= $echo . "=============\n"; 2097 $announce_string .= $echo . $text; 2098 $announce_string .= $echo . "=============\n"; 2099 print $announce_string; 2100 $module_announced{$prj}++; 2101}; 2102 2103sub are_all_dependent { 2104 my $build_queue = shift; 2105 my $folder = ''; 2106 my $first_candidate = undef; 2107 foreach my $prj (keys %$build_queue) { 2108 $folder = find_indep_prj($projects_deps_hash{$prj}); 2109 $first_candidate = $folder if (!defined $first_candidate); 2110 }; 2111 $folder = $first_candidate; 2112 return '' if ($first_candidate); 2113 return '1'; 2114}; 2115 2116 2117# 2118# Procedure defines if the local directory is a 2119# complete module, an image or a link 2120# return values: lnk link 2121# img incomplete (image) 2122# mod complete (module) 2123# 2124sub modules_classify { 2125 my @modules = @_; 2126 foreach my $module (sort @modules) { 2127 if (!defined $module_paths{$module}) { 2128 $modules_types{$module} = 'img'; 2129 next; 2130 }; 2131 if (( $module_paths{$module} =~ /\.lnk$/) || ($module_paths{$module} =~ /\.link$/) 2132 || (!defined $active_modules{$module})) { 2133 $modules_types{$module} = 'lnk'; 2134 next; 2135 }; 2136 $modules_types{$module} = 'mod'; 2137 }; 2138}; 2139 2140# 2141# This procedure provides consistency for cws 2142# and optimized build (ie in case of --with_branches, -all:prj_name 2143# and -since switches) 2144# 2145sub provide_consistency { 2146 check_dir(); 2147 foreach my $var_ref (\$build_all_cont, \$build_since) { 2148 if ($$var_ref) { 2149 return if (defined $module_paths{$$var_ref}); 2150 print_error("Cannot find module '$$var_ref'", 9); 2151 return; 2152 }; 2153 }; 2154}; 2155 2156# 2157# Get the workspace list ('stand.lst'), either from 'localini' 2158# or, if this is not possible, from 'globalini. 2159# (Heiner's proprietary :) 2160# 2161sub get_workspace_lst 2162{ 2163 my $home = $ENV{HOME}; 2164 my $inifile = $ENV{HOME}. '/localini/stand.lst'; 2165 if (-f $inifile) { 2166 return $inifile; 2167 }; 2168 return ''; 2169} 2170 2171# 2172# Procedure clears up module for incompatible build 2173# 2174sub ensure_clear_module { 2175 my $module = shift; 2176 if ($modules_types{$module} eq 'mod') { 2177 clear_module($module); 2178 return; 2179 }; 2180 if ($modules_types{$module} eq 'lnk' && (File::Basename::basename($module_paths{$module}) ne $module)) { 2181 if(rename($module_paths{$module}, File::Basename::dirname($module_paths{$module}) ."/$module")) { 2182 $module_paths{$module} = File::Basename::dirname($module_paths{$module}) ."/$module"; 2183 clear_module($module); 2184 } else { 2185 print_error("Cannot rename link to $module. Please rename it manually"); 2186 }; 2187 }; 2188}; 2189 2190# 2191# Procedure removes output tree from the module (without common trees) 2192# 2193sub clear_module { 2194 my $module = shift; 2195 print "Removing module's $module output trees...\n"; 2196 print "\n" and return if ($show); 2197 opendir DIRHANDLE, $module_paths{$module}; 2198 my @dir_content = readdir(DIRHANDLE); 2199 closedir(DIRHANDLE); 2200 foreach (@dir_content) { 2201 next if (/^\.+$/); 2202 my $dir = correct_path($module_paths{$module}.'/'.$_); 2203 if ((!-d $dir.'/.svn') && is_output_tree($dir)) { 2204 #print "I would delete $dir\n"; 2205 rmtree("$dir", 0, 1); 2206 if (-d $dir) { 2207 system("$remove_command $dir"); 2208 if (-d $dir) { 2209 push(@warnings, "Cannot delete $dir"); 2210#print_error("Cannot delete $dir"); 2211 } else { 2212 print STDERR (">>> Removed $dir by force\n"); 2213 }; 2214 }; 2215 }; 2216 }; 2217}; 2218 2219# 2220# Figure out if the directory is an output tree 2221# 2222sub is_output_tree { 2223 my $dir = shift; 2224 $dir =~ /([\w\d\.]+)$/; 2225 $_ = $1; 2226 return '1' if (defined $platforms{$_}); 2227 if ($only_common) { 2228 return '1' if ($_ eq $only_common); 2229 } else { 2230 if (scalar keys %platforms < scalar keys %platforms_to_copy) { 2231 return ''; 2232 }; 2233 return '1' if (/^common$/); 2234 return '1' if (/^common\.pro$/); 2235 }; 2236 return ''; 2237}; 2238sub get_tmp_dir { 2239 my $tmp_dir; 2240 if( defined($ENV{TMPDIR}) ) { 2241 $tmp_dir = $ENV{TMPDIR} . '/'; 2242 } elsif( defined($ENV{TMP}) ) { 2243 $tmp_dir = $ENV{TMP} . '/'; 2244 } else { 2245 $tmp_dir = '/tmp/'; 2246 } 2247 $tmp_dir = tempdir ( DIR => $tmp_dir ); 2248 if (!-d $tmp_dir) { 2249 print_error("Cannot create temporary directory for checkout in $tmp_dir") if ($@); 2250 }; 2251 return $tmp_dir; 2252}; 2253 2254sub retrieve_build_list { 2255 my $module = shift; 2256 my $old_fh = select(STDOUT); 2257 2258 # Try to get global depencies from solver's build.lst if such exists 2259 my $solver_inc_dir = "$ENV{SOLARVER}/$ENV{OUTPATH}"; 2260 $solver_inc_dir .= $ENV{PROEXT} if (defined $ENV{PROEXT}); 2261 $solver_inc_dir .= '/inc'; 2262 $solver_inc_dir .= $ENV{UPDMINOREXT} if (defined $ENV{UPDMINOREXT}); 2263 $solver_inc_dir .= "/$module"; 2264 $solver_inc_dir = correct_path($solver_inc_dir); 2265 $dead_parents{$module}++; 2266 print "Fetching dependencies for module $module from solver..."; 2267 foreach my $onelist (@possible_build_lists) { 2268 my $build_list_candidate = "$solver_inc_dir/$onelist"; 2269 if (-e $build_list_candidate) { 2270 print " ok\n"; 2271 select($old_fh); 2272 return $build_list_candidate; 2273 }; 2274 } 2275 print(" failed\n"); 2276 print_error("incomplete dependencies!\n"); 2277 return undef; 2278}; 2279 2280sub fix_permissions { 2281 my $file = $File::Find::name; 2282 return unless -f $file; 2283 chmod '0664', $file; 2284}; 2285 2286sub prepare_build_from_with_branches { 2287 my ($full_deps_hash, $reversed_full_deps_hash) = @_; 2288 foreach my $prerequisite (keys %$full_deps_hash) { 2289 foreach my $dependent_module (keys %incompatibles) { 2290 if (defined ${$$reversed_full_deps_hash{$prerequisite}}{$dependent_module}) { 2291 remove_from_dependencies($prerequisite, $full_deps_hash); 2292 delete $$full_deps_hash{$prerequisite}; 2293# print "Removed $prerequisite\n"; 2294 last; 2295 }; 2296 }; 2297 }; 2298}; 2299 2300# 2301# Removes projects which it is not necessary to build 2302# in incompatible build 2303# 2304sub prepare_incompatible_build { 2305 my ($prj, $deps_hash, @missing_modules); 2306 $deps_hash = shift; 2307 foreach my $module (keys %incompatibles) { 2308 if (!defined $$deps_hash{$module}) { 2309 print_error("The module $initial_module is independent from $module\n"); 2310 } 2311 $incompatibles{$module} = $$deps_hash{$module}; 2312 delete $$deps_hash{$module}; 2313 } 2314 while ($prj = pick_prj_to_build($deps_hash)) { 2315 remove_from_dependencies($prj, $deps_hash); 2316 remove_from_dependencies($prj, \%incompatibles); 2317 }; 2318 foreach (keys %incompatibles) { 2319 $$deps_hash{$_} = $incompatibles{$_}; 2320 }; 2321 if ($build_all_cont) { 2322 prepare_build_all_cont($deps_hash); 2323 delete $$deps_hash{$build_all_cont}; 2324 }; 2325 @modules_built = keys %$deps_hash; 2326 %add_to_config = %$deps_hash; 2327 if ($prepare) { 2328 if ((!(defined $ENV{UPDATER} && (!defined $ENV{CWS_WORK_STAMP}))) || (defined $ENV{CWS_WORK_STAMP})) { 2329 $source_config->add_active_modules([keys %add_to_config], 0); 2330 } 2331 clear_delivered(); 2332 } 2333 my @old_output_trees = (); 2334 foreach $prj (sort keys %$deps_hash) { 2335 if ($prepare) { 2336 ensure_clear_module($prj); 2337 } else { 2338 next if ($show); 2339 if ($modules_types{$prj} ne 'mod') { 2340 push(@missing_modules, $prj); 2341 } elsif (-d $module_paths{$prj}. '/'. $ENV{INPATH}) { 2342 push(@old_output_trees, $prj); 2343 }; 2344 }; 2345 }; 2346 if (scalar @missing_modules) { 2347 my $warning_string = 'Following modules are inconsistent/missing: ' . "@missing_modules"; 2348 push(@warnings, $warning_string); 2349 }; 2350 if ($build_all_cont) { 2351 $$deps_hash{$build_all_cont} = (); 2352 $build_all_cont = ''; 2353 }; 2354 if( scalar @old_output_trees) { 2355 my $warning_string = 'Some modules contain old output trees! Please check: ' . "@old_output_trees"; 2356 push(@warnings, $warning_string); 2357 }; 2358 if (!$generate_config && scalar @warnings) { 2359 print "WARNING(S):\n"; 2360 print STDERR "$_\n" foreach (@warnings); 2361 print "\nATTENTION: If you are performing an incompatible build, please break the build with Ctrl+C and prepare the workspace with \"--prepare\" switch!\n\n" if (!$prepare); 2362 sleep(10); 2363 }; 2364 if ($prepare) { 2365 print "\nPreparation finished"; 2366 if (scalar @warnings) { 2367 print " with WARNINGS!!\n\n"; 2368 } else {print " successfully\n\n";} 2369 } 2370 do_exit(0) if ($prepare); 2371}; 2372 2373# 2374# Removes projects which it is not necessary to build 2375# with --all:prj_name or --since switch 2376# 2377sub prepare_build_all_cont { 2378 my ($prj, $deps_hash, $border_prj); 2379 $deps_hash = shift; 2380 $border_prj = $build_all_cont if ($build_all_cont); 2381 $border_prj = $build_since if ($build_since); 2382 while ($prj = pick_prj_to_build($deps_hash)) { 2383 my $orig_prj = ''; 2384 $orig_prj = $` if ($prj =~ /\.lnk$/o); 2385 $orig_prj = $` if ($prj =~ /\.link$/o); 2386 if (($border_prj ne $prj) && 2387 ($border_prj ne $orig_prj)) { 2388 remove_from_dependencies($prj, $deps_hash); 2389 next; 2390 } else { 2391 if ($build_all_cont) { 2392 $$deps_hash{$prj} = (); 2393 } else { 2394 remove_from_dependencies($prj, $deps_hash); 2395 }; 2396 return; 2397 }; 2398 }; 2399}; 2400 2401sub get_modes { 2402 my $option = ''; 2403 while ($option = shift @ARGV) { 2404 if ($option =~ /^-+/) { 2405 unshift(@ARGV, $option); 2406 return; 2407 } else { 2408 if ($option =~ /,/) { 2409 $build_modes{$`}++; 2410 unshift(@ARGV, $') if ($'); 2411 } else {$build_modes{$option}++;}; 2412 }; 2413 }; 2414 $build_modes{$option}++; 2415}; 2416 2417sub get_list_of_modules { 2418 my $option = ''; 2419 my $hash_ref = shift; 2420 while ($option = shift @ARGV) { 2421 if ($option =~ /^-+/) { 2422 unshift(@ARGV, $option); 2423 return; 2424 } else { 2425 if ($option =~ /,/) { 2426 foreach (split /,/, $option) { 2427 next if (!$_); 2428 $$hash_ref{$_}++; 2429 }; 2430 } else { 2431 $$hash_ref{$option}++; 2432 }; 2433 }; 2434 }; 2435# if (!scalar %$hash_ref) { 2436# print_error('No module list supplied!!'); 2437# }; 2438}; 2439 2440sub get_modules_passed { 2441 my $hash_ref = shift; 2442 my $option = ''; 2443 while ($option = shift @ARGV) { 2444 if ($option =~ /^-+/) { 2445 unshift(@ARGV, $option); 2446 return; 2447 } else { 2448 if ($option =~ /(:)/) { 2449 $option = $`; 2450 print_error("\'--from\' switch collision") if ($build_all_cont); 2451 $build_all_cont = $'; 2452 }; 2453 $$hash_ref{$option}++; 2454 }; 2455 }; 2456}; 2457 2458sub get_workspace_platforms { 2459 my $workspace_patforms = shift; 2460 my $solver_path = $ENV{SOLARVERSION}; 2461 opendir(SOLVERDIR, $solver_path); 2462 my @dir_list = readdir(SOLVERDIR); 2463 close SOLVERDIR; 2464 foreach (@dir_list) { 2465 next if /^common/; 2466 next if /^\./; 2467 if (open(LS, "ls $solver_path/$_/inc/*minor.mk 2>$nul |")) { 2468 foreach my $string (<LS>) { 2469 chomp $string; 2470 if ($string =~ /minor.mk$/) { 2471 $$workspace_patforms{$_}++ 2472 }; 2473 }; 2474 close LS; 2475 }; 2476 }; 2477}; 2478 2479sub get_platforms { 2480 my $platforms_ref = shift; 2481 if ($only_platform) { 2482 foreach (split(',', $only_platform)) { 2483 $$platforms_ref{$_}++; 2484 } 2485 $platforms_ref = \%platforms_to_copy; 2486 }; 2487 2488 my $workspace_lst = get_workspace_lst(); 2489 if ($workspace_lst) { 2490 my $workspace_db; 2491 eval { $workspace_db = GenInfoParser->new(); }; 2492 if (!$@) { 2493 my $success = $workspace_db->load_list($workspace_lst); 2494 if ( !$success ) { 2495 print_error("Can't load workspace list '$workspace_lst'.", 4); 2496 } 2497 my $access_path = $ENV{WORK_STAMP} . '/Environments'; 2498 my @platforms_available = $workspace_db->get_keys($access_path); 2499 my $solver = $ENV{SOLARVERSION}; 2500 foreach (@platforms_available) { 2501 my $s_path = $solver . '/' . $_; 2502 $$platforms_ref{$_}++ if (-d $s_path); 2503 }; 2504 } else { 2505 get_workspace_platforms(\%platforms); 2506 }; 2507 }; 2508 2509 if (!scalar keys %platforms) { 2510 # An Auses wish - fallback to INPATH for new platforms 2511 if (defined $ENV{INPATH}) { 2512 $$platforms_ref{$ENV{INPATH}}++; 2513 } else { 2514 print_error("There is no platform found!!") ; 2515 }; 2516 }; 2517}; 2518 2519# 2520# This procedure clears solver from delivered 2521# by the modules to be build 2522# 2523sub clear_delivered { 2524 my $message = 'Clearing up delivered'; 2525 my %backup_vars; 2526 my $deliver_delete_switches = '-delete'; 2527 if (scalar keys %platforms < scalar keys %platforms_to_copy) { 2528 $message .= ' without common trees'; 2529 $deliver_delete_switches .= ' -dontdeletecommon'; 2530 $only_common = ''; 2531 }; 2532 print "$message\n"; 2533 2534 foreach my $platform (keys %platforms) { 2535 print "\nRemoving files delivered for $platform\n"; 2536 my %solar_vars = (); 2537 read_ssolar_vars($platform, \%solar_vars); 2538 if (scalar keys %solar_vars) { 2539 foreach (keys %solar_vars) { 2540 if (!defined $backup_vars{$_}) { 2541 $backup_vars{$_} = $ENV{$_}; 2542 }; 2543 $ENV{$_} = $solar_vars{$_}; 2544 }; 2545 }; 2546 my $undeliver = "$deliver_command $deliver_delete_switches $nul"; 2547# my $current_dir = getcwd(); 2548 foreach my $module (sort @modules_built) { 2549 if (chdir($module_paths{$module})) { 2550 print "Removing delivered from module $module\n"; 2551 next if ($show); 2552 if (system($undeliver)) { 2553 $ENV{$_} = $backup_vars{$_} foreach (keys %backup_vars); 2554 print_error("Cannot run: $undeliver"); 2555 } 2556 } else { 2557 push(@warnings, "Could not remove delivered files from the module $module. Your build can become inconsistent.\n"); 2558 }; 2559 }; 2560# chdir $current_dir; 2561# getcwd(); 2562 }; 2563 $ENV{$_} = $backup_vars{$_} foreach (keys %backup_vars); 2564}; 2565 2566# 2567# Run setsolar for given platform and 2568# write all variables needed in %solar_vars hash 2569# 2570sub read_ssolar_vars { 2571 my ($setsolar, $tmp_file); 2572 $setsolar = $ENV{ENV_ROOT} . '/etools/setsolar.pl'; 2573 my ($platform, $solar_vars) = @_; 2574 $setsolar = '/net/jumbo2.germany/buildenv/r/etools/setsolar.pl' if ! -e $setsolar; 2575 $tmp_file = $ENV{HOME} . "/.solar.env.$$.tmp"; 2576 if (!-e $setsolar) { 2577 print STDERR "There is no setsolar found. Falling back to current platform settings\n"; 2578 return; 2579 } 2580 my $pro = ""; 2581 if ($platform =~ /\.pro$/) { 2582 $pro = "-pro"; 2583 $platform = $`; 2584 }; 2585 2586 my ($verswitch, $source_root, $cwsname); 2587 $verswitch = "-ver $ENV{UPDMINOR}" if (defined $ENV{UPDMINOR}); 2588 $source_root = '-sourceroot' if (defined $ENV{SOURCE_ROOT_USED}); 2589 my $cws_name = "-cwsname $ENV{CWS_WORK_STAMP}" if (defined $ENV{CWS_WORK_STAMP}); 2590 2591 my $param = "-$ENV{WORK_STAMP} $verswitch $source_root $cws_name $pro $platform"; 2592 my $ss_command = "$perl $setsolar -file $tmp_file $param $nul"; 2593 if (system($ss_command)) { 2594 unlink $tmp_file; 2595 print_error("Cannot run command:\n$ss_command"); 2596 }; 2597 get_solar_vars($solar_vars, $tmp_file); 2598}; 2599 2600# 2601# read variables to hash 2602# 2603sub get_solar_vars { 2604 my ($solar_vars, $file) = @_; 2605 my ($var, $value); 2606 open SOLARTABLE, "<$file" or die "can�t open solarfile $file"; 2607 while(<SOLARTABLE>) { 2608 s/\r\n//o; 2609 next if(!/^\w+\s+(\w+)/o); 2610 next if (!defined $deliver_env{$1}); 2611 $var = $1; 2612 /\'(\S+)\'$/o; 2613 $value = $1; 2614 $$solar_vars{$var} = $value; 2615 }; 2616 close SOLARTABLE; 2617 unlink $file; 2618} 2619 2620# 2621# Procedure renames <module>.lnk (.link) into <module> 2622# 2623sub get_current_module { 2624 my $module_name = shift; 2625 my $link_name = $module_name . '.lnk'; 2626 $link_name .= '.link' if (-e $workspace_path.$module_name . '.link'); 2627 chdir $workspace_path; 2628 getcwd(); 2629 print "\nBreaking link to module $module_name"; 2630 my $result = rename $link_name, $module_name; 2631 if ( ! $result ) { 2632 print_error("Cannot rename $module_name: $!\n"); 2633 } 2634 if ( $initial_module eq $link_name) { 2635 $initial_module = $module_name; 2636 } 2637 chdir $module_name; 2638 getcwd(); 2639}; 2640 2641sub check_dir { 2642 my $start_dir = getcwd(); 2643 my @dir_entries = split(/[\\\/]/, $ENV{PWD}); 2644 my $current_module = $dir_entries[$#dir_entries]; 2645 if (($current_module =~ /(\.lnk)$/) || ($current_module =~ /(\.link)$/)) { 2646 $current_module = $`; 2647 # we're dealing with a link => fallback to SOLARSRC under UNIX 2648 $workspace_path = $ENV{SOLARSRC}.'/'; 2649 get_current_module($current_module); 2650 return; 2651 } else { 2652 chdir $start_dir; 2653 getcwd(); 2654 }; 2655}; 2656 2657# 2658# Store all available build modi in %build_modes 2659# 2660sub get_build_modes { 2661 return if (scalar keys %build_modes); 2662 if (defined $ENV{BUILD_TYPE}) { 2663 if ($ENV{BUILD_TYPE} =~ /\s+/o) { 2664 my @build_modes = split (/\s+/, $ENV{BUILD_TYPE}); 2665 $build_modes{$_}++ foreach (@build_modes); 2666 } else { 2667 $build_modes{$ENV{BUILD_TYPE}}++; 2668 }; 2669 return; 2670 }; 2671}; 2672 2673# 2674# pick only the modules, that should be built for 2675# build types from %build_modes 2676# 2677sub pick_for_build_type { 2678 my $modules = shift; 2679 my @mod_array = split(/\s+/, $modules); 2680 print_error("Wrongly written dependencies string:\n $modules\n") if ($mod_array[$#mod_array] ne 'NULL'); 2681 pop @mod_array; 2682 my @modules_to_build; 2683 foreach (@mod_array) { 2684 if (/(\w+):(\S+)/o) { 2685 push(@modules_to_build, $2) if (defined $build_modes{$1}); 2686 next; 2687 }; 2688 push(@modules_to_build, $_); 2689 }; 2690 return @modules_to_build; 2691}; 2692 2693sub do_exit { 2694# close_server_socket(); 2695 my $exit_code = shift; 2696 $build_finished++; 2697 generate_html_file(1); 2698 if ( $^O eq 'os2' ) 2699 { 2700 # perl 5.10 returns 'resource busy' for rmtree 2701 rmdir(correct_path($tmp_dir)) if ($tmp_dir); 2702 } 2703 rmtree(correct_path($tmp_dir), 0, 0) if ($tmp_dir); 2704 print STDERR "Cannot delete $tmp_dir. Please remove it manually\n" if (-d $tmp_dir); 2705 exit($exit_code); 2706}; 2707 2708# 2709# Procedure sorts module in user-frendly order 2710# 2711sub sort_modules_appearance { 2712 foreach (keys %dead_parents) { 2713 delete $build_is_finished{$_} if (defined $build_is_finished{$_}); 2714 delete $build_in_progress{$_} if (defined $build_in_progress{$_}); 2715 }; 2716 foreach (keys %build_is_finished) { 2717 delete $build_in_progress{$_} if (defined $build_in_progress{$_}); 2718 delete $build_in_progress_shown{$_} if (defined $build_in_progress_shown{$_}); 2719 }; 2720 my @modules_order = sort keys %modules_with_errors; 2721 foreach (keys %modules_with_errors) { 2722 delete $build_in_progress{$_} if (defined $build_in_progress{$_}); 2723 delete $build_is_finished{$_} if (defined $build_is_finished{$_}); 2724 delete $build_in_progress_shown{$_} if (defined $build_in_progress_shown{$_}); 2725 }; 2726 $build_in_progress_shown{$_}++ foreach (keys %build_in_progress); 2727 push(@modules_order, $_) foreach (sort { $build_in_progress_shown{$b} <=> $build_in_progress_shown{$a} } keys %build_in_progress_shown); 2728 push(@modules_order, $_) foreach (sort keys %build_is_finished); 2729 foreach(sort keys %html_info) { 2730 next if (defined $build_is_finished{$_} || defined $build_in_progress{$_} || defined $modules_with_errors{$_}); 2731 push(@modules_order, $_); 2732 }; 2733 return @modules_order; 2734}; 2735 2736sub generate_html_file { 2737 return if (!$html); 2738 my $force_update = shift; 2739 $force_update++ if ($debug); 2740 $html_last_updated = time; 2741 my @modules_order = sort_modules_appearance(); 2742 my ($successes_percent, $errors_percent) = get_progress_percentage(scalar keys %html_info, scalar keys %build_is_finished, scalar keys %modules_with_errors); 2743 my $build_duration = get_time_line(time - $build_time); 2744 my $temp_html_file = File::Temp::tmpnam($tmp_dir); 2745 my $title; 2746 $title = $ENV{CWS_WORK_STAMP} . ': ' if (defined $ENV{CWS_WORK_STAMP}); 2747 $title .= $ENV{INPATH}; 2748 die("Cannot open $temp_html_file") if (!open(HTML, ">$temp_html_file")); 2749 print HTML '<html><head>'; 2750 print HTML '<TITLE id=MainTitle>' . $title . '</TITLE>'; 2751 print HTML '<script type="text/javascript">' . "\n"; 2752 print HTML 'initFrames();' . "\n"; 2753 print HTML 'var IntervalID;' . "\n"; 2754 print HTML 'function loadFrame_0() {' . "\n"; 2755 print HTML ' document.write("<html>");' . "\n"; 2756 print HTML ' document.write("<head>");' . "\n"; 2757 print HTML ' document.write("</head>");' . "\n"; 2758 print HTML ' document.write("<body>");' . "\n"; 2759 if ($build_finished) { 2760 print HTML 'document.write("<h3 align=center style=\"color:red\">Build process is finished</h3>");' . "\n"; 2761 print HTML ' top.frames[0].clearInterval(top.frames[0].IntervalID);' . "\n"; 2762 } elsif ($interactive) { 2763 print HTML 'document.write(" <div id=divContext style=\"border: 1px solid; display: none; position: absolute\">");' . "\n"; 2764 print HTML 'document.write(" <ul style=\"margin: 0; padding: 0.3em; list-style-type: none; background-color: lightgrey;\" :li:hover {} :hr {border: 0; border-bottom: 1px solid grey; margin: 3px 0px 3px 0px; width: 10em;} :a {border: 0 !important;} >");' . "\n"; 2765 print HTML 'document.write(" <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aRebuild href=\"#\">Rebuild module</a></li>");' . "\n"; 2766 print HTML 'document.write(" <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aDelete href=\"#\" >Remove module</a></li>");' . "\n"; 2767 print HTML 'document.write(" </ul>");' . "\n"; 2768 print HTML 'document.write(" </div>");' . "\n"; 2769 }; 2770 if ($build_all_parents) { 2771 print HTML 'document.write("<table valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n"; 2772 print HTML 'document.write(" <tr>");' . "\n"; 2773 print HTML 'document.write(" <td><a id=ErroneousModules href=\"javascript:top.Error(\'\', \''; 2774 print HTML join('<br>', sort keys %modules_with_errors); 2775 print HTML '\', \'\')\"); title=\"'; 2776 print HTML scalar keys %modules_with_errors; 2777 print HTML ' module(s) with errors\">Total Progress:</a></td>");' . "\n"; 2778 print HTML 'document.write(" <td>");' . "\n"; 2779 print HTML 'document.write(" <table width=100px valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n"; 2780 print HTML 'document.write(" <tr>");' . "\n"; 2781 print HTML 'document.write(" <td height=20px width='; 2782 print HTML $successes_percent + $errors_percent; 2783 if (scalar keys %modules_with_errors) { 2784 print HTML '% bgcolor=red valign=top></td>");' . "\n"; 2785 } else { 2786 print HTML '% bgcolor=#25A528 valign=top></td>");' . "\n"; 2787 }; 2788 print HTML 'document.write(" <td width='; 2789 print HTML 100 - ($successes_percent + $errors_percent); 2790 print HTML '% bgcolor=lightgrey valign=top></td>");' . "\n"; 2791 print HTML 'document.write(" </tr>");' . "\n"; 2792 print HTML 'document.write(" </table>");' . "\n"; 2793 print HTML 'document.write(" </td>");' . "\n"; 2794 print HTML 'document.write(" <td align=right>  Build time: ' . $build_duration .'</td>");' . "\n"; 2795 print HTML 'document.write(" </tr>");' . "\n"; 2796 print HTML 'document.write("</table>");' . "\n"; 2797 }; 2798 2799 print HTML 'document.write("<table width=100% bgcolor=white>");' . "\n"; 2800 print HTML 'document.write(" <tr>");' . "\n"; 2801 print HTML 'document.write(" <td width=30% align=\"center\"><strong style=\"color:blue\">Module</strong></td>");' . "\n"; 2802 print HTML 'document.write(" <td width=* align=\"center\"><strong style=\"color:blue\">Status</strong></td>");' . "\n"; 2803 print HTML 'document.write(" <td width=15% align=\"center\"><strong style=\"color:blue\">CPU Time</strong></td>");' . "\n"; 2804 print HTML 'document.write(" </tr>");' . "\n"; 2805 2806 foreach (@modules_order) { 2807 next if ($modules_types{$_} eq 'lnk'); 2808 next if (!defined $active_modules{$_}); 2809 my ($errors_info_line, $dirs_info_line, $errors_number, $successes_percent, $errors_percent, $time) = get_html_info($_); 2810#<one module> 2811 print HTML 'document.write(" <tr>");' . "\n"; 2812 print HTML 'document.write(" <td width=*>");' . "\n"; 2813 2814 if (defined $dirs_info_line) { 2815 print HTML 'document.write(" <a id='; 2816 print HTML $_; 2817 print HTML ' href=\"javascript:top.Error(\''; 2818 print HTML $_ , '\', ' ; 2819 print HTML $errors_info_line; 2820 print HTML ','; 2821 print HTML $dirs_info_line; 2822 print HTML ')\"); title=\"'; 2823 print HTML $errors_number; 2824 print HTML ' error(s)\">', $_, '</a>");' . "\n"; 2825 } else { 2826# print HTML 'document.write("<em style=color:gray>' . $_ . '</em>");'; 2827#### print HTML 'document.write("<em style=color:gray>' . $_ ."href=\'http://$local_host_ip:$html_port/delete=\'$_". '</em>");'; 2828 2829 print HTML 'document.write(" <a target=\'infoframe\' id='; 2830 print HTML $_; 2831 print HTML ' href=\"javascript:void(0)\"; title=\"Remove module\">' . $_ . '</a>");' . "\n"; 2832 }; 2833 2834 2835 print HTML 'document.write(" </td>");' . "\n"; 2836 print HTML 'document.write(" <td>");' . "\n"; 2837 print HTML 'document.write(" <table width=100% valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n"; 2838 print HTML 'document.write(" <tr>");' . "\n"; 2839 print HTML 'document.write(" <td height=15 width='; 2840 2841 print HTML $successes_percent + $errors_percent; 2842 if ($errors_number) { 2843 print HTML '% bgcolor=red valign=top></td>");' . "\n"; 2844 } else { 2845 print HTML '% bgcolor=#25A528 valign=top></td>");' . "\n"; 2846 }; 2847 print HTML 'document.write(" <td width='; 2848 2849 print HTML 100 - ($successes_percent + $errors_percent); 2850 print HTML '% bgcolor=lightgrey valign=top></td>");' . "\n"; 2851 print HTML 'document.write(" </tr>");' . "\n"; 2852 print HTML 'document.write(" </table>");' . "\n"; 2853 print HTML 'document.write(" </td>");' . "\n"; 2854 print HTML 'document.write(" <td align=\"center\">', $time, '</td>");' . "\n"; 2855 print HTML 'document.write(" </tr>");' . "\n"; 2856# </one module> 2857 } 2858 print HTML 'document.write(" </table>");' . "\n"; 2859 print HTML 'document.write(" </body>");' . "\n"; 2860 print HTML 'document.write("</html>");' . "\n"; 2861 print HTML 'document.close();' . "\n"; 2862 print HTML 'refreshInfoFrames();' . "\n"; 2863 print HTML '}' . "\n"; 2864 2865 2866 if (!$build_finished && $interactive ) { 2867 print HTML 'var _replaceContext = false;' . "\n"; 2868 print HTML 'var _mouseOverContext = false;' . "\n"; 2869 print HTML 'var _noContext = false;' . "\n"; 2870 print HTML 'var _divContext = $(\'divContext\');' . "\n"; 2871 print HTML 'var activeElement = 0;' . "\n"; 2872 print HTML 'function $(id) {return document.getElementById(id);}' . "\n"; 2873 print HTML 'InitContext();' . "\n"; 2874 print HTML 'function InitContext()' . "\n"; 2875 print HTML '{' . "\n"; 2876 print HTML ' $(\'aRebuild\').target = \'infoframe\';' . "\n"; 2877 print HTML ' $(\'aDelete\').target = \'infoframe\';' . "\n"; 2878 print HTML ' $(\'aRebuild\').style.color = \'black\';' . "\n"; 2879 print HTML ' $(\'aDelete\').style.color = \'black\';' . "\n"; 2880 print HTML ' _divContext.onmouseover = function() { _mouseOverContext = true; };' . "\n"; 2881 print HTML ' _divContext.onmouseout = function() { _mouseOverContext = false; };' . "\n"; 2882 print HTML ' _divContext.onclick = function() { _divContext.style.display = \'none\'; };' . "\n"; 2883 print HTML ' document.body.onmousedown = ContextMouseDown;' . "\n"; 2884 print HTML ' document.body.oncontextmenu = ContextShow;' . "\n"; 2885 print HTML '}' . "\n"; 2886 print HTML 'function ContextMouseDown(event) {' . "\n"; 2887 print HTML ' if (_noContext || _mouseOverContext) return;' . "\n"; 2888 print HTML ' if (event == null) event = window.event;' . "\n"; 2889 print HTML ' var target = event.target != null ? event.target : event.srcElement;' . "\n"; 2890 print HTML ' if (event.button == 2 && target.tagName.toLowerCase() == \'a\')' . "\n"; 2891 print HTML ' _replaceContext = true;' . "\n"; 2892 print HTML ' else if (!_mouseOverContext)' . "\n"; 2893 print HTML ' _divContext.style.display = \'none\';' . "\n"; 2894 print HTML '}' . "\n"; 2895 print HTML 'function ContextShow(event) {' . "\n"; 2896 print HTML ' if (_noContext || _mouseOverContext) return;' . "\n"; 2897 print HTML ' if (event == null) event = window.event;' . "\n"; 2898 print HTML ' var target = event.target != null ? event.target : event.srcElement;' . "\n"; 2899 print HTML ' if (_replaceContext) {' . "\n"; 2900 print HTML ' $(\'aRebuild\').href = \'http://'. $local_host_ip .':' . $html_port . '/rebuild=\' + target.id;' . "\n"; 2901 print HTML ' $(\'aDelete\').href = \'http://'. $local_host_ip .':' . $html_port . '/delete=\' + target.id' . "\n"; 2902 print HTML ' var scrollTop = document.body.scrollTop ? document.body.scrollTop : '; 2903 print HTML 'document.documentElement.scrollTop;' . "\n"; 2904 print HTML ' var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : '; 2905 print HTML 'document.documentElement.scrollLeft;' . "\n"; 2906 print HTML ' _divContext.style.display = \'none\';' . "\n"; 2907 print HTML ' _divContext.style.left = event.clientX + scrollLeft + \'px\';' . "\n"; 2908 print HTML ' _divContext.style.top = event.clientY + scrollTop + \'px\';' . "\n"; 2909 print HTML ' _divContext.style.display = \'block\';' . "\n"; 2910 print HTML ' _replaceContext = false;' . "\n"; 2911 print HTML ' return false;' . "\n"; 2912 print HTML ' }' . "\n"; 2913 print HTML '}' . "\n"; 2914 }; 2915 2916 print HTML 'function refreshInfoFrames() { ' . "\n"; 2917 print HTML ' var ModuleHref = top.innerFrame.frames[0].document.getElementById("ErroneousModules").getAttribute(\'href\');' . "\n"; 2918 print HTML ' eval(ModuleHref);' . "\n"; 2919 print HTML ' if (top.innerFrame.frames[1].document.getElementById("ModuleJobs") != null) {' . "\n"; 2920 print HTML ' var ModuleName = top.innerFrame.frames[1].document.getElementById("ModuleJobs").getAttribute(\'name\');' . "\n"; 2921 print HTML ' ModuleHref = top.innerFrame.frames[0].document.getElementById(ModuleName).getAttribute(\'href\');' . "\n"; 2922 print HTML ' var HrefString = ModuleHref.toString();' . "\n"; 2923 print HTML ' var RefEntries = HrefString.split(",");' . "\n"; 2924 print HTML ' var RefreshParams = new Array();' . "\n"; 2925 print HTML ' for (i = 0; i < RefEntries.length; i++) {' . "\n"; 2926 print HTML ' RefreshParams[i] = RefEntries[i].substring(RefEntries[i].indexOf("\'") + 1, RefEntries[i].lastIndexOf("\'"));' . "\n"; 2927 print HTML ' };' . "\n"; 2928 print HTML ' FillFrame_1(RefreshParams[0], RefreshParams[1], RefreshParams[2]);' . "\n"; 2929 print HTML ' }' . "\n"; 2930 print HTML '}' . "\n"; 2931 print HTML 'function loadFrame_1() {' . "\n"; 2932 print HTML ' document.write("<h3 align=center>Jobs</h3>");' . "\n"; 2933 print HTML ' document.write("Click on the project of interest");' . "\n"; 2934 print HTML ' document.close();' . "\n"; 2935 print HTML '}' . "\n"; 2936 print HTML 'function loadFrame_2() {' . "\n"; 2937 print HTML ' document.write("<tr bgcolor=lightgrey<td><h3>Errors</h3></pre></td></tr>");' . "\n"; 2938 print HTML ' document.write("Click on the project of interest");' . "\n"; 2939 print HTML ' document.close();' . "\n"; 2940 print HTML '} function getStatusInnerHTML(Status) { var StatusInnerHtml;' . "\n"; 2941 print HTML ' if (Status == "success") {' . "\n"; 2942 print HTML ' StatusInnerHtml = "<em style=color:green>";' . "\n"; 2943 print HTML ' } else if (Status == "building") {' . "\n"; 2944 print HTML ' StatusInnerHtml = "<em style=color:blue>";' . "\n"; 2945 print HTML ' } else if (Status == "error") {' . "\n"; 2946 print HTML ' StatusInnerHtml = "<em style=color:red>";' . "\n"; 2947 print HTML ' } else {' . "\n"; 2948 print HTML ' StatusInnerHtml = "<em style=color:gray>";' . "\n"; 2949 print HTML ' };' . "\n"; 2950 print HTML ' StatusInnerHtml += Status + "</em>";' . "\n"; 2951 print HTML ' return StatusInnerHtml;' . "\n"; 2952 print HTML '} ' . "\n"; 2953 print HTML 'function ShowLog(LogFilePath, ModuleJob) {' . "\n"; 2954 print HTML ' top.innerFrame.frames[2].location = LogFilePath;' . "\n"; 2955 print HTML '};' . "\n"; 2956 print HTML 'function FillFrame_1(Module, Message1, Message2) {' . "\n"; 2957 print HTML ' var FullUpdate = 1;' . "\n"; 2958 print HTML ' if (top.innerFrame.frames[1].document.getElementById("ModuleJobs") != null) {' . "\n"; 2959 print HTML ' var ModuleName = top.innerFrame.frames[1].document.getElementById("ModuleJobs").getAttribute(\'name\');' . "\n"; 2960 print HTML ' if (Module == ModuleName) FullUpdate = 0;' . "\n"; 2961 print HTML ' }' . "\n"; 2962 print HTML ' if (FullUpdate) {' . "\n"; 2963 print HTML ' top.innerFrame.frames[1].document.write("<h3 align=center>Jobs in module " + Module + ":</h3>");' . "\n"; 2964 print HTML ' top.innerFrame.frames[1].document.write("<table id=ModuleJobs name=" + Module + " width=100% bgcolor=white>");' . "\n"; 2965 print HTML ' top.innerFrame.frames[1].document.write(" <tr>");' . "\n"; 2966 print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Status</strong></td>");' . "\n"; 2967 print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Job</strong></td>");' . "\n"; 2968 print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Start Time</strong></td>");' . "\n"; 2969 print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Finish Time</strong></td>");' . "\n"; 2970 print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Client</strong></td>");' . "\n" if ($server_mode); 2971 print HTML ' top.innerFrame.frames[1].document.write(" </tr>");' . "\n"; 2972 print HTML ' var dir_info_strings = Message2.split("<br><br>");' . "\n"; 2973 print HTML ' for (i = 0; i < dir_info_strings.length; i++) {' . "\n"; 2974 print HTML ' var dir_info_array = dir_info_strings[i].split("<br>");' . "\n"; 2975 print HTML ' top.innerFrame.frames[1].document.write(" <tr status=" + dir_info_array[0] + ">");' . "\n"; 2976 print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>");' . "\n"; 2977 print HTML ' top.innerFrame.frames[1].document.write( getStatusInnerHTML(dir_info_array[0]) + " ");' . "\n"; 2978 print HTML ' top.innerFrame.frames[1].document.write(" </td>");' . "\n"; 2979 print HTML ' if (dir_info_array[4] == "@") {' . "\n"; 2980 print HTML ' top.innerFrame.frames[1].document.write(" <td style=white-space:nowrap>" + dir_info_array[1] + "</td>");' . "\n"; 2981 print HTML ' } else {' . "\n"; 2982 print HTML ' top.innerFrame.frames[1].document.write(" <td><a href=\"javascript:top.ShowLog(\'" + dir_info_array[4] + "\', \'" + dir_info_array[1] + "\')\"); title=\"Show Log\">" + dir_info_array[1] + "</a></td>");' . "\n"; 2983 print HTML ' };' . "\n"; 2984 print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>" + dir_info_array[2] + "</td>");' . "\n"; 2985 print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>" + dir_info_array[3] + "</td>");' . "\n"; 2986 print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>" + dir_info_array[5] + "</td>");' . "\n" if ($server_mode); 2987 print HTML ' top.innerFrame.frames[1].document.write(" </tr>");' . "\n"; 2988 print HTML ' };' . "\n"; 2989 print HTML ' top.innerFrame.frames[1].document.write("</table>");' . "\n"; 2990 print HTML ' } else {' . "\n"; 2991 print HTML ' var dir_info_strings = Message2.split("<br><br>");' . "\n"; 2992 print HTML ' var ModuleRows = top.innerFrame.frames[1].document.getElementById("ModuleJobs").rows;' . "\n"; 2993 print HTML ' for (i = 0; i < dir_info_strings.length; i++) {' . "\n"; 2994 print HTML ' var dir_info_array = dir_info_strings[i].split("<br>");' . "\n"; 2995 print HTML ' var OldStatus = ModuleRows[i + 1].getAttribute(\'status\');' . "\n"; 2996 print HTML ' if(dir_info_array[0] != OldStatus) {' . "\n"; 2997 print HTML ' var DirectoryInfos = ModuleRows[i + 1].cells;' . "\n"; 2998 print HTML ' DirectoryInfos[0].innerHTML = getStatusInnerHTML(dir_info_array[0]) + " ";' . "\n"; 2999 print HTML ' if (dir_info_array[4] != "@") {' . "\n"; 3000 print HTML ' DirectoryInfos[1].innerHTML = "<a href=\"javascript:top.ShowLog(\'" + dir_info_array[4] + "\', \'" + dir_info_array[1] + "\')\"); title=\"Show Log\">" + dir_info_array[1] + "</a>";' . "\n"; 3001 print HTML ' };' . "\n"; 3002 print HTML ' DirectoryInfos[2].innerHTML = dir_info_array[2];' . "\n"; 3003 print HTML ' DirectoryInfos[3].innerHTML = dir_info_array[3];' . "\n"; 3004 print HTML ' DirectoryInfos[4].innerHTML = dir_info_array[5];' . "\n" if ($server_mode); 3005 print HTML ' };' . "\n"; 3006 print HTML ' };' . "\n"; 3007 print HTML ' };' . "\n"; 3008 print HTML ' top.innerFrame.frames[1].document.close();' . "\n"; 3009 print HTML '};' . "\n"; 3010 print HTML 'function Error(Module, Message1, Message2) {' . "\n"; 3011 print HTML ' if (top.innerFrame.frames[2].location) {' . "\n"; 3012 print HTML ' var urlquery = location.href.split("?");' . "\n"; 3013 print HTML ' top.innerFrame.frames[2].location = urlquery[0] + "?initFrame2";' . "\n"; 3014 print HTML ' }' . "\n"; 3015 print HTML ' if (Module == \'\') {' . "\n"; 3016 print HTML ' if (Message1 != \'\') {' . "\n"; 3017 print HTML ' var erroneous_modules = Message1.split("<br>");' . "\n"; 3018 print HTML ' var ErrorNumber = erroneous_modules.length;' . "\n"; 3019 3020 print HTML ' top.innerFrame.frames[2].document.write("<h3 id=ErroneousModules errors=" + erroneous_modules.length + ">Modules with errors:</h3>");' . "\n"; 3021 print HTML ' for (i = 0; i < ErrorNumber; i++) {' . "\n"; 3022 print HTML ' var ModuleObj = top.innerFrame.frames[0].document.getElementById(erroneous_modules[i]);' . "\n"; 3023 print HTML ' top.innerFrame.frames[2].document.write("<a href=\"");' . "\n"; 3024 print HTML ' top.innerFrame.frames[2].document.write(ModuleObj.getAttribute(\'href\'));' . "\n"; 3025 print HTML ' top.innerFrame.frames[2].document.write("\"); title=\"");' . "\n"; 3026 print HTML ' top.innerFrame.frames[2].document.write("\">" + erroneous_modules[i] + "</a>  ");' . "\n"; 3027 print HTML ' };' . "\n"; 3028 print HTML ' top.innerFrame.frames[2].document.close();' . "\n"; 3029 print HTML ' };' . "\n"; 3030 print HTML ' }' . "\n"; 3031 print HTML '}' . "\n"; 3032 print HTML 'function updateInnerFrame() {' . "\n"; 3033 print HTML ' top.innerFrame.frames[0].document.location.reload();' . "\n"; 3034 print HTML ' refreshInfoFrames();' . "\n"; 3035 print HTML '};' . "\n\n"; 3036 3037 print HTML 'function setRefreshRate() {' . "\n"; 3038 print HTML ' RefreshRate = document.Formular.rate.value;' . "\n"; 3039 print HTML ' if (!isNaN(RefreshRate * 1)) {' . "\n"; 3040 print HTML ' top.frames[0].clearInterval(IntervalID);' . "\n"; 3041 print HTML ' IntervalID = top.frames[0].setInterval("updateInnerFrame()", RefreshRate * 1000);' . "\n"; 3042 print HTML ' };' . "\n"; 3043 print HTML '};' . "\n"; 3044 3045 print HTML 'function initFrames() {' . "\n"; 3046 print HTML ' var urlquery = location.href.split("?");' . "\n"; 3047 print HTML ' if (urlquery.length == 1) {' . "\n"; 3048 print HTML ' document.write("<html><head><TITLE id=MainTitle>' . $ENV{INPATH} .'</TITLE>");' . "\n"; 3049 print HTML ' document.write(" <frameset rows=\"36,*\">");' . "\n"; 3050 print HTML ' document.write(" <frame name=\"topFrame\" src=\"" + urlquery + "?initTop\"/>");' . "\n"; 3051 print HTML ' document.write(" <frame name=\"innerFrame\" src=\"" + urlquery + "?initInnerPage\"/>");' . "\n"; 3052 print HTML ' document.write(" </frameset>");' . "\n"; 3053 print HTML ' document.write("</head></html>");' . "\n"; 3054 print HTML ' } else if (urlquery[1].substring(0,7) == "initTop") {' . "\n"; 3055 print HTML ' var urlquerycontent = urlquery[1].split("=");' . "\n"; 3056 print HTML ' var UpdateRate = 10' . "\n"; 3057 print HTML ' if (urlquerycontent.length > 2) {' . "\n"; 3058 print HTML ' if (isNaN(urlquerycontent[2] * 1)) {' . "\n"; 3059 print HTML ' alert(urlquerycontent[2] + " is not a number. Ignored.");' . "\n"; 3060 print HTML ' } else {' . "\n"; 3061 print HTML ' UpdateRate = urlquerycontent[2];' . "\n"; 3062 print HTML ' };' . "\n"; 3063 print HTML ' };' . "\n"; 3064 print HTML ' document.write("<html><body>");' . "\n"; 3065 print HTML ' document.write("<table border=\"0\" width=\"100%\"> <tr>");' . "\n"; 3066 print HTML ' document.write("<td align=\"left\"><h3>Build process progress status</h3></td>");' . "\n"; 3067 print HTML ' document.write("<td align=\"right\">");' . "\n"; 3068 print HTML ' document.write("<FORM name=\"Formular\" onsubmit=\"setRefreshRate()\">");' . "\n"; 3069 print HTML ' document.write("<input type=\"hidden\" name=\"initTop\" value=\"\"/>");' . "\n"; 3070 print HTML ' document.write("<input type=\"text\" id=\"RateValue\" name=\"rate\" autocomplete=\"off\" value=\"" + UpdateRate + "\" size=\"1\"/>");' . "\n"; 3071 print HTML ' document.write("<input type=\"submit\" value=\"Update refresh rate (sec)\">");' . "\n"; 3072 print HTML ' document.write("</FORM>");' . "\n"; 3073 print HTML ' document.write("</td></tr></table>");' . "\n"; 3074 print HTML ' document.write(" </frameset>");' . "\n"; 3075 print HTML ' document.write("</body></html>");' . "\n"; 3076 print HTML ' top.frames[0].clearInterval(IntervalID);' . "\n"; 3077 print HTML ' IntervalID = top.frames[0].setInterval("updateInnerFrame()", UpdateRate * 1000);' . "\n"; 3078 print HTML ' } else if (urlquery[1] == "initInnerPage") {' . "\n"; 3079 print HTML ' document.write("<html><head>");' . "\n"; 3080 print HTML ' document.write(\' <frameset rows="50%,50%\">\');' . "\n"; 3081 print HTML ' document.write(\' <frameset cols="50%,50%">\');' . "\n"; 3082 print HTML ' document.write(\' <frame src="\');' . "\n"; 3083 print HTML ' document.write(urlquery[0]);' . "\n"; 3084 print HTML ' document.write(\'?initFrame0"/>\');' . "\n"; 3085 print HTML ' document.write(\' <frame src="\');' . "\n"; 3086 print HTML ' document.write(urlquery[0]);' . "\n"; 3087 print HTML ' document.write(\'?initFrame1"/>\');' . "\n"; 3088 print HTML ' document.write(\' </frameset>\');' . "\n"; 3089 print HTML ' document.write(\' <frame src="\');' . "\n"; 3090 print HTML ' document.write(urlquery[0]);' . "\n"; 3091 print HTML ' document.write(\'?initFrame2" name="infoframe"/>\');' . "\n"; 3092 print HTML ' document.write(\' </frameset>\');' . "\n"; 3093 print HTML ' document.write("</head></html>");' . "\n"; 3094 print HTML ' } else {' . "\n"; 3095 print HTML ' if (urlquery[1] == "initFrame0" ) {' . "\n"; 3096 print HTML ' loadFrame_0();' . "\n"; 3097 print HTML ' } else if (urlquery[1] == "initFrame1" ) { ' . "\n"; 3098 print HTML ' loadFrame_1();' . "\n"; 3099 print HTML ' } else if (urlquery[1] == "initFrame2" ) {' . "\n"; 3100 print HTML ' loadFrame_2();' . "\n"; 3101 print HTML ' }' . "\n"; 3102 print HTML ' };' . "\n"; 3103 print HTML '};' . "\n"; 3104 print HTML '</script><noscript>Your browser doesn\'t support JavaScript!</noscript></head></html>' . "\n"; 3105 close HTML; 3106 rename_file($temp_html_file, $html_file); 3107}; 3108 3109sub get_local_time_line { 3110 my $epoch_time = shift; 3111 my $local_time_line; 3112 my @time_array; 3113 if ($epoch_time) { 3114 @time_array = localtime($epoch_time); 3115 $local_time_line = sprintf("%02d:%02d:%02d", $time_array[2], $time_array[1], $time_array[0]); 3116 } else { 3117 $local_time_line = '-'; 3118 }; 3119 return $local_time_line; 3120}; 3121 3122sub get_dirs_info_line { 3123 my $job = shift; 3124 my $dirs_info_line = $jobs_hash{$job}->{STATUS} . '<br>'; 3125 my @time_array; 3126 my $log_path_string; 3127 $dirs_info_line .= $jobs_hash{$job}->{SHORT_NAME} . '<br>'; 3128 $dirs_info_line .= get_local_time_line($jobs_hash{$job}->{START_TIME}) . '<br>'; 3129 $dirs_info_line .= get_local_time_line($jobs_hash{$job}->{FINISH_TIME}) . '<br>'; 3130 if ($jobs_hash{$job}->{STATUS} eq 'waiting' || (!-f $jobs_hash{$job}->{LONG_LOG_PATH})) { 3131 $dirs_info_line .= '@'; 3132 } else { 3133 if (defined $html_path) { 3134 $log_path_string = $jobs_hash{$job}->{LONG_LOG_PATH}; 3135 } else { 3136 $log_path_string = $jobs_hash{$job}->{LOG_PATH}; 3137 }; 3138 $log_path_string =~ s/\\/\//g; 3139 $dirs_info_line .= $log_path_string; 3140 }; 3141 $dirs_info_line .= '<br>'; 3142 $dirs_info_line .= $jobs_hash{$job}->{CLIENT} . '<br>' if ($server_mode); 3143 return $dirs_info_line; 3144}; 3145 3146sub get_html_info { 3147 my $module = shift; 3148 my $module_info_hash = $html_info{$module}; 3149 my $dirs = $$module_info_hash{DIRS}; 3150 my $dirs_number = scalar @$dirs; 3151 my $dirs_info_line = '\''; 3152 if ($dirs_number) { 3153 my %dirs_sorted_by_order = (); 3154 foreach (@$dirs) { 3155 $dirs_sorted_by_order{$jobs_hash{$_}->{BUILD_NUMBER}} = $_; 3156 } 3157 foreach (sort {$a <=> $b} keys %dirs_sorted_by_order) { 3158 $dirs_info_line .= get_dirs_info_line($dirs_sorted_by_order{$_}) . '<br>'; 3159 } 3160 } else { 3161 return(undef, undef, 0, 0, 0, '-'); 3162# $dirs_info_line .= 'No information available yet'; 3163 }; 3164 $dirs_info_line =~ s/(<br>)*$//o; 3165 $dirs_info_line .= '\''; 3166 $dirs = $$module_info_hash{SUCCESSFUL}; 3167 my $successful_number = scalar @$dirs; 3168 $dirs = $$module_info_hash{ERRORFUL}; 3169 my $errorful_number = scalar @$dirs; 3170 my $errors_info_line = '\''; 3171 if ($errorful_number) { 3172 $errors_info_line .= $_ . '<br>' foreach (@$dirs); 3173 } else { 3174 $errors_info_line .= 'No errors'; 3175 }; 3176 $errors_info_line .= '\''; 3177# if (defined $full_info) { 3178 my $time_line = get_time_line($$module_info_hash{BUILD_TIME}); 3179 my ($successes_percent, $errors_percent) = get_progress_percentage($dirs_number - 1, $successful_number - 1, $errorful_number); 3180 return($errors_info_line, $dirs_info_line, $errorful_number, $successes_percent, $errors_percent, $time_line); 3181# } else { 3182# return($errors_info_line, $dirs_info_line, $errorful_number); 3183# }; 3184}; 3185 3186sub get_time_line { 3187 use integer; 3188 my $seconds = shift; 3189 my $hours = $seconds/3600; 3190 my $minits = ($seconds/60)%60; 3191 $seconds -= ($hours*3600 + $minits*60); 3192 return(sprintf("%02d\:%02d\:%02d" , $hours, $minits, $seconds)); 3193}; 3194 3195sub get_progress_percentage { 3196 use integer; 3197 my ($dirs_number, $successful_number, $errorful_number) = @_; 3198 return (0 ,0) if (!$dirs_number); 3199 my $errors_percent = ($errorful_number * 100)/ $dirs_number; 3200 my $successes_percent; 3201 if ($dirs_number == ($successful_number + $errorful_number)) { 3202 $successes_percent = 100 - $errors_percent; 3203 } else { 3204 $successes_percent = ($successful_number * 100)/ $dirs_number; 3205 }; 3206 return ($successes_percent, $errors_percent); 3207}; 3208 3209# 3210# This procedure stores the dmake result in %html_info 3211# 3212sub html_store_job_info { 3213 return if (!$html); 3214 my ($deps_hash, $build_dir, $error_code) = @_; 3215 my $force_update = 0; 3216 if ($build_dir =~ /(\s)/o && (defined $error_code)) { 3217 $force_update++ if (!children_number()); 3218 } 3219 my $module = $module_by_hash{$deps_hash}; 3220 my $module_info_hash = $html_info{$module}; 3221 my $dmake_array; 3222 if (defined $error_code) { 3223 $jobs_hash{$build_dir}->{FINISH_TIME} = time(); 3224 $$module_info_hash{BUILD_TIME} += $jobs_hash{$build_dir}->{FINISH_TIME} - $jobs_hash{$build_dir}->{START_TIME}; 3225 if ($error_code) { 3226 $jobs_hash{$build_dir}->{STATUS} = 'error'; 3227 $dmake_array = $$module_info_hash{ERRORFUL}; 3228 $build_dir =~ s/\\/\//g; 3229 $modules_with_errors{$module}++; 3230 } else { 3231 if ($build_dir =~ /(\s)announce/o) { 3232 $jobs_hash{$build_dir}->{STATUS} = '-'; 3233 } else { 3234 $jobs_hash{$build_dir}->{STATUS} = 'success'; 3235 }; 3236 $dmake_array = $$module_info_hash{SUCCESSFUL}; 3237 }; 3238 push (@$dmake_array, $build_dir); 3239 }; 3240}; 3241 3242sub start_server_on_port { 3243 my $port = shift; 3244 my $socket_obj = shift; 3245 $client_timeout = 1 if (!$parent_process); 3246 if ($ENV{GUI} eq 'WNT') { 3247 $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(), 3248 LocalPort => $port, 3249 Proto => 'tcp', 3250 Listen => 100); # 100 clients can be on queue, I think it is enough 3251 } else { 3252 $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(), 3253 LocalPort => $port, 3254 Proto => 'tcp', 3255 ReuseAddr => 1, 3256 Listen => 100); # 100 clients can be on queue, I think it is enough 3257 }; 3258 return('Cannot create socket object') if (!defined $$socket_obj); 3259 my $timeout = $$socket_obj->timeout($client_timeout); 3260 $$socket_obj->autoflush(1); 3261 if ($parent_process && $debug) { 3262 print "SERVER started on port $port\n"; 3263 } else { 3264 print "html_port:$html_port html_socket_obj: $html_socket_obj\n"; 3265 }; 3266 return 0; 3267}; 3268 3269sub accept_html_connection { 3270 my $new_socket_obj = undef; 3271 $new_socket_obj = $html_socket_obj->accept(); 3272 return $new_socket_obj; 3273}; 3274 3275sub accept_connection { 3276 my $new_socket_obj = undef; 3277 do { 3278 $new_socket_obj = $server_socket_obj->accept(); 3279 if (!$new_socket_obj) { 3280 print "Timeout on incoming connection\n"; 3281 check_client_jobs(); 3282 }; 3283 } while (!$new_socket_obj); 3284 return $new_socket_obj; 3285}; 3286 3287sub check_client_jobs { 3288 foreach (keys %clients_times) { 3289 if (time - $clients_times{$_} > $client_timeout) { 3290 print "Client's $_ Job: \"$clients_jobs{$_}\" apparently got lost...\n"; 3291 print "Scheduling for rebuild...\n"; 3292 print "You might need to check the $_\n"; 3293 $lost_client_jobs{$clients_jobs{$_}}++; 3294 delete $processes_hash{$_}; 3295 delete $clients_jobs{$_}; 3296 delete $clients_times{$_}; 3297# } else { 3298# print time - $clients_times{$_} . "\n"; 3299 }; 3300 }; 3301}; 3302 3303sub get_server_ports { 3304 # use port 7890 as default 3305 my $default_port = 7890; 3306 if ($ports_string) { 3307 @server_ports = split( /:/, $ports_string); 3308 } else { 3309 @server_ports = ($default_port .. $default_port + 4); 3310 }; 3311}; 3312 3313sub run_server { 3314 my @build_queue = (); # array, containing queue of projects 3315 # to build 3316 my $error = 0; 3317 if (scalar @server_ports) { 3318 foreach (@server_ports) { 3319 $error = start_server_on_port($_, \$server_socket_obj); 3320 if ($error) { 3321 print STDERR "port $_: $error\n"; 3322 } else { 3323# $SIG{KILL} = \&stop_server; 3324# $SIG{INT} = \&stop_server; 3325# $SIG{TERM} = \&stop_server; 3326# $SIG{QUIT} = \&stop_server; 3327 last; 3328 }; 3329 }; 3330 print_error('Unable to start server on port(s): ' . "@server_ports\n") if ($error); 3331 } else { 3332 print_error('No ports for server to start'); 3333 }; 3334 3335 my $client_addr; 3336 my $job_string_base = get_job_string_base(); 3337 my $new_socket_obj; 3338 while ($new_socket_obj = accept_connection()) { 3339 check_client_jobs(); 3340 # find out who connected 3341 my $client_ipnum = $new_socket_obj->peerhost(); 3342 my $client_host = gethostbyaddr(inet_aton($client_ipnum), AF_INET); 3343 # print who is connected 3344 # send them a message, close connection 3345 my $client_message = <$new_socket_obj>; 3346 chomp $client_message; 3347 my @client_data = split(/ /, $client_message); 3348 my %client_hash = (); 3349 foreach (@client_data) { 3350 /(=)/; 3351 $client_hash{$`} = $'; 3352 } 3353 my $pid = $client_hash{pid} . '@' . $client_host; 3354 if (defined $client_hash{platform}) { 3355 if ($client_hash{platform} ne $ENV{OUTPATH} || (defined $client_hash{osname} && ($^O ne $client_hash{osname}))) { 3356 print $new_socket_obj "Wrong platform"; 3357 close($new_socket_obj); 3358 next; 3359 }; 3360 } else { 3361 if ($client_hash{result} eq "0") { 3362# print "$clients_jobs{$pid} succedded on $pid\n"; 3363 } else { 3364 print "Error $client_hash{result}\n"; 3365 if (store_error($pid, $client_hash{result})) { 3366 print $new_socket_obj $job_string_base . $clients_jobs{$pid}; 3367 close($new_socket_obj); 3368 $clients_times{$pid} = time; 3369 next; 3370 }; 3371 }; 3372 delete $clients_times{$pid}; 3373 clear_from_child($pid); 3374 delete $clients_jobs{$pid}; 3375 $verbose_mode && print 'Running processes: ', children_number(), "\n"; 3376 # Actually, next 3 strings are only for even distribution 3377 # of clients if there are more than one build server running 3378 print $new_socket_obj 'No job'; 3379 close($new_socket_obj); 3380 next; 3381 }; 3382 my $job_string; 3383 my @lost_jobs = keys %lost_client_jobs; 3384 if (scalar @lost_jobs) { 3385 $job_string = $lost_jobs[0]; 3386 delete $lost_client_jobs{$lost_jobs[0]}; 3387 } else { 3388# $job_string = get_job_string(\@build_queue, $pid); 3389 $job_string = get_job_string(\@build_queue); 3390 }; 3391 if ($job_string) { 3392 my $job_dir = $job_jobdir{$job_string}; 3393 $processes_hash{$pid} = $job_dir; 3394 $jobs_hash{$job_dir}->{CLIENT} = $pid; 3395 print "$pid got $job_dir\n"; 3396 print $new_socket_obj $job_string_base . $job_string; 3397 $clients_jobs{$pid} = $job_string; 3398 $clients_times{$pid} = time; 3399 my $children_running = children_number(); 3400 $verbose_mode && print 'Running processes: ', $children_running, "\n"; 3401 $maximal_processes = $children_running if ($children_running > $maximal_processes); 3402 } else { 3403 print $new_socket_obj 'No job'; 3404 }; 3405 close($new_socket_obj); 3406 }; 3407}; 3408 3409# 3410# Procedure returns the part of the job string that is similar for all clients 3411# 3412sub get_job_string_base { 3413 if ($setenv_string) { 3414 return "setenv_string=$setenv_string "; 3415 }; 3416 my $job_string_base = "server_pid=$$ setsolar_cmd=$ENV{SETSOLAR_CMD} "; 3417 $job_string_base .= "source_root=$ENV{SOURCE_ROOT} " if (defined $ENV{SOURCE_ROOT}); 3418 $job_string_base .= "updater=$ENV{UPDATER} " if (defined $ENV{UPDATER}); 3419 return $job_string_base; 3420}; 3421 3422sub get_job_string { 3423 my $build_queue = shift; 3424 my $job = $dmake; 3425 my ($job_dir, $dependencies_hash); 3426 if ($build_all_parents) { 3427 fill_modules_queue($build_queue); 3428 do { 3429 ($job_dir, $dependencies_hash) = pick_jobdir($build_queue); 3430 return '' if (!$job_dir); 3431 $jobs_hash{$job_dir}->{START_TIME} = time(); 3432 $jobs_hash{$job_dir}->{STATUS} = 'building'; 3433 if ($job_dir =~ /(\s)$pre_job/o) { 3434 do_custom_job($job_dir, $dependencies_hash); 3435 $job_dir = ''; 3436 }; 3437 } while (!$job_dir); 3438 } else { 3439 $dependencies_hash = \%local_deps_hash; 3440 do { 3441 $job_dir = pick_prj_to_build(\%local_deps_hash); 3442 if (!$job_dir && !children_number()) { 3443 cancel_build() if (scalar keys %broken_build); 3444 mp_success_exit(); 3445 }; 3446 return '' if (!$job_dir); 3447 $jobs_hash{$job_dir}->{START_TIME} = time(); 3448 $jobs_hash{$job_dir}->{STATUS} = 'building'; 3449 if ($job_dir =~ /(\s)$pre_job/o) { 3450# if ($' eq $pre_job) { 3451 do_custom_job($job_dir, $dependencies_hash); 3452 $job_dir = ''; 3453# } 3454 }; 3455 } while (!$job_dir); 3456 }; 3457 $running_children{$dependencies_hash}++; 3458 $folders_hashes{$job_dir} = $dependencies_hash; 3459 my $log_file = $jobs_hash{$job_dir}->{LONG_LOG_PATH}; 3460 my $full_job_dir = $job_dir; 3461 if ($job_dir =~ /(\s)/o) { 3462 $job = $'; 3463 $job = $deliver_command if ($job eq $post_job); 3464 $full_job_dir = $module_paths{$`}; 3465 } 3466 my $log_dir = File::Basename::dirname($log_file); 3467 if (!-d $log_dir) { 3468 chdir $full_job_dir; 3469 getcwd(); 3470 system("$perl $mkout"); 3471 }; 3472 my $job_string = "job_dir=$full_job_dir job=$job log=$log_file"; 3473 $job_jobdir{$job_string} = $job_dir; 3474 return $job_string; 3475}; 3476 3477sub pick_jobdir { 3478 my $build_queue = shift; 3479 my $i = 0; 3480 foreach (@$build_queue) { 3481 my $prj = $$build_queue[$i]; 3482 my $prj_deps_hash = $projects_deps_hash{$prj}; 3483 if (defined $modules_with_errors{$prj_deps_hash} && !$ignore) { 3484 push (@broken_module_names, $prj); 3485 splice (@$build_queue, $i, 1); 3486 next; 3487 }; 3488 $running_children{$prj_deps_hash} = 0 if (!defined $running_children{$prj_deps_hash}); 3489 my $child_nick = pick_prj_to_build($prj_deps_hash); 3490 if ($child_nick) { 3491 return ($child_nick, $prj_deps_hash); 3492 } 3493 if ((!scalar keys %$prj_deps_hash) && !$running_children{$prj_deps_hash}) { 3494 if (!defined $modules_with_errors{$prj_deps_hash} || $ignore) 3495 { 3496 remove_from_dependencies($prj, \%global_deps_hash); 3497 $build_is_finished{$prj}++; 3498 splice (@$build_queue, $i, 1); 3499 next; 3500 }; 3501 }; 3502 $i++; 3503 }; 3504}; 3505 3506sub fill_modules_queue { 3507 my $build_queue = shift; 3508 my $prj; 3509 while ($prj = pick_prj_to_build(\%global_deps_hash)) { 3510 push @$build_queue, $prj; 3511 $projects_deps_hash{$prj} = {}; 3512 get_module_dep_hash($prj, $projects_deps_hash{$prj}); 3513 my $info_hash = $html_info{$prj}; 3514 $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$prj}, $prj); 3515 $module_by_hash{$projects_deps_hash{$prj}} = $prj; 3516 }; 3517 if (!$prj && !children_number() && (!scalar @$build_queue)) { 3518 cancel_build() if (scalar keys %broken_build); 3519 mp_success_exit(); 3520 }; 3521}; 3522 3523sub is_gnumake_module { 3524 my $module = shift; 3525 my $bridgemakefile = $source_config->get_module_path($module) . "/prj/makefile.mk"; 3526 return (-e $bridgemakefile); 3527} 3528 3529sub check_partial_gnumake_build { 3530 if(!$build_all_parents && is_gnumake_module(shift)) { 3531 print "This module has been migrated to GNU make.\n"; 3532 print "You can only use build --all/--since here with build.pl.\n"; 3533 print "To do the equivalent of 'build && deliver' call:\n"; 3534 print "\tmake -sr\n"; 3535 print "in the module root (This will modify the solver).\n"; 3536 exit 1; 3537 } 3538} 3539