1. mst
  2. ooo340

Commits

vg  committed c1aacc3

CWS-TOOLING: integrate CWS buildtool05
2009-09-29 10:58:16 +0200 vg r276511 : #i105002#,#i105277#,#160100# manage build process via html page, some fixes

  • Participants
  • Parent commits 0d68570
  • Branches default

Comments (0)

Files changed (1)

File solenv/bin/build.pl

View file
  • Ignore whitespace
     use POSIX;
     use Cwd qw (cwd);
     use File::Path;
-    use File::Temp qw(tmpnam);
+    use File::Temp qw(tmpnam tempdir);
     use File::Find;
     use Socket;
     use IO::Socket::INET;
-    
+    use IO::Select;
+    use Fcntl;
+    use POSIX qw(:errno_h);
+    use Sys::Hostname;
+
     use lib ("$ENV{SOLARENV}/bin/modules");
     use SourceConfig;
     
     if ($ENV{GUI} eq 'WNT' && !$cygwin) {
         eval { require Win32::Process; import Win32::Process; };
         $enable_multiprocessing = 0 if ($@);
+        eval { require Win32::Pipe; import Win32::Pipe; };
     };
     
     ### for XML file format
 #### script id #####
 
     ( $script_name = $0 ) =~ s/^.*\b(\w+)\.pl$/$1/;
-
-    $id_str = ' $Revision$ ';
+    $id_str = ' $Revision: 275224 $ ';
     $id_str =~ /Revision:\s+(\S+)\s+\$/
       ? ($script_rev = $1) : ($script_rev = "-");
 
     $custom_job = '';
     $post_custom_job = '';
     %LocalDepsHash = ();
-    %BuildQueue = ();
     %PathHash = ();
     %PlatformHash = ();
     %AliveDependencies = ();
     %global_deps_hash = (); # hash of dependencies of the all modules
-    %broken_modules_hashes = ();   # hash of modules hashes, which cannot be built further
+    %global_deps_hash_backup = (); # backup hash of external dependencies of the all modules
+    %module_deps_hash_backup = (); # backup hash of internal dependencies for aech module
+    %modules_with_errors = ();   # hash of modules hashes, which cannot be built further
     @broken_modules_names = ();   # array of modules, which cannot be built further
     @dmake_args = ();
     %dead_parents = ();
     $CurrentPrj = '';
-    $no_projects = 0;
-    $only_dependent = 0;
-    $build_from = '';
+    $all_dependent = 1;  # a flag indicating if the hash has independent keys
+    $build_from_with_branches = '';
     $build_all_cont = '';
     $build_since = '';
     $dlv_switch = '';
     $child = 0;
     %processes_hash = ();
-#    %module_announced = ();
+    %module_announced = ();
     $prepare = ''; # prepare for following incompatible build
     $ignore = '';
     $html = '';
 #    %weight_stored = ();
     $grab_output = 1;
     $stop_build_on_error = 0; # for multiprocessing mode: do not build further module if there is an error
+    $interactive = 0; # for interactive mode... (for testing purpose enabled by default)
+    $parent_process = 1;
     $server_mode = 0;
     $setenv_string = ''; # string for configuration of the client environment
     $ports_string = ''; # string with possible ports for server
     @server_ports = ();
-    $socket_obj = undef; # socket object for server
+    $html_port;
+    $server_socket_obj = undef; # socket object for server
+    $html_socket_obj = undef; # socket object for server
     my %clients_jobs = ();
     my %clients_times = ();
     my $client_timeout = 0; # time for client to build (in sec)... 
                             # the server considered as an error/client crash 
     my %lost_client_jobs = (); # hash containing lost jobs
     my %job_jobdir = (); # hash containing job-dir pairs
+    my $reschedule_queue = 0;
+    my %module_build_queue = ();
+    my %reversed_dependencies = ();
     my %module_paths = (); # hash with absolute module paths  
     my %active_modules = ();
     my $generate_config = 0;
     my %add_to_config = ();
     my %remove_from_config = ();
     my $clear_config = 0;
+    my $finisched_children = 0;
+    my $debug = 0;
+    %module_deps_hash_pids = ();
 ### main ###
 
     get_options();
     provide_consistency() if (defined $ENV{CWS_WORK_STAMP} && defined($ENV{COMMON_ENV_TOOLS}));
 
     $deliver_command = $ENV{DELIVER};
+    $deliver_command .= ' -verbose' if ($html);
     $deliver_command .= ' '. $dlv_switch if ($dlv_switch);
     $ENV{mk_tmp}++;
     %prj_platform = ();
     };
 
     print $new_line;
-
+    get_server_ports();
+    start_interactive() if ($interactive);
+    
     if ($checkparents) {
 	    GetParentDeps( $CurrentPrj, \%global_deps_hash );
     } else {
     };
 };
 
