PageRenderTime 68ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/solenv/bin/build.pl

https://bitbucket.org/markjenkins/libreoffice_ubuntu-debian-fixes
Perl | 2926 lines | 2632 code | 129 blank | 165 comment | 363 complexity | a972cdb647879201cbcc94c1d08a6000 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause-No-Nuclear-License-2014
  1. :
  2. eval 'exec perl -S $0 ${1+"$@"}'
  3. if 0;
  4. #*************************************************************************
  5. #
  6. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  7. #
  8. # Copyright 2000, 2010 Oracle and/or its affiliates.
  9. #
  10. # OpenOffice.org - a multi-platform office productivity suite
  11. #
  12. # This file is part of OpenOffice.org.
  13. #
  14. # OpenOffice.org is free software: you can redistribute it and/or modify
  15. # it under the terms of the GNU Lesser General Public License version 3
  16. # only, as published by the Free Software Foundation.
  17. #
  18. # OpenOffice.org is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU Lesser General Public License version 3 for more details
  22. # (a copy is included in the LICENSE file that accompanied this code).
  23. #
  24. # You should have received a copy of the GNU Lesser General Public License
  25. # version 3 along with OpenOffice.org. If not, see
  26. # <http://www.openoffice.org/license.html>
  27. # for a copy of the LGPLv3 License.
  28. #
  29. #*************************************************************************
  30. #
  31. # build - build entire project
  32. #
  33. use strict;
  34. use Config;
  35. use POSIX;
  36. use Cwd qw (cwd);
  37. use File::Path;
  38. use File::Temp qw(tmpnam tempdir);
  39. use File::Find;
  40. use Socket;
  41. use IO::Socket::INET;
  42. use IO::Select;
  43. use Fcntl;
  44. use POSIX qw(:errno_h);
  45. use Sys::Hostname;
  46. use IPC::Open3;
  47. use lib ("$ENV{SOLARENV}/bin/modules");
  48. use SourceConfig;
  49. use RepositoryHelper;
  50. use Cwd 'chdir';
  51. my $in_so_env = 0;
  52. if (defined $ENV{COMMON_ENV_TOOLS}) {
  53. unshift(@INC, "$ENV{COMMON_ENV_TOOLS}/modules");
  54. $in_so_env++;
  55. };
  56. my $verbose_mode = 0;
  57. if (defined $ENV{verbose} || defined $ENV{VERBOSE}) {
  58. $verbose_mode = ($ENV{verbose} =~ /^t\S*$/i);
  59. }
  60. ### for XML file format
  61. eval { require XMLBuildListParser; import XMLBuildListParser; };
  62. my $enable_xml = 0;
  63. my @modes_array = ();
  64. if (!$@) {
  65. $enable_xml = 1;
  66. @modes_array = split('\s' , $ENV{BUILD_TYPE});
  67. };
  68. #### script id #####
  69. #########################
  70. # #
  71. # Global Variables #
  72. # #
  73. #########################
  74. my $modules_number++;
  75. my $perl = 'perl';
  76. my $remove_command = 'rm -rf';
  77. my $nul = '> /dev/null';
  78. my $processes_to_run = 0;
  79. # delete $pid when not needed
  80. my %projects_deps_hash = (); # hash of projects with no dependencies,
  81. # that could be built now
  82. my %broken_build = (); # hash of hashes of the modules,
  83. # where build was broken (error occurred)
  84. my %folders_hashes = ();
  85. my %running_children = ();
  86. my $dependencies_hash = 0;
  87. my $cmd_file = '';
  88. my $build_all_parents = 0;
  89. my $show = 0;
  90. my $checkparents = 0;
  91. my $deliver = 0;
  92. my $pre_custom_job = '';
  93. my $custom_job = '';
  94. my $post_custom_job = '';
  95. my %local_deps_hash = ();
  96. my %path_hash = ();
  97. my %platform_hash = ();
  98. my %alive_dependencies = ();
  99. my %global_deps_hash = (); # hash of dependencies of the all modules
  100. my %global_deps_hash_backup = (); # backup hash of external dependencies of the all modules
  101. my %module_deps_hash_backup = (); # backup hash of internal dependencies for each module
  102. my @broken_modules_names = (); # array of modules, which cannot be built further
  103. my @dmake_args = ();
  104. my %dead_parents = ();
  105. my $initial_module = '';
  106. my $all_dependent = 1; # a flag indicating if the hash has independent keys
  107. my $build_from_with_branches = '';
  108. my $build_all_cont = '';
  109. my $build_since = '';
  110. my $dlv_switch = '';
  111. my $child = 0;
  112. my %processes_hash = ();
  113. my %module_announced = ();
  114. my $ignore = '';
  115. my $html = '';
  116. my @ignored_errors = ();
  117. my %incompatibles = ();
  118. my %skip_modules = ();
  119. my %exclude_branches = ();
  120. my $only_platform = ''; # the only platform to prepare
  121. my $only_common = ''; # the only common output tree to delete when preparing
  122. my %build_modes = ();
  123. my $maximal_processes = 0; # the max number of the processes run
  124. my %modules_types = (); # modules types ('mod', 'img', 'lnk') hash
  125. my %platforms = (); # platforms available or being working with
  126. my %platforms_to_copy = (); # copy output trees for the platforms when --prepare
  127. my $tmp_dir = get_tmp_dir(); # temp directory for checkout and other actions
  128. my %build_list_paths = (); # build lists names
  129. my %build_lists_hash = (); # hash of arrays $build_lists_hash{$module} = \($path, $xml_list_object)
  130. my $pre_job = 'announce'; # job to add for not-single module build
  131. my $post_job = ''; # -"-
  132. my @warnings = (); # array of warnings to be shown at the end of the process
  133. my @errors = (); # array of errors to be shown at the end of the process
  134. my %html_info = (); # hash containing all necessary info for generating of html page
  135. my %module_by_hash = (); # hash containing all modules names as values and correspondent hashes as keys
  136. my %build_in_progress = (); # hash of modules currently being built
  137. my %build_is_finished = (); # hash of already built modules
  138. my %modules_with_errors = (); # hash of modules with build errors
  139. my %build_in_progress_shown = (); # hash of modules being built,
  140. # and shown last time (to keep order)
  141. my $build_time = time;
  142. my %jobs_hash = ();
  143. my $html_path = undef;
  144. my $build_finished = 0;
  145. my $html_file = '';
  146. my %had_error = (); # hack for mysterious windows problems - try run dmake 2 times if first time there was an error
  147. my $mkout = correct_path("$ENV{SOLARENV}/bin/mkout.pl");
  148. my %weights_hash = (); # hash contains info about how many modules are dependent from one module
  149. my $stop_build_on_error = 0; # for multiprocessing mode: do not build further module if there is an error
  150. my $interactive = 0; # for interactive mode... (for testing purpose enabled by default)
  151. my $parent_process = 1;
  152. my @server_ports = ();
  153. my $html_port = 0;
  154. my $html_socket_obj = undef; # socket object for server
  155. my $client_timeout = 0; # time for client to build (in sec)...
  156. # The longest time period after that
  157. # the server considered as an error/client crash
  158. my $reschedule_queue = 0;
  159. my %module_build_queue = ();
  160. my %reversed_dependencies = ();
  161. my %module_paths = (); # hash with absolute module paths
  162. my %active_modules = ();
  163. my $finished_children = 0;
  164. my $debug = 0;
  165. my %module_deps_hash_pids = ();
  166. my @argv = @ARGV;
  167. my $zenity_pid = 0;
  168. my $zenity_in = '';
  169. my $zenity_out = '';
  170. my $zenity_err = '';
  171. my $last_message_time = 0;
  172. my $verbose = 0;
  173. my @modules_built = ();
  174. my $deliver_command = "deliver.pl";
  175. my %prj_platform = ();
  176. my $check_error_string = '';
  177. my $dmake = '';
  178. my $dmake_args = '';
  179. my $echo = '';
  180. my $new_line = "\n";
  181. my $incompatible = 0;
  182. my $local_host_ip = 'localhost';
  183. my $tail_build_modules_mk = "$ENV{SOLARENV}/gbuild/tail_build_modules.mk";
  184. my $tail_build_module_dir = $ENV{"SRCDIR"};
  185. my $tail_build_prj = "tail_build";
  186. my $cross_tail_build_prj = "cross_tail_build";
  187. my $total_modules = 0;
  188. ### main ###
  189. get_options();
  190. zenity_open();
  191. zenity_tooltip("Starting build.");
  192. get_build_modes();
  193. my %deliver_env = ();
  194. my $workspace_path = get_workspace_path(); # This also sets $initial_module
  195. my $build_error_log = Cwd::realpath(correct_path($workspace_path)) ."/build_error.log";
  196. my $workdir = $ENV{WORKDIR};
  197. my $source_config = SourceConfig -> new($workspace_path);
  198. check_partial_gnumake_build($initial_module);
  199. system("rm -f $build_error_log");
  200. if ($html) {
  201. if (defined $html_path) {
  202. $html_file = correct_path($html_path . '/' . $ENV{INPATH}. '.build.html');
  203. } else {
  204. my $log_directory = Cwd::realpath(correct_path($workspace_path . '/..')) . '/log';
  205. if ((!-d $log_directory) && (!mkdir($log_directory))) {
  206. print_error("Cannot create $log_directory for writing html file\n");
  207. };
  208. $html_file = $log_directory . '/' . $ENV{INPATH}. '.build.html';
  209. print "\nPath to html status page: $html_file\n";
  210. };
  211. };
  212. get_module_and_buildlist_paths();
  213. $deliver_command .= ' -verbose' if ($html || $verbose);
  214. $deliver_command .= ' '. $dlv_switch if ($dlv_switch);
  215. $ENV{mk_tmp}++;
  216. get_commands();
  217. unlink ($cmd_file);
  218. if ($cmd_file) {
  219. if (open (CMD_FILE, ">>$cmd_file")) {
  220. select CMD_FILE;
  221. $echo = 'echo ';
  222. if ($ENV{GUI_FOR_BUILD} ne 'UNX') {
  223. $new_line = "echo.\n";
  224. print "\@$echo off\npushd\n";
  225. } else {
  226. $new_line = $echo."\"\"\n";
  227. };
  228. } else {
  229. print_error ("Cannot open file $cmd_file");
  230. };
  231. };
  232. print $new_line;
  233. get_server_ports();
  234. start_interactive() if ($interactive);
  235. if ($checkparents) {
  236. get_parent_deps( $initial_module, \%global_deps_hash );
  237. } else {
  238. build_all();
  239. }
  240. if (scalar keys %broken_build) {
  241. cancel_build();
  242. };
  243. print_warnings();
  244. if (scalar keys %active_modules) {
  245. foreach (keys %dead_parents) {
  246. delete $dead_parents{$_} if (!defined $active_modules{$_});
  247. };
  248. };
  249. if (scalar keys %dead_parents) {
  250. print $new_line.$new_line;
  251. print $echo."WARNING! Project(s):\n";
  252. foreach (keys %dead_parents) {
  253. print $echo."$_\n";
  254. };
  255. print $new_line;
  256. print $echo."not found and couldn't be built. dependencies on that module(s) ignored. Maybe you should correct build lists.\n";
  257. print $new_line;
  258. do_exit(1) if ($checkparents);
  259. };
  260. if (($ENV{GUI_FOR_BUILD} ne 'UNX') && $cmd_file) {
  261. print "popd\n";
  262. };
  263. $ENV{mk_tmp} = '';
  264. if ($cmd_file) {
  265. close CMD_FILE;
  266. print STDOUT "Script $cmd_file generated\n";
  267. };
  268. if ($ignore && scalar @ignored_errors) {
  269. print STDERR "\nERROR: next directories could not be built:\n";
  270. foreach (@ignored_errors) {
  271. print STDERR "\t$_\n";
  272. };
  273. print STDERR "\nERROR: please check these directories and build the corresponding module(s) anew!!\n\n";
  274. do_exit(1);
  275. };
  276. do_exit(0);
  277. #########################
  278. # #
  279. # Procedures #
  280. # #
  281. #########################
  282. sub print_warnings {
  283. if (scalar @warnings) {
  284. print STDERR "\nWARNING(S):\n";
  285. print STDERR $_ foreach (@warnings);
  286. };
  287. };
  288. sub rename_file {
  289. my ($old_file_name, $new_file_name, $throw_error) = @_;
  290. if(-e $old_file_name) {
  291. rename($old_file_name, $new_file_name) or system("mv", $old_file_name, $new_file_name);
  292. if (-e $old_file_name) {
  293. system("rm -rf $old_file_name") if (!unlink $old_file_name);
  294. };
  295. } elsif ($throw_error) {
  296. print_error("No such file $old_file_name");
  297. };
  298. };
  299. sub start_interactive {
  300. my $pid = open(HTML_PIPE, "-|");
  301. print "Pipe is open\n";
  302. if ($pid) { # parent
  303. # make file handle non-blocking
  304. my $flags = '';
  305. fcntl(HTML_PIPE, F_GETFL, $flags);
  306. $flags |= O_NONBLOCK;
  307. fcntl(HTML_PIPE, F_SETFL, $flags);
  308. } else { # child
  309. $parent_process = 0;
  310. start_html_listener();
  311. };
  312. };
  313. sub start_html_listener {
  314. $html_port = $server_ports[$#server_ports];
  315. do {
  316. $html_port++
  317. } while (start_server_on_port($html_port, \$html_socket_obj));
  318. print "html_port:$html_port html_socket_obj: $html_socket_obj\n";
  319. my $new_socket_obj;
  320. do {
  321. $new_socket_obj = accept_html_connection();
  322. if (defined $new_socket_obj) {
  323. my $html_message;
  324. $html_message = <$new_socket_obj>;
  325. chomp $html_message;
  326. print $html_message . "\n";
  327. my $socket_message = '';
  328. for my $action ('rebuild', 'delete') {
  329. if ($html_message =~ /$action=(\S+)/) {
  330. print $new_socket_obj "Module $1 is scheduled for $action";
  331. };
  332. };
  333. close($new_socket_obj);
  334. } else {
  335. sleep(10);
  336. };
  337. } while(1);
  338. };
  339. sub get_html_orders {
  340. return if (!$interactive);
  341. my $buffer_size = 1024;
  342. my $buffer;
  343. my $rv;
  344. my $full_buffer = '';
  345. my %modules_to_rebuild = ();
  346. my %modules_to_delete = ();
  347. while ($rv = sysread(HTML_PIPE, $buffer, $buffer_size)) {
  348. $full_buffer .= $buffer;
  349. };
  350. my @html_messages = split(/\n/, $full_buffer);
  351. foreach (@html_messages) {
  352. if (/^html_port:(\d+)/) {
  353. $html_port = $1;
  354. print "Html port is: $html_port\n";
  355. next;
  356. };# GET /rebuild=officenames HTTP/1.0
  357. print "Message: $_\n";
  358. chomp;
  359. if (/GET\s+\/delete=(\S+)[:(\S+)]*\s*HTTP/) {
  360. $modules_to_delete{$1} = $2;
  361. print "$1 scheduled for removal from build for \n";
  362. }
  363. if (/GET\s+\/rebuild=(\S+)[:(\S+)]*\s*HTTP/) {
  364. if (defined $global_deps_hash{$1}) {
  365. print "!!! /tarModule $1 has not been built. Html order ignored\n";
  366. } else {
  367. $modules_to_rebuild{$1} = $2;
  368. print "Scheduled $1 for rebuild\n";
  369. }
  370. }
  371. };
  372. if (scalar keys %modules_to_delete) {
  373. $reschedule_queue++;
  374. schedule_delete(\%modules_to_delete);
  375. generate_html_file();
  376. };
  377. if (scalar keys %modules_to_rebuild) {
  378. $reschedule_queue++;
  379. schedule_rebuild(\%modules_to_rebuild);
  380. generate_html_file();
  381. };
  382. };
  383. sub schedule_delete {
  384. my $modules_to_delete = shift;
  385. foreach (keys %$modules_to_delete) {
  386. print "Schedule module $_ for delete\n";
  387. delete ($global_deps_hash{$_});
  388. delete ($global_deps_hash_backup{$_});
  389. if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) {
  390. kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}};
  391. handle_dead_children(0);
  392. };
  393. remove_from_dependencies($_, \%global_deps_hash);
  394. remove_from_dependencies($_, \%global_deps_hash_backup);
  395. delete $reversed_dependencies{$_};
  396. delete $build_is_finished{$_} if defined $build_is_finished{$_};
  397. delete $modules_with_errors{$_} if defined $modules_with_errors{$_};
  398. delete $module_announced{$_} if defined $module_announced{$_};
  399. delete $html_info{$_} if defined $html_info{$_};
  400. delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_};
  401. };
  402. };
  403. sub schedule_rebuild {
  404. my $modules_to_rebuild = shift;
  405. foreach (keys %$modules_to_rebuild) {
  406. if (defined $$modules_to_rebuild{$_}) {
  407. print "Schedule directory for rebuild";
  408. } else {
  409. print "Schedule complete $_ module for rebuild\n";
  410. if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) {
  411. kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}};
  412. handle_dead_children(0);
  413. };
  414. delete $build_is_finished{$_} if defined $build_is_finished{$_};
  415. delete $modules_with_errors{$_} if defined $modules_with_errors{$_};
  416. delete $module_announced{$_};
  417. initialize_html_info($_);
  418. foreach my $waiter (keys %{$reversed_dependencies{$_}}) {
  419. # for rebuild_all_dependent - refacture "if" condition
  420. ${$global_deps_hash{$waiter}}{$_}++ if (!defined $build_is_finished{$waiter});
  421. };
  422. delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_};
  423. my %single_module_dep_hash = ();
  424. foreach my $module (keys %{$global_deps_hash_backup{$_}}) {
  425. if (defined ${$global_deps_hash_backup{$_}}{$module} && (!defined $build_is_finished{$module})) {
  426. $single_module_dep_hash{$module}++;
  427. };
  428. };
  429. $global_deps_hash{$_} = \%single_module_dep_hash;
  430. };
  431. };
  432. };
  433. #
  434. # procedure retrieves build list path
  435. # (all possibilities are taken into account)
  436. #
  437. sub get_build_list_path {
  438. my $module = shift;
  439. return $build_list_paths{$module} if (defined $build_list_paths{$module});
  440. return $build_list_paths{$module} if (defined $build_list_paths{$module});
  441. my $possible_dir_path = $module_paths{$module}.'/prj/';
  442. if (-d $possible_dir_path)
  443. {
  444. my $possible_build_list_path = correct_path($possible_dir_path . "build.lst");
  445. if (-f $possible_build_list_path)
  446. {
  447. $build_list_paths{$module} = $possible_build_list_path;
  448. return $possible_build_list_path;
  449. };
  450. print_error("There's no build.lst for $module");
  451. };
  452. $dead_parents{$module}++;
  453. return $build_list_paths{$module};
  454. };
  455. #
  456. # Get dependencies hash of the current and all parent projects
  457. #
  458. sub get_parent_deps {
  459. my $prj_dir = shift;
  460. my $deps_hash = shift;
  461. my @unresolved_parents = ($prj_dir);
  462. my %skipped_branches = ();
  463. while (my $module = pop(@unresolved_parents)) {
  464. next if (defined $$deps_hash{$module});
  465. my %parents_deps_hash = ();
  466. foreach (get_parents_array($module)) {
  467. if (defined $exclude_branches{$_}) {
  468. $skipped_branches{$_}++;
  469. next;
  470. };
  471. $parents_deps_hash{$_}++;
  472. }
  473. $$deps_hash{$module} = \%parents_deps_hash;
  474. foreach my $parent (keys %parents_deps_hash) {
  475. if (!defined($$deps_hash{$parent}) && (!defined $exclude_branches{$module})) {
  476. push (@unresolved_parents, $parent);
  477. };
  478. };
  479. };
  480. check_deps_hash($deps_hash);
  481. foreach (keys %skipped_branches) {
  482. print $echo . "Skipping module's $_ branch\n";
  483. delete $exclude_branches{$_};
  484. };
  485. my @missing_branches = keys %exclude_branches;
  486. if (scalar @missing_branches) {
  487. print_error("For $prj_dir branche(s): \"@missing_branches\" not found\n");
  488. };
  489. };
  490. sub store_weights {
  491. my $deps_hash = shift;
  492. foreach (keys %$deps_hash) {
  493. foreach my $module_deps_hash ($$deps_hash{$_}) {
  494. foreach my $dependency (keys %$module_deps_hash) {
  495. $weights_hash{$dependency}++;
  496. };
  497. };
  498. };
  499. };
  500. #
  501. # This procedure builds comlete dependency for each module, ie if the deps look like:
  502. # mod1 -> mod2 -> mod3 -> mod4,mod5,
  503. # than mod1 get mod3,mod4,mod5 as eplicit list of deps, not only mod2 as earlier
  504. #
  505. sub expand_dependencies {
  506. my $deps_hash = shift;
  507. foreach my $module1 (keys %$deps_hash) {
  508. foreach my $module2 (keys %$deps_hash) {
  509. next if ($module1 eq $module2);
  510. if (defined ${$$deps_hash{$module2}}{$module1}) {
  511. ${$$deps_hash{$module2}}{$_}++ foreach (keys %{$$deps_hash{$module1}})
  512. };
  513. };
  514. };
  515. };
  516. #
  517. # Gets list of tail_build modules.
  518. #
  519. sub get_tail_build_modules {
  520. my $tail_build_prj = shift;
  521. my $make = $ENV{'GNUMAKE'};
  522. my $build_type = $ENV{'BUILD_TYPE'};
  523. my $tail_build_mk = "$tail_build_module_dir/Module_$tail_build_prj.mk";
  524. my $modules_str = `$make --no-print-directory -r -f $tail_build_modules_mk get_modules TAIL_BUILD_MK=$tail_build_mk BUILD_TYPE='$build_type'`;
  525. chomp $modules_str;
  526. my %modules = ();
  527. foreach my $module (split /\s+/, $modules_str) {
  528. $modules{$module} = 1;
  529. }
  530. return %modules;
  531. }
  532. sub _filter_tail_build_dependencies {
  533. my $deps_hash = shift;
  534. my $tail_build_prj = shift;
  535. if (!defined $$deps_hash{$tail_build_prj}) {
  536. # nothing to do
  537. return;
  538. }
  539. my %tail_build_modules = get_tail_build_modules($tail_build_prj);
  540. # first remove tail_build modules from deps.
  541. foreach my $prj (keys %tail_build_modules) {
  542. if (defined $$deps_hash{$prj}) {
  543. delete $$deps_hash{$prj};
  544. }
  545. }
  546. # do the actual replacement
  547. foreach my $prj (keys %$deps_hash) {
  548. my @tail_build_deps = ();
  549. my $deps = $$deps_hash{$prj};
  550. # remove deps. that are in tail_build
  551. foreach my $dep (keys %$deps) {
  552. if (defined $tail_build_modules{$dep}) {
  553. print "$prj depends on $tail_build_prj\[$dep\]\n";
  554. push @tail_build_deps, $dep;
  555. delete $$deps{$dep};
  556. }
  557. }
  558. # insert dep. on tail_build, if necessary
  559. if (@tail_build_deps && !defined $$deps{$tail_build_prj}) {
  560. $$deps{$tail_build_prj} = 1;
  561. }
  562. }
  563. }
  564. #
  565. # Replaces all deps on modules from tail_build by dep on tail_build
  566. # itself. I.e., if a module foo depends on (sal, sfx2, svx) and (sfx2,
  567. # svx) are in tail_build, foo will be depending on (sal, tail_build).
  568. #
  569. # Works on cross_tail_build too, in case of cross-compilation.
  570. #
  571. sub filter_tail_build_dependencies {
  572. my $deps_hash = shift;
  573. _filter_tail_build_dependencies($deps_hash, $tail_build_prj);
  574. _filter_tail_build_dependencies($deps_hash, $cross_tail_build_prj);
  575. }
  576. #
  577. # This procedure fills the second hash with reversed dependencies,
  578. # ie, with info about modules "waiting" for the module
  579. #
  580. sub reverse_dependencies {
  581. my ($deps_hash, $reversed) = @_;
  582. foreach my $module (keys %$deps_hash) {
  583. foreach (keys %{$$deps_hash{$module}}) {
  584. if (defined $$reversed{$_}) {
  585. ${$$reversed{$_}}{$module}++
  586. } else {
  587. my %single_module_dep_hash = ($module => 1);
  588. $$reversed{$_} = \%single_module_dep_hash;
  589. };
  590. };
  591. };
  592. };
  593. #
  594. # Build everything that should be built
  595. #
  596. sub build_all {
  597. if ($build_all_parents) {
  598. my ($prj, $prj_dir, $orig_prj);
  599. get_parent_deps( $initial_module, \%global_deps_hash);
  600. filter_tail_build_dependencies(\%global_deps_hash);
  601. if (scalar keys %active_modules) {
  602. $active_modules{$initial_module}++;
  603. $modules_types{$initial_module} = 'mod';
  604. };
  605. expand_dependencies (\%global_deps_hash);
  606. prepare_incompatible_build(\%global_deps_hash) if ($incompatible && (!$build_from_with_branches));
  607. if ($build_from_with_branches) {
  608. my %reversed_full_deps_hash = ();
  609. reverse_dependencies(\%global_deps_hash, \%reversed_full_deps_hash);
  610. prepare_build_from_with_branches(\%global_deps_hash, \%reversed_full_deps_hash);
  611. }
  612. if ($build_all_cont || $build_since) {
  613. store_weights(\%global_deps_hash);
  614. prepare_build_all_cont(\%global_deps_hash);
  615. %weights_hash = ();
  616. };
  617. if ($incompatible) {
  618. my @missing_modules = ();
  619. foreach (sort keys %global_deps_hash) {
  620. push(@missing_modules, $_) if (!defined $active_modules{$_});
  621. };
  622. };
  623. foreach my $module (keys %dead_parents, keys %skip_modules) {
  624. remove_from_dependencies($module, \%global_deps_hash);
  625. delete ($global_deps_hash{$module}) if (defined $global_deps_hash{$module});
  626. };
  627. store_weights(\%global_deps_hash);
  628. backup_deps_hash(\%global_deps_hash, \%global_deps_hash_backup);
  629. reverse_dependencies(\%global_deps_hash_backup, \%reversed_dependencies);
  630. $modules_number = scalar keys %global_deps_hash;
  631. initialize_html_info($_) foreach (keys %global_deps_hash);
  632. if ($processes_to_run) {
  633. build_multiprocessing();
  634. return;
  635. };
  636. while ($prj = pick_prj_to_build(\%global_deps_hash)) {
  637. if (!defined $dead_parents{$prj}) {
  638. if (scalar keys %broken_build) {
  639. print $echo . "Skipping project $prj because of error(s)\n";
  640. remove_from_dependencies($prj, \%global_deps_hash);
  641. $build_is_finished{$prj}++;
  642. next;
  643. };
  644. $prj_dir = $module_paths{$prj};
  645. get_module_dep_hash($prj, \%local_deps_hash);
  646. my $info_hash = $html_info{$prj};
  647. $$info_hash{DIRS} = check_deps_hash(\%local_deps_hash, $prj);
  648. $module_by_hash{\%local_deps_hash} = $prj;
  649. build_dependent(\%local_deps_hash);
  650. print $check_error_string;
  651. };
  652. remove_from_dependencies($prj, \%global_deps_hash);
  653. $build_is_finished{$prj}++;
  654. };
  655. } else {
  656. store_build_list_content($initial_module);
  657. get_module_dep_hash($initial_module, \%local_deps_hash);
  658. initialize_html_info($initial_module);
  659. my $info_hash = $html_info{$initial_module};
  660. $$info_hash{DIRS} = check_deps_hash(\%local_deps_hash, $initial_module);
  661. $module_by_hash{\%local_deps_hash} = $initial_module;
  662. build_dependent(\%local_deps_hash);
  663. };
  664. };
  665. sub backup_deps_hash {
  666. my $source_hash = shift;
  667. my $backup_hash = shift;
  668. foreach my $key (keys %$source_hash) {
  669. my %values_hash = %{$$source_hash{$key}};
  670. $$backup_hash{$key} = \%values_hash;
  671. };
  672. };
  673. sub initialize_html_info {
  674. my $module = shift;
  675. return if (defined $dead_parents{$module});
  676. $html_info{$module} = { 'DIRS' => [],
  677. 'ERRORFUL' => [],
  678. 'SUCCESSFUL' => [],
  679. 'BUILD_TIME' => 0};
  680. }
  681. #
  682. # Do job
  683. #
  684. sub dmake_dir {
  685. my ($new_job_name, $error_code);
  686. my $job_name = shift;
  687. $jobs_hash{$job_name}->{START_TIME} = time();
  688. $jobs_hash{$job_name}->{STATUS} = 'building';
  689. if ($job_name =~ /(\s)/o && (!-d $job_name)) {
  690. $error_code = do_custom_job($job_name, \%local_deps_hash);
  691. } else {
  692. html_store_job_info(\%local_deps_hash, $job_name);
  693. print_error("$job_name not found!!\n") if (!-d $job_name);
  694. if (!-d $job_name) {
  695. $new_job_name = $job_name;
  696. $new_job_name =~ s/_simple//g;
  697. if ((-d $new_job_name)) {
  698. print("\nTrying $new_job_name, $job_name not found!!\n");
  699. $job_name = $new_job_name;
  700. } else {
  701. print_error("\n$job_name not found!!\n");
  702. }
  703. }
  704. if ($cmd_file) {
  705. print "cd $job_name\n";
  706. print $check_error_string;
  707. print $echo.$job_name."\n";
  708. print "$dmake\n";
  709. print $check_error_string;
  710. } else {
  711. print "Entering $job_name\n";
  712. };
  713. remove_from_dependencies($job_name, \%local_deps_hash) if (!$child);
  714. return if ($cmd_file || $show);
  715. $error_code = run_job($dmake, $job_name);
  716. #if dmake fails, have a go at regenerating the dependencies
  717. #and try again. dmakes normal failure is 255, while death on signal is 254
  718. my $real_exit_code = $error_code >> 8;
  719. if (($ENV{GUI_FOR_BUILD} eq 'WNT') && ($real_exit_code == 255) && ($ENV{nodep} eq '') && ($ENV{depend} eq '')) {
  720. print "Retrying $job_name\n";
  721. $error_code = run_job($dmake, $job_name);
  722. }
  723. html_store_job_info(\%local_deps_hash, $job_name, $error_code) if (!$child);
  724. };
  725. if ($error_code && $ignore) {
  726. push(@ignored_errors, $job_name);
  727. $error_code = 0;
  728. };
  729. if ($child) {
  730. my $oldfh = select STDERR;
  731. $| = 1;
  732. select $oldfh;
  733. $| =1;
  734. if ($error_code) {
  735. _exit($error_code >> 8);
  736. } else {
  737. _exit($? >> 8) if ($? && ($? != -1));
  738. };
  739. _exit(0);
  740. } elsif ($error_code && ($error_code != -1)) {
  741. $broken_build{$job_name} = $error_code;
  742. return $error_code;
  743. };
  744. };
  745. #
  746. # Procedure stores information about build list (and)
  747. # build list object in build_lists_hash
  748. #
  749. sub store_build_list_content {
  750. my $module = shift;
  751. my $build_list_path = get_build_list_path($module);
  752. return undef if (!defined $build_list_path);
  753. return if (!$build_list_path);
  754. if (open (BUILD_LST, $build_list_path))
  755. {
  756. my @build_lst = <BUILD_LST>;
  757. $build_lists_hash{$module} = \@build_lst;
  758. close BUILD_LST;
  759. return;
  760. };
  761. $dead_parents{$module}++;
  762. }
  763. #
  764. # Get string (list) of parent projects to build
  765. #
  766. sub get_parents_array {
  767. my $module = shift;
  768. store_build_list_content($module);
  769. my $build_list_ref = $build_lists_hash{$module};
  770. if (ref($build_list_ref) eq 'XMLBuildListParser') {
  771. return $build_list_ref->getModuleDependencies(\@modes_array);
  772. };
  773. foreach (@$build_list_ref) {
  774. if ($_ =~ /#/) {
  775. if ($`) {
  776. $_ = $`;
  777. } else {
  778. next;
  779. };
  780. };
  781. s/\r\n//;
  782. if ($_ =~ /\:+\s+/) {
  783. return pick_for_build_type($');
  784. };
  785. };
  786. return ();
  787. };
  788. #
  789. # get folders' platform infos
  790. #
  791. sub get_prj_platform {
  792. my $build_list_ref = shift;
  793. my ($prj_alias, $line);
  794. foreach(@$build_list_ref) {
  795. s/\r\n//;
  796. $line++;
  797. if ($_ =~ /\snmake\s/) {
  798. if ($' =~ /\s*-\s+(\w+)[,\S+]*\s+(\S+)/ ) { #'
  799. my $platform = $1;
  800. my $alias = $2;
  801. print_error ("There is no correct alias set in the line $line!") if ($alias eq 'NULL');
  802. mark_platform($alias, $platform);
  803. } else {
  804. print_error("Misspelling in line: \n$_");
  805. };
  806. };
  807. };
  808. };
  809. #
  810. # Procedure populate the dependencies hash with
  811. # information from XML build list object
  812. #
  813. sub get_deps_from_object {
  814. my ($module, $build_list_object, $dependencies_hash) = @_;
  815. foreach my $dir ($build_list_object->getJobDirectories("make", $ENV{GUI})) {
  816. $path_hash{$dir} = $module_paths{$module};
  817. $path_hash{$dir} .= $dir if ($dir ne '/');
  818. my %deps_hash = ();
  819. foreach my $dep ($build_list_object->getJobDependencies($dir, "make", $ENV{GUI})) {
  820. $deps_hash{$dep}++;
  821. };
  822. $$dependencies_hash{$dir} = \%deps_hash;
  823. };
  824. };
  825. #
  826. # this function wraps the get_module_dep_hash and backups the resultung hash
  827. #
  828. sub get_module_dep_hash {
  829. my ($module, $module_dep_hash) = @_;
  830. if (defined $module_deps_hash_backup{$module}) {
  831. backup_deps_hash($module_deps_hash_backup{$module}, $module_dep_hash);
  832. } else {
  833. get_deps_hash($module, $module_dep_hash);
  834. my %values_hash = ();
  835. backup_deps_hash($module_dep_hash, \%values_hash);
  836. $module_deps_hash_backup{$module} = \%values_hash;
  837. }
  838. };
  839. #
  840. # Getting hashes of all internal dependencies and additional
  841. # information for given project
  842. #
  843. sub get_deps_hash {
  844. my ($dummy, $module_to_build);
  845. my %dead_dependencies = ();
  846. $module_to_build = shift;
  847. my $dependencies_hash = shift;
  848. if ($custom_job)
  849. {
  850. add_prerequisite_job($dependencies_hash, $module_to_build, $pre_custom_job);
  851. add_prerequisite_job($dependencies_hash, $module_to_build, $pre_job);
  852. add_dependent_job($dependencies_hash, $module_to_build, $custom_job);
  853. add_dependent_job($dependencies_hash, $module_to_build, $post_job);
  854. add_dependent_job($dependencies_hash, $module_to_build, $post_custom_job);
  855. return;
  856. };
  857. my $build_list_ref = $build_lists_hash{$module_to_build};
  858. if (ref($build_list_ref) eq 'XMLBuildListParser') {
  859. get_deps_from_object($module_to_build, $build_list_ref, $dependencies_hash);
  860. } else {
  861. get_prj_platform($build_list_ref);
  862. foreach (@$build_list_ref) {
  863. if ($_ =~ /#/o) {
  864. next if (!$`);
  865. $_ = $`;
  866. };
  867. s/\r\n//;
  868. if ($_ =~ /\s+nmake\s+/o) {
  869. my ($platform, $dependencies, $dir, $dir_alias);
  870. my %deps_hash = ();
  871. $dependencies = $';
  872. $dummy = $`;
  873. $dummy =~ /(\S+)\s+(\S*)/o;
  874. $dir = $2;
  875. $dependencies =~ /(\w+)/o;
  876. $platform = $1;
  877. $dependencies = $';
  878. while ($dependencies =~ /,(\w+)/o) {
  879. $dependencies = $'; #'
  880. };
  881. $dependencies =~ /\s+(\S+)\s+/o;
  882. $dir_alias = $1;
  883. if (!check_platform($platform)) {
  884. next if (defined $platform_hash{$dir_alias});
  885. $dead_dependencies{$dir_alias}++;
  886. next;
  887. };
  888. delete $dead_dependencies{$dir_alias} if (defined $dead_dependencies{$dir_alias});
  889. 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});
  890. $platform_hash{$dir_alias}++;
  891. $dependencies = $'; #'
  892. print_error("$module_to_build/prj/build.lst has wrongly written dependencies string:\n$_\n") if (!$dependencies);
  893. $deps_hash{$_}++ foreach (get_dependency_array($dependencies));
  894. $$dependencies_hash{$dir_alias} = \%deps_hash;
  895. my $local_dir = '';
  896. if ($dir =~ /(\\|\/)/o) {
  897. $local_dir = "/$'";
  898. };
  899. $path_hash{$dir_alias} = correct_path($module_paths{$module_to_build} . $local_dir);
  900. } elsif ($_ !~ /^\s*$/ && $_ !~ /^\w*\s/o) {
  901. chomp;
  902. push(@errors, $_);
  903. };
  904. };
  905. if (scalar @errors) {
  906. my $message = "$module_to_build/prj/build.lst has wrongly written string(s):\n";
  907. $message .= "$_\n" foreach(@errors);
  908. if ($processes_to_run) {
  909. $broken_build{$module_to_build} = $message;
  910. $dependencies_hash = undef;
  911. return;
  912. } else {
  913. print_error($message);
  914. };
  915. };
  916. foreach my $alias (keys %dead_dependencies) {
  917. next if defined $alive_dependencies{$alias};
  918. # if (!IsHashNative($alias)) {
  919. remove_from_dependencies($alias, $dependencies_hash);
  920. delete $dead_dependencies{$alias};
  921. # };
  922. };
  923. };
  924. resolve_aliases($dependencies_hash, \%path_hash);
  925. add_prerequisite_job($dependencies_hash, $module_to_build, $pre_custom_job);
  926. add_prerequisite_job($dependencies_hash, $module_to_build, $pre_job);
  927. add_dependent_job($dependencies_hash, $module_to_build, $custom_job);
  928. add_dependent_job($dependencies_hash, $module_to_build, $post_job) if ($module_to_build ne $initial_module);
  929. add_dependent_job($dependencies_hash, $module_to_build, $post_custom_job);
  930. store_weights($dependencies_hash);
  931. };
  932. #
  933. # procedure adds which is independent from anothers, but anothers are dependent from it
  934. #
  935. sub add_prerequisite_job {
  936. my ($dependencies_hash, $module, $job) = @_;
  937. return if (!$job);
  938. $job = "$module $job";
  939. foreach (keys %$dependencies_hash) {
  940. my $deps_hash = $$dependencies_hash{$_};
  941. $$deps_hash{$job}++;
  942. };
  943. $$dependencies_hash{$job} = {};
  944. };
  945. #
  946. # procedure adds a job wich is dependent from all already registered jobs
  947. #
  948. sub add_dependent_job {
  949. # $post_job is dependent from all jobs
  950. my ($dependencies_hash, $module, $job) = @_;
  951. return if (!$job);
  952. my %deps_hash = ();
  953. $deps_hash{$_}++ foreach (keys %$dependencies_hash);
  954. $$dependencies_hash{"$module $job"} = \%deps_hash;
  955. };
  956. #
  957. # this procedure converts aliases to absolute paths
  958. #
  959. sub resolve_aliases {
  960. my ($dependencies_hash, $path_hash) = @_;
  961. foreach my $dir_alias (keys %$dependencies_hash) {
  962. my $aliases_hash_ref = $$dependencies_hash{$dir_alias};
  963. my %paths_hash = ();
  964. foreach (keys %$aliases_hash_ref) {
  965. $paths_hash{$$path_hash{$_}}++;
  966. };
  967. delete $$dependencies_hash{$dir_alias};
  968. $$dependencies_hash{$$path_hash{$dir_alias}} = \%paths_hash;
  969. };
  970. };
  971. #
  972. # mark platform in order to prove if alias has been used according to specs
  973. #
  974. sub mark_platform {
  975. my $prj_alias = shift;
  976. if (exists $prj_platform{$prj_alias}) {
  977. $prj_platform{$prj_alias} = 'all';
  978. } else {
  979. $prj_platform{$prj_alias} = shift;
  980. };
  981. };
  982. #
  983. # Convert path from abstract (with '\' and/or '/' delimiters)
  984. # to system-independent
  985. #
  986. sub correct_path {
  987. $_ = shift;
  988. s/\\/\//g;
  989. return $_;
  990. };
  991. sub check_dmake {
  992. if (open(DMAKEVERSION, "dmake -V |")) {
  993. my @dmake_version = <DMAKEVERSION>;
  994. close DMAKEVERSION;
  995. return;
  996. };
  997. my $error_message = 'dmake: Command not found.';
  998. $error_message .= ' Please rerun bootstrap' if (!defined $ENV{COMMON_ENV_TOOLS});
  999. print_error($error_message);
  1000. };
  1001. #
  1002. # Get platform-dependent commands
  1003. #
  1004. sub get_commands {
  1005. my $arg = '';
  1006. # Setting alias for dmake
  1007. $dmake = 'dmake';
  1008. check_dmake();
  1009. if ($cmd_file) {
  1010. if ($ENV{GUI_FOR_BUILD} eq 'UNX') {
  1011. $check_error_string = "if \"\$?\" != \"0\" exit\n";
  1012. } else {
  1013. $check_error_string = "if \"\%?\" != \"0\" quit\n";
  1014. };
  1015. };
  1016. $dmake_args = join(' ', 'dmake', @dmake_args);
  1017. while ($arg = pop(@dmake_args)) {
  1018. $dmake .= ' '.$arg;
  1019. };
  1020. $dmake .= ' verbose=true' if ($html || $verbose);
  1021. };
  1022. #
  1023. # Procedure retrieves list of projects to be built from build.lst
  1024. #
  1025. sub get_workspace_path {
  1026. if (!defined $ENV{GUI}) {
  1027. $ENV{mk_tmp} = '';
  1028. die "No environment set\n";
  1029. };
  1030. my $repository_helper = RepositoryHelper->new();
  1031. my $workspace_path = $repository_helper->get_repository_root();
  1032. my $initial_dir = $repository_helper->get_initial_directory();
  1033. if ($workspace_path eq $initial_dir) {
  1034. print_error('Found no project to build');
  1035. };
  1036. $initial_module = substr($initial_dir, length($workspace_path) + 1);
  1037. if ($initial_module =~ /(\\|\/)/) {
  1038. $initial_module = $`;
  1039. };
  1040. $module_paths{$initial_module} = $workspace_path . "/$initial_module";
  1041. return $workspace_path;
  1042. };
  1043. #
  1044. # Picks project which can be built now from hash and then deletes it from hash
  1045. #
  1046. sub pick_prj_to_build {
  1047. my $deps_hash = shift;
  1048. get_html_orders();
  1049. my $prj = find_indep_prj($deps_hash);
  1050. if ($prj) {
  1051. delete $$deps_hash{$prj};
  1052. generate_html_file();
  1053. };
  1054. return $prj;
  1055. };
  1056. #
  1057. # Make a decision if the project should be built on this platform
  1058. #
  1059. sub check_platform {
  1060. my $platform = shift;
  1061. return 1 if ($platform eq 'all');
  1062. return 1 if (($ENV{GUI} eq 'UNX') && ($platform eq 'u'));
  1063. return 1 if (($ENV{GUI} eq 'WNT') &&
  1064. (($platform eq 'w') || ($platform eq 'n')));
  1065. return 0;
  1066. };
  1067. #
  1068. # Remove project to build ahead from dependencies and make an array
  1069. # of all from given project dependent projects
  1070. #
  1071. sub remove_from_dependencies {
  1072. my ($exclude_prj, $i, $prj, $dependencies);
  1073. $exclude_prj = shift;
  1074. $dependencies = shift;
  1075. foreach $prj (keys %$dependencies) {
  1076. my $prj_deps_hash = $$dependencies{$prj};
  1077. delete $$prj_deps_hash{$exclude_prj} if (defined $$prj_deps_hash{$exclude_prj});
  1078. };
  1079. };
  1080. #
  1081. # Check the hash for consistency
  1082. #
  1083. sub check_deps_hash {
  1084. my ($deps_hash_ref, $module) = @_;
  1085. my @possible_order;
  1086. my $module_path = $module_paths{$module} if (defined $module);
  1087. return if (!scalar keys %$deps_hash_ref);
  1088. my %deps_hash = ();
  1089. my $consistent;
  1090. backup_deps_hash($deps_hash_ref, \%deps_hash);
  1091. my $string;
  1092. my $log_name;
  1093. my $log_path;
  1094. my $long_log_path;
  1095. my $build_number = 0;
  1096. do {
  1097. $consistent = '';
  1098. foreach my $key (sort keys %deps_hash) {
  1099. my $local_deps_ref = $deps_hash{$key};
  1100. if (!scalar keys %$local_deps_ref) {
  1101. if (defined $module) {
  1102. $build_number++;
  1103. $string = undef;
  1104. if ($key =~ /(\s)/o) {
  1105. $string = $key;
  1106. } else {
  1107. if (length($key) == length($module_path)) {
  1108. $string = './';
  1109. } else {
  1110. $string = substr($key, length($module_path) + 1);
  1111. $string =~ s/\\/\//go;
  1112. };
  1113. };
  1114. $log_name = $string;
  1115. if ($log_name eq "$module $custom_job") {
  1116. $log_name = "custom_job";
  1117. };
  1118. if ($log_name eq "$module $pre_custom_job") {
  1119. $log_name = "pre_custom_job";
  1120. };
  1121. if ($log_name eq "$module $post_custom_job") {
  1122. $log_name = "post_custom_job";
  1123. };
  1124. $log_name =~ s/\\|\//\./g;
  1125. $log_name =~ s/\s/_/g;
  1126. $log_name = $module if ($log_name =~ /^\.+$/);
  1127. $log_name .= '.txt';
  1128. if ( $source_config->is_gbuild($module) )
  1129. {
  1130. $log_path = correct_path("$workdir/Logs/${module}_${log_name}");
  1131. $long_log_path = correct_path("$workdir/Logs/${module}_${log_name}");
  1132. }
  1133. else
  1134. {
  1135. $log_path = '../' . $source_config->get_module_repository($module) . "/$module/$ENV{INPATH}/misc/logs/$log_name",
  1136. $long_log_path = correct_path($module_paths{$module} . "/$ENV{INPATH}/misc/logs/$log_name"),
  1137. }
  1138. push(@possible_order, $key);
  1139. $jobs_hash{$key} = { SHORT_NAME => $string,
  1140. BUILD_NUMBER => $build_number,
  1141. STATUS => 'waiting',
  1142. LOG_PATH => $log_path,
  1143. LONG_LOG_PATH => $long_log_path,
  1144. MODULE => $module,
  1145. START_TIME => 0,
  1146. FINISH_TIME => 0,
  1147. CLIENT => '-'
  1148. };
  1149. };
  1150. remove_from_dependencies($key, \%deps_hash);
  1151. delete $deps_hash{$key};
  1152. $consistent++;
  1153. };
  1154. };
  1155. } while ($consistent && (scalar keys %deps_hash));
  1156. return \@possible_order if ($consistent);
  1157. print STDERR "Fatal error:";
  1158. foreach (keys %deps_hash) {
  1159. print STDERR "\n\t$_ depends on: ";
  1160. foreach my $i (keys %{$deps_hash{$_}}) {
  1161. print STDERR (' ', $i);
  1162. };
  1163. };
  1164. if ($child) {
  1165. my $oldfh = select STDERR;
  1166. $| = 1;
  1167. _do_exit(1);
  1168. } else {
  1169. print_error("There are dead or circular dependencies\n");
  1170. };
  1171. };
  1172. #
  1173. # Find project with no dependencies left.
  1174. #
  1175. sub find_indep_prj {
  1176. my ($dependencies, $i);
  1177. my @candidates = ();
  1178. $all_dependent = 1;
  1179. handle_dead_children(0) if ($processes_to_run);
  1180. my $children = children_number();
  1181. return '' if ($children && ($children >= $processes_to_run));
  1182. $dependencies = shift;
  1183. if (scalar keys %$dependencies) {
  1184. foreach my $job (keys %$dependencies) {
  1185. if (!scalar keys %{$$dependencies{$job}}) {
  1186. push(@candidates, $job);
  1187. last if (!$processes_to_run);
  1188. };
  1189. };
  1190. if (scalar @candidates) {
  1191. $all_dependent = 0;
  1192. my $best_candidate = undef;
  1193. my $best_weight = 0;
  1194. if (scalar @candidates > 1) {
  1195. foreach my $candidate (@candidates) {
  1196. my $candidate_weight = get_waiters_number($candidate);
  1197. if ($candidate_weight > $best_weight) {
  1198. $best_candidate = $candidate;
  1199. $best_weight = $candidate_weight;
  1200. };
  1201. };
  1202. if (defined $best_candidate) {
  1203. return $best_candidate;
  1204. }
  1205. }
  1206. my @sorted_candidates = sort(@candidates);
  1207. return $sorted_candidates[0];
  1208. };
  1209. };
  1210. return '';
  1211. };
  1212. sub get_waiters_number {
  1213. my $module = shift;
  1214. if (defined $weights_hash{$module}) {
  1215. return $weights_hash{$module};
  1216. };
  1217. if (defined $reversed_dependencies{$module}) {
  1218. return scalar keys %{$reversed_dependencies{$module}};
  1219. };
  1220. return 0;
  1221. };
  1222. #
  1223. # Check if given entry is HASH-native, that is not a user-defined data
  1224. #
  1225. #sub IsHashNative {
  1226. # my $prj = shift;
  1227. # return 1 if ($prj =~ /^HASH\(0x[\d | a | b | c | d | e | f]{6,}\)/);
  1228. # return 0;
  1229. #};
  1230. #
  1231. # Getting array of dependencies from the string given
  1232. #
  1233. sub get_dependency_array {
  1234. my ($dep_string, @dependencies, $parent_prj, $prj, $string);
  1235. @dependencies = ();
  1236. $dep_string = shift;
  1237. $string = $dep_string;
  1238. $prj = shift;
  1239. while ($dep_string !~ /^NULL/o) {
  1240. print_error("Project $prj has wrongly written dependencies string:\n $string") if (!$dep_string);
  1241. $dep_string =~ /(\S+)\s*/o;
  1242. $parent_prj = $1;
  1243. $dep_string = $'; #'
  1244. if ($parent_prj =~ /\.(\w+)$/o) {
  1245. $parent_prj = $`;
  1246. if (($prj_platform{$parent_prj} ne $1) &&
  1247. ($prj_platform{$parent_prj} ne 'all')) {
  1248. print_error ("$parent_prj\.$1 is a wrongly dependency identifier!\nCheck if it is platform dependent");
  1249. };
  1250. $alive_dependencies{$parent_prj}++ if (check_platform($1));
  1251. push(@dependencies, $parent_prj);
  1252. } else {
  1253. if ((exists($prj_platform{$parent_prj})) &&
  1254. ($prj_platform{$parent_prj} ne 'all') ) {
  1255. print_error("$parent_prj is a wrongly used dependency identifier!\nCheck if it is platform dependent");
  1256. };
  1257. push(@dependencies, $parent_prj);
  1258. };
  1259. };
  1260. return @dependencies;
  1261. };
  1262. sub print_error {
  1263. my $message = shift;
  1264. my $force = shift;
  1265. $modules_number -= scalar keys %global_deps_hash;
  1266. $modules_number -= 1;
  1267. print STDERR "\nERROR: $message\n";
  1268. $ENV{mk_tmp} = '';
  1269. if ($cmd_file) {
  1270. close CMD_FILE;
  1271. unlink ($cmd_file);
  1272. };
  1273. if (!$child) {
  1274. $ENV{mk_tmp} = '';
  1275. close CMD_FILE if ($cmd_file);
  1276. unlink ($cmd_file);
  1277. do_exit(1);
  1278. };
  1279. do_exit(1) if (defined $force);
  1280. };
  1281. sub usage {
  1282. print STDERR "\nbuild\n";
  1283. 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] [--deliver|-d [--dlv_switch deliver_switch]]] [-P processes] [--show|-s] [--help|-h] [--file|-F] [--ignore|-i] [--version|-V] [--mode|-m OOo[,SO[,EXT]] [--html [--html_path html_file_path]] [--pre_job=pre_job_sring] [--job=job_string|-j] [--post_job=post_job_sring] [--stoponerror] [--exclude_branch_from prj_name1[:prj_name2] [prj_name3 [...]]] [--interactive] [--verbose]\n";
  1284. print STDERR "Example1: build --from sfx2\n";
  1285. print STDERR " - build all projects dependent from sfx2, starting with sfx2, finishing with the current module\n";
  1286. print STDERR "Example2: build --all:sfx2\n";
  1287. print STDERR " - the same as --all, but skip all projects that have been already built when using \"--all\" switch before sfx2\n";
  1288. print STDERR "Example3(for unixes):\n";
  1289. print STDERR " build --all --pre_job=echo\\ Starting\\ job\\ in\\ \\\$PWD --job=some_script.sh --post_job=echo\\ Job\\ in\\ \\\$PWD\\ is\\ made\n";
  1290. 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";
  1291. print STDERR "\nSwitches:\n";
  1292. print STDERR " --all - build all projects from very beginning till current one\n";
  1293. print STDERR " --from - build all projects dependent from the specified (including it) till current one\n";
  1294. print STDERR " --exclude_branch_from - exclude module(s) and its branch from the build\n";
  1295. print STDERR " --mode OOo - build only projects needed for OpenOffice.org\n";
  1296. print STDERR " --with_branches- the same as \"--from\" but with build all projects in neighbour branches\n";
  1297. print STDERR " --skip - do not build certain module(s)\n";
  1298. print STDERR " --since - build all projects beginning from the specified till current one (the same as \"--all:prj_name\", but skipping prj_name)\n";
  1299. print STDERR " --checkmodules - check if all required parent projects are availlable\n";
  1300. print STDERR " --show - show what is going to be built\n";
  1301. print STDERR " --file - generate command file file_name\n";
  1302. print STDERR " --deliver - only deliver, no build (usable for \'-all\' and \'-from\' keys)\n";
  1303. print STDERR " -P - start multiprocessing build, with number of processes passed\n";
  1304. print STDERR " --dlv_switch - use deliver with the switch specified\n";
  1305. print STDERR " --help - print help info\n";
  1306. print STDERR " --ignore - force tool to ignore errors\n";
  1307. print STDERR " --html - generate html page with build status\n";
  1308. print STDERR " file named $ENV{INPATH}.build.html will be generated in $ENV{SRC_ROOT}\n";
  1309. print STDERR " --html_path - set html page path\n";
  1310. print STDERR " --stoponerror - stop build when error occurs (for mp builds)\n";
  1311. print STDERR " --interactive - start interactive build process (process can be managed via html page)\n";
  1312. print STDERR " --verbose - generates a detailed output of the build process\n";
  1313. print STDERR " Custom jobs:\n";
  1314. 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";
  1315. 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";
  1316. 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";
  1317. print STDERR "Default: - build current project\n";
  1318. print STDERR "Unknown switches passed to dmake\n";
  1319. };
  1320. #
  1321. # Get all options passed
  1322. #
  1323. sub get_options {
  1324. my $arg;
  1325. while ($arg = shift @ARGV) {
  1326. if ($arg =~ /^-P$/) { $processes_to_run = shift @ARGV; next; }
  1327. if ($arg =~ /^-P(\d+)$/) { $processes_to_run = $1; next; }
  1328. if ($arg =~ /^--all$/) { $build_all_parents = 1; next; }
  1329. if ($arg =~ /^-a$/) { $build_all_parents = 1; next; }
  1330. if ($arg =~ /^--show$/) { $show = 1; next; }
  1331. if ($arg =~ /^--checkmodules$/) { $checkparents = 1; $ignore = 1; next; }
  1332. if ($arg =~ /^-s$/) { $show = 1; next; }
  1333. if ($arg =~ /^--deliver$/) { $deliver = 1; next; }
  1334. if ($arg =~ /^(--job=)/) { $custom_job = $'; next; }
  1335. if ($arg =~ /^(--pre_job=)/) { $pre_custom_job = $'; next; }
  1336. if ($arg =~ /^(--post_job=)/) { $post_custom_job = $'; next; } #'
  1337. if ($arg =~ /^-d$/) { $deliver = 1; next; }
  1338. if ($arg =~ /^--dlv_switch$/) { $dlv_switch = shift @ARGV; next; }
  1339. if ($arg =~ /^--file$/) { $cmd_file = shift @ARGV; next; }
  1340. if ($arg =~ /^-F$/) { $cmd_file = shift @ARGV; next; }
  1341. if ($arg =~ /^--skip$/) { get_modules_passed(\%skip_modules); next; }
  1342. if ($arg =~ /^--all:(\S+)$/) { $build_all_parents = 1;
  1343. $build_all_cont = $1; next; }
  1344. if ($arg =~ /^-a:(\S+)$/) { $build_all_parents = 1;
  1345. $build_all_cont = $1; next; }
  1346. if ($arg =~ /^--from$/ || $arg =~ /^-f$/) {
  1347. $build_all_parents = 1;
  1348. get_modules_passed(\%incompatibles); next; }
  1349. if ($arg =~ /^--since$/) { $build_all_parents = 1;
  1350. $build_since = shift @ARGV; next; }
  1351. if ($arg =~ /^-c$/) { $build_all_parents = 1;
  1352. $build_since = shift @ARGV; next; }
  1353. if ($arg =~ /^-s$/) { $build_all_parents = 1;
  1354. $build_since = shift @ARGV; next; }
  1355. if ($arg =~ /^--help$/) { usage(); do_exit(0); }
  1356. if ($arg =~ /^-h$/) { usage(); do_exit(0); }
  1357. if ($arg =~ /^--ignore$/) { $ignore = 1; next; }
  1358. if ($arg =~ /^--html$/) { $html = 1; next; }
  1359. if ($arg =~ /^--html_path$/) { $html_path = shift @ARGV; next; }
  1360. if ($arg =~ /^-i$/) { $ignore = 1; next; }
  1361. if ($arg =~ /^--version$/) { do_exit(0); }
  1362. if ($arg =~ /^-V$/) { do_exit(0); }
  1363. if ($arg =~ /^-m$/) { get_modes(); next; }
  1364. if ($arg =~ /^--mode$/) { get_modes(); next; }
  1365. if ($arg =~ /^--stoponerror$/) { $stop_build_on_error = 1; next; }
  1366. if ($arg =~ /^--interactive$/) { $interactive = 1; next; }
  1367. if ($arg =~ /^--verbose$/) { $verbose = 1; next; }
  1368. if ($arg =~ /^--$/) {
  1369. push (@dmake_args, get_dmake_args()) if (!$custom_job);
  1370. next;
  1371. };
  1372. push (@dmake_args, $arg);
  1373. };
  1374. if (!$html) {
  1375. print_error("\"--html_path\" switch is used only with \"--html\"") if ($html_path);
  1376. };
  1377. if ((scalar keys %exclude_branches) && !$build_all_parents) {
  1378. print_error("\"--exclude_branch_from\" is not applicable for one module builds!!");
  1379. };
  1380. print_error('Switches --with_branches and --all collision') if ($build_from_with_branches && $build_all_cont);
  1381. print_error('Switch --skip is for building multiple modules only!!') if ((scalar keys %skip_modules) && (!$build_all_parents));
  1382. print_error('Switches --with_branches and --since collision') if ($build_from_with_branches && $build_since);
  1383. if ($show) {
  1384. $processes_to_run = 0;
  1385. $cmd_file = '';
  1386. };
  1387. print_error('Switches --job and --deliver collision') if ($custom_job && $deliver);
  1388. $custom_job = 'deliver' if $deliver;
  1389. $post_job = 'deliver' if (!$custom_job);
  1390. $incompatible = scalar keys %incompatibles;
  1391. if ($processes_to_run) {
  1392. if ($ignore && !$html) {
  1393. print_error("Cannot ignore errors in multiprocessing build");
  1394. };
  1395. } elsif ($stop_build_on_error) {
  1396. print_error("Switch --stoponerror is only for multiprocessing builds");
  1397. };
  1398. if ($only_platform) {
  1399. $only_common = 'common';
  1400. $only_common .= '.pro' if ($only_platform =~ /\.pro$/);
  1401. };
  1402. if ($interactive) {
  1403. $html++; # enable html page generation...
  1404. my $local_host_name = hostname();
  1405. $local_host_ip = inet_ntoa(scalar(gethostbyname($local_host_name)) || 'localhost');
  1406. }
  1407. # Default build modes(for OpenOffice.org)
  1408. $ENV{BUILD_TYPE} = 'OOo EXT' if (!defined $ENV{BUILD_TYPE});
  1409. @ARGV = @dmake_args;
  1410. foreach $arg (@dmake_args) {
  1411. $arg =~ /^verbose=(\S+)$/i and $verbose_mode = ($1 =~ /^t\S*$/i);
  1412. }
  1413. };
  1414. sub get_module_and_buildlist_paths {
  1415. if ($build_all_parents || $checkparents) {
  1416. $active_modules{$_}++ foreach ($source_config->get_active_modules());
  1417. my %active_modules_copy = %active_modules;
  1418. foreach my $module ($source_config->get_all_modules()) {
  1419. delete $active_modules_copy{$module} if defined($active_modules_copy{$module});
  1420. $module_paths{$module} = $source_config->get_module_path($module);
  1421. $build_list_paths{$module} = $source_config->get_module_build_list($module);
  1422. }
  1423. $dead_parents{$_}++ foreach (keys %active_modules_copy);
  1424. };
  1425. };
  1426. sub get_dmake_args {
  1427. my $arg;
  1428. my @job_args = ();
  1429. while ($arg = shift @ARGV) {
  1430. next if ($arg =~ /^--$/);
  1431. push (@job_args, $arg);
  1432. };
  1433. return @job_args;
  1434. };
  1435. #
  1436. # cancel build when one of children has error exit code
  1437. #
  1438. sub cancel_build {
  1439. my $broken_modules_number = scalar @broken_modules_names;
  1440. print STDERR "\n";
  1441. print STDERR "-----------------------------------------------------------------------\n";
  1442. print STDERR " Oh dear - something failed during the build - sorry !\n";
  1443. print STDERR " For more help with debugging build errors, please see the section in:\n";
  1444. print STDERR " http://wiki.documentfoundation.org/Development\n";
  1445. print STDERR "\n";
  1446. if (!$broken_modules_number || !$build_all_parents) {
  1447. while (children_number()) {
  1448. handle_dead_children(1);
  1449. }
  1450. }
  1451. if (keys %broken_build) {
  1452. print STDERR " internal build errors:\n\n";
  1453. foreach (keys %broken_build) {
  1454. print STDERR "ERROR: error " . $broken_build{$_} . " occurred while making $_\n";
  1455. };
  1456. print STDERR "\n";
  1457. }
  1458. my $module = shift @broken_modules_names;
  1459. if ($broken_modules_number > 1) {
  1460. print STDERR " it seems you are using a threaded build, which means that the\n";
  1461. print STDERR " actual compile error is probably hidden far above, and could be\n";
  1462. print STDERR " inside any of these other modules:\n";
  1463. print STDERR " @broken_modules_names\n";
  1464. print STDERR " please re-run build inside each one to isolate the problem.\n";
  1465. } else {
  1466. print STDERR " it seems that the error is inside '$module', please re-run build\n";
  1467. print STDERR " inside this module to isolate the error and/or test your fix.\n";
  1468. }
  1469. print STDERR "\n";
  1470. print STDERR "-----------------------------------------------------------------------\n";
  1471. print STDERR "To rebuild a specific module:\n";
  1472. print STDERR "\n";
  1473. if ($module eq 'tail_build') {
  1474. print STDERR "$ENV{GNUMAKE} $module.clean # not recommended, this will re-build almost everything\n";
  1475. } else {
  1476. print STDERR "$ENV{GNUMAKE} $module.clean # optional\n";
  1477. }
  1478. print STDERR "$ENV{GNUMAKE} $module\n";
  1479. print STDERR "\n";
  1480. print STDERR "when the problem is isolated and fixed, re-run '$ENV{GNUMAKE}'\n";
  1481. zenity_message("LibreOffice Build Failed!");
  1482. zenity_close();
  1483. do_exit(1);
  1484. };
  1485. #
  1486. # Function for storing errors in multiprocessing AllParents build
  1487. #
  1488. sub store_error {
  1489. my ($pid, $error_code) = @_;
  1490. return 0 if (!$error_code);
  1491. #we don't care if zenity itself crashes, e.g. rhbz#670895
  1492. if (zenity_enabled()) {
  1493. return 0 if ($zenity_pid == $pid);
  1494. }
  1495. my $child_nick = $processes_hash{$pid};
  1496. if ($ENV{GUI_FOR_BUILD} eq 'WNT') {
  1497. if (!defined $had_error{$child_nick}) {
  1498. $had_error{$child_nick}++;
  1499. return 1;
  1500. };
  1501. };
  1502. $modules_with_errors{$folders_hashes{$child_nick}}++;
  1503. $broken_build{$child_nick} = $error_code;
  1504. if ($stop_build_on_error) {
  1505. clear_from_child($pid);
  1506. # Let all children finish their work
  1507. while (children_number()) {
  1508. handle_dead_children(1);
  1509. };
  1510. cancel_build();
  1511. };
  1512. return 0;
  1513. };
  1514. #
  1515. # child handler (clears (or stores info about) the terminated child)
  1516. #
  1517. sub handle_dead_children {
  1518. my $running_children = children_number();
  1519. return if (!$running_children);
  1520. my $force_wait = shift;
  1521. my $try_once_more = 0;
  1522. do {
  1523. my $pid = 0;
  1524. if (children_number() >= $processes_to_run ||
  1525. ($force_wait && ($running_children == children_number()))) {
  1526. $pid = wait();
  1527. } else {
  1528. $pid = waitpid( -1, &WNOHANG);
  1529. };
  1530. if ($pid > 0) {
  1531. $try_once_more = store_error($pid, $?);
  1532. if ($try_once_more) {
  1533. give_second_chance($pid);
  1534. } else {
  1535. clear_from_child($pid);
  1536. };
  1537. $finished_children++;
  1538. };
  1539. } while(children_number() >= $processes_to_run);
  1540. };
  1541. sub give_second_chance {
  1542. my $pid = shift;
  1543. # A malicious hack for mysterious windows problems - try 2 times
  1544. # to run dmake in the same directory if errors occurs
  1545. my $child_nick = $processes_hash{$pid};
  1546. $running_children{$folders_hashes{$child_nick}}--;
  1547. delete $processes_hash{$pid};
  1548. start_child($child_nick, $folders_hashes{$child_nick});
  1549. };
  1550. sub clear_from_child {
  1551. my $pid = shift;
  1552. my $child_nick = $processes_hash{$pid};
  1553. my $error_code = 0;
  1554. if (defined $broken_build{$child_nick}) {
  1555. $error_code = $broken_build{$child_nick};
  1556. } else {
  1557. remove_from_dependencies($child_nick,
  1558. $folders_hashes{$child_nick});
  1559. };
  1560. foreach (keys %module_deps_hash_pids) {
  1561. delete ${$module_deps_hash_pids{$_}}{$pid} if defined (${$module_deps_hash_pids{$_}}{$pid});
  1562. };
  1563. my $module = $module_by_hash{$folders_hashes{$child_nick}};
  1564. html_store_job_info($folders_hashes{$child_nick}, $child_nick, $error_code);
  1565. $running_children{$folders_hashes{$child_nick}}--;
  1566. delete $processes_hash{$pid};
  1567. $verbose_mode && print 'Running processes: ' . children_number() . "\n";
  1568. };
  1569. #
  1570. # Build the entire project according to queue of dependencies
  1571. #
  1572. sub build_dependent {
  1573. $dependencies_hash = shift;
  1574. my $pid = 0;
  1575. my $child_nick = '';
  1576. $running_children{$dependencies_hash} = 0 if (!defined $running_children{$dependencies_hash});
  1577. while ($child_nick = pick_prj_to_build($dependencies_hash)) {
  1578. if ($processes_to_run) {
  1579. do {
  1580. if (defined $modules_with_errors{$dependencies_hash} && !$ignore) {
  1581. return 0 if ($build_all_parents);
  1582. last;
  1583. };
  1584. # start current child & all
  1585. # that could be started now
  1586. if ($child_nick) {
  1587. start_child($child_nick, $dependencies_hash);
  1588. return 1 if ($build_all_parents);
  1589. } else {
  1590. return 0 if ($build_all_parents);
  1591. if (scalar keys %$dependencies_hash) {
  1592. handle_dead_children(1);
  1593. };
  1594. };
  1595. $child_nick = pick_prj_to_build($dependencies_hash);
  1596. } while (scalar keys %$dependencies_hash || $child_nick);
  1597. while (children_number()) {
  1598. handle_dead_children(1);
  1599. };
  1600. if (defined $modules_with_errors{$dependencies_hash}) {
  1601. push(@broken_modules_names, $module_by_hash{$dependencies_hash});
  1602. cancel_build();
  1603. }
  1604. mp_success_exit();
  1605. } else {
  1606. if (dmake_dir($child_nick)) {
  1607. push(@broken_modules_names, $module_by_hash{$dependencies_hash});
  1608. cancel_build();
  1609. };
  1610. };
  1611. $child_nick = '';
  1612. };
  1613. };
  1614. sub children_number {
  1615. return scalar keys %processes_hash;
  1616. };
  1617. sub start_child {
  1618. my ($job_dir, $dependencies_hash) = @_;
  1619. $jobs_hash{$job_dir}->{START_TIME} = time();
  1620. $jobs_hash{$job_dir}->{STATUS} = 'building';
  1621. if ($job_dir =~ /(\s)/o) {
  1622. my $error_code = undef;
  1623. if ($job_dir !~ /\sdeliver$/o) {
  1624. $error_code = do_custom_job($job_dir, $dependencies_hash);
  1625. return;
  1626. }
  1627. };
  1628. $build_in_progress{$module_by_hash{$dependencies_hash}}++;
  1629. html_store_job_info($dependencies_hash, $job_dir);
  1630. my $pid = undef;
  1631. my $children_running;
  1632. my $oldfh = select STDOUT;
  1633. $| = 1;
  1634. if ($pid = fork) { # parent
  1635. select $oldfh;
  1636. $processes_hash{$pid} = $job_dir;
  1637. $children_running = children_number();
  1638. $verbose_mode && print 'Running processes: ', $children_running, "\n";
  1639. $maximal_processes = $children_running if ($children_running > $maximal_processes);
  1640. $folders_hashes{$job_dir} = $dependencies_hash;
  1641. store_pid($dependencies_hash, $pid);
  1642. $running_children{$dependencies_hash}++;
  1643. } elsif (defined $pid) { # child
  1644. select $oldfh;
  1645. $child = 1;
  1646. dmake_dir($job_dir);
  1647. do_exit(1);
  1648. };
  1649. };
  1650. sub store_pid {
  1651. my ($deps_hash, $pid) = @_;
  1652. if (!defined $module_deps_hash_pids{$deps_hash}) {
  1653. my %module_hash_pids = ();
  1654. $module_deps_hash_pids{$deps_hash} = \%module_hash_pids;
  1655. };
  1656. ${$module_deps_hash_pids{$deps_hash}}{$pid}++;
  1657. };
  1658. #
  1659. # Build everything that should be built multiprocessing version
  1660. #
  1661. sub build_multiprocessing {
  1662. my $prj;
  1663. do {
  1664. my $got_module = 0;
  1665. $finished_children = 0;
  1666. while ($prj = pick_prj_to_build(\%global_deps_hash)) {
  1667. if (!defined $projects_deps_hash{$prj}) {
  1668. $projects_deps_hash{$prj} = {};
  1669. get_module_dep_hash($prj, $projects_deps_hash{$prj});
  1670. my $info_hash = $html_info{$prj};
  1671. $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$prj}, $prj);
  1672. $module_by_hash{$projects_deps_hash{$prj}} = $prj;
  1673. }
  1674. $module_build_queue{$prj}++;
  1675. $got_module++;
  1676. };
  1677. if (!$got_module) {
  1678. cancel_build() if ((!scalar keys %module_build_queue) && !children_number());
  1679. if (!$finished_children) {
  1680. handle_dead_children(1);
  1681. };
  1682. };
  1683. build_actual_queue(\%module_build_queue);
  1684. } while (scalar keys %global_deps_hash);
  1685. # Let the last module be built till the end
  1686. while (scalar keys %module_build_queue) {
  1687. build_actual_queue(\%module_build_queue);
  1688. handle_dead_children(1);
  1689. };
  1690. # Let all children finish their work
  1691. while (children_number()) {
  1692. handle_dead_children(1);
  1693. };
  1694. cancel_build() if (scalar keys %broken_build);
  1695. mp_success_exit();
  1696. };
  1697. sub mp_success_exit {
  1698. print "\nMultiprocessing build is finished\n";
  1699. print "Maximal number of processes run: $maximal_processes\n";
  1700. zenity_message("LibreOffice Build Success!");
  1701. zenity_close();
  1702. do_exit(0);
  1703. };
  1704. #
  1705. # Here the built queue is built as long as possible
  1706. #
  1707. sub build_actual_queue {
  1708. my $build_queue = shift;
  1709. my $finished_projects = 0;
  1710. do {
  1711. my @sorted_queue = sort {(scalar keys %{$projects_deps_hash{$a}}) <=> (scalar keys %{$projects_deps_hash{$b}})} keys %$build_queue;
  1712. my $started_children = 0;
  1713. foreach my $prj (keys %$build_queue) {
  1714. get_html_orders();
  1715. if ($reschedule_queue) {
  1716. $reschedule_queue = 0;
  1717. foreach (keys %$build_queue) {
  1718. # Remove the module from the build queue if there is a dependency emerged
  1719. if ((defined $global_deps_hash{$_}) && (scalar keys %{$global_deps_hash{$_}})) {
  1720. delete $$build_queue{$_};
  1721. };
  1722. delete $$build_queue{$_} if (!defined $global_deps_hash_backup{$_})
  1723. };
  1724. return;
  1725. };
  1726. if (defined $modules_with_errors{$projects_deps_hash{$prj}} && !$ignore) {
  1727. push (@broken_modules_names, $prj);
  1728. delete $$build_queue{$prj};
  1729. next;
  1730. };
  1731. $started_children += build_dependent($projects_deps_hash{$prj});
  1732. if ((!scalar keys %{$projects_deps_hash{$prj}}) &&
  1733. !$running_children{$projects_deps_hash{$prj}}) {
  1734. if (!defined $modules_with_errors{$projects_deps_hash{$prj}} || $ignore)
  1735. {
  1736. remove_from_dependencies($prj, \%global_deps_hash);
  1737. $build_is_finished{$prj}++;
  1738. delete $$build_queue{$prj};
  1739. $finished_projects++;
  1740. };
  1741. };
  1742. };
  1743. # trigger wait
  1744. if (!$started_children) {
  1745. if ($finished_projects) {
  1746. return;
  1747. } else {
  1748. handle_dead_children(1);
  1749. };
  1750. };
  1751. } while (scalar keys %$build_queue);
  1752. };
  1753. sub run_job {
  1754. my ($job, $path, $registered_name) = @_;
  1755. my $job_to_do = $job;
  1756. my $error_code = 0;
  1757. print "$registered_name\n";
  1758. return 0 if ( $show );
  1759. $job_to_do = $deliver_command if ($job eq 'deliver');
  1760. $registered_name = $path if (!defined $registered_name);
  1761. chdir $path;
  1762. getcwd();
  1763. if ( $source_config->is_gbuild($jobs_hash{$registered_name}->{MODULE}) )
  1764. {
  1765. if ( $job eq 'deliver' )
  1766. {
  1767. return 0;
  1768. }
  1769. else
  1770. {
  1771. return 1 if (! $path =~ /prj$/ );
  1772. my $gbuild_flags = '-j' . $ENV{PARALLELISM};
  1773. my $gbuild_target = 'all slowcheck';
  1774. if ($registered_name =~ /tail_build\/prj$/ )
  1775. {
  1776. $gbuild_target = $ENV{gb_TAILBUILDTARGET};
  1777. }
  1778. $gbuild_flags .= ' ' . $ENV{GMAKE_OPTIONS};
  1779. $job_to_do = "$ENV{GNUMAKE} -f Makefile $gbuild_flags $gbuild_target gb_PARTIALBUILD=T";
  1780. my $make_path = $path;
  1781. $make_path =~ s!/prj$!!;
  1782. chdir $make_path;
  1783. getcwd();
  1784. print "gbuild module $make_path: $job_to_do\n";
  1785. }
  1786. }
  1787. system("$job_to_do");
  1788. return $?;
  1789. };
  1790. sub do_custom_job {
  1791. my ($module_job, $dependencies_hash) = @_;
  1792. $module_job =~ /(\s)/o;
  1793. my $module = $`;
  1794. my $job = $'; #'
  1795. html_store_job_info($dependencies_hash, $module_job);
  1796. my $error_code = 0;
  1797. if ($job eq $pre_job) {
  1798. announce_module($module);
  1799. remove_from_dependencies($module_job, $dependencies_hash);
  1800. } else {
  1801. $error_code = run_job($job, $module_paths{$module}, $module_job);
  1802. if ($error_code) {
  1803. # give windows one more chance
  1804. if ($ENV{GUI_FOR_BUILD} eq 'WNT') {
  1805. $error_code = run_job($job, $module_paths{$module}, $module_job);
  1806. };
  1807. };
  1808. if ($error_code && $ignore) {
  1809. push(@ignored_errors, $module_job);
  1810. $error_code = 0;
  1811. };
  1812. if ($error_code) {
  1813. $modules_with_errors{$dependencies_hash}++;
  1814. # $broken_build{$module_job} = $error_code;
  1815. } else {
  1816. remove_from_dependencies($module_job, $dependencies_hash);
  1817. };
  1818. };
  1819. html_store_job_info($dependencies_hash, $module_job, $error_code);
  1820. return $error_code;
  1821. };
  1822. #
  1823. # Print announcement for module just started
  1824. #
  1825. sub announce_module {
  1826. my $prj = shift;
  1827. $build_in_progress{$prj}++;
  1828. print_announce($prj);
  1829. };
  1830. sub print_announce {
  1831. my $prj = shift;
  1832. return if (defined $module_announced{$prj});
  1833. my $text;
  1834. if ($custom_job)
  1835. {
  1836. $text = "Running custom job \"$custom_job\" in module $prj\n";
  1837. }
  1838. else
  1839. {
  1840. $text = "Building module $prj\n";
  1841. };
  1842. if (!$total_modules) {
  1843. $total_modules = scalar(keys %global_deps_hash) + 1;
  1844. }
  1845. my $modules_started = scalar(keys %module_announced) + 1;
  1846. $text = "($modules_started/$total_modules) $text";
  1847. my $announce_string = $new_line;
  1848. $announce_string .= $echo . "=============\n";
  1849. $announce_string .= $echo . $text;
  1850. $announce_string .= $echo . "=============\n";
  1851. print $announce_string;
  1852. my $percent_progress = $modules_started / $total_modules;
  1853. zenity_tooltip("$text");
  1854. my $zenity_icon = create_progress_svg($percent_progress);
  1855. zenity_icon( $zenity_icon ) if ( $zenity_icon );
  1856. $module_announced{$prj}++;
  1857. };
  1858. sub create_progress_svg {
  1859. # The colors are rather arbitrarily chosen, but with a very minor attempt
  1860. # to be readable by color-blind folks. A second round cut might make
  1861. # the fill and stroke colors configurable.
  1862. # This function currently leaves a stray svg file in the tmp directory.
  1863. # This shouldn't be too much of a problem, but if the next person in line
  1864. # wants to remove this, go ahead.
  1865. if (! zenity_enabled()) {
  1866. return undef;
  1867. }
  1868. my $pi = 3.1415923;
  1869. my $percentage = shift;
  1870. my $path = $percentage > .5 ? '1,1' : '0,1';
  1871. # Creating a "clock" progress meter that starts from the 12 position; the
  1872. # cursor starts in the center (M50,50), then goes immediately vertical
  1873. # (v-50). Associating sin with x, because it's the /difference/ of where
  1874. # the cursor needs to move. Other relevent documentation may be found at
  1875. #
  1876. # http://www.w3.org/TR/SVG11/paths.html#PathElement and
  1877. # http://www.w3.org/TR/SVG11/images/paths/arcs02.svg
  1878. my $x = 50 * sin( $percentage * 2 * $pi );
  1879. my $y = 50 - 50 * cos( $percentage * 2 * $pi );
  1880. my $progress_file = "$tmp_dir/lo_build_progress.svg";
  1881. open( PROGRESS, '>', $progress_file ) or return undef;
  1882. print PROGRESS <<EOF;
  1883. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  1884. <svg
  1885. xmlns:dc="http://purl.org/dc/elements/1.1/"
  1886. xmlns:cc="http://creativecommons.org/ns#"
  1887. xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  1888. xmlns:svg="http://www.w3.org/2000/svg"
  1889. xmlns="http://www.w3.org/2000/svg"
  1890. version="1.1"
  1891. viewBox="0 0 100 100">
  1892. <path
  1893. d="M50,50 v-50 a50,50 0 $path $x,$y z"
  1894. fill="#aaa"
  1895. stroke="#00f"
  1896. stroke-width="1" />
  1897. </svg>
  1898. EOF
  1899. close( PROGRESS );
  1900. return $progress_file;
  1901. }
  1902. sub zenity_enabled {
  1903. return 0 if ($ENV{ENABLE_ZENITY} ne "TRUE");
  1904. return 0 if (!defined $ENV{DISPLAY});
  1905. return 1 if ($ENV{DISPLAY} =~ m/^:/); # local displays only
  1906. return 0;
  1907. }
  1908. sub zenity_open {
  1909. if (zenity_enabled()) {
  1910. $SIG{PIPE} = 'IGNORE';
  1911. $zenity_pid = open3($zenity_in, $zenity_out, $zenity_err,
  1912. "zenity --notification --listen");
  1913. };
  1914. };
  1915. sub zenity_close {
  1916. if (zenity_enabled()) {
  1917. sleep(1); # Give Zenity a chance to show the message.
  1918. close($zenity_in);
  1919. };
  1920. };
  1921. sub zenity_icon {
  1922. if (zenity_enabled()) {
  1923. my $filename = shift;
  1924. print $zenity_in "icon: $filename\n";
  1925. };
  1926. };
  1927. sub zenity_tooltip {
  1928. my $current_message_time = time();
  1929. return if (!($current_message_time > $last_message_time + 5));
  1930. $last_message_time = $current_message_time;
  1931. if (zenity_enabled()) {
  1932. my $text = shift;
  1933. print $zenity_in "tooltip: LibreOffice Build: $text\n";
  1934. };
  1935. };
  1936. sub zenity_message {
  1937. if (zenity_enabled()) {
  1938. my $text = shift;
  1939. print $zenity_in "message: $text\n";
  1940. };
  1941. };
  1942. #
  1943. # Procedure removes output tree from the module (without common trees)
  1944. #
  1945. sub clear_module {
  1946. my $module = shift;
  1947. print "Removing module's $module output trees...\n";
  1948. print "\n" and return if ($show);
  1949. opendir DIRHANDLE, $module_paths{$module};
  1950. my @dir_content = readdir(DIRHANDLE);
  1951. closedir(DIRHANDLE);
  1952. foreach (@dir_content) {
  1953. next if (/^\.+$/);
  1954. my $dir = correct_path($module_paths{$module}.'/'.$_);
  1955. if ((!-d $dir.'/.svn') && is_output_tree($dir)) {
  1956. rmtree("$dir", 0, 1);
  1957. if (-d $dir) {
  1958. system("$remove_command $dir");
  1959. if (-d $dir) {
  1960. push(@warnings, "Cannot delete $dir");
  1961. } else {
  1962. print STDERR (">>> Removed $dir by force\n");
  1963. };
  1964. };
  1965. };
  1966. };
  1967. };
  1968. #
  1969. # Figure out if the directory is an output tree
  1970. #
  1971. sub is_output_tree {
  1972. my $dir = shift;
  1973. $dir =~ /([\w\d\.]+)$/;
  1974. $_ = $1;
  1975. return '1' if (defined $platforms{$_});
  1976. if ($only_common) {
  1977. return '1' if ($_ eq $only_common);
  1978. } else {
  1979. if (scalar keys %platforms < scalar keys %platforms_to_copy) {
  1980. return '';
  1981. };
  1982. return '1' if (/^common$/);
  1983. return '1' if (/^common\.pro$/);
  1984. };
  1985. return '';
  1986. };
  1987. sub get_tmp_dir {
  1988. my $tmp_dir;
  1989. if( defined($ENV{TMPDIR}) ) {
  1990. $tmp_dir = $ENV{TMPDIR} . '/';
  1991. } elsif( defined($ENV{TMP}) ) {
  1992. $tmp_dir = $ENV{TMP} . '/';
  1993. } else {
  1994. $tmp_dir = '/tmp/';
  1995. }
  1996. $tmp_dir = tempdir ( DIR => $tmp_dir );
  1997. if (!-d $tmp_dir) {
  1998. print_error("Cannot create temporary directory for checkout in $tmp_dir") if ($@);
  1999. };
  2000. return $tmp_dir;
  2001. };
  2002. sub prepare_build_from_with_branches {
  2003. my ($full_deps_hash, $reversed_full_deps_hash) = @_;
  2004. foreach my $prerequisite (keys %$full_deps_hash) {
  2005. foreach my $dependent_module (keys %incompatibles) {
  2006. if (defined ${$$reversed_full_deps_hash{$prerequisite}}{$dependent_module}) {
  2007. remove_from_dependencies($prerequisite, $full_deps_hash);
  2008. delete $$full_deps_hash{$prerequisite};
  2009. last;
  2010. };
  2011. };
  2012. };
  2013. };
  2014. #
  2015. # Removes projects which it is not necessary to build
  2016. # in incompatible build
  2017. #
  2018. sub prepare_incompatible_build {
  2019. my ($prj, $deps_hash, @missing_modules);
  2020. $deps_hash = shift;
  2021. foreach my $module (keys %incompatibles) {
  2022. if (!defined $$deps_hash{$module}) {
  2023. print_error("The module $initial_module is independent from $module\n");
  2024. }
  2025. $incompatibles{$module} = $$deps_hash{$module};
  2026. delete $$deps_hash{$module};
  2027. }
  2028. while ($prj = pick_prj_to_build($deps_hash)) {
  2029. remove_from_dependencies($prj, $deps_hash);
  2030. remove_from_dependencies($prj, \%incompatibles);
  2031. };
  2032. foreach (keys %incompatibles) {
  2033. $$deps_hash{$_} = $incompatibles{$_};
  2034. };
  2035. if ($build_all_cont) {
  2036. prepare_build_all_cont($deps_hash);
  2037. delete $$deps_hash{$build_all_cont};
  2038. };
  2039. @modules_built = keys %$deps_hash;
  2040. my $old_output_tree = '';
  2041. foreach $prj (sort keys %$deps_hash)
  2042. {
  2043. next if ($show);
  2044. if ($modules_types{$prj} ne 'mod')
  2045. {
  2046. push(@missing_modules, $prj);
  2047. }
  2048. elsif (-d $module_paths{$prj}. '/'. $ENV{INPATH})
  2049. {
  2050. $old_output_tree++;
  2051. };
  2052. };
  2053. if (scalar @missing_modules) {
  2054. my $warning_string = 'Following modules are inconsistent/missing: ' . "@missing_modules";
  2055. push(@warnings, $warning_string);
  2056. };
  2057. if ($build_all_cont) {
  2058. $$deps_hash{$build_all_cont} = ();
  2059. $build_all_cont = '';
  2060. };
  2061. if ($old_output_tree) {
  2062. push(@warnings, 'Some module(s) contain old output tree(s)!');
  2063. };
  2064. if (scalar @warnings)
  2065. {
  2066. print "WARNING(S):\n";
  2067. print STDERR "$_\n" foreach (@warnings);
  2068. 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";
  2069. sleep(5);
  2070. };
  2071. };
  2072. #
  2073. # Removes projects which it is not necessary to build
  2074. # with --all:prj_name or --since switch
  2075. #
  2076. sub prepare_build_all_cont {
  2077. my ($prj, $deps_hash, $border_prj);
  2078. $deps_hash = shift;
  2079. $border_prj = $build_all_cont if ($build_all_cont);
  2080. $border_prj = $build_since if ($build_since);
  2081. while ($prj = pick_prj_to_build($deps_hash)) {
  2082. if (($border_prj ne $prj) &&
  2083. ($border_prj ne '')) {
  2084. remove_from_dependencies($prj, $deps_hash);
  2085. next;
  2086. } else {
  2087. if ($build_all_cont) {
  2088. $$deps_hash{$prj} = ();
  2089. } else {
  2090. remove_from_dependencies($prj, $deps_hash);
  2091. };
  2092. return;
  2093. };
  2094. };
  2095. };
  2096. sub get_modes {
  2097. my $option = '';
  2098. while ($option = shift @ARGV) {
  2099. if ($option =~ /^-+/) {
  2100. unshift(@ARGV, $option);
  2101. return;
  2102. } else {
  2103. if ($option =~ /,/) {
  2104. $build_modes{$`}++;
  2105. unshift(@ARGV, $') if ($');
  2106. } else {$build_modes{$option}++;};
  2107. };
  2108. };
  2109. $build_modes{$option}++;
  2110. };
  2111. sub get_modules_passed {
  2112. my $hash_ref = shift;
  2113. my $option = '';
  2114. while ($option = shift @ARGV) {
  2115. if ($option =~ /^-+/) {
  2116. unshift(@ARGV, $option);
  2117. return;
  2118. } else {
  2119. if ($option =~ /(:)/) {
  2120. $option = $`;
  2121. print_error("\'--from\' switch collision") if ($build_all_cont);
  2122. $build_all_cont = $'; #'
  2123. };
  2124. $$hash_ref{$option}++;
  2125. };
  2126. };
  2127. };
  2128. #
  2129. # Store all available build modi in %build_modes
  2130. #
  2131. sub get_build_modes {
  2132. return if (scalar keys %build_modes);
  2133. if (defined $ENV{BUILD_TYPE}) {
  2134. if ($ENV{BUILD_TYPE} =~ /\s+/o) {
  2135. my @build_modes = split (/\s+/, $ENV{BUILD_TYPE});
  2136. $build_modes{$_}++ foreach (@build_modes);
  2137. } else {
  2138. $build_modes{$ENV{BUILD_TYPE}}++;
  2139. };
  2140. return;
  2141. };
  2142. };
  2143. #
  2144. # pick only the modules, that should be built for
  2145. # build types from %build_modes
  2146. #
  2147. sub pick_for_build_type {
  2148. my $modules = shift;
  2149. my @mod_array = split(/\s+/, $modules);
  2150. print_error("Wrongly written dependencies string:\n $modules\n") if ($mod_array[$#mod_array] ne 'NULL');
  2151. pop @mod_array;
  2152. my @modules_to_build;
  2153. foreach (@mod_array) {
  2154. if (/(\w+):(\S+)/o) {
  2155. push(@modules_to_build, $2) if (defined $build_modes{$1});
  2156. next;
  2157. };
  2158. push(@modules_to_build, $_);
  2159. };
  2160. return @modules_to_build;
  2161. };
  2162. sub do_exit {
  2163. my $exit_code = shift;
  2164. $build_finished++;
  2165. generate_html_file(1);
  2166. rmtree(correct_path($tmp_dir), 0, 0) if ($tmp_dir);
  2167. print STDERR "Cannot delete $tmp_dir. Please remove it manually\n" if (-d $tmp_dir);
  2168. exit($exit_code);
  2169. };
  2170. #
  2171. # Procedure sorts module in user-frendly order
  2172. #
  2173. sub sort_modules_appearance {
  2174. foreach (keys %dead_parents) {
  2175. delete $build_is_finished{$_} if (defined $build_is_finished{$_});
  2176. delete $build_in_progress{$_} if (defined $build_in_progress{$_});
  2177. };
  2178. foreach (keys %build_is_finished) {
  2179. delete $build_in_progress{$_} if (defined $build_in_progress{$_});
  2180. delete $build_in_progress_shown{$_} if (defined $build_in_progress_shown{$_});
  2181. };
  2182. my @modules_order = sort keys %modules_with_errors;
  2183. foreach (keys %modules_with_errors) {
  2184. delete $build_in_progress{$_} if (defined $build_in_progress{$_});
  2185. delete $build_is_finished{$_} if (defined $build_is_finished{$_});
  2186. delete $build_in_progress_shown{$_} if (defined $build_in_progress_shown{$_});
  2187. };
  2188. $build_in_progress_shown{$_}++ foreach (keys %build_in_progress);
  2189. push(@modules_order, $_) foreach (sort { $build_in_progress_shown{$b} <=> $build_in_progress_shown{$a} } keys %build_in_progress_shown);
  2190. push(@modules_order, $_) foreach (sort keys %build_is_finished);
  2191. foreach(sort keys %html_info) {
  2192. next if (defined $build_is_finished{$_} || defined $build_in_progress{$_} || defined $modules_with_errors{$_});
  2193. push(@modules_order, $_);
  2194. };
  2195. return @modules_order;
  2196. };
  2197. sub generate_html_file {
  2198. return if (!$html);
  2199. my $force_update = shift;
  2200. $force_update++ if ($debug);
  2201. my @modules_order = sort_modules_appearance();
  2202. my ($successes_percent, $errors_percent) = get_progress_percentage(scalar keys %html_info, scalar keys %build_is_finished, scalar keys %modules_with_errors);
  2203. my $build_duration = get_time_line(time - $build_time);
  2204. my $temp_html_file = File::Temp::tmpnam($tmp_dir);
  2205. my $title;
  2206. $title = $ENV{INPATH};
  2207. die("Cannot open $temp_html_file") if (!open(HTML, ">$temp_html_file"));
  2208. print HTML '<html><head>';
  2209. print HTML '<TITLE id=MainTitle>' . $title . '</TITLE>';
  2210. print HTML '<script type="text/javascript">' . "\n";
  2211. print HTML 'initFrames();' . "\n";
  2212. print HTML 'var IntervalID;' . "\n";
  2213. print HTML 'function loadFrame_0() {' . "\n";
  2214. print HTML ' document.write("<html>");' . "\n";
  2215. print HTML ' document.write("<head>");' . "\n";
  2216. print HTML ' document.write("</head>");' . "\n";
  2217. print HTML ' document.write("<body>");' . "\n";
  2218. if ($build_finished) {
  2219. print HTML 'document.write("<h3 align=center style=\"color:red\">Build process is finished</h3>");' . "\n";
  2220. print HTML ' top.frames[0].clearInterval(top.frames[0].IntervalID);' . "\n";
  2221. } elsif ($interactive) {
  2222. print HTML 'document.write(" <div id=divContext style=\"border: 1px solid; display: none; position: absolute\">");' . "\n";
  2223. 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";
  2224. print HTML 'document.write(" <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aRebuild href=\"#\">Rebuild module</a></li>");' . "\n";
  2225. print HTML 'document.write(" <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aDelete href=\"#\" >Remove module</a></li>");' . "\n";
  2226. print HTML 'document.write(" </ul>");' . "\n";
  2227. print HTML 'document.write(" </div>");' . "\n";
  2228. };
  2229. if ($build_all_parents) {
  2230. print HTML 'document.write("<table valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n";
  2231. print HTML 'document.write(" <tr>");' . "\n";
  2232. print HTML 'document.write(" <td><a id=ErroneousModules href=\"javascript:top.Error(\'\', \'';
  2233. print HTML join('<br>', sort keys %modules_with_errors);
  2234. print HTML '\', \'\')\"); title=\"';
  2235. print HTML scalar keys %modules_with_errors;
  2236. print HTML ' module(s) with errors\">Total Progress:</a></td>");' . "\n";
  2237. print HTML 'document.write(" <td>");' . "\n";
  2238. print HTML 'document.write(" <table width=100px valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n";
  2239. print HTML 'document.write(" <tr>");' . "\n";
  2240. print HTML 'document.write(" <td height=20px width=';
  2241. print HTML $successes_percent + $errors_percent;
  2242. if (scalar keys %modules_with_errors) {
  2243. print HTML '% bgcolor=red valign=top></td>");' . "\n";
  2244. } else {
  2245. print HTML '% bgcolor=#25A528 valign=top></td>");' . "\n";
  2246. };
  2247. print HTML 'document.write(" <td width=';
  2248. print HTML 100 - ($successes_percent + $errors_percent);
  2249. print HTML '% bgcolor=lightgrey valign=top></td>");' . "\n";
  2250. print HTML 'document.write(" </tr>");' . "\n";
  2251. print HTML 'document.write(" </table>");' . "\n";
  2252. print HTML 'document.write(" </td>");' . "\n";
  2253. print HTML 'document.write(" <td align=right>&nbsp Build time: ' . $build_duration .'</td>");' . "\n";
  2254. print HTML 'document.write(" </tr>");' . "\n";
  2255. print HTML 'document.write("</table>");' . "\n";
  2256. };
  2257. print HTML 'document.write("<table width=100% bgcolor=white>");' . "\n";
  2258. print HTML 'document.write(" <tr>");' . "\n";
  2259. print HTML 'document.write(" <td width=30% align=\"center\"><strong style=\"color:blue\">Module</strong></td>");' . "\n";
  2260. print HTML 'document.write(" <td width=* align=\"center\"><strong style=\"color:blue\">Status</strong></td>");' . "\n";
  2261. print HTML 'document.write(" <td width=15% align=\"center\"><strong style=\"color:blue\">CPU Time</strong></td>");' . "\n";
  2262. print HTML 'document.write(" </tr>");' . "\n";
  2263. foreach (@modules_order) {
  2264. next if ($modules_types{$_} eq 'lnk');
  2265. next if (!defined $active_modules{$_});
  2266. my ($errors_info_line, $dirs_info_line, $errors_number, $successes_percent, $errors_percent, $time) = get_html_info($_);
  2267. #<one module>
  2268. print HTML 'document.write(" <tr>");' . "\n";
  2269. print HTML 'document.write(" <td width=*>");' . "\n";
  2270. if (defined $dirs_info_line) {
  2271. print HTML 'document.write(" <a id=';
  2272. print HTML $_;
  2273. print HTML ' href=\"javascript:top.Error(\'';
  2274. print HTML $_ , '\', ' ;
  2275. print HTML $errors_info_line;
  2276. print HTML ',';
  2277. print HTML $dirs_info_line;
  2278. print HTML ')\"); title=\"';
  2279. print HTML $errors_number;
  2280. print HTML ' error(s)\">', $_, '</a>");' . "\n";
  2281. } else {
  2282. print HTML 'document.write(" <a target=\'infoframe\' id=';
  2283. print HTML $_;
  2284. print HTML ' href=\"javascript:void(0)\"; title=\"Remove module\">' . $_ . '</a>");' . "\n";
  2285. };
  2286. print HTML 'document.write(" </td>");' . "\n";
  2287. print HTML 'document.write(" <td>");' . "\n";
  2288. print HTML 'document.write(" <table width=100% valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n";
  2289. print HTML 'document.write(" <tr>");' . "\n";
  2290. print HTML 'document.write(" <td height=15* width=';
  2291. print HTML $successes_percent + $errors_percent;
  2292. if ($errors_number) {
  2293. print HTML '% bgcolor=red valign=top></td>");' . "\n";
  2294. } else {
  2295. print HTML '% bgcolor=#25A528 valign=top></td>");' . "\n";
  2296. };
  2297. print HTML 'document.write(" <td width=';
  2298. print HTML 100 - ($successes_percent + $errors_percent);
  2299. print HTML '% bgcolor=lightgrey valign=top></td>");' . "\n";
  2300. print HTML 'document.write(" </tr>");' . "\n";
  2301. print HTML 'document.write(" </table>");' . "\n";
  2302. print HTML 'document.write(" </td>");' . "\n";
  2303. print HTML 'document.write(" <td align=\"center\">', $time, '</td>");' . "\n";
  2304. print HTML 'document.write(" </tr>");' . "\n";
  2305. # </one module>
  2306. }
  2307. print HTML 'document.write(" </table>");' . "\n";
  2308. print HTML 'document.write(" </body>");' . "\n";
  2309. print HTML 'document.write("</html>");' . "\n";
  2310. print HTML 'document.close();' . "\n";
  2311. print HTML 'refreshInfoFrames();' . "\n";
  2312. print HTML '}' . "\n";
  2313. if (!$build_finished && $interactive ) {
  2314. print HTML 'var _replaceContext = false;' . "\n";
  2315. print HTML 'var _mouseOverContext = false;' . "\n";
  2316. print HTML 'var _noContext = false;' . "\n";
  2317. print HTML 'var _divContext = $(\'divContext\');' . "\n";
  2318. print HTML 'var activeElement = 0;' . "\n";
  2319. print HTML 'function $(id) {return document.getElementById(id);}' . "\n";
  2320. print HTML 'InitContext();' . "\n";
  2321. print HTML 'function InitContext()' . "\n";
  2322. print HTML '{' . "\n";
  2323. print HTML ' $(\'aRebuild\').target = \'infoframe\';' . "\n";
  2324. print HTML ' $(\'aDelete\').target = \'infoframe\';' . "\n";
  2325. print HTML ' $(\'aRebuild\').style.color = \'black\';' . "\n";
  2326. print HTML ' $(\'aDelete\').style.color = \'black\';' . "\n";
  2327. print HTML ' _divContext.onmouseover = function() { _mouseOverContext = true; };' . "\n";
  2328. print HTML ' _divContext.onmouseout = function() { _mouseOverContext = false; };' . "\n";
  2329. print HTML ' _divContext.onclick = function() { _divContext.style.display = \'none\'; };' . "\n";
  2330. print HTML ' document.body.onmousedown = ContextMouseDown;' . "\n";
  2331. print HTML ' document.body.oncontextmenu = ContextShow;' . "\n";
  2332. print HTML '}' . "\n";
  2333. print HTML 'function ContextMouseDown(event) {' . "\n";
  2334. print HTML ' if (_noContext || _mouseOverContext) return;' . "\n";
  2335. print HTML ' if (event == null) event = window.event;' . "\n";
  2336. print HTML ' var target = event.target != null ? event.target : event.srcElement;' . "\n";
  2337. print HTML ' if (event.button == 2 && target.tagName.toLowerCase() == \'a\')' . "\n";
  2338. print HTML ' _replaceContext = true;' . "\n";
  2339. print HTML ' else if (!_mouseOverContext)' . "\n";
  2340. print HTML ' _divContext.style.display = \'none\';' . "\n";
  2341. print HTML '}' . "\n";
  2342. print HTML 'function ContextShow(event) {' . "\n";
  2343. print HTML ' if (_noContext || _mouseOverContext) return;' . "\n";
  2344. print HTML ' if (event == null) event = window.event;' . "\n";
  2345. print HTML ' var target = event.target != null ? event.target : event.srcElement;' . "\n";
  2346. print HTML ' if (_replaceContext) {' . "\n";
  2347. print HTML ' $(\'aRebuild\').href = \'http://'. $local_host_ip .':' . $html_port . '/rebuild=\' + target.id;' . "\n";
  2348. print HTML ' $(\'aDelete\').href = \'http://'. $local_host_ip .':' . $html_port . '/delete=\' + target.id' . "\n";
  2349. print HTML ' var scrollTop = document.body.scrollTop ? document.body.scrollTop : ';
  2350. print HTML 'document.documentElement.scrollTop;' . "\n";
  2351. print HTML ' var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : ';
  2352. print HTML 'document.documentElement.scrollLeft;' . "\n";
  2353. print HTML ' _divContext.style.display = \'none\';' . "\n";
  2354. print HTML ' _divContext.style.left = event.clientX + scrollLeft + \'px\';' . "\n";
  2355. print HTML ' _divContext.style.top = event.clientY + scrollTop + \'px\';' . "\n";
  2356. print HTML ' _divContext.style.display = \'block\';' . "\n";
  2357. print HTML ' _replaceContext = false;' . "\n";
  2358. print HTML ' return false;' . "\n";
  2359. print HTML ' }' . "\n";
  2360. print HTML '}' . "\n";
  2361. };
  2362. print HTML 'function refreshInfoFrames() { ' . "\n";
  2363. print HTML ' var ModuleNameObj = top.innerFrame.frames[2].document.getElementById("ModuleErrors");' . "\n";
  2364. print HTML ' if (ModuleNameObj != null) {' . "\n";
  2365. print HTML ' var ModuleName = ModuleNameObj.getAttribute(\'name\');' . "\n";
  2366. print HTML ' var ModuleHref = top.innerFrame.frames[0].document.getElementById(ModuleName).getAttribute(\'href\');' . "\n";
  2367. print HTML ' eval(ModuleHref);' . "\n";
  2368. print HTML ' } else if (top.innerFrame.frames[2].document.getElementById("ErroneousModules") != null) {' . "\n";
  2369. print HTML ' var ModuleHref = top.innerFrame.frames[0].document.getElementById("ErroneousModules").getAttribute(\'href\');' . "\n";
  2370. print HTML ' eval(ModuleHref);' . "\n";
  2371. print HTML ' if (top.innerFrame.frames[1].document.getElementById("ModuleJobs") != null) {' . "\n";
  2372. print HTML ' var ModuleName = top.innerFrame.frames[1].document.getElementById("ModuleJobs").getAttribute(\'name\');' . "\n";
  2373. print HTML ' ModuleHref = top.innerFrame.frames[0].document.getElementById(ModuleName).getAttribute(\'href\');' . "\n";
  2374. print HTML ' var HrefString = ModuleHref.toString();' . "\n";
  2375. print HTML ' var RefEntries = HrefString.split(",");' . "\n";
  2376. print HTML ' var RefreshParams = new Array();' . "\n";
  2377. print HTML ' for (i = 0; i < RefEntries.length; i++) {' . "\n";
  2378. print HTML ' RefreshParams[i] = RefEntries[i].substring(RefEntries[i].indexOf("\'") + 1, RefEntries[i].lastIndexOf("\'"));' . "\n";
  2379. print HTML ' };' . "\n";
  2380. print HTML ' FillFrame_1(RefreshParams[0], RefreshParams[1], RefreshParams[2]);' . "\n";
  2381. print HTML ' }' . "\n";
  2382. print HTML ' };' . "\n";
  2383. print HTML '}' . "\n";
  2384. print HTML 'function loadFrame_1() {' . "\n";
  2385. print HTML ' document.write("<h3 align=center>Jobs</h3>");' . "\n";
  2386. print HTML ' document.write("Click on the project of interest");' . "\n";
  2387. print HTML ' document.close();' . "\n";
  2388. print HTML '}' . "\n";
  2389. print HTML 'function loadFrame_2() {' . "\n";
  2390. print HTML ' document.write("<tr bgcolor=lightgrey<td><h3>Errors</h3></pre></td></tr>");' . "\n";
  2391. print HTML ' document.write("Click on the project of interest");' . "\n";
  2392. print HTML ' document.close();' . "\n";
  2393. print HTML '} function getStatusInnerHTML(Status) { var StatusInnerHtml;' . "\n";
  2394. print HTML ' if (Status == "success") {' . "\n";
  2395. print HTML ' StatusInnerHtml = "<em style=color:green>";' . "\n";
  2396. print HTML ' } else if (Status == "building") {' . "\n";
  2397. print HTML ' StatusInnerHtml = "<em style=color:blue>";' . "\n";
  2398. print HTML ' } else if (Status == "error") {' . "\n";
  2399. print HTML ' StatusInnerHtml = "<em style=color:red>";' . "\n";
  2400. print HTML ' } else {' . "\n";
  2401. print HTML ' StatusInnerHtml = "<em style=color:gray>";' . "\n";
  2402. print HTML ' };' . "\n";
  2403. print HTML ' StatusInnerHtml += Status + "</em>";' . "\n";
  2404. print HTML ' return StatusInnerHtml;' . "\n";
  2405. print HTML '} ' . "\n";
  2406. print HTML 'function ShowLog(LogFilePath, ModuleJob) {' . "\n";
  2407. print HTML ' top.innerFrame.frames[2].document.write("<h3 id=ModuleErrors name=\"" + null + "\">Log for " + ModuleJob + "</h3>");' . "\n";
  2408. print HTML ' top.innerFrame.frames[2].document.write("<iframe id=LogFile name=Log src="';
  2409. if (defined $html_path) {
  2410. print HTML 'file://';
  2411. }
  2412. print HTML '+ LogFilePath + " width=100%></iframe>");' . "\n";
  2413. print HTML ' top.innerFrame.frames[2].document.close();' . "\n";
  2414. print HTML '};' . "\n";
  2415. print HTML 'function FillFrame_1(Module, Message1, Message2) {' . "\n";
  2416. print HTML ' var FullUpdate = 1;' . "\n";
  2417. print HTML ' if (top.innerFrame.frames[1].document.getElementById("ModuleJobs") != null) {' . "\n";
  2418. print HTML ' var ModuleName = top.innerFrame.frames[1].document.getElementById("ModuleJobs").getAttribute(\'name\');' . "\n";
  2419. print HTML ' if (Module == ModuleName) FullUpdate = 0;' . "\n";
  2420. print HTML ' }' . "\n";
  2421. print HTML ' if (FullUpdate) {' . "\n";
  2422. print HTML ' top.innerFrame.frames[1].document.write("<h3 align=center>Jobs in module " + Module + ":</h3>");' . "\n";
  2423. print HTML ' top.innerFrame.frames[1].document.write("<table id=ModuleJobs name=" + Module + " width=100% bgcolor=white>");' . "\n";
  2424. print HTML ' top.innerFrame.frames[1].document.write(" <tr>");' . "\n";
  2425. print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Status</strong></td>");' . "\n";
  2426. print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Job</strong></td>");' . "\n";
  2427. print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Start Time</strong></td>");' . "\n";
  2428. print HTML ' top.innerFrame.frames[1].document.write(" <td width=* align=center><strong style=color:blue>Finish Time</strong></td>");' . "\n";
  2429. print HTML ' top.innerFrame.frames[1].document.write(" </tr>");' . "\n";
  2430. print HTML ' var dir_info_strings = Message2.split("<br><br>");' . "\n";
  2431. print HTML ' for (i = 0; i < dir_info_strings.length; i++) {' . "\n";
  2432. print HTML ' var dir_info_array = dir_info_strings[i].split("<br>");' . "\n";
  2433. print HTML ' top.innerFrame.frames[1].document.write(" <tr status=" + dir_info_array[0] + ">");' . "\n";
  2434. print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>");' . "\n";
  2435. print HTML ' top.innerFrame.frames[1].document.write( getStatusInnerHTML(dir_info_array[0]) + "&nbsp");' . "\n";
  2436. print HTML ' top.innerFrame.frames[1].document.write(" </td>");' . "\n";
  2437. print HTML ' if (dir_info_array[4] == "@") {' . "\n";
  2438. print HTML ' top.innerFrame.frames[1].document.write(" <td style=white-space:nowrap>" + dir_info_array[1] + "</td>");' . "\n";
  2439. print HTML ' } else {' . "\n";
  2440. 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";
  2441. print HTML ' };' . "\n";
  2442. print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>" + dir_info_array[2] + "</td>");' . "\n";
  2443. print HTML ' top.innerFrame.frames[1].document.write(" <td align=center>" + dir_info_array[3] + "</td>");' . "\n";
  2444. print HTML ' top.innerFrame.frames[1].document.write(" </tr>");' . "\n";
  2445. print HTML ' };' . "\n";
  2446. print HTML ' top.innerFrame.frames[1].document.write("</table>");' . "\n";
  2447. print HTML ' } else {' . "\n";
  2448. print HTML ' var dir_info_strings = Message2.split("<br><br>");' . "\n";
  2449. print HTML ' var ModuleRows = top.innerFrame.frames[1].document.getElementById("ModuleJobs").rows;' . "\n";
  2450. print HTML ' for (i = 0; i < dir_info_strings.length; i++) {' . "\n";
  2451. print HTML ' var dir_info_array = dir_info_strings[i].split("<br>");' . "\n";
  2452. print HTML ' var OldStatus = ModuleRows[i + 1].getAttribute(\'status\');' . "\n";
  2453. print HTML ' if(dir_info_array[0] != OldStatus) {' . "\n";
  2454. print HTML ' var DirectoryInfos = ModuleRows[i + 1].cells;' . "\n";
  2455. print HTML ' DirectoryInfos[0].innerHTML = getStatusInnerHTML(dir_info_array[0]) + "&nbsp";' . "\n";
  2456. print HTML ' if (dir_info_array[4] != "@") {' . "\n";
  2457. 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";
  2458. print HTML ' };' . "\n";
  2459. print HTML ' DirectoryInfos[2].innerHTML = dir_info_array[2];' . "\n";
  2460. print HTML ' DirectoryInfos[3].innerHTML = dir_info_array[3];' . "\n";
  2461. print HTML ' };' . "\n";
  2462. print HTML ' };' . "\n";
  2463. print HTML ' };' . "\n";
  2464. print HTML ' top.innerFrame.frames[1].document.close();' . "\n";
  2465. print HTML '};' . "\n";
  2466. print HTML 'function Error(Module, Message1, Message2) {' . "\n";
  2467. print HTML ' if (Module == \'\') {' . "\n";
  2468. print HTML ' if (Message1 != \'\') {' . "\n";
  2469. print HTML ' var erroneous_modules = Message1.split("<br>");' . "\n";
  2470. print HTML ' var ErrorNumber = erroneous_modules.length;' . "\n";
  2471. print HTML ' top.innerFrame.frames[2].document.write("<h3 id=ErroneousModules errors=" + erroneous_modules.length + ">Modules with errors:</h3>");' . "\n";
  2472. print HTML ' for (i = 0; i < ErrorNumber; i++) {' . "\n";
  2473. print HTML ' var ModuleObj = top.innerFrame.frames[0].document.getElementById(erroneous_modules[i]);' . "\n";
  2474. print HTML ' top.innerFrame.frames[2].document.write("<a href=\"");' . "\n";
  2475. print HTML ' top.innerFrame.frames[2].document.write(ModuleObj.getAttribute(\'href\'));' . "\n";
  2476. print HTML ' top.innerFrame.frames[2].document.write("\"); title=\"");' . "\n";
  2477. print HTML ' top.innerFrame.frames[2].document.write("\">" + erroneous_modules[i] + "</a>&nbsp ");' . "\n";
  2478. print HTML ' };' . "\n";
  2479. print HTML ' top.innerFrame.frames[2].document.close();' . "\n";
  2480. print HTML ' };' . "\n";
  2481. print HTML ' } else {' . "\n";
  2482. print HTML ' var ModuleNameObj = top.innerFrame.frames[2].document.getElementById("ModuleErrors");' . "\n";
  2483. print HTML ' var OldErrors = null;' . "\n";
  2484. print HTML ' var ErrorNumber = Message1.split("<br>").length;' . "\n";
  2485. print HTML ' if ((ModuleNameObj != null) && (Module == ModuleNameObj.getAttribute(\'name\')) ) {' . "\n";
  2486. print HTML ' OldErrors = ModuleNameObj.getAttribute(\'errors\');' . "\n";
  2487. print HTML ' }' . "\n";
  2488. print HTML ' if ((OldErrors == null) || (OldErrors != ErrorNumber)) {' . "\n";
  2489. print HTML ' top.innerFrame.frames[2].document.write("<h3 id=ModuleErrors errors=" + ErrorNumber + " name=\"" + Module + "\">Errors in module " + Module + ":</h3>");' . "\n";
  2490. print HTML ' top.innerFrame.frames[2].document.write(Message1);' . "\n";
  2491. print HTML ' top.innerFrame.frames[2].document.close();' . "\n";
  2492. print HTML ' }' . "\n";
  2493. print HTML ' FillFrame_1(Module, Message1, Message2);' . "\n";
  2494. print HTML ' }' . "\n";
  2495. print HTML '}' . "\n";
  2496. print HTML 'function updateInnerFrame() {' . "\n";
  2497. print HTML ' top.innerFrame.frames[0].document.location.reload();' . "\n";
  2498. print HTML ' refreshInfoFrames();' . "\n";
  2499. print HTML '};' . "\n\n";
  2500. print HTML 'function setRefreshRate() {' . "\n";
  2501. print HTML ' RefreshRate = document.Formular.rate.value;' . "\n";
  2502. print HTML ' if (!isNaN(RefreshRate * 1)) {' . "\n";
  2503. print HTML ' top.frames[0].clearInterval(IntervalID);' . "\n";
  2504. print HTML ' IntervalID = top.frames[0].setInterval("updateInnerFrame()", RefreshRate * 1000);' . "\n";
  2505. print HTML ' };' . "\n";
  2506. print HTML '};' . "\n";
  2507. print HTML 'function initFrames() {' . "\n";
  2508. print HTML ' var urlquery = location.href.split("?");' . "\n";
  2509. print HTML ' if (urlquery.length == 1) {' . "\n";
  2510. print HTML ' document.write("<html><head><TITLE id=MainTitle>' . $ENV{INPATH} .'</TITLE>");' . "\n";
  2511. print HTML ' document.write(" <frameset rows=\"12%,88%\">");' . "\n";
  2512. print HTML ' document.write(" <frame name=\"topFrame\" src=\"" + urlquery + "?initTop\"/>");' . "\n";
  2513. print HTML ' document.write(" <frame name=\"innerFrame\" src=\"" + urlquery + "?initInnerPage\"/>");' . "\n";
  2514. print HTML ' document.write(" </frameset>");' . "\n";
  2515. print HTML ' document.write("</head></html>");' . "\n";
  2516. print HTML ' } else if (urlquery[1].substring(0,7) == "initTop") {' . "\n";
  2517. print HTML ' var urlquerycontent = urlquery[1].split("=");' . "\n";
  2518. print HTML ' var UpdateRate = 10' . "\n";
  2519. print HTML ' if (urlquerycontent.length > 2) {' . "\n";
  2520. print HTML ' if (isNaN(urlquerycontent[2] * 1)) {' . "\n";
  2521. print HTML ' alert(urlquerycontent[2] + " is not a number. Ignored.");' . "\n";
  2522. print HTML ' } else {' . "\n";
  2523. print HTML ' UpdateRate = urlquerycontent[2];' . "\n";
  2524. print HTML ' };' . "\n";
  2525. print HTML ' };' . "\n";
  2526. print HTML ' document.write("<html><body>");' . "\n";
  2527. print HTML ' document.write("<h3 align=center>Build process progress status</h3>");' . "\n";
  2528. print HTML ' document.write("<div align=\"right\">");' . "\n";
  2529. print HTML ' document.write(" <table border=\"0\"> <tr>");' . "\n";
  2530. print HTML ' document.write("<td>Refresh rate(sec):</td>");' . "\n";
  2531. print HTML ' document.write("<th>");' . "\n";
  2532. print HTML ' document.write("<FORM name=\"Formular\" onsubmit=\"setRefreshRate()\">");' . "\n";
  2533. print HTML ' document.write("<input type=\"hidden\" name=\"initTop\" value=\"\"/>");' . "\n";
  2534. print HTML ' document.write("<input type=\"text\" id=\"RateValue\" name=\"rate\" autocomplete=\"off\" value=\"" + UpdateRate + "\" size=\"1\"/>");' . "\n";
  2535. print HTML ' document.write("<input type=\"submit\" value=\"OK\">");' . "\n";
  2536. print HTML ' document.write("</FORM>");' . "\n";
  2537. print HTML ' document.write("</th></tr></table>");' . "\n";
  2538. print HTML ' document.write("</div>");' . "\n";
  2539. print HTML ' document.write(" </frameset>");' . "\n";
  2540. print HTML ' document.write("</body></html>");' . "\n";
  2541. print HTML ' top.frames[0].clearInterval(IntervalID);' . "\n";
  2542. print HTML ' IntervalID = top.frames[0].setInterval("updateInnerFrame()", UpdateRate * 1000);' . "\n";
  2543. print HTML ' } else if (urlquery[1] == "initInnerPage") {' . "\n";
  2544. print HTML ' document.write("<html><head>");' . "\n";
  2545. print HTML ' document.write(\' <frameset rows="80%,20%\">\');' . "\n";
  2546. print HTML ' document.write(\' <frameset cols="70%,30%">\');' . "\n";
  2547. print HTML ' document.write(\' <frame src="\');' . "\n";
  2548. print HTML ' document.write(urlquery[0]);' . "\n";
  2549. print HTML ' document.write(\'?initFrame0"/>\');' . "\n";
  2550. print HTML ' document.write(\' <frame src="\');' . "\n";
  2551. print HTML ' document.write(urlquery[0]);' . "\n";
  2552. print HTML ' document.write(\'?initFrame1"/>\');' . "\n";
  2553. print HTML ' document.write(\' </frameset>\');' . "\n";
  2554. print HTML ' document.write(\' <frame src="\');' . "\n";
  2555. print HTML ' document.write(urlquery[0]);' . "\n";
  2556. print HTML ' document.write(\'?initFrame2" name="infoframe"/>\');' . "\n";
  2557. print HTML ' document.write(\' </frameset>\');' . "\n";
  2558. print HTML ' document.write("</head></html>");' . "\n";
  2559. print HTML ' } else {' . "\n";
  2560. print HTML ' if (urlquery[1] == "initFrame0" ) {' . "\n";
  2561. print HTML ' loadFrame_0();' . "\n";
  2562. print HTML ' } else if (urlquery[1] == "initFrame1" ) { ' . "\n";
  2563. print HTML ' loadFrame_1();' . "\n";
  2564. print HTML ' } else if (urlquery[1] == "initFrame2" ) {' . "\n";
  2565. print HTML ' loadFrame_2();' . "\n";
  2566. print HTML ' }' . "\n";
  2567. print HTML ' };' . "\n";
  2568. print HTML '};' . "\n";
  2569. print HTML '</script><noscript>Your browser doesn\'t support JavaScript!</noscript></head></html>' . "\n";
  2570. close HTML;
  2571. rename_file($temp_html_file, $html_file);
  2572. };
  2573. sub get_local_time_line {
  2574. my $epoch_time = shift;
  2575. my $local_time_line;
  2576. my @time_array;
  2577. if ($epoch_time) {
  2578. @time_array = localtime($epoch_time);
  2579. $local_time_line = sprintf("%02d:%02d:%02d", $time_array[2], $time_array[1], $time_array[0]);
  2580. } else {
  2581. $local_time_line = '-';
  2582. };
  2583. return $local_time_line;
  2584. };
  2585. sub get_dirs_info_line {
  2586. my $job = shift;
  2587. my $dirs_info_line = $jobs_hash{$job}->{STATUS} . '<br>';
  2588. my @time_array;
  2589. my $log_path_string;
  2590. $dirs_info_line .= $jobs_hash{$job}->{SHORT_NAME} . '<br>';
  2591. $dirs_info_line .= get_local_time_line($jobs_hash{$job}->{START_TIME}) . '<br>';
  2592. $dirs_info_line .= get_local_time_line($jobs_hash{$job}->{FINISH_TIME}) . '<br>';
  2593. if ($jobs_hash{$job}->{STATUS} eq 'waiting' || (!-f $jobs_hash{$job}->{LONG_LOG_PATH})) {
  2594. $dirs_info_line .= '@';
  2595. } else {
  2596. if (defined $html_path) {
  2597. $log_path_string = $jobs_hash{$job}->{LONG_LOG_PATH};
  2598. } else {
  2599. $log_path_string = $jobs_hash{$job}->{LOG_PATH};
  2600. };
  2601. $log_path_string =~ s/\\/\//g;
  2602. $dirs_info_line .= $log_path_string;
  2603. };
  2604. $dirs_info_line .= '<br>';
  2605. return $dirs_info_line;
  2606. };
  2607. sub get_html_info {
  2608. my $module = shift;
  2609. my $module_info_hash = $html_info{$module};
  2610. my $dirs = $$module_info_hash{DIRS};
  2611. my $dirs_number = scalar @$dirs;
  2612. my $dirs_info_line = '\'';
  2613. if ($dirs_number) {
  2614. my %dirs_sorted_by_order = ();
  2615. foreach (@$dirs) {
  2616. $dirs_sorted_by_order{$jobs_hash{$_}->{BUILD_NUMBER}} = $_;
  2617. }
  2618. foreach (sort {$a <=> $b} keys %dirs_sorted_by_order) {
  2619. $dirs_info_line .= get_dirs_info_line($dirs_sorted_by_order{$_}) . '<br>';
  2620. }
  2621. } else {
  2622. return(undef, undef, 0, 0, 0, '-');
  2623. };
  2624. $dirs_info_line =~ s/(<br>)*$//o;
  2625. $dirs_info_line .= '\'';
  2626. $dirs = $$module_info_hash{SUCCESSFUL};
  2627. my $successful_number = scalar @$dirs;
  2628. $dirs = $$module_info_hash{ERRORFUL};
  2629. my $errorful_number = scalar @$dirs;
  2630. my $errors_info_line = '\'';
  2631. if ($errorful_number) {
  2632. $errors_info_line .= $_ . '<br>' foreach (@$dirs);
  2633. } else {
  2634. $errors_info_line .= 'No errors';
  2635. };
  2636. $errors_info_line .= '\'';
  2637. my $time_line = get_time_line($$module_info_hash{BUILD_TIME});
  2638. my ($successes_percent, $errors_percent) = get_progress_percentage($dirs_number - 1, $successful_number - 1, $errorful_number);
  2639. return($errors_info_line, $dirs_info_line, $errorful_number, $successes_percent, $errors_percent, $time_line);
  2640. };
  2641. sub get_time_line {
  2642. use integer;
  2643. my $seconds = shift;
  2644. my $hours = $seconds/3600;
  2645. my $minits = ($seconds/60)%60;
  2646. $seconds -= ($hours*3600 + $minits*60);
  2647. return(sprintf("%02d\:%02d\:%02d" , $hours, $minits, $seconds));
  2648. };
  2649. sub get_progress_percentage {
  2650. use integer;
  2651. my ($dirs_number, $successful_number, $errorful_number) = @_;
  2652. return (0 ,0) if (!$dirs_number);
  2653. my $errors_percent = ($errorful_number * 100)/ $dirs_number;
  2654. my $successes_percent;
  2655. if ($dirs_number == ($successful_number + $errorful_number)) {
  2656. $successes_percent = 100 - $errors_percent;
  2657. } else {
  2658. $successes_percent = ($successful_number * 100)/ $dirs_number;
  2659. };
  2660. return ($successes_percent, $errors_percent);
  2661. };
  2662. #
  2663. # This procedure stores the dmake result in %html_info
  2664. #
  2665. sub html_store_job_info {
  2666. return if (!$html);
  2667. my ($deps_hash, $build_dir, $error_code) = @_;
  2668. my $force_update = 0;
  2669. if ($build_dir =~ /(\s)/o && (defined $error_code)) {
  2670. $force_update++ if (!children_number());
  2671. }
  2672. my $module = $module_by_hash{$deps_hash};
  2673. my $module_info_hash = $html_info{$module};
  2674. my $dmake_array;
  2675. if (defined $error_code) {
  2676. $jobs_hash{$build_dir}->{FINISH_TIME} = time();
  2677. $$module_info_hash{BUILD_TIME} += $jobs_hash{$build_dir}->{FINISH_TIME} - $jobs_hash{$build_dir}->{START_TIME};
  2678. if ($error_code) {
  2679. $jobs_hash{$build_dir}->{STATUS} = 'error';
  2680. $dmake_array = $$module_info_hash{ERRORFUL};
  2681. $build_dir =~ s/\\/\//g;
  2682. $modules_with_errors{$module}++;
  2683. } else {
  2684. if ($build_dir =~ /(\s)announce/o) {
  2685. $jobs_hash{$build_dir}->{STATUS} = '-';
  2686. } else {
  2687. $jobs_hash{$build_dir}->{STATUS} = 'success';
  2688. };
  2689. $dmake_array = $$module_info_hash{SUCCESSFUL};
  2690. };
  2691. push (@$dmake_array, $build_dir);
  2692. };
  2693. };
  2694. sub start_server_on_port {
  2695. my $port = shift;
  2696. my $socket_obj = shift;
  2697. $client_timeout = 1 if (!$parent_process);
  2698. if ($ENV{GUI_FOR_BUILD} eq 'WNT') {
  2699. $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
  2700. LocalPort => $port,
  2701. Proto => 'tcp',
  2702. Listen => 100); # 100 clients can be on queue, I think it is enough
  2703. } else {
  2704. $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
  2705. LocalPort => $port,
  2706. Proto => 'tcp',
  2707. ReuseAddr => 1,
  2708. Listen => 100); # 100 clients can be on queue, I think it is enough
  2709. };
  2710. return('Cannot create socket object') if (!defined $$socket_obj);
  2711. my $timeout = $$socket_obj->timeout($client_timeout);
  2712. $$socket_obj->autoflush(1);
  2713. if ($parent_process && $debug) {
  2714. print "SERVER started on port $port\n";
  2715. } else {
  2716. print "html_port:$html_port html_socket_obj: $html_socket_obj\n";
  2717. };
  2718. return 0;
  2719. };
  2720. sub accept_html_connection {
  2721. my $new_socket_obj = undef;
  2722. $new_socket_obj = $html_socket_obj->accept();
  2723. return $new_socket_obj;
  2724. };
  2725. sub get_server_ports {
  2726. # use port 7890 as default
  2727. my $default_port = 7890;
  2728. @server_ports = ($default_port .. $default_port + 4);
  2729. };
  2730. sub check_partial_gnumake_build
  2731. {
  2732. if(!$build_all_parents && $source_config->is_gbuild(shift) )
  2733. {
  2734. print "This module has been migrated to GNU make.\n";
  2735. print "You can only use build --all/--since here with build.pl.\n";
  2736. print "To do the equivalent of 'build && deliver' call:\n";
  2737. print "\t$ENV{GNUMAKE} -r\n";
  2738. print "in the module root.\n";
  2739. exit 1;
  2740. }
  2741. }