+sub start_interactive {
+    if ( $^O eq 'MSWin32' ) {
+        my $posix_sys_wait = 'POSIX ":sys_wait_h"';
+        eval "use $posix_sys_wait";
+        die "couldn't use $posix_sys_wait: $!\n" if ($@);
+        
+        pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!";
+        pipe(HTML_PIPE, TO_PARENT) or die "pipe: $!";
+
+
+        if (my $pid = fork()) {
+            $html_listener_pid = 1;
+            close FROM_PARENT;
+            close TO_PARENT;
+            ioctl(HTML_PIPE, 0x8004667e, 1);
+            return;
+        } else {
+            close HTML_PIPE;
+            close TO_CHILD;
+            select TO_PARENT;
+            $|++;
+            $parent_process = 0;
+            start_html_listener();
+        }
+    } else {
+        $pid = open(HTML_PIPE, "-|");
+        print "Pipe is open\n";
+
+        if ($pid) {   # parent
+            # make file handle non-bloking
+            my $flags = '';
+            fcntl(HTML_PIPE, F_GETFL, $flags);
+            $flags |= O_NONBLOCK;
+            fcntl(HTML_PIPE, F_SETFL, $flags);
+        } else {      # child
+            $parent_process = 0;
+            start_html_listener();
+        };
+    };
+};
+
+sub start_html_listener {
+    $html_port = $server_ports[$#server_ports];
+    do {
+        $html_port++
+    } while (start_server_on_port($html_port, \$html_socket_obj));
+    print "html_port:$html_port html_socket_obj: $html_socket_obj\n";
+    my $new_socket_obj;
+    do {
+        $new_socket_obj = accept_html_connection();
+        if (defined $new_socket_obj) {
+            my $html_message;
+            $html_message = <$new_socket_obj>;
+            chomp $html_message;
+            print $html_message . "\n";
+            my $socket_message = '';
+            for my $action ('rebuild', 'delete') {
+                if ($html_message =~ /$action=(\S+)/) {
+                    print $new_socket_obj "Module $1 is scheduled for $action";
+                };
+            };
+            close($new_socket_obj);
+        } else {
+            sleep(10);
+        };
+    } while(1);
+};
+
+sub start_html_message_trigger {
+	my $child_id=fork(); ### VG: for windows there is a "simulation of the "fork"", no new procs... One can use Win32::Process::Create
+	
+	if ($child_id) {
+	    # parent 
+	    $html_message_trigger{$child_id}++;
+#	    print "started listener trigger\n";
+	} else {
+        my $buffer_size = 1024;
+        my $buffer;
+        my $rv;
+        my $full_buffer = '';
+        my %modules_to_rebuild = ();
+        while ($rv = sysread(HTML_PIPE, $buffer, $buffer_size)) {
+            $full_buffer .= $buffer;
+        };
+        if (length $full_buffer) {
+            print "**********Got message $fullbuffer\n";
+            socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!";
+            if (connect(SOCKET, $paddr)) {
+                $full_buffer .= "\n";
+                syswrite SOCKET, $full_buffer, length $full_buffer;
+#                close SOCKET or die "Child close socket: $!";
+            } else {
+                die "Child connect: $!";
+            };
+        }
+        _exit(0);
+	};
+};
+
+sub get_html_orders {
+#    print "Parent gonna read\n";
+    return if (!$interactive);    
+    my $buffer_size = 1024;
+    my $buffer;
+    my $rv;
+    my $full_buffer = '';
+    my %modules_to_rebuild = ();
+    my %modules_to_delete = ();
+        while ($rv = sysread(HTML_PIPE, $buffer, $buffer_size)) {
+            $full_buffer .= $buffer;
+        };
+#    };
+    my @html_messages = split(/\n/, $full_buffer);
+    foreach (@html_messages) {
+        if (/^html_port:(\d+)/) {
+            $html_port = $1;
+            print "Html port is: $html_port\n";
+            next;
+        };# GET /rebuild=officenames HTTP/1.0
+        print "Message: $_\n";
+        chomp;
+        if (/GET\s+\/delete=(\S+)[:(\S+)]*\s*HTTP/) {
+            $modules_to_delete{$1} = $2;
+            print "$1 scheduled for removal from build for \n";
+        }
+        if (/GET\s+\/rebuild=(\S+)[:(\S+)]*\s*HTTP/) {
+            if (defined $global_deps_hash{$1}) {
+                print "!!! /tarModule $1 has not been built. Html order ignored\n";
+            } else {
+                $modules_to_rebuild{$1} = $2;
+                print "Scheduled $1 for rebuild\n";
+            }
+        }
+    };
+    if (scalar keys %modules_to_delete) {
+        $reschedule_queue++;
+        schedule_delete(\%modules_to_delete);
+        generate_html_file();
+    };
+    if (scalar keys %modules_to_rebuild) {
+        $reschedule_queue++;
+        schedule_rebuild(\%modules_to_rebuild);
+        generate_html_file();
+    };
+#    print "Parent got nothing to read\n";
+};
+
+sub schedule_delete {
+    my $modules_to_delete = shift;
+    foreach (keys %$modules_to_delete) {
+        print "Schedule module $_ for delete\n";
+        delete ($global_deps_hash{$_});
+        delete ($global_deps_hash_backup{$_});
+        if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) {
+            kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}};
+            handle_dead_children(0);
+        };
+        RemoveFromDependencies($_, \%global_deps_hash);
+        RemoveFromDependencies($_, \%global_deps_hash_backup);
+        delete $reversed_dependencies{$_};
+        delete $build_is_finished{$_} if defined $build_is_finished{$_};
+        delete $modules_with_errors{$_} if defined $modules_with_errors{$_};
+        delete $module_announced{$_} if defined $module_announced{$_};
+        delete $html_info{$_} if defined $html_info{$_};
+        delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_};
+    };
+};
+
+sub schedule_rebuild {
+    my $modules_to_rebuild = shift;
+    foreach (keys %$modules_to_rebuild) {
+        if (defined $$modules_to_rebuild{$_}) {
+            print "Schedule directory for rebuild";
+        } else {
+            print "Schedule complete $_ module for rebuild\n";
+            if (scalar keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}}) {
+                kill 9, keys %{$module_deps_hash_pids{$projects_deps_hash{$_}}};
+                handle_dead_children(0);
+            };
+            delete $build_is_finished{$_} if defined $build_is_finished{$_};
+            delete $modules_with_errors{$_} if defined $modules_with_errors{$_};
+            delete $module_announced{$_};
+            initialize_html_info($_);
+
+            foreach my $waiter (keys %{$reversed_dependencies{$_}}) {
+                # for rebuild_all_dependent - refacture "if" condition
+                ${$global_deps_hash{$waiter}}{$_}++ if (!defined $build_is_finished{$waiter});
+            };
+            delete $projects_deps_hash{$_} if defined $projects_deps_hash{$_};
+            my %single_module_dep_hash = ();
+            foreach my $module (keys %{$global_deps_hash_backup{$_}}) {
+                if (defined ${$global_deps_hash_backup{$_}}{$module} && (!defined $build_is_finished{$module})) {
+                    $single_module_dep_hash{$module}++;
+                };
+            };
+            $global_deps_hash{$_} = \%single_module_dep_hash;
+        };
+    };
+};
+    
+    
 #
 # procedure retrieves build list path
 # (all possibilities are taken into account)
 };
 
 #
+# This procedure builds comlete dependency for each module, ie if the deps look like:
+# mod1 -> mod2 -> mod3 -> mod4,mod5, 
+# than mod1 get mod3,mod4,mod5 as eplicit list of deps, not only mod2 as earlier
+#
+sub expand_dependencies {
+    my $deps_hash = shift;
+
+    foreach my $module1 (keys %$deps_hash) {
+        foreach my $module2 (keys %$deps_hash) {
+            next if ($module1 eq $module2);
+            if (defined ${$$deps_hash{$module2}}{$module1}) {
+                ${$$deps_hash{$module2}}{$_}++ foreach (keys %{$$deps_hash{$module1}})
+            };
+        };
+    };
+};
+
+#
+# This procedure fills out the %reversed_dependencies hash,
+# the hash contaninig the info about modules "waiting" for the module
+#
+sub reverse_dependensies {
+    my $deps_hash = shift;
+    foreach my $module (keys %$deps_hash) {
+        foreach (keys %{$$deps_hash{$module}}) {
+            if (defined $reversed_dependencies{$_}) {
+                ${$reversed_dependencies{$_}}{$module}++
+            } else {
+                my %single_module_dep_hash = ($module => 1);
+                $reversed_dependencies{$_} = \%single_module_dep_hash;
+            }; 
+        };
+    };
+};
+
+#
 # Build everything that should be built
 #
 sub BuildAll {
             push (@warnings, "\nThere are active module in $source_config_file. Inactive modules are skipped.\n\n");
             prepare_build_all_cont(\%global_deps_hash);
         };
+        backup_deps_hash(\%global_deps_hash, \%global_deps_hash_backup);
+        expand_dependencies (\%global_deps_hash_backup);
+        reverse_dependensies(\%global_deps_hash_backup);
         $modules_number = scalar keys %global_deps_hash;
         initialize_html_info($_) foreach (keys %global_deps_hash);
         if ($QuantityToBuild) {
         if ($server_mode) {
             run_server();
         };
-        while ($Prj = PickPrjToBuild(\%global_deps_hash)) {
+        while ($Prj = pick_prj_to_build(\%global_deps_hash)) {
             if (!defined $dead_parents{$Prj}) {              
                 if (scalar keys %broken_build) {
                     print $echo . "Skipping project $Prj because of error(s)\n";
                 };
 
                 $PrjDir = $module_paths{$Prj};
-                get_deps_hash($Prj, \%LocalDepsHash);
+                get_module_dep_hash($Prj, \%LocalDepsHash);
                 my $info_hash = $html_info{$Prj};
                 $$info_hash{DIRS} = check_deps_hash(\%LocalDepsHash, $Prj);
                 $module_by_hash{\%LocalDepsHash} = $Prj;
             
             RemoveFromDependencies($Prj, \%global_deps_hash);
             $build_is_finished{$Prj}++;
-            $no_projects = 0;
         };
     } else {
         store_build_list_content($CurrentPrj);
-        get_deps_hash($CurrentPrj, \%LocalDepsHash);
+        get_module_dep_hash($CurrentPrj, \%LocalDepsHash);
         initialize_html_info($CurrentPrj);
         my $info_hash = $html_info{$CurrentPrj};
         $$info_hash{DIRS} = check_deps_hash(\%LocalDepsHash, $CurrentPrj);
     };
 };
 
+sub backup_deps_hash {
+    my $source_hash = shift;
+    my $backup_hash = shift;
+    foreach $key (keys %$source_hash) {
+        my %values_hash = %{$$source_hash{$key}};
+        $$backup_hash{$key} = \%values_hash;
+    };
+};
+
 sub initialize_html_info {
     my $module = shift;
     return if (defined $dead_parents{$module});
     my $BuildDir = shift;
     $jobs_hash{$BuildDir}->{START_TIME} = time();
     $jobs_hash{$BuildDir}->{STATUS} = 'building';
-    if ($BuildDir =~ /(\s)/o) {
+    if ($BuildDir =~ /(\s)/o && (!-d $BuildDir)) {
+        print "\n$BuildDir\n\n" if ($BuildDir =~ /\sdeliver$/o);
         $error_code = do_custom_job($BuildDir, \%LocalDepsHash);
     } else {
         html_store_job_info(\%LocalDepsHash, $BuildDir);
     };
 };
 
+#
+# this function wraps the get_module_dep_hash and backups the resultung hash
+#
+sub get_module_dep_hash {
+    my ($module, $module_dep_hash) = @_;
+    if (defined $module_deps_hash_backup{$module}) {
+        backup_deps_hash($module_deps_hash_backup{$module}, $module_dep_hash);
+    } else {
+        get_deps_hash($module, $module_dep_hash);
+        my %values_hash = ();
+        backup_deps_hash($module_dep_hash, \%values_hash);
+        $module_deps_hash_backup{$module} = \%values_hash;
+    }
+};
 
 #
 # Getting hashes of all internal dependencies and additional
     };
 
     my  $build_list_ref = $build_lists_hash{$module_to_build};
-    delete $build_lists_hash{$module_to_build};
+#    delete $build_lists_hash{$module_to_build};
     if (ref($build_list_ref) eq 'XMLBuildListParser') {
         get_deps_from_object($module_to_build, $build_list_ref, $dependencies_hash);
     } else {
                 print_error("$module_to_build/prj/build.lst has wrongly written dependencies string:\n$_\n") if (!$Dependencies);
                 $deps_hash{$_}++ foreach (GetDependenciesArray($Dependencies));
                 $$dependencies_hash{$DirAlias} = \%deps_hash;
-                $BuildQueue{$DirAlias}++;
                 my $local_dir = '';
                 if ($Dir =~ /(\\|\/)/o) {
-                    $local_dir = $';
+                    $local_dir = "/$'";
                 };
-                $PathHash{$DirAlias} = CorrectPath($module_paths{$module_to_build} . "/$local_dir");
+                $PathHash{$DirAlias} = CorrectPath($module_paths{$module_to_build} . $local_dir);
             } elsif ($_ !~ /^\s*$/ && $_ !~ /^\w*\s/o) {
                 chomp;
                 push(@errors, $_);
 #
 # Picks project which can be built now from hash and then deletes it from hash
 #
-sub PickPrjToBuild {
+sub pick_prj_to_build {
     my $DepsHash = shift;
-    handle_dead_children(0) if ($QuantityToBuild);
-    my $Prj = FindIndepPrj($DepsHash);
-    delete $$DepsHash{$Prj};
-    generate_html_file();
+    get_html_orders();
+    my $Prj = find_indep_prj($DepsHash);
+    if ($Prj) {
+        delete $$DepsHash{$Prj};
+        generate_html_file();
+    };
     return $Prj;
 };
 
     my @possible_order;
     my $module_path = $module_paths{$module} if (defined $module);
     return if (!scalar keys %$deps_hash_ref);
-    my %deps_hash = %$deps_hash_ref;
+    my %deps_hash = ();
     my $consistent;
-    foreach $key (keys %$deps_hash_ref) {
-        my %values_hash = %{$$deps_hash_ref{$key}};
-        $deps_hash{$key} = \%values_hash;
-    };
+    backup_deps_hash($deps_hash_ref, \%deps_hash);
     my $string;
     my $log_name;
     my $build_number = 0;
 #
 # Find project with no dependencies left.
 #
-sub FindIndepPrj {
-    my ($Prj, @Prjs, $Dependencies, $i);
+sub find_indep_prj {
+    my ($Dependencies, $i);
     my @candidates = ();
+    $all_dependent = 1;
+    handle_dead_children(0) if ($QuantityToBuild);
     my $children = children_number();
     return '' if (!$server_mode && $children && ($children >= $QuantityToBuild));
     $Dependencies = shift;
-    @Prjs = keys %$Dependencies;
-    if ($#Prjs != -1) {
-        foreach $Prj (@Prjs) {
-            next if (&IsHashNative($Prj));
-            my $PrjDeps = $$Dependencies{$Prj};
-            push(@candidates, $Prj) if (!scalar keys %$PrjDeps);
+    if (scalar keys %$Dependencies) {
+        foreach my $job (keys %$Dependencies) {
+            push(@candidates, $job) if (!scalar keys %{$$Dependencies{$job}});
         };
         if (scalar @candidates) {
+            $all_dependent = 0;
             my $best_candidate = undef;
-            my $weight = 0;
-            foreach my $candidate (sort @candidates) {
-                if (defined $weights_hash{$candidate} && $weights_hash{$candidate} > $weight) {
-                    $best_candidate = $candidate;
-                    $weight = $weights_hash{$candidate};
+            my $best_weight = 0;
+            if (scalar @candidates > 1) {
+                foreach my $candidate (@candidates) {
+                    my $candidate_weight = get_waiters_number($candidate);
+                    if ($candidate_weight > $best_weight) {
+                        $best_candidate = $candidate;
+                        $best_weight = $candidate_weight;
+                    };
                 };
-            };
-            if (defined $best_candidate) {
-                return $best_candidate;
+                if (defined $best_candidate) {
+                    return $best_candidate;
+                }
             }
             my @sorted_candidates = sort(@candidates);
             return $sorted_candidates[0];
         };
-        return '';
-    } else {
-        $no_projects = 1;
-        return '';
     };
+    return '';
+};
+
+sub get_waiters_number {
+    my $module = shift;
+    if (defined $weights_hash{$module}) {
+        return $weights_hash{$module};
+    };
+    if (defined $reversed_dependencies{$module}) {
+        return scalar keys %{$reversed_dependencies{$module}};
+    };
+    return 0;
 };
 
 #
 
 sub usage {
     print STDERR "\nbuild\n";
-    print STDERR "Syntax:    build    [--all|-a[:prj_name]]|[--from|-f prj_name1[:prj_name2] [prj_name3 [...]]]|[--since|-c prj_name] [--with_branches|-b]|[--prepare|-p][:platform] [--dontchekoutmissingmodules]] [--deliver|-d [--dlv_switch deliver_switch]]] [-P processes|--server [--setenvstring \"string\"] [--client_timeout MIN] [--port port1[:port2:...:portN]]] [--show|-s] [--help|-h] [--file|-F] [--ignore|-i] [--version|-V] [--mode|-m OOo[,SO[,EXT]] [--html [--html_path html_file_path] [--dontgraboutput]] [--pre_job=pre_job_sring] [--job=job_string|-j] [--post_job=post_job_sring] [--stoponerror] [--genconf [--removeall|--clear|--remove|--add module1,module2[,...,moduleN]]]\n";
+    print STDERR "Syntax:    build    [--all|-a[:prj_name]]|[--from|-f prj_name1[:prj_name2] [prj_name3 [...]]]|[--since|-c prj_name] [--with_branches|-b]|[--prepare|-p][:platform] [--deliver|-d [--dlv_switch deliver_switch]]] [-P processes|--server [--setenvstring \"string\"] [--client_timeout MIN] [--port port1[:port2:...:portN]]] [--show|-s] [--help|-h] [--file|-F] [--ignore|-i] [--version|-V] [--mode|-m OOo[,SO[,EXT]] [--html [--html_path html_file_path] [--dontgraboutput]] [--pre_job=pre_job_sring] [--job=job_string|-j] [--post_job=post_job_sring] [--stoponerror] [--genconf [--removeall|--clear|--remove|--add module1,module2[,...,moduleN]]] [--interactive]\n";
     print STDERR "Example1:    build --from sfx2\n";
     print STDERR "                     - build all projects dependent from sfx2, starting with sfx2, finishing with the current module\n";
     print STDERR "Example2:    build --all:sfx2\n";
     print STDERR "          --removeall|--clear          - remove all active modules(s) from configuration file\n";
 
     print STDERR "        --stoponerror      - stop build when error occurs (for mp builds)\n";
-    print STDERR "        --dontchekoutmissingmodules - do not chekout missing modules when running prepare (links still will be broken)\n";
+    print STDERR "        --interactive      - start interactive build process (process can be managed via html page)\n";
     print STDERR "   Custom jobs:\n";
     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";
     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";
         $arg =~ /^-F$/        and $cmd_file = shift @ARGV             and next;
 
         $arg =~ /^--with_branches$/        and $BuildAllParents = 1
-                                and $build_from = shift @ARGV         and next;
+                                and $build_from_with_branches = shift @ARGV         and next;
         $arg =~ /^-b$/        and $BuildAllParents = 1
-                                and $build_from = shift @ARGV         and next;
+                                and $build_from_with_branches = shift @ARGV         and next;
 
         $arg =~ /^--all:(\S+)$/ and $BuildAllParents = 1
                                 and $build_all_cont = $1            and next;
         $arg =~ /^-m$/            and get_modes()         and next;
         $arg =~ /^--mode$/        and get_modes()         and next;
         $arg =~ /^--stoponerror$/        and $stop_build_on_error = 1         and next;
+        $arg =~ /^--interactive$/        and $interactive = 1         and next;
         if ($arg =~ /^--$/) {
             push (@dmake_args, get_dmake_args()) if (!$custom_job);
             next;
         print_error("\"--dontgraboutput\" switch is used only with \"--html\"") if ($dont_grab_output);
     };
     $grab_output = 0 if ($dont_grab_output);
-    print_error('Switches --with_branches and --all collision') if ($build_from && $build_all_cont);
+    print_error('Switches --with_branches and --all collision') if ($build_from_with_branches && $build_all_cont);
 #    print_error('Please prepare the workspace on one of UNIX platforms') if ($prepare && ($ENV{GUI} ne 'UNX'));
-    print_error('Switches --with_branches and --since collision') if ($build_from && $build_since);
+    print_error('Switches --with_branches and --since collision') if ($build_from_with_branches && $build_since);
     if ($show) {
         $QuantityToBuild = 0;
         $cmd_file = '';
             print_error("Switches -P and --server collision");
         };
     } elsif ($stop_build_on_error) {
-        print_error("Switche --stoponerror is only for multiprocessing builds");
+        print_error("Switch --stoponerror is only for multiprocessing builds");
     };
     if ($server_mode) {
         $html++;
         $only_common = 'common';
         $only_common .= '.pro' if ($only_platform =~ /\.pro$/);
     };
+    if ($interactive) {
+        $html++; # enable html page generation...
+        $local_host_name = hostname();
+        $local_host_ip = inet_ntoa(scalar(gethostbyname($local_host_name)) || 'localhost');
+    }
     # Default build modes(for OpenOffice.org)
     $ENV{BUILD_TYPE} = 'OOo EXT' if (!defined $ENV{BUILD_TYPE});
     @ARGV = @dmake_args;
 };
 
 #
-# Function for storing error in multiprocessing AllParents build
+# Function for storing errors in multiprocessing AllParents build
 #
 sub store_error {
     my ($pid, $error_code) = @_;
             return 1;
         };
     };
-    $broken_modules_hashes{$folders_hashes{$child_nick}}++;
+    $modules_with_errors{$folders_hashes{$child_nick}}++;
     $broken_build{$child_nick} = $error_code;
     if ($stop_build_on_error) {
         clear_from_child($pid);
                 } else {
                     clear_from_child($pid);
                 };
+                $finisched_children++;
             };
         };
     } while(children_number() >= $QuantityToBuild);
         RemoveFromDependencies($child_nick,
                             $folders_hashes{$child_nick});
     };
+    foreach (keys %module_deps_hash_pids) {
+        delete ${$module_deps_hash_pids{$_}}{$pid} if defined (${$module_deps_hash_pids{$_}}{$pid});
+    };
     my $module = $module_by_hash{$folders_hashes{$child_nick}};
     html_store_job_info($folders_hashes{$child_nick}, $child_nick, $error_code);
     $running_children{$folders_hashes{$child_nick}}--;
     delete $processes_hash{$pid};
-    $only_dependent = 0;
     print 'Running processes: ' . children_number() . "\n";
 };
 
     my $pid = 0;
     my $child_nick = '';
     $running_children{$dependencies_hash} = 0 if (!defined $running_children{$dependencies_hash});
-    while ($child_nick = PickPrjToBuild($dependencies_hash)) {
-        if (($QuantityToBuild)) { # multiprocessing not for $BuildAllParents (-all etc)!!
+    while ($child_nick = pick_prj_to_build($dependencies_hash)) {
+        if ($QuantityToBuild) {
             do {
-                handle_dead_children(0);
-                if (defined $broken_modules_hashes{$dependencies_hash} && !$ignore) {
-                    return if ($BuildAllParents);
+                if (defined $modules_with_errors{$dependencies_hash} && !$ignore) {
+                    return 0 if ($BuildAllParents);
                     last;
                 };
                 # start current child & all
                 # that could be started now
                 start_child($child_nick, $dependencies_hash) if ($child_nick);
-                $child_nick = PickPrjToBuild($dependencies_hash);
-                if (!$child_nick) {
-                    return if ($BuildAllParents);
-                    handle_dead_children(1) if (!$no_projects);
-                };
-            } while (!$no_projects);
-            return if ($BuildAllParents);
+                return 1 if ($BuildAllParents);
+                $child_nick = pick_prj_to_build($dependencies_hash);
+            } while (scalar keys %$dependencies_hash);
             while (children_number()) {
+#                print "#### 1902: Starting waiting for dead child\n";
                 handle_dead_children(1);
             };
 #            if (defined $last_module) {
 #                $build_is_finished{$last_module}++ if (!defined $modules_with_errors{$last_module});
 #            };
 
-            if (defined $broken_modules_hashes{$dependencies_hash}) {
+            if (defined $modules_with_errors{$dependencies_hash}) {
                 cancel_build();
             }
             mp_success_exit();
     $jobs_hash{$job_dir}->{STATUS} = 'building';
     if ($job_dir =~ /(\s)/o) {
         my $error_code = undef;
-        $error_code = do_custom_job($job_dir, $dependencies_hash);
-        return;
+        if ($job_dir !~ /\sdeliver$/o) {
+            $error_code = do_custom_job($job_dir, $dependencies_hash);
+            return;
+        }
     };
+    $build_in_progress{$module_by_hash{$dependencies_hash}}++;
     html_store_job_info($dependencies_hash, $job_dir);
     my $pid = undef;
     my $children_running;
     my $oldfh = select STDOUT;
     $| = 1;
-    if ($ENV{GUI} eq 'WNT' && !$cygwin) {
-        print "$job_dir\n";
-        my $process_obj = undef;
-        my $rc = Win32::Process::Create($process_obj, $dmake_bin,
-                                    $dmake_args, 
-			                        0, 0, #NORMAL_PRIORITY_CLASS,
-                                    $job_dir);
-#        my $rc = Win32::Process::Create($process_obj, $_4nt_exe,
-#                                    "/c $dmake_batch", 
-#			                        0, NORMAL_PRIORITY_CLASS,
-#                                    $job_dir);
-        print_error("Cannot start child process") if (!$rc);
-        $pid = $process_obj->GetProcessID();
-        $windows_procs{$pid} = $process_obj;
-    } else {
-        if ($pid = fork) { # parent
-        } elsif (defined $pid) { # child
-            select $oldfh;
-            $child = 1;
-            dmake_dir($job_dir);
-            do_exit(1);
-        };
+    if ($pid = fork) { # parent
+        select $oldfh;
+        $processes_hash{$pid} = $job_dir;
+        $children_running = children_number();
+        print 'Running processes: ', $children_running, "\n";
+        $maximal_processes = $children_running if ($children_running > $maximal_processes);
+        $folders_hashes{$job_dir} = $dependencies_hash;
+        store_pid($dependencies_hash, $pid);
+        $running_children{$dependencies_hash}++;
+    } elsif (defined $pid) { # child
+        select $oldfh;
+        $child = 1;
+        dmake_dir($job_dir);
+        do_exit(1);
     };
-    select $oldfh;
-    $processes_hash{$pid} = $job_dir;
-    $children_running = children_number();
-    print 'Running processes: ', $children_running, "\n";
-    $maximal_processes = $children_running if ($children_running > $maximal_processes);
-    $folders_hashes{$job_dir} = $dependencies_hash;
-    $running_children{$dependencies_hash}++;
+};
+
+sub store_pid {
+    my ($deps_hash, $pid) = @_;
+    if (!defined $module_deps_hash_pids{$deps_hash}) {
+        my %module_hash_pids = ();
+        $module_deps_hash_pids{$deps_hash} = \%module_hash_pids;
+    };
+    ${$module_deps_hash_pids{$deps_hash}}{$pid}++;
 };
 
 #
 #
 sub build_multiprocessing {
     my $Prj;
-    my @build_queue = ();        # array, containing queue of projects
-                                # to build
     do {
-        while ($Prj = PickPrjToBuild(\%global_deps_hash)) {
-            push @build_queue, $Prj;
-            $projects_deps_hash{$Prj} = {};
-            get_deps_hash($Prj, $projects_deps_hash{$Prj});
-            my $info_hash = $html_info{$Prj};
-            $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$Prj}, $Prj);
-            $module_by_hash{$projects_deps_hash{$Prj}} = $Prj;
+        my $got_module = 0;
+        $finisched_children = 0;
+        while ($Prj = pick_prj_to_build(\%global_deps_hash)) {
+            if (!defined $projects_deps_hash{$Prj}) {
+                $projects_deps_hash{$Prj} = {};
+                get_module_dep_hash($Prj, $projects_deps_hash{$Prj});
+                my $info_hash = $html_info{$Prj};
+                $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$Prj}, $Prj);
+                $module_by_hash{$projects_deps_hash{$Prj}} = $Prj;
+            }
+            $module_build_queue{$Prj}++;
+            $got_module++;
         };
-        if (!$Prj || !defined $projects_deps_hash{$Prj}) {
-            cancel_build() if (!scalar @build_queue && !children_number());
-            handle_dead_children(1);
-        }
-        build_actual_queue(\@build_queue);
-    } while (scalar (keys %global_deps_hash));
+        if (!$got_module) {
+            cancel_build() if ((!scalar keys %module_build_queue) && !children_number());
+            if (!$finisched_children) {
+#                print "#### 1979: Starting waiting for dead child\n";
+                handle_dead_children(1);
+            };
+        };
+        build_actual_queue(\%module_build_queue);
+    } while (scalar keys %global_deps_hash);
     # Let the last module be built till the end
-    while (scalar @build_queue) {
-        build_actual_queue(\@build_queue);
+    while (scalar keys %module_build_queue) {
+        build_actual_queue(\%module_build_queue);
+#        print "#### 1988: Starting waiting for dead child\n";
         handle_dead_children(1);
     };
     # Let all children finish their work 
 #
 sub build_actual_queue {
     my $build_queue = shift;
-    my $i = 0;
+    my $finished_projects = 0; 
     do {
-        while ($i <= (scalar(@$build_queue) - 1)) {
-            $Prj = $$build_queue[$i];
-            if (defined $broken_modules_hashes{$projects_deps_hash{$Prj}} && !$ignore) {
+        my @sorted_queue = sort {(scalar keys %{$projects_deps_hash{$a}}) <=> (scalar keys %{$projects_deps_hash{$b}})} keys %$build_queue;
+        my $started_children = 0; 
+#        foreach $Prj (@sorted_queue) {
+        foreach $Prj (keys %$build_queue) {
+            get_html_orders();
+            if ($reschedule_queue) {
+                $reschedule_queue = 0;
+                foreach (keys %$build_queue) {
+                    # Remove the module from the build queue if there is a dependency emerged
+                    if ((defined $global_deps_hash{$_}) && (scalar keys %{$global_deps_hash{$_}})) {
+                        delete $$build_queue{$_};
+                    };
+                    delete $$build_queue{$_} if (!defined $global_deps_hash_backup{$_})
+                };
+                return;
+            };
+            if (defined $modules_with_errors{$projects_deps_hash{$Prj}} && !$ignore) {
                 push (@broken_modules_names, $Prj);
-                splice (@$build_queue, $i, 1);
+                delete $$build_queue{$Prj};
                 next;
             };
-            $only_dependent = 0;
-            $no_projects = 0;
-            BuildDependent($projects_deps_hash{$Prj});
-            handle_dead_children(0);
-            if ($no_projects &&
+            $started_children =+ BuildDependent($projects_deps_hash{$Prj});
+            if ((!scalar keys %{$projects_deps_hash{$Prj}}) &&
                 !$running_children{$projects_deps_hash{$Prj}}) {
-                if (!defined $broken_modules_hashes{$projects_deps_hash{$Prj}} || $ignore)
+                if (!defined $modules_with_errors{$projects_deps_hash{$Prj}} || $ignore)
                 {
                     RemoveFromDependencies($Prj, \%global_deps_hash);
                     $build_is_finished{$Prj}++;
-                    splice (@$build_queue, $i, 1);
-                    next;
+                    delete $$build_queue{$Prj};
+                    $finished_projects++;
                 };
             };
-            $i++;
         };
-        $i = 0;
-    } while (!are_all_dependent($build_queue));
+        # trigger wait
+        if (!$started_children) {
+            if ($finished_projects) {
+                return;
+            } else {
+                handle_dead_children(1);
+            };
+        };
+    } while (scalar keys %$build_queue);
 };
 
 sub run_job {
             };
         };
         if ($error_code) {
-            $broken_modules_hashes{$dependencies_hash}++;
+            $modules_with_errors{$dependencies_hash}++;
             $broken_build{$module} = $error_code;
         } else {
             RemoveFromDependencies($module_job, $dependencies_hash);
 
 sub print_announce {
     my $Prj = shift;
+    return if (defined $module_announced{$Prj});
     my $prj_type = '';
     $prj_type = $modules_types{$Prj} if (defined $modules_types{$Prj});
     my $text;
         };
         $build_is_finished{$Prj}++;
     } elsif ($prj_type eq 'img') {
-#        return if (defined $module_announced{$`});
         $text = "Skipping incomplete $Prj\n";
         $build_is_finished{$Prj}++;
     } elsif ($custom_job) {
     } else {
         $text = "Building module $Prj\n";
     };
-    print $echo . "=============\n";
-    print $echo . $text;
+    my $announce_string = $new_line;
+    $announce_string .= $echo . "=============\n";
+    $announce_string .= $echo . $text;
+    $announce_string .= $echo . "=============\n";
+    print $announce_string;
+    $module_announced{$Prj}++;
 };
 
 sub are_all_dependent {
     my $build_queue = shift;
     my $folder = '';
-    foreach my $prj (@$build_queue) {
-        $folder = FindIndepPrj($projects_deps_hash{$prj});
-        return '' if ($folder);
+    my $first_candidate = undef;
+    foreach my $prj (keys %$build_queue) {
+        $folder = find_indep_prj($projects_deps_hash{$prj});
+        $first_candidate = $folder if (!defined $first_candidate);
     };
+    $folder = $first_candidate;
+    return '' if ($first_candidate);
     return '1';
 };
 
 #
 sub provide_consistency {
     check_dir();
-    foreach my $module_ref (\$build_from, \$build_all_cont, \$build_since) {
-        if ($$module_ref) {
-            return if (defined $module_paths{$$module_ref});
-            print_error("Cannot find module '$$module_ref'", 9);
+    foreach $var_ref (\$build_from_with_branches, \$build_all_cont, \$build_since) {
+        if ($$var_ref) {
+            return if (defined $module_paths{$$var_ref});
+            print_error("Cannot find module '$$var_ref'", 9);
             return;
         };
     };
     } else {
        $tmp_dir = '/tmp/';
     }
-    
-    return File::Temp::tempdir(DIR =>$tmp_dir);
-    
-#    $tmp_dir .= $$ while (-e $tmp_dir);
-#    $tmp_dir = CorrectPath($tmp_dir);
-#    eval {mkpath($tmp_dir)};
-#    print_error("Cannot create temporary directory in $tmp_dir") if ($@);
-#    return $tmp_dir;
+    $tmp_dir = tempdir ( DIR => $tmp_dir );
+    if (!-d $tmp_dir) {
+        print_error("Cannot create temporary directory for checkout in $tmp_dir") if ($@);
+    };
+    return $tmp_dir;
 };
 
 
         $incompatibles{$incomp_prj} = $$deps_hash{$incomp_prj};
         delete $$deps_hash{$incomp_prj};
     }
-    while ($prj = PickPrjToBuild($deps_hash)) {
+    while ($prj = pick_prj_to_build($deps_hash)) {
         RemoveFromDependencies($prj, $deps_hash);
         RemoveFromDependencies($prj, \%incompatibles);
     };
     my ($prj, $deps_hash);
     $deps_hash = shift;
     my %from_deps_hash = ();   # hash of dependencies of the -from project
-    GetParentDeps($build_from, \%from_deps_hash);
+    GetParentDeps($build_from_with_branches, \%from_deps_hash);
     foreach $prj (keys %from_deps_hash) {
         delete $$deps_hash{$prj};
         RemoveFromDependencies($prj, $deps_hash);
     $deps_hash = shift;
     $border_prj = $build_all_cont if ($build_all_cont);
     $border_prj = $build_since if ($build_since);
-    while ($prj = PickPrjToBuild($deps_hash)) {
+    while ($prj = pick_prj_to_build($deps_hash)) {
         $orig_prj = '';
         $orig_prj = $` if ($prj =~ /\.lnk$/o);
         $orig_prj = $` if ($prj =~ /\.link$/o);
         } else {
             if ($option =~ /(:)/) {
                 $option = $`;
-                print_error("-from switch collision") if ($build_all_cont);
+                print_error("\'--from\' switch collision") if ($build_all_cont);
                 $build_all_cont = $';
             };
             $incompatibles{$option}++;
     print "$message\n";
     
     foreach my $platform (keys %platforms) {
-        print "\nRemoving delivered for $platform\n";
+        print "\nRemoving files delivered for $platform\n";
         my %solar_vars = ();
         read_ssolar_vars($platform, \%solar_vars);
         if (scalar keys %solar_vars) {
         my $undeliver = "$deliver_command $deliver_delete_switches $nul";
 #        my $current_dir = getcwd();
         foreach my $module (sort @modules_built) {
-            if (chdir($module_paths{$module})) {
+            if (!chdir($module_paths{$module})) {
                 push(@warnings, "Could not remove delivered files from the module $module. Your build can become inconsistent.\n");
             } else {
                 print "Removing delivered from module $module\n";
         # perl 5.10 returns 'resource busy' for rmtree
         rmdir(CorrectPath($tmp_dir)) if ($tmp_dir);
     }
-    rmtree(CorrectPath($tmp_dir), 1, 0) if ($tmp_dir);
+    rmtree(CorrectPath($tmp_dir), 0, 0) if ($tmp_dir);
+    print STDERR "Cannot delete $tmp_dir. Please remove it manually\n" if (-d $tmp_dir);
     exit($exit_code);
 };
 
         delete $build_in_progress_shown{$_} if (defined $build_in_progress_shown{$_});
     };
     $build_in_progress_shown{$_}++ foreach (keys %build_in_progress);
-    push(@modules_order, $_) foreach (sort keys %build_in_progress_shown);
+    push(@modules_order, $_) foreach (sort { $build_in_progress_shown{$b} <=> $build_in_progress_shown{$a} }  keys %build_in_progress_shown);
     push(@modules_order, $_) foreach (sort keys %build_is_finished);
     foreach(sort keys %html_info) {
         next if (defined $build_is_finished{$_} || defined $build_in_progress{$_} || defined $modules_with_errors{$_});
 sub generate_html_file {
     return if (!$html);
     my $force_update = shift;
+    $force_update++ if ($debug);
     $html_last_updated = time;
     my @modules_order = sort_modules_appearance();
     my ($successes_percent, $errors_percent) = get_progress_percentage(scalar keys %html_info, scalar keys %build_is_finished, scalar keys %modules_with_errors);
     print HTML 'initFrames();' . "\n";
     print HTML 'var IntervalID;' . "\n";
     print HTML 'function loadFrame_0() {' . "\n";
-    print HTML 'document.write("<html>");' . "\n";
-    print HTML 'document.write("<head>");' . "\n";
-    print HTML 'document.write("</head>");' . "\n";
-    print HTML 'document.write("<body>");' . "\n";
+    print HTML '    document.write("<html>");' . "\n";
+    print HTML '    document.write("<head>");' . "\n";
+    print HTML '    document.write("</head>");' . "\n";
+    print HTML '    document.write("<body>");' . "\n";
     if ($build_finished) {
         print HTML 'document.write("<h3 align=center style=\"color:red\">Build process is finished</h3>");' . "\n";
         print HTML '        top.frames[0].clearInterval(top.frames[0].IntervalID);' . "\n";
+    } elsif ($interactive) {
+        print HTML 'document.write("    <div id=divContext style=\"border: 1px solid; display: none; position: absolute\">");' . "\n";
+        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";
+        print HTML 'document.write("            <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aRebuild href=\"#\">Rebuild module</a></li>");' . "\n";
+        print HTML 'document.write("            <li><a onmouseover=\"this.style.color=\'red\'\" onmouseout=\"this.style.color=\'black\'\" id=aDelete href=\"#\" >Remove module</a></li>");' . "\n";
+        print HTML 'document.write("        </ul>");' . "\n";
+        print HTML 'document.write("    </div>");' . "\n";
     };
     if ($BuildAllParents) {
         print HTML 'document.write("<table valign=top cellpadding=0 hspace=0 vspace=0 cellspacing=0 border=0>");' . "\n";
             print HTML $errors_number;
             print HTML ' error(s)\">', $_, '</a>");' . "\n";
         } else {
-            print HTML 'document.write("<em style=color:gray>' . $_ . '</em>");';
+#            print HTML 'document.write("<em style=color:gray>' . $_ . '</em>");';
+####            print HTML 'document.write("<em style=color:gray>' . $_ ."href=\'http://$local_host_ip:$html_port/delete=\'$_". '</em>");';
+            
+            print HTML 'document.write("            <a target=\'infoframe\' id=';
+            print HTML $_;
+            print HTML ' href=\"javascript:void(0)\"; title=\"Remove module\">' . $_ . '</a>");' . "\n";
         };
 
 
         print HTML 'document.write("    </tr>");' . "\n";
 # </one module>
     } 
-    print HTML 'document.write("</table>");' . "\n";
-    print HTML 'document.write("</body>");' . "\n";
+    print HTML 'document.write("        </table>");' . "\n";
+    print HTML 'document.write("    </body>");' . "\n";
     print HTML 'document.write("</html>");' . "\n";
     print HTML 'document.close();' . "\n";
     print HTML 'refreshInfoFrames();' . "\n";
     print HTML '}' . "\n";
-    
+
+
+    if (!$build_finished && $interactive ) {
+        print HTML 'var _replaceContext = false;' . "\n";
+        print HTML 'var _mouseOverContext = false;' . "\n";
+        print HTML 'var _noContext = false;' . "\n";
+        print HTML 'var _divContext = $(\'divContext\');' . "\n";
+        print HTML 'var activeElement = 0;' . "\n";
+        print HTML 'function $(id) {return document.getElementById(id);}' . "\n";
+        print HTML 'InitContext();' . "\n";
+        print HTML 'function InitContext()' . "\n";
+        print HTML '{' . "\n";
+        print HTML '    $(\'aRebuild\').target = \'infoframe\';' . "\n";
+        print HTML '    $(\'aDelete\').target = \'infoframe\';' . "\n";
+        print HTML '    $(\'aRebuild\').style.color = \'black\';' . "\n";
+        print HTML '    $(\'aDelete\').style.color = \'black\';' . "\n";
+        print HTML '    _divContext.onmouseover = function() { _mouseOverContext = true; };' . "\n";
+        print HTML '    _divContext.onmouseout = function() { _mouseOverContext = false; };' . "\n";
+        print HTML '    _divContext.onclick = function() { _divContext.style.display = \'none\'; };' . "\n";
+        print HTML '    document.body.onmousedown = ContextMouseDown;' . "\n";
+        print HTML '    document.body.oncontextmenu = ContextShow;' . "\n";
+        print HTML '}' . "\n";
+        print HTML 'function ContextMouseDown(event) {' . "\n";
+        print HTML '    if (_noContext || _mouseOverContext) return;' . "\n";
+        print HTML '    if (event == null) event = window.event;' . "\n";
+        print HTML '    var target = event.target != null ? event.target : event.srcElement;' . "\n";
+        print HTML '    if (event.button == 2 && target.tagName.toLowerCase() == \'a\')' . "\n";
+        print HTML '        _replaceContext = true;' . "\n";
+        print HTML '    else if (!_mouseOverContext)' . "\n";
+        print HTML '        _divContext.style.display = \'none\';' . "\n";
+        print HTML '}' . "\n";
+        print HTML 'function ContextShow(event) {' . "\n";
+        print HTML '    if (_noContext || _mouseOverContext) return;' . "\n";
+        print HTML '    if (event == null) event = window.event;' . "\n";
+        print HTML '    var target = event.target != null ? event.target : event.srcElement;' . "\n";
+        print HTML '    if (_replaceContext) {' . "\n";
+        print HTML '        $(\'aRebuild\').href = \'http://'. $local_host_ip .':' . $html_port . '/rebuild=\' + target.id;' . "\n";
+        print HTML '        $(\'aDelete\').href = \'http://'. $local_host_ip .':' . $html_port . '/delete=\' + target.id' . "\n";
+        print HTML '        var scrollTop = document.body.scrollTop ? document.body.scrollTop : ';
+        print HTML 'document.documentElement.scrollTop;' . "\n";
+        print HTML '        var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : ';
+        print HTML 'document.documentElement.scrollLeft;' . "\n";
+        print HTML '        _divContext.style.display = \'none\';' . "\n";
+        print HTML '        _divContext.style.left = event.clientX + scrollLeft + \'px\';' . "\n";
+        print HTML '        _divContext.style.top = event.clientY + scrollTop + \'px\';' . "\n";
+        print HTML '        _divContext.style.display = \'block\';' . "\n";
+        print HTML '        _replaceContext = false;' . "\n";
+        print HTML '        return false;' . "\n";
+        print HTML '    }' . "\n";
+        print HTML '}' . "\n";
+    };
+
     print HTML 'function refreshInfoFrames() {        ' . "\n";
     print HTML '    var ModuleNameObj = top.innerFrame.frames[2].document.getElementById("ModuleErrors");' . "\n";
     print HTML '    if (ModuleNameObj != null) {' . "\n";
     print HTML '    StatusInnerHtml += Status + "</em>";' . "\n";
     print HTML '    return StatusInnerHtml;' . "\n";
     print HTML '}    ' . "\n";
-    print HTML 'function ShowLog(LogFilePath) {' . "\n";
+    print HTML 'function ShowLog(LogFilePath, ModuleJob) {' . "\n";
+    print HTML '    top.innerFrame.frames[2].document.write("<h3 id=ModuleErrors name=\"" + null + "\">Log for " + ModuleJob + "</h3>");' . "\n";
+    print HTML '    top.innerFrame.frames[2].document.write("<iframe id=LogFile name=Log src="';
 	if (defined $html_path) {
-		print HTML '    top.innerFrame.frames[2].document.location.replace("file://"+LogFilePath);' . "\n";
-	} else {
-		print HTML '    top.innerFrame.frames[2].document.location.replace(LogFilePath);' . "\n";
+		print HTML 'file://';
 	}
+	print HTML '+ LogFilePath + " width=100%></iframe>");' . "\n"; 
     print HTML '    top.innerFrame.frames[2].document.close();' . "\n";
     print HTML '};' . "\n";
     print HTML 'function FillFrame_1(Module, Message1, Message2) {' . "\n";
     print HTML '            if (dir_info_array[4] == "@") {' . "\n";
     print HTML '                top.innerFrame.frames[1].document.write("        <td style=white-space:nowrap>" + dir_info_array[1] + "</td>");' . "\n";
     print HTML '            } else {' . "\n";
-    print HTML '                top.innerFrame.frames[1].document.write("        <td><a href=\"javascript:top.ShowLog(\'" + dir_info_array[4] + "\')\"); title=\"Show Log\">" + dir_info_array[1] + "</a></td>");' . "\n";
+    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";
     print HTML '            };' . "\n";
     print HTML '            top.innerFrame.frames[1].document.write("        <td align=center>" + dir_info_array[2] + "</td>");' . "\n";
     print HTML '            top.innerFrame.frames[1].document.write("        <td align=center>" + dir_info_array[3] + "</td>");' . "\n";
     print HTML '                var DirectoryInfos = ModuleRows[i + 1].cells;' . "\n";
     print HTML '                DirectoryInfos[0].innerHTML = getStatusInnerHTML(dir_info_array[0]) + "&nbsp";' . "\n";
     print HTML '                if (dir_info_array[4] != "@") {' . "\n";
-    print HTML '                    DirectoryInfos[1].innerHTML = "<a href=\"javascript:top.ShowLog(\'" + dir_info_array[4] + "\')\"); title=\"Show Log\">" + dir_info_array[1] + "</a>";' . "\n";
+    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";
     print HTML '                };' . "\n";
     print HTML '                DirectoryInfos[2].innerHTML = dir_info_array[2];' . "\n";
     print HTML '                DirectoryInfos[3].innerHTML = dir_info_array[3];' . "\n";
     print HTML '        document.write(\'        </frameset>\');' . "\n";
     print HTML '        document.write(\'            <frame src="\');' . "\n";
     print HTML '        document.write(urlquery[0]);' . "\n";
-    print HTML '        document.write(\'?initFrame2"/>\');' . "\n";
+    print HTML '        document.write(\'?initFrame2"  name="infoframe"/>\');' . "\n";
     print HTML '        document.write(\'    </frameset>\');' . "\n";
     print HTML '        document.write("</head></html>");' . "\n";
     print HTML '    } else {' . "\n";
     $errors_info_line .= '\'';
 #    if (defined $full_info) {
     my $time_line = get_time_line($$module_info_hash{BUILD_TIME});
-        my ($successes_percent, $errors_percent) = get_progress_percentage($dirs_number, $successful_number, $errorful_number); 
+        my ($successes_percent, $errors_percent) = get_progress_percentage($dirs_number - 1, $successful_number - 1, $errorful_number); 
         return($errors_info_line, $dirs_info_line, $errorful_number, $successes_percent, $errors_percent, $time_line);
 #    } else {
 #        return($errors_info_line, $dirs_info_line, $errorful_number);
             $build_dir =~ s/\\/\//g;
             $modules_with_errors{$module}++;
         } else {
-            $jobs_hash{$build_dir}->{STATUS} = 'success';
+            if ($build_dir =~ /(\s)announce/o) {
+                $jobs_hash{$build_dir}->{STATUS} = '-';
+            } else {
+                $jobs_hash{$build_dir}->{STATUS} = 'success';
+            };
             $dmake_array = $$module_info_hash{SUCCESSFUL};
         };
         push (@$dmake_array, $build_dir);
 
 sub start_server_on_port {
     my $port = shift;
+    my $socket_obj = shift;
+    $client_timeout = 1 if (!$parent_process);
     if ($ENV{GUI} eq 'WNT') {
-        $socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
+        $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
                                   LocalPort => $port,
                                   Proto     => 'tcp',
                                   Listen    => 100); # 100 clients can be on queue, I think it is enough
     } else {
-        $socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
+        $$socket_obj = new IO::Socket::INET (#LocalAddr => hostname(),
                                   LocalPort => $port,
                                   Proto     => 'tcp',
                                   ReuseAddr     => 1,
                                   Listen    => 100); # 100 clients can be on queue, I think it is enough
     };
-    return('Cannot create socket object') if (!defined $socket_obj);
-    my $timeout = $socket_obj->timeout($client_timeout);
-    $socket_obj->autoflush(1);
-    print "SERVER started on port $port\n";
+    return('Cannot create socket object') if (!defined $$socket_obj);
+    my $timeout = $$socket_obj->timeout($client_timeout);
+    $$socket_obj->autoflush(1);
+    if ($parent_process && $debug) {
+        print "SERVER started on port $port\n";
+    } else {
+        print "html_port:$html_port html_socket_obj: $html_socket_obj\n";
+    };
     return 0;
 };
 
+sub accept_html_connection {
+    my $new_socket_obj = undef;
+    $new_socket_obj = $html_socket_obj->accept();
+    return $new_socket_obj;
+};
+
 sub accept_connection {
     my $new_socket_obj = undef;
     do {
-        $new_socket_obj = $socket_obj->accept();
+        $new_socket_obj = $server_socket_obj->accept();
         if (!$new_socket_obj) {
             print "Timeout on incoming connection\n";
             check_client_jobs();
     };
 };
 
-sub run_server {
-    my @build_queue = ();        # array, containing queue of projects
-                                # to build
+sub get_server_ports {
     # use port 7890 as default
     my $default_port = 7890;
     if ($ports_string) {
     } else {
         @server_ports = ($default_port .. $default_port + 4);
     };
+};
+
+sub run_server {
+    my @build_queue = ();        # array, containing queue of projects
+                                # to build
     my $error = 0;
     if (scalar @server_ports) {
         foreach (@server_ports) {
-            $error = start_server_on_port($_);
+            $error = start_server_on_port($_, \$server_socket_obj);
             if ($error) {
                 print STDERR "port $_: $error\n";
             } else {
                 last;
             };
         };
+        print_error('Unable to start server on port(s): ' . "@server_ports\n") if ($error);
+    } else {
+        print_error('No ports for server to start');
     };
-    print_error('It is impossible to start server on port(s): ' . "@server_ports\n") if ($error);
 
     my $client_addr;
     my $job_string_base = get_job_string_base();
     } else {
         $dependencies_hash = \%LocalDepsHash;
         do {
-            $job_dir = PickPrjToBuild(\%LocalDepsHash);
+            $job_dir = pick_prj_to_build(\%LocalDepsHash);
             if (!$job_dir && !children_number()) {
                 cancel_build() if (scalar keys %broken_build);
                 mp_success_exit();
     foreach (@$build_queue) {
         $Prj = $$build_queue[$i];
         my $prj_deps_hash = $projects_deps_hash{$Prj};
-        if (defined $broken_modules_hashes{$prj_deps_hash} && !$ignore) {
+        if (defined $modules_with_errors{$prj_deps_hash} && !$ignore) {
             push (@broken_modules_names, $Prj);
             splice (@$build_queue, $i, 1);
             next;
         };
-        $only_dependent = 0;
-        $no_projects = 0;
         $running_children{$prj_deps_hash} = 0 if (!defined $running_children{$prj_deps_hash});
-        $child_nick = PickPrjToBuild($prj_deps_hash);
+        $child_nick = pick_prj_to_build($prj_deps_hash);
         if ($child_nick) {
             return ($child_nick, $prj_deps_hash);
         }
-        if ($no_projects && !$running_children{$prj_deps_hash}) {
-            if (!defined $broken_modules_hashes{$prj_deps_hash} || $ignore)
+        if ((!scalar keys %$prj_deps_hash) && !$running_children{$prj_deps_hash}) {
+            if (!defined $modules_with_errors{$prj_deps_hash} || $ignore)
             {
                 RemoveFromDependencies($Prj, \%global_deps_hash);
                 $build_is_finished{$Prj}++;
 sub fill_modules_queue {
     my $build_queue = shift;
     my $Prj;
-    while ($Prj = PickPrjToBuild(\%global_deps_hash)) {
+    while ($Prj = pick_prj_to_build(\%global_deps_hash)) {
         push @$build_queue, $Prj;
         $projects_deps_hash{$Prj} = {};
-        get_deps_hash($Prj, $projects_deps_hash{$Prj});
+        get_module_dep_hash($Prj, $projects_deps_hash{$Prj});
         my $info_hash = $html_info{$Prj};
         $$info_hash{DIRS} = check_deps_hash($projects_deps_hash{$Prj}, $Prj);
         $module_by_hash{$projects_deps_hash{$Prj}} = $Prj;