2004-06-25 18:23:20 -05:00
:
eval 'exec perl -wS $0 ${1+"$@"}'
if 0 ;
#*************************************************************************
#
2005-09-07 16:07:25 -05:00
# OpenOffice.org - a multi-platform office productivity suite
2004-06-25 18:23:20 -05:00
#
2005-09-07 16:07:25 -05:00
# $RCSfile: cwsresync.pl,v $
2004-06-25 18:23:20 -05:00
#
2008-02-18 02:12:35 -06:00
# $Revision: 1.34 $
2004-06-25 18:23:20 -05:00
#
2008-02-18 02:12:35 -06:00
# last change: $Author: rt $ $Date: 2008-02-18 09:12:35 $
2004-06-25 18:23:20 -05:00
#
2005-09-07 16:07:25 -05:00
# The Contents of this file are made available subject to
# the terms of GNU Lesser General Public License Version 2.1.
2004-06-25 18:23:20 -05:00
#
#
2005-09-07 16:07:25 -05:00
# GNU Lesser General Public License Version 2.1
# =============================================
# Copyright 2005 by Sun Microsystems, Inc.
# 901 San Antonio Road, Palo Alto, CA 94303, USA
2004-06-25 18:23:20 -05:00
#
2005-09-07 16:07:25 -05:00
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 2.1, as published by the Free Software Foundation.
2004-06-25 18:23:20 -05:00
#
2005-09-07 16:07:25 -05:00
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
2004-06-25 18:23:20 -05:00
#
2005-09-07 16:07:25 -05:00
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
2004-06-25 18:23:20 -05:00
#
#*************************************************************************
#
# cwsresync.pl - sync child workspace modules/files with newer
# milestones of master workspace
#
use strict ;
use Cwd ;
use File::Basename ;
use File::Copy ;
use File::Find ;
use File::Glob ;
use File::Path ;
2007-08-27 07:31:52 -05:00
use Getopt::Long qw( :config no_ignore_case ) ;
2004-06-25 18:23:20 -05:00
use IO::Handle ;
2007-08-27 07:31:52 -05:00
use IO::File ;
2005-11-07 10:05:43 -06:00
use Carp ;
2004-06-25 18:23:20 -05:00
#### module lookup
2004-08-12 09:11:19 -05:00
my @ lib_dirs ;
BEGIN {
if ( ! defined ( $ ENV { SOLARENV } ) ) {
die "No environment found (environment variable SOLARENV is undefined)" ;
}
push ( @ lib_dirs , "$ENV{SOLARENV}/bin/modules" ) ;
2007-08-27 07:31:52 -05:00
push ( @ lib_dirs , "$ENV{SOLARENV}/bin/modules/PCVSLib/lib" ) ;
2004-08-12 09:11:19 -05:00
push ( @ lib_dirs , "$ENV{COMMON_ENV_TOOLS}/modules" ) if defined ( $ ENV { COMMON_ENV_TOOLS } ) ;
}
use lib ( @ lib_dirs ) ;
2004-06-25 18:23:20 -05:00
use Cws ;
eval { require Logging ; import Logging ; } ;
my $ log = undef ;
$ log = Logging - > new ( ) if ( ! $@ ) ;
eval {
require EnvHelper ; import EnvHelper ;
require CopyPrj ; import CopyPrj ;
} ;
use Cvs ;
use GenInfoParser ;
use CwsConfig ;
2007-08-27 07:31:52 -05:00
use CwsCvsOps ;
2007-09-05 11:37:29 -05:00
use CvsModule ; # to be removed ASAP
2004-06-25 18:23:20 -05:00
#### script id #####
( my $ script_name = $ 0 ) =~ s/^.*\b(\w+)\.pl$/$1/ ;
my $ script_rev ;
2008-02-18 02:12:35 -06:00
my $ id_str = ' $Revision: 1.34 $ ' ;
2004-06-25 18:23:20 -05:00
$ id_str =~ /Revision:\s+(\S+)\s+\$/
? ( $ script_rev = $ 1 ) : ( $ script_rev = "-" ) ;
print "$script_name -- version: $script_rev\n" ;
#### hardcoded globals #####
2006-07-05 15:55:29 -05:00
my @ xtra_files = ( "*.mk" , "*.flg" , "libCrun*" , "libCstd*" , "libgcc*" , "libstdc*" ) ;
2004-06-25 18:23:20 -05:00
my $ platform_resynced_flag = ".cwsresync_complete" ;
2007-08-27 07:31:52 -05:00
# ignore these files silently during resync
my % resync_silent_ignore_files = ( 'wntmsci3' = > 1 ,
'wntmsci7' = > 1 ,
'wntmsci8' = > 1 ) ;
# ignore these files silently during resync
my % resync_always_move_tags = ( 'wntmsci10' = > 1 ) ;
2004-06-25 18:23:20 -05:00
# modules to be obligatory copied to each cws
2007-09-05 11:37:29 -05:00
my % obligatory_modules = ( 'solenv' = > 1 ,
'default_images' = > 1 ,
'custom_images' = > 1 ,
'ooo_custom_images' = > 1 ,
'external_images' = > 1 ,
'postprocess' = > 1 ,
'instset_native' = > 1 ,
'instsetoo_native' = > 1 ,
'smoketest_native' = > 1 ,
'smoketestoo_native' = > 1 ) ;
2004-06-25 18:23:20 -05:00
#### global #####
2007-08-27 07:31:52 -05:00
my $ opt_debug = 0 ; # misc traces for debugging purposes
my $ opt_commit = 0 ; # commit changes
my $ opt_merge = 0 ; # merge from MWS into CWS
my $ opt_link = 0 ; # relink modules, update solver
my $ opt_remove_trees = 0 ; # remove output trees & solver (OO option)
my $ opt_complete_modules = 0 ; # checkout complete modules for merge ops
my @ args_bak = @ ARGV ; # store the @ARGS here for logging
my @ problem_log = ( ) ;
2004-06-25 18:23:20 -05:00
my $ umask = umask ( ) ;
if ( ! defined ( $ umask ) ) {
$ umask = 22 ;
}
2004-12-13 10:26:41 -06:00
my $ opt_force_checkout = '' ;
my $ opt_skip_update = 0 ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
# some overall stats
my % global_stats = ( 'new' = > 0 ,
'removed' = > 0 ,
'merged' = > 0 ,
'moved' = > 0 ,
'anchor' = > 0 ,
'conflict' = > 0 ,
'alert' = > 0 ,
'ignored' = > 0
) ;
2004-06-25 18:23:20 -05:00
#### main #####
my $ parameter_list = $ log - > array2string ( ";" , @ args_bak ) if ( defined $ log ) ;
my ( $ dir , $ milestone , @ args ) = parse_options ( ) ;
my $ cws = get_and_verify_cws ( ) ;
2004-09-07 03:52:22 -05:00
if ( $ milestone ) {
verify_milestone_or_exit ( $ cws , $ milestone ) ;
}
2005-04-22 07:35:09 -05:00
my @ action_list = parse_args ( $ cws , $ dir , $ milestone , @ args ) ;
2004-06-25 18:23:20 -05:00
walk_action_list ( $ cws , $ dir , $ milestone , @ action_list ) ;
2007-08-27 07:31:52 -05:00
print_plog ( ) ;
2004-08-23 05:26:52 -05:00
log_stats ( ) ;
2004-06-25 18:23:20 -05:00
exit ( 0 ) ;
#### subroutines ####
sub log_stats
{
my $ statistic_log_message ;
$ statistic_log_message = "success : " ;
$ statistic_log_message . = "merge mode : " if $ opt_merge ;
$ statistic_log_message . = "commit mode : " if $ opt_commit ;
$ statistic_log_message . = "link mode : " if $ opt_link ;
2004-12-13 10:26:41 -06:00
$ statistic_log_message . = "remove output trees mode : " if $ opt_remove_trees ;
2004-06-25 18:23:20 -05:00
$ statistic_log_message . = "new: $global_stats{'new'} " if $ global_stats { 'new' } ;
$ statistic_log_message . = "removed: $global_stats{'removed'} " if $ global_stats { 'removed' } ;
$ statistic_log_message . = "merged: $global_stats{'merged'} " if $ global_stats { 'merged' } ;
$ statistic_log_message . = "moved: $global_stats{'moved'} " if $ global_stats { 'moved' } ;
2007-08-27 07:31:52 -05:00
$ statistic_log_message . = "anchor: $global_stats{'anchor'} " if $ global_stats { 'anchor' } ;
2004-06-25 18:23:20 -05:00
$ statistic_log_message . = "conflicts: $global_stats{'conflict'} " if $ global_stats { 'conflict' } ;
$ statistic_log_message . = "alerts: $global_stats{'alert'} " if $ global_stats { 'alert' } ;
2007-08-27 07:31:52 -05:00
$ statistic_log_message . = "ignored: $global_stats{'ignored'} " if $ global_stats { 'ignored' } ;
2004-06-25 18:23:20 -05:00
$ log - > end_log_extended ( $ script_name , "unknown" , $ statistic_log_message ) if ( defined $ log ) ;
} ##create_log_stats
# Get child workspace from environment.
sub get_and_verify_cws
{
my $ childws = $ ENV { CWS_WORK_STAMP } ;
my $ masterws = $ ENV { WORK_STAMP } ;
if ( ! defined ( $ childws ) || ! defined ( $ masterws ) ) {
print_error ( "Can't determine child workspace environment.\n"
. "Please initialize environment with setsolar ..." , 1 ) ;
}
my $ cws = Cws - > new ( ) ;
$ cws - > child ( $ childws ) ;
$ cws - > master ( $ masterws ) ;
$ log - > start_log_extended ( $ script_name , $ parameter_list , $ masterws , $ childws ) if ( defined $ log ) ;
# check if we got a valid child workspace
my $ id = $ cws - > eis_id ( ) ;
2007-08-27 07:31:52 -05:00
print "Master: $masterws, Child: $childws, $id\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
if ( ! $ id ) {
print_error ( "Child workspace $childws for master workspace $masterws not found in EIS database." , 2 ) ;
}
return $ cws ;
}
# Parse options and do some sanity checks;
sub parse_options
{ my $ dir = 0 ;
my $ help = 0 ;
2007-08-27 07:31:52 -05:00
my $ success = GetOptions ( 'h' = > \ $ help , 'd=s' = > \ $ dir , 'debug' = > \ $ opt_debug ,
2004-06-25 18:23:20 -05:00
'm=s' = > \ $ opt_merge , 'c' = > \ $ opt_commit , 'l=s' = > \ $ opt_link ,
2004-12-13 10:26:41 -06:00
'a' = > \ $ opt_force_checkout , 'r' = > \ $ opt_remove_trees ,
2007-08-27 07:31:52 -05:00
'f' = > \ $ opt_skip_update , 'F' = > \ $ opt_complete_modules ) ;
2004-06-25 18:23:20 -05:00
if ( ! $ success || $ help ) {
usage ( ) ;
exit ( 1 ) ;
}
# some sanity checks
2004-12-13 10:26:41 -06:00
if ( ! ( $ opt_merge || $ opt_commit || $ opt_link || $ opt_remove_trees ) ) {
2004-06-25 18:23:20 -05:00
print_error ( "Please specify one of '-m', '-c', '-l'." , 0 ) if defined ( $ log ) ;
print_error ( "Please specify one of '-m', '-c', '-l', '-r'." , 0 ) if ! defined ( $ log ) ;
usage ( ) ;
exit ( 1 ) ;
}
if ( ( $ opt_merge || $ opt_commit ) && ! @ ARGV ) {
usage ( ) ;
exit ( 1 ) ;
}
2004-08-23 05:26:52 -05:00
my $ milestone = $ opt_merge || $ opt_link ;
2004-06-25 18:23:20 -05:00
if ( ( $ opt_merge && $ opt_commit ) ||
( $ opt_merge && $ opt_link ) ||
( $ opt_commit && $ opt_link ) )
{
print_error ( "The options '-m milestone', '-c', '-l milestone' are mutally exclusive." , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
if ( $ opt_link && $ dir ) {
print_error ( "The options '-l milestone' and '-d' are mutally exclusive." , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
2005-04-22 07:35:09 -05:00
if ( $ milestone eq 'HEAD' && $ opt_link ) {
print_error ( "'HEAD' is not a valid milestone for '-l milestone' option." , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
2007-08-27 07:31:52 -05:00
if ( $ opt_complete_modules && ! $ opt_merge ) {
print_error ( "option '-F' requires merge step (option '-m milestone' must be set)." , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
2004-06-25 18:23:20 -05:00
$ dir = $ dir ? $ dir : cwd ( ) ;
# check directory
if ( ! - d $ dir ) {
print_error ( "'$dir' is not a directory." , 1 ) ;
}
if ( ! - w $ dir ) {
print_error ( "Can't write to directory '$dir'." , 1 ) ;
}
2004-08-23 05:26:52 -05:00
return ( $ dir , $ milestone , @ ARGV ) ;
2004-06-25 18:23:20 -05:00
}
2004-12-13 10:26:41 -06:00
# Parse and verify args. Check that all necessary preconditions are fulfilled
2004-06-25 18:23:20 -05:00
# and fill the action_list
sub parse_args
{
2005-04-22 07:35:09 -05:00
my $ cws = shift ;
my $ dir = shift ;
my $ milestone = shift ;
2004-06-25 18:23:20 -05:00
my @ args = @ _ ;
# For each entry in the args list we'll prepare a corresponding entry
# in the action list. An arg may be a module, a dir in a cvs module
# or a file in a cvs module. With each arg is an action associated,
# this may be 'resync_module_action', 'resync_dir_action', 'resync_file_action',
# 'commit_dir_action', 'commit_file_action' or 'relink_cws_action' depending on the
# type of the arg and the operation mode
# The action list has the following format
# $action_list [$i] = [$arg, $action]
my @ action_list = ( ) ;
# The 'merge' and 'commit' modes share quite a bit of logic. The 'link' mode
# is completely independent
2004-12-13 10:26:41 -06:00
if ( ( @ args > 0 ) && ( $ opt_link || $ opt_remove_trees ) ) {
2004-06-25 18:23:20 -05:00
print_error ( "Invalid argument." , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
if ( $ opt_link ) {
push ( @ action_list , [ undef , 'relink_cws_action' ] ) ;
2004-12-13 10:26:41 -06:00
} elsif ( $ opt_remove_trees ) {
2004-06-25 18:23:20 -05:00
push ( @ action_list , [ undef , 'remove_output_trees' ] ) ;
}
else {
# Sanity check
if ( @ args > 1 ) {
foreach ( @ args ) {
if ( $ _ eq 'all' ) {
print_error ( "either specify 'all' or a list of modules/files." , 1 ) ;
}
}
}
2005-04-22 07:35:09 -05:00
# If HEAD is specified as milestone, make sure that every argument is really a file.
if ( $ milestone eq 'HEAD' ) {
foreach ( @ args ) {
if ( ! - f $ _ ) {
print_error ( "Only files are allowed as argument for resyncing against HEAD" , 0 ) ;
print_error ( "'$_' is not a file: $!" , 1 ) ;
}
}
}
2004-06-25 18:23:20 -05:00
if ( is_in_module ( $ dir ) ) {
# check arguments for inside module operation
check_or_exit ( $ cws , $ dir , @ args ) ;
foreach my $ arg ( @ args ) {
if ( - f $ arg ) {
my $ action = $ opt_commit ? 'commit_file_action' : 'resync_file_action' ;
push ( @ action_list , [ $ arg , $ action ] ) ;
}
else {
my $ action = $ opt_commit ? 'commit_dir_action' : 'resync_dir_action' ;
push ( @ action_list , [ $ arg , $ action ] ) ;
}
}
}
else {
my @ modules = expand_and_verify_modules ( $ cws , @ args ) ;
# check arguments for modules level operation
if ( is_scratch_dir ( $ dir ) ) {
my $ action = $ opt_commit ? 'commit_dir_action' : 'resync_module_action' ;
foreach ( @ modules ) {
push ( @ action_list , [ $ _ , $ action ] ) ;
}
}
else {
check_or_exit ( $ cws , $ dir , @ modules ) ;
my $ action = $ opt_commit ? 'commit_dir_action' : 'resync_dir_action' ;
foreach ( @ modules ) {
push ( @ action_list , [ $ _ , $ action ] ) ;
}
}
}
}
2005-04-22 07:35:09 -05:00
2004-06-25 18:23:20 -05:00
return @ action_list ;
}
# Check if all arguments are physically present on the disk
# either as files or directories
sub check_or_exit
{
my $ cws = shift ;
my $ dir = shift ;
my @ args = @ _ ;
my $ error ;
foreach my $ arg ( @ args ) {
if ( ! - e "$dir/$arg" ) {
print_error ( "Can't find '$dir/$arg': $!" , 0 ) ;
$ error + + ;
}
}
if ( $ error ) {
print_error ( "Please run '$script_name -m' either in an empty scratch directory," , 0 ) ;
2004-12-13 10:26:41 -06:00
print_error ( "or in a directory containing all specified modules," , 0 ) ;
2004-06-25 18:23:20 -05:00
print_error ( "or, if inside a module," , 0 ) ;
print_error ( "make certain that all specified files/directories exist." , 2 ) ;
}
return ;
}
# Check if we operate inside a module.
sub is_in_module
{
my $ dir = shift ;
return - d "$dir/CVS" ? 1 : 0 ;
}
# Check if directory contains modules
sub is_modules_level
{
my $ dir = shift ;
return 0 if is_in_module ( $ dir ) ;
my @ cvsdirs = glob ( "$dir/*/CVS" ) ;
return @ cvsdirs ? 1 : 0 ;
}
# Check if directory is a scratch directory
sub is_scratch_dir
{
my $ dir = shift ;
return ( is_in_module ( $ dir ) || is_modules_level ( $ dir ) ) ? 0 : 1 ;
}
# Check if requested modules are registered with child workspace.
sub expand_and_verify_modules
{
my $ cws = shift ;
my @ modules = @ _ ;
my @ registered_modules = $ cws - > modules ( ) ;
my $ child = $ cws - > child ( ) ;
# call with empty modules list
return @ registered_modules if $ modules [ 0 ] eq 'all' ;
# create hash for easier searching
my % registered_modules_hash = ( ) ;
for ( @ registered_modules ) {
$ registered_modules_hash { $ _ } + + ;
}
foreach ( @ modules ) {
if ( ! exists $ registered_modules_hash { $ _ } ) {
print_error ( "Module '$_' is not registered for child '$child'." , 2 ) ;
}
}
return @ modules ;
}
# Process the action list
sub walk_action_list
{
my $ cws = shift ;
my $ dir = shift ;
my $ qualified_milestone = shift ;
my @ action_list = @ _ ;
foreach my $ entry_ref ( @ action_list ) {
no strict ; # disable strict refs for the next call
& { $ entry_ref - > [ 1 ] } ( $ cws , $ dir , $ qualified_milestone , $ entry_ref - > [ 0 ] ) ;
}
2007-08-27 07:31:52 -05:00
if ( ! $ opt_link ) {
# emit some stats
print_message ( " ========== Totals: ==========" ) if scalar ( % global_stats ) ;
print_message ( "New file(s) : $global_stats{'new'}" ) if $ global_stats { 'new' } ;
print_message ( "Remove file(s) : $global_stats{'removed'}" ) if $ global_stats { 'removed' } ;
print_message ( "Merge file(s) : $global_stats{'merged'}" ) if $ global_stats { 'merged' } ;
print_message ( "Conflict(s) : $global_stats{'conflict'}" ) if $ global_stats { 'conflict' } ;
print_message ( "Move branch tag(s) : $global_stats{'moved'}" ) if $ global_stats { 'moved' } ;
print_message ( "Move anchor(s) : $global_stats{'anchor'}" ) if $ global_stats { 'anchor' } ;
print_message ( "Alert(s) : $global_stats{'alert'}" ) if $ global_stats { 'alert' } ;
print_message ( "Ignored : $global_stats{'ignored'}" ) if $ global_stats { 'ignored' } ;
2004-06-25 18:23:20 -05:00
}
return ;
}
2007-08-27 07:31:52 -05:00
# Merge a whole module in scratch space.
2004-06-25 18:23:20 -05:00
sub resync_module_action
{
my $ cws = shift ;
my $ dir = shift ;
my $ qualified_milestone = shift ;
my $ module = shift ;
2007-08-27 07:31:52 -05:00
print_message ( "" ) ;
print_message ( " ========== Merging '$module' ==========" ) ;
print_message ( "" ) ;
2004-06-25 18:23:20 -05:00
my ( $ master_branch_tag , $ cws_branch_tag , $ cws_anchor_tag ) = $ cws - > get_tags ( ) ;
my $ milestone_tag = get_milestone_tag ( $ cws , $ qualified_milestone ) ;
2007-08-27 07:31:52 -05:00
my $ cvs_handle = get_cvs_handle ( $ cws , 'config' , $ module ) ;
if ( ! defined ( $ cvs_handle ) ) {
2004-12-13 10:26:41 -06:00
print_warning ( "Skipping '$module' ..." ) ;
2007-08-27 07:31:52 -05:00
print_warning ( "This might happen if '$module' is obsolete." ) ;
2004-12-13 10:26:41 -06:00
return ;
}
2007-08-27 07:31:52 -05:00
print_message ( "Retrieving changes for '$module' ..." ) ;
my $ changes_ref = $ cvs_handle - > get_changed_files ( $ module , $ cws_anchor_tag , $ milestone_tag ) ;
my @ files_to_checkout ;
foreach ( @ { $ changes_ref } ) {
push ( @ files_to_checkout , $ _ - > [ 0 ] ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ nfiles_to_checkout = @ files_to_checkout ;
if ( $ opt_complete_modules ) {
print_message ( "Check out module '$module' ..." ) ;
$ cvs_handle - > checkout ( $ dir , $ module , undef , $ cws_branch_tag ) ;
}
elsif ( $ nfiles_to_checkout > 0 ) {
print_message ( "Check out $nfiles_to_checkout file(s) from module '$module' ..." ) ;
$ cvs_handle - > checkout ( $ dir , $ module , \ @ files_to_checkout , $ cws_branch_tag ) ;
}
else {
print_message ( "nothing to do for module '$module'" ) ;
2007-10-09 09:02:22 -05:00
# still create a directory even if nothing is to be done, for the benefit of the
# commit operation
if ( ! mkdir ( "$dir/$module" ) ) {
print_error ( "Can't mkdir() '$dir/$module': $!" , 6 ) ;
}
if ( ! open ( README , ">$dir/$module/readme" ) ) {
print_error ( "can't open file '$dir/$module/readme': $!" , 7 ) ;
}
print README "Nothing to be resynced here\n" ;
close ( README ) ;
2007-08-27 07:31:52 -05:00
return ;
}
2004-06-25 18:23:20 -05:00
my $ save_dir = cwd ( ) ;
# chdir into module
if ( ! chdir ( "$dir/$module" ) ) {
2007-10-09 09:02:22 -05:00
print_error ( "Can't chdir() to '$dir/$module': $!" , 6 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ stats_ref = merge_files ( $ cws_anchor_tag , $ milestone_tag , $ changes_ref , $ cvs_handle , $ module ) ;
2004-06-25 18:23:20 -05:00
# chdir back
chdir ( $ save_dir ) ;
2007-08-27 07:31:52 -05:00
$ global_stats { 'new' } += $ stats_ref - > { 'new' } ;
$ global_stats { 'removed' } += $ stats_ref - > { 'removed' } ;
$ global_stats { 'merged' } += $ stats_ref - > { 'merged' } ;
$ global_stats { 'moved' } += $ stats_ref - > { 'moved' } ;
$ global_stats { 'anchor' } += $ stats_ref - > { 'anchor' } ;
$ global_stats { 'conflict' } += $ stats_ref - > { 'conflict' } ;
$ global_stats { 'alert' } += $ stats_ref - > { 'alert' } ;
$ global_stats { 'ignored' } += $ stats_ref - > { 'ignored' } ;
print_message ( " ---------- '$module' stats:-----------" ) if scalar ( % { $ stats_ref } ) ;
print_message ( "New file(s) : $stats_ref->{'new'}" ) if $ stats_ref - > { 'new' } ;
print_message ( "Remove file(s) : $stats_ref->{'removed'}" ) if $ stats_ref - > { 'removed' } ;
print_message ( "Merge file(s) : $stats_ref->{'merged'}" ) if $ stats_ref - > { 'merged' } ;
print_message ( "Conflict(s) : $stats_ref->{'conflict'}" ) if $ stats_ref - > { 'conflict' } ;
print_message ( "Move tag(s) : $stats_ref->{'moved'}" ) if $ stats_ref - > { 'moved' } ;
print_message ( "Move anchor(s) : $stats_ref->{'anchor'}" ) if $ stats_ref - > { 'anchor' } ;
print_message ( "Alert(s) : $stats_ref->{'alert'}" ) if $ stats_ref - > { 'alert' } ;
print_message ( "Ignored file(s): $stats_ref->{'ignored'}" ) if $ stats_ref - > { 'ignored' } ;
2004-06-25 18:23:20 -05:00
return ;
}
2007-08-27 07:31:52 -05:00
# resync_dir_action: not possible
2004-06-25 18:23:20 -05:00
sub resync_dir_action
{
my $ cws = shift ;
my $ dir = shift ;
my $ qualified_milestone = shift ;
my $ cvs_dir = shift ;
2007-08-27 07:31:52 -05:00
print_error ( "Resyncing directories is not possible." , 0 ) ;
2004-06-25 18:23:20 -05:00
print_error ( "Please resync either complete modules in a scratch" , 0 ) ;
2007-08-27 07:31:52 -05:00
print_error ( "directory or resync a list of files," , 99 ) ;
2004-06-25 18:23:20 -05:00
return ;
}
sub resync_file_action
{
my $ cws = shift ;
2007-08-27 07:31:52 -05:00
my $ dir = shift ; # unused, remove me
2004-06-25 18:23:20 -05:00
my $ qualified_milestone = shift ;
my $ file = shift ;
2007-08-27 07:31:52 -05:00
if ( exists $ resync_silent_ignore_files { basename ( $ file ) } ) {
print_error ( "Can't resync special file '$file'!" , 33 ) ;
2005-04-22 07:35:09 -05:00
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my ( $ master_branch_tag , $ cws_branch_tag , $ cws_anchor_tag ) = $ cws - > get_tags ( ) ;
my $ milestone_tag ;
2005-04-22 07:35:09 -05:00
if ( $ qualified_milestone eq 'HEAD' ) {
2007-08-27 07:31:52 -05:00
$ milestone_tag = $ master_branch_tag ? $ master_branch_tag : 'HEAD' ;
2005-04-22 07:35:09 -05:00
}
else {
2007-08-27 07:31:52 -05:00
$ milestone_tag = get_milestone_tag ( $ cws , $ qualified_milestone ) ;
2005-04-22 07:35:09 -05:00
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my $ directory = dirname ( $ file ) ;
my $ cvs_handle = get_cvs_handle ( $ cws , 'directory' , $ directory ) ;
if ( ! defined ( $ cvs_handle ) ) {
print_message ( "resync_file_action(): can't get cvs_handle" ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ rep = $ cvs_handle - > get_relative_path ( $ directory ) ;
print_message ( "Retrieving changes for '$file' ..." ) ;
my $ changes_ref = $ cvs_handle - > get_changed_files ( "$rep/$file" , $ cws_anchor_tag , $ milestone_tag ) ;
if ( ! @ { $ changes_ref } ) {
print_warning ( "'$file' already on resync level '$milestone_tag'\n" ) ;
exit ( 0 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
# changes_ref contains the path to the file relative to the module (including module prefix)
# replace with local path
$ changes_ref - > [ 0 ] - > [ 0 ] = $ file ;
my $ stats_ref = merge_files ( $ cws_anchor_tag , $ milestone_tag , $ changes_ref , $ cvs_handle , '' ) ;
$ global_stats { 'new' } += $ stats_ref - > { 'new' } ;
$ global_stats { 'removed' } += $ stats_ref - > { 'removed' } ;
$ global_stats { 'merged' } += $ stats_ref - > { 'merged' } ;
$ global_stats { 'moved' } += $ stats_ref - > { 'moved' } ;
$ global_stats { 'anchor' } += $ stats_ref - > { 'anchor' } ;
print_message ( "New file(s): $stats_ref->{'new'}" ) if $ stats_ref - > { 'new' } ;
print_message ( "Removed file(s): $stats_ref->{'removed'}" ) if $ stats_ref - > { 'removed' } ;
print_message ( "Commit file(s): $stats_ref->{'merged'}" ) if $ stats_ref - > { 'merged' } ;
print_message ( "Move branch tag(s): $stats_ref->{'moved'}" ) if $ stats_ref - > { 'moved' } ;
print_message ( "Move anchor tags(s): $stats_ref->{'anchor'}" ) if $ stats_ref - > { 'anchor' } ;
2004-06-25 18:23:20 -05:00
return ;
}
sub commit_dir_action
{
my $ cws = shift ;
my $ dir = shift ;
my $ qualified_milestone = shift ; # unused and not initialized
my $ cvs_dir = shift ;
print_message ( "========== Commit changes to '$cvs_dir': ==========" ) ;
my $ save_dir = cwd ( ) ;
# chdir into module
if ( ! chdir ( "$dir/$cvs_dir" ) ) {
2004-12-13 10:26:41 -06:00
print_warning ( "Can't chdir() to '$cvs_dir'." ) ;
print_warning ( "Skipping '$cvs_dir'." ) ;
return ;
2004-06-25 18:23:20 -05:00
}
local @ main:: changed_files ;
find ( \ & wanted , '.' ) ;
2007-10-09 09:02:22 -05:00
if ( @ main:: changed_files ) {
my $ stats_ref = commit_files ( $ cws , \ @ main:: changed_files , $ cvs_dir ) ;
2004-06-25 18:23:20 -05:00
2007-10-09 09:02:22 -05:00
$ global_stats { 'merged' } += $ stats_ref - > { 'merged' } ;
$ global_stats { 'moved' } += $ stats_ref - > { 'moved' } ;
$ global_stats { 'anchor' } += $ stats_ref - > { 'anchor' } ;
print_message ( " ========== '$cvs_dir' stats: ==========" ) if scalar ( % { $ stats_ref } ) ;
print_message ( "Commit file(s) : $stats_ref->{'merged'}" ) if $ stats_ref - > { 'merged' } ;
print_message ( "Move branch tag(s) : $stats_ref->{'moved'}" ) if $ stats_ref - > { 'moved' } ;
print_message ( "Move anchor tags(s): $stats_ref->{'anchor'}" ) if $ stats_ref - > { 'anchor' } ;
}
2004-06-25 18:23:20 -05:00
2007-10-09 09:02:22 -05:00
chdir ( $ save_dir ) ;
2004-06-25 18:23:20 -05:00
return ;
}
sub commit_file_action
{
my $ cws = shift ;
2007-08-27 07:31:52 -05:00
my $ dir = shift ; # ununsed, remove me
2004-06-25 18:23:20 -05:00
my $ qualified_milestone = shift ; # unused and not initialized
my $ file = shift ;
2007-08-27 07:31:52 -05:00
my $ cvs_dir = dirname ( $ file ) ;
if ( ! - e "$file.resync" ) {
print_error ( "Can't find '$file.resync'. Please use the 'cwsresync -m' step on file '$file' first." , 55 )
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ stats_ref = commit_files ( $ cws , [ $ file ] , $ cvs_dir ) ;
$ global_stats { 'merged' } += $ stats_ref - > { 'merged' } ;
$ global_stats { 'moved' } += $ stats_ref - > { 'moved' } ;
$ global_stats { 'anchor' } += $ stats_ref - > { 'anchor' } ;
print_message ( "Commit file(s) : $stats_ref->{'merged'}" ) if $ stats_ref - > { 'merged' } ;
print_message ( "Move branch tag(s) : $stats_ref->{'moved'}" ) if $ stats_ref - > { 'moved' } ;
print_message ( "Move anchor tags(s): $stats_ref->{'anchor'}" ) if $ stats_ref - > { 'anchor' } ;
2004-06-25 18:23:20 -05:00
return ;
}
# TODO: put into module later... see also cwsadd.pl
sub get_mws_location
{
use GenInfoParser ;
my $ masterws = shift ;
my $ result = 0 ;
my $ workspace_lst = EnvHelper:: get_workspace_lst ( ) ;
my $ workspace_db = GenInfoParser - > new ( ) ;
$ result = $ workspace_db - > load_list ( $ workspace_lst ) ;
if ( ! $ result ) {
print_message ( "Can't load workspace list '$workspace_lst'." ) ;
return "" ;
}
my $ workspace = $ workspace_db - > get_key ( $ masterws ) ;
print_error ( "Master workspace '$masterws' not found in '$workspace_lst' database." , 3 ) if ( ! $ workspace ) ;
my $ wslocation = $ workspace_db - > get_value ( $ masterws . "/Drives/o:/UnixVolume" ) ;
print_error ( "Location of master workspace '$masterws' not found in '$workspace_lst' database." , 3 ) if ( ! defined ( $ wslocation ) ) ;
if ( ! - d $ wslocation ) {
2006-02-20 04:59:06 -06:00
print_message ( "Master workspace not found at '$wslocation'!" ) ;
2004-06-25 18:23:20 -05:00
return "" ;
}
return $ wslocation ;
}
sub remove_module
{
my $ module_p = shift ;
my $ result = 0 ;
if ( - l $ module_p ) {
2007-08-27 07:31:52 -05:00
print "unlink module $module_p\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
$ result |= ! unlink $ module_p ;
}
if ( - l $ module_p . ".lnk" ) {
2007-08-27 07:31:52 -05:00
print "unlink module $module_p.lnk\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
$ result |= ! unlink "$module_p.lnk" ;
}
if ( - d $ module_p ) {
2007-08-27 07:31:52 -05:00
print "rm -rf $module_p\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
$ result |= system ( "rm -rf $module_p" ) ;
} elsif ( - e $ module_p ) {
2007-08-27 07:31:52 -05:00
print "no idea what this is... $module_p\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
print_error ( "Couldn't remove $module_p\[.lnk\]. Giving up." , 1 ) ;
}
return $ result ;
}
#
# Procedure copies module to specified path
#
sub copyprj_module
{
my $ module_name = shift ;
my $ src_dest = shift ;
print "copyprj $module_name\n" ;
# hash, that should contain all the
# data needed by CopyPrj module
my % ENVHASH = ( ) ;
my % projects_to_copy = ( ) ;
$ ENVHASH { 'projects_hash' } = \ % projects_to_copy ;
$ ENVHASH { 'no_otree' } = 1 ;
$ ENVHASH { 'no_path' } = 1 ;
$ ENVHASH { 'only_otree' } = 0 ;
$ ENVHASH { 'only_update' } = 1 ;
$ ENVHASH { 'last_minor' } = 0 ;
$ ENVHASH { 'spec_src' } = 0 ;
$ ENVHASH { 'dest' } = "$src_dest" ;
$ ENVHASH { 'prj_to_copy' } = '' ;
$ ENVHASH { 'i_server' } = '' ;
$ ENVHASH { 'current_dir' } = cwd ( ) ;
$ ENVHASH { 'remote' } = '' ;
2005-01-24 08:07:16 -06:00
$ ENVHASH { 'force_checkout' } = 1 if ( $ opt_force_checkout ) ;
$ ENVHASH { RESYNC_UPDMINOR } = $ opt_link if ( defined $ opt_link ) ;
2004-06-25 18:23:20 -05:00
$ projects_to_copy { $ module_name } + + ;
CopyPrj:: copy_projects ( \ % ENVHASH ) ;
} ;
sub get_platforms_hash {
my $ cws = shift ;
my $ minor_mk_name = $ ENV { UPD } . 'minor.mk' ;
my @ files ;
my % platforms = ( ) ;
find sub { push @ files , $ File:: Find:: name if - f _ && /$minor_mk_name/ } , $ ENV { SOLARVER } ;
foreach my $ entry ( @ files ) {
do {
$ entry = dirname ( $ entry ) ;
} while ( $ entry =~ /[\\\/]inc[\.\w+]?$/o ) ;
$ platforms { basename ( $ entry ) } + + ;
} ;
$ platforms { $ ENV { INPATH } } + + ;
return % platforms ;
}
#
# remove all output trees
#
sub remove_output_trees {
my $ cws = shift ;
my % platforms = get_platforms_hash ( $ cws ) ;
my $ stand_dir = $ ENV { SRC_ROOT } ;
if ( ! opendir ( SOURCE_ROOT , $ stand_dir ) ) {
print_error ( "Root dir of child workspace not accessible: $!" , 1 ) ;
} ;
my @ found_dirs = readdir ( SOURCE_ROOT ) ;
closedir SOURCE_ROOT ;
my $ module_dir = '' ;
my @ warnings = ( ) ;
foreach my $ module ( @ found_dirs ) {
$ module_dir = "$stand_dir/$module" ;
next if ( ! - d $ module_dir ) ;
print_message ( "Removing output trees from $module..." ) ;
foreach my $ plarform ( keys % platforms ) {
my $ output_tree = "$module_dir/$plarform" ;
next if ( ! - d $ output_tree ) ;
if ( ! rmtree ( $ output_tree , 0 , 1 ) ) {
push ( @ warnings , $ output_tree ) ;
} ;
}
} ;
print_message ( "Removing solver ..." ) ;
foreach my $ platform ( keys % platforms ) {
my $ output_tree = $ ENV { SOLARVERSION } . "/$platform" ;
next if ( ! - d $ output_tree ) ;
if ( ! rmtree ( $ output_tree , 0 , 1 ) ) {
push ( @ warnings , $ output_tree ) ;
} ;
} ;
print_warning ( "'$_' cannot be deleted. Please remove it manually" ) foreach ( @ warnings ) ;
print_message ( "Please run configure & bootstrap again\n" ) if ! defined ( $ log ) ;
} ;
#
# Update the sources to the correspondent master tag
#
sub update_sources {
my ( $ cws , $ new_master , $ milestone ) = @ _ ;
my @ added_modules = $ cws - > modules ( ) ;
my % added_modules_hash = ( ) ;
my ( $ master_branch_tag , $ cws_branch_tag , $ cws_root_tag ) = $ cws - > get_tags ( $ new_master , $ milestone ) ;
my $ master_milestone_tag = $ cws - > get_master_tag ( $ new_master , $ milestone ) ;
my $ stand_dir = $ ENV { SRC_ROOT } ;
$ added_modules_hash { $ _ } + + foreach ( @ added_modules ) ;
if ( ! opendir ( SOURCE_ROOT , $ stand_dir ) ) {
print_error ( "Root dir of child ($stand_dir) workspace not accessible: $!" , 1 ) ;
} ;
2004-12-13 10:26:41 -06:00
2005-12-06 10:55:23 -06:00
my @ found_dirs = ( ) ;
my $ cvs_module ;
my % cvs_aliases ;
2004-12-13 10:26:41 -06:00
if ( $ opt_skip_update ) {
print "Skipping main tree update\n" ;
}
2005-12-06 10:55:23 -06:00
else {
@ found_dirs = readdir ( SOURCE_ROOT ) ;
closedir ( SOURCE_ROOT ) ;
# TODO clean this incredible mess up
$ cvs_module = get_cvs_module ( 'solenv' ) ; # solenv always on OOo CVS server
% cvs_aliases = $ cvs_module - > get_aliases_hash ( ) ;
}
2004-06-25 18:23:20 -05:00
foreach my $ module ( @ found_dirs ) {
next if ( ! - d $ stand_dir . "/$module/CVS" ) ;
print "\tUpdating '$module'" ;
$ cvs_module - > module ( $ module ) ;
2005-12-06 10:55:23 -06:00
my $ result = '' ;
2004-06-25 18:23:20 -05:00
if ( defined $ added_modules_hash { $ module } ) {
print " with '$cws_branch_tag' ...\n" ;
$ result = $ cvs_module - > update ( $ stand_dir , $ cws_branch_tag , '-dP' ) ;
delete $ added_modules_hash { $ module } ;
} elsif ( defined $ cvs_aliases { $ module } ) {
print " with $master_milestone_tag' ...\n" ;
$ result = $ cvs_module - > update ( $ stand_dir , $ master_milestone_tag , '-dP' ) ;
} else {
print_warning ( "... Unknown module. Skipping..." ) ;
next ;
} ;
2004-12-13 10:26:41 -06:00
$ cvs_module - > handle_update_information ( $ result ) ;
2004-06-25 18:23:20 -05:00
} ;
register_cws_milestone ( $ cws , $ new_master , $ milestone ) ;
return ;
} ;
sub register_cws_milestone {
my ( $ cws , $ new_master , $ milestone ) = @ _ ;
if ( $ cws - > master ( ) ne $ new_master ) {
2008-02-18 02:12:35 -06:00
my @ push_return = $ cws - > set_master_and_milestone ( $ new_master , $ milestone ) ;
if ( ( $ push_return [ 0 ] ne $ new_master ) || ( $ push_return [ 1 ] ne $ milestone ) ) {
print_error ( "Couldn't push new master and milestone to database" , 1 ) ;
2004-06-25 18:23:20 -05:00
} ;
2008-02-18 02:12:35 -06:00
} else {
my $ push_return = '' ;
$ push_return = $ cws - > milestone ( $ milestone ) ;
if ( $ push_return ne $ milestone ) {
print_error ( "Couldn't push new milestone to database" , 1 ) ;
}
2004-06-25 18:23:20 -05:00
}
print_message ( "Current milestone of CWS updated to '$milestone'." ) ;
print_message ( "Remove the old and most likely incompatible module output trees and solver with:" ) ;
print_message ( "\tcwsresync -r" ) ;
}
# Implements the link action: relink all modules and update solver
sub relink_cws_action
{
my $ cws = shift ;
my $ dir = shift ; # ignore, this is never set
my $ qualified_milestone = shift ;
my $ cws_master = $ cws - > master ( ) ;
my ( $ new_master , $ milestone ) ;
if ( $ qualified_milestone =~ /:/ ) {
( $ new_master , $ milestone ) = split ( /:/ , $ qualified_milestone ) ;
}
else {
$ new_master = $ cws_master ;
$ milestone = $ qualified_milestone ;
}
# ause: Deine Spielwiese
no warnings ;
my $ result = 0 ;
my $ success = 0 ;
my $ sourceroot ;
my $ mws_location ;
my $ mws_accessible = 0 ;
my $ dest_dir ;
my @ found_platforms ;
my @ opt_platforms ;
my $ found_resync_flags = 0 ;
print_message ( "Doing some checks ..." ) ;
2004-12-13 10:26:41 -06:00
# hack to get the milestone :-(((((
2004-06-25 18:23:20 -05:00
if ( ! defined ( $ cws - > milestone ( ) ) )
{
$ cws - > milestone ( $ ENV { UPDMINOR } ) ; # = $ENV{UPDMINOR};
}
# milestone is different from the current milestone
if ( "$new_master" eq "$cws_master" ) {
print_error ( "Child workspace \"" . $ cws - > child ( ) . "\" already based on milestone \"$milestone\"" , 1 ) if $ cws - > milestone ( ) eq $ milestone ;
}
return update_sources ( $ cws , $ new_master , $ milestone ) if ( ! defined $ log ) ; # HACK
# SOURCE_ROOT set correct
print_error ( "Environment variable \"SOURCE_ROOT\" not set." , 1 ) if ! defined ( $ ENV { SOURCE_ROOT } ) ;
$ sourceroot = $ ENV { SOURCE_ROOT } ;
print_error ( "Environment variable \"SOURCE_ROOT\" pointing to something incorrect." , 1 ) if ! - d "$sourceroot/" . $ cws_master . "/src." . $ cws - > milestone ( ) ;
# desired milestone doesn't exist in cws dir or mws changes
if ( "$new_master" eq "$cws_master" ) {
print_error ( "Looks like there is already a milestone \"$milestone\" in $sourceroot/" . $ cws_master . "." , 1 ) if - d "$sourceroot/" . $ cws_master . "/src.$milestone" ;
my @ checklist = glob ( "$sourceroot/$cws_master/*/inc.$milestone/*.mk" ) ;
print_message ( "Looks like there is already a milestone \"$milestone\" in $sourceroot/" . $ cws_master . " output trees." ) if $# checklist != - 1 ;
}
# mws filesystem accessible
$ mws_location = get_mws_location ( $ new_master ) ;
if ( "$mws_location" ne "" ) {
# our OS isn't windows
2004-08-12 09:11:19 -05:00
if ( $^O =~ "MSWin32" || $^O =~ "cygwin" ) {
2004-06-25 18:23:20 -05:00
print_error ( "Sorry! not for windows" , 2 ) ;
}
$ mws_accessible = 1 ;
} else {
print_message ( "Trying without access to master workspace." ) ;
$ mws_accessible = 0 ;
}
#check if sourceroot points to mws location
2007-08-27 07:31:52 -05:00
print "$sourceroot <-> $mws_location\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
my $ mws_location_string = $ mws_location ;
if ( $ mws_location_string =~ /\/net/ ) {
my @ tmplst = split /\// , $ mws_location ;
2007-08-27 07:31:52 -05:00
print "list @tmplst\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
shift @ tmplst ;
shift @ tmplst ;
shift @ tmplst ;
2007-08-27 07:31:52 -05:00
print "list @tmplst\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
$ mws_location_string = "/" . join '/' , @ tmplst ;
}
2007-08-27 07:31:52 -05:00
print "$sourceroot <-> $mws_location_string\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
if ( $ sourceroot =~ /$mws_location_string/ ) {
print_error ( "Root dir of child workspace and master directory are too similar\n$sourceroot <-> *$mws_location_string" , 1 )
}
print_message ( "Updating solver." ) ;
2005-04-22 07:35:09 -05:00
my @ added_modules = $ cws - > modules ( ) ;
2004-06-25 18:23:20 -05:00
if ( $ mws_accessible )
{
require sync_dir ; import sync_dir ;
#TODO: check for complete mws milestone
print_message ( "Removing previous solver..." ) ;
# find all existing output trees in cws
$ result = opendir ( SOLVER , "$sourceroot/" . $ cws_master ) ;
if ( ! $ result ) { print_error ( "Root dir of child workspace not accessible: $!" , 1 ) } ;
my @ found_dirs = readdir ( SOLVER ) ;
closedir ( SOLVER ) ;
foreach my $ dir_candidate ( @ found_dirs )
{
#remove . and ..
next if ( $ dir_candidate eq "." || $ dir_candidate eq ".." ) ;
# check for the remains of previous tries...
if ( - d "$sourceroot/$cws_master/$dir_candidate/inc.$milestone" ) {
# check if there is a complete tree
if ( - f "$sourceroot/$cws_master/$dir_candidate/inc.$milestone/$platform_resynced_flag" ) {
$ found_resync_flags + + ;
next ;
}
# try to remove rubbish...
$ result = system ( "rm -rf $sourceroot/$cws_master/$dir_candidate/*.$milestone" ) ;
if ( $ result ) {
print_error ( "Couldn't cleanup \"$sourceroot/$cws_master/$dir_candidate/*.$milestone\". Please do manually!" , 1 ) ;
}
# ...and fake the old minor.
$ result = mkpath ( "$sourceroot/" . $ cws_master . "/$dir_candidate/inc." . $ cws - > milestone ( ) , 0 , 0777 - $ umask ) ;
}
if ( - d "$sourceroot/" . $ cws_master . "/$dir_candidate/inc." . $ cws - > milestone ( ) )
{
push @ found_platforms , $ dir_candidate ;
}
}
if ( ! @ found_platforms )
{
print_message ( "No output trees to remove" ) ;
$ success = 0 ;
}
# remove them
$ result = 0 ;
foreach my $ platform ( @ found_platforms ) {
next if ( - f "$sourceroot/$cws_master/$platform/inc.$milestone/$platform_resynced_flag" ) ;
print_message ( "Removing $platform" ) ;
if ( - d "$sourceroot/$cws_master/$platform" ) {
# make sure it's recognized when restarting
my $ tmp_result = mkpath ( "$sourceroot/$cws_master/$platform/inc.$milestone" , 0 , 0777 - $ umask ) ;
$ result |= system ( "rm -rf $sourceroot/$cws_master/$platform/*." . $ cws - > milestone ( ) ) ;
} else {
print_error ( "\"$sourceroot/$cws_master/$platform\" isn't a directory," , 0 ) ;
print_error ( "trying to rename..." , 0 ) ;
$ result |= system ( "mv $sourceroot/$cws_master/$platform $sourceroot/$cws_master/$platform.renamed" ) ;
}
}
print_error ( "Couldn\'t remove existing solver on child workspace." , 1 ) if $ result ;
# find all existing output trees in mws or use list
# no opt list yet - take the trees that were use before resync
@ opt_platforms = @ found_platforms ;
@ found_platforms = ( ) ;
# find platforms to copy
if ( $# opt_platforms != - 1 || $ found_resync_flags > 0 ) {
@ found_platforms = map ( lc , @ opt_platforms ) ;
} else {
print_error ( "this is an implementaion bug!" , 1 ) ;
}
# copy all wanted output trees
$ sync_dir:: do_keepzip = 1 ;
2007-03-12 09:50:49 -05:00
sync_dir:: set_excludelist ( \ @ added_modules ) ; # omit added modules
sync_dir:: addto_excludelist ( [ "instset_native" , "instsetoo_native" ] ) ; # omit instset* modules
2004-09-09 08:48:46 -05:00
my $ btarget = "finalize" ;
2004-06-25 18:23:20 -05:00
foreach my $ platform ( @ found_platforms )
{
2004-12-13 10:26:41 -06:00
# don't copy tree that was already successful
2004-06-25 18:23:20 -05:00
next if ( - f "$sourceroot/$cws_master/$platform/inc.$milestone/$platform_resynced_flag" ) ;
% sync_dir:: done_hash = ( ) ;
print "Create copy of solver for $platform ( ~ 1GB disk space needed !)\n" ;
my $ zipsource = "$mws_location/" . $ new_master . "/$platform/zip.$milestone" ;
my $ copy_dest = "$sourceroot/" . $ cws_master . "/$platform/zip.$milestone" ;
if ( - d "$sourceroot/" . $ cws_master . "/$platform" )
{
# print_error ("$dir/$platform : Please restart on a clean directory tree!", 1);
}
if ( ! - d $ copy_dest )
{
$ result = mkpath ( $ copy_dest , 0 , 0777 - $ umask ) ;
if ( ! $ result ) { print_error ( "Cannot create output tree $copy_dest : $!" , 1 ) } ;
}
my $ unzip_dest = $ copy_dest ;
$ unzip_dest =~ s/(.*)\/.*$/$1/ ;
if ( ! - e "$unzip_dest/prepared" ) {
$ result = sync_dir:: prepare_minor_unzip ( $ unzip_dest , "." . $ milestone ) ;
open ( PREPARED , ">$unzip_dest/prepared" ) ;
close ( PREPARED ) ;
}
STDOUT - > autoflush ( 1 ) ;
$ result = & sync_dir:: recurse_unzip ( $ zipsource , $ copy_dest , $ btarget ) ;
STDOUT - > autoflush ( 0 ) ;
if ( $ result )
{
# renaming back before exit
$ result = sync_dir:: finish_minor_unzip ( $ unzip_dest , "." . $ milestone ) ;
print_error ( "Copying files to $copy_dest failed : $!" , 1 ) ;
}
$ result = sync_dir:: finish_minor_unzip ( $ unzip_dest , "." . $ milestone ) ;
unlink "$unzip_dest/prepared.$milestone" if - e "$unzip_dest/prepared.$milestone" ;
open ( COMPLETE , ">$sourceroot/$cws_master/$platform/inc.$milestone/$platform_resynced_flag" ) ;
close ( COMPLETE ) ;
2006-06-20 06:38:38 -05:00
# cleanup: remove zip files
print "remove zip.$milestone\n" ;
$ result = system ( "rm -rf $copy_dest" ) ;
if ( $ result ) {
print_warning ( "Could not clean up zip file directory 'copy_dest'" ) ;
}
2004-06-25 18:23:20 -05:00
}
foreach my $ oneextra ( @ xtra_files )
{
my @ globlist = glob ( "$mws_location/" . $ new_master . "/[!s]*/*.$milestone/$oneextra" ) ;
if ( $# globlist == - 1 ) {
print "tried $oneextra in $mws_location/" . $ new_master . "/[!s]*/*.$milestone/$oneextra\n" ;
}
foreach my $ onefile ( @ globlist )
{
my $ destfile = $ onefile ;
my $ m_dir = "$mws_location/" . $ new_master ;
my $ c_dir = "$sourceroot/" . $ cws_master ;
$ destfile =~ s #$m_dir#$c_dir#;
2006-11-24 09:20:34 -06:00
if ( - d dirname ( $ destfile ) )
2004-06-25 18:23:20 -05:00
{
2006-11-24 09:20:34 -06:00
$ result = copy ( $ onefile , $ destfile ) ;
if ( ! $ result ) { print_error ( "Copying $onefile to CWS failed: $!" , 1 ) } ;
# preserve timestamp
my @ from_stat = stat ( $ onefile ) ;
utime ( $ from_stat [ 9 ] , $ from_stat [ 9 ] , $ destfile ) ;
2004-06-25 18:23:20 -05:00
}
}
}
} else {
print_error ( "solver tree resync without mws access not yet implemented" , 5 ) ;
}
print_message ( "Recreating CWS source tree with MWS milestone '$milestone'." ) ;
if ( $ mws_accessible ) {
# all but added modules
my % modules_hash = ( ) ;
2007-08-27 07:31:52 -05:00
print "debug: added modules: @added_modules\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
$ result = opendir ( SOURCE , "$mws_location/" . $ new_master . "/src." . $ milestone ) ;
if ( ! $ result ) { print_error ( "Source dir of master workspace not accessible: $!" , 1 ) } ;
my @ mws_found_modules = readdir ( SOURCE ) ;
closedir ( SOURCE ) ;
foreach my $ module ( @ mws_found_modules ) { $ modules_hash { $ module } + + ; }
delete $ modules_hash { "." } ;
delete $ modules_hash { ".." } ;
foreach my $ module ( @ added_modules ) { delete $ modules_hash { $ module } ; }
if ( ! scalar ( keys ( % modules_hash ) ) )
{
print_error ( "No valid source tree to copy" , 0 ) ;
$ success = 0 ;
}
2007-08-27 07:31:52 -05:00
print "debug: number of modules left: " . scalar ( keys ( % modules_hash ) ) . "\n" if $ opt_debug ;
2004-06-25 18:23:20 -05:00
# now remove them
print_message ( "Removing old modules" ) ;
$ dest_dir = "$sourceroot/" . $ cws_master . "/src." . $ cws - > milestone ( ) ;
$ result = 0 ;
# don't touch solenv if added
if ( defined $ modules_hash { "solenv" } ) {
# backup "solenv" for restarting...
$ result = system ( "mv $dest_dir/solenv $dest_dir/solenv.keep" ) ;
print_error ( "Couldn't backup \"solenv\". You better check your tree..." , 1 ) if $ result ;
}
foreach my $ module ( keys % modules_hash ) {
my $ module_path = $ dest_dir . "/$module" ;
$ result |= remove_module ( $ module_path ) ;
}
print_error ( "Couldn\'t cleanup source tree. Please check." , 1 ) if ( $ result ) ;
# copy instset, res, solenv, link all missing
# preparing pseudo environment for copyprj
$ ENV { SRC_ROOT } = "$mws_location/" . $ new_master . "/src.$milestone" ;
$ success = 1 ;
foreach my $ module ( keys % modules_hash ) {
# copy modules which are required to be accessable with their
# orginal name without .lnk extension
if ( defined $ obligatory_modules { $ module } ) {
& copyprj_module ( $ module , $ dest_dir ) ;
next ;
} ;
if ( - d "$mws_location/" . $ new_master . "/src.$milestone/$module" ) {
if ( - l "$dest_dir/$module.lnk" &&
readlink ( "$dest_dir/$module.lnk" ) eq "$mws_location/" . $ new_master . "/src.$milestone/$module" )
{
next ;
} else {
# better...
$ result = symlink ( "$mws_location/" . $ new_master . "/src.$milestone/$module" , "$dest_dir/$module.lnk" ) ;
}
if ( ! $ result ) {
print_error ( "Couldn't create link from $mws_location/" . $ new_master . "/src.$milestone/$module to $dest_dir/$module" , 0 ) ;
$ success = 0 ;
}
}
}
if ( defined $ modules_hash { "solenv" } ) {
my $ solenv_path = $ dest_dir . "/solenv.keep" ;
$ result |= remove_module ( $ solenv_path ) ;
}
} else {
print_error ( "source tree resync without mws access not yet implemented" , 5 ) ;
# remove all but added modules
# checkout all missing
}
# rename src.* directory
rename $ dest_dir , "$sourceroot/" . $ cws_master . "/src.$milestone" ;
# master changed?
if ( $ cws_master ne $ new_master ) {
# push new master if different
2008-02-18 02:12:35 -06:00
my @ push_return = $ cws - > set_master_and_milestone ( $ new_master , $ milestone ) ;
if ( ( $ push_return [ 0 ] ne $ new_master ) || ( $ push_return [ 1 ] ne $ milestone ) ) {
print_error ( "Couldn't push new master and milestone to database" ) ;
2006-06-20 06:38:38 -05:00
} else {
2008-02-18 02:12:35 -06:00
print_message ( "Successfully pushed new master and milestone to database" ) ;
2004-06-25 18:23:20 -05:00
}
# rename WORKSPACE directory if different
chdir ( $ sourceroot ) if ( cwd ( ) eq "$sourceroot/cws_master" ) ;
rename "$sourceroot/$cws_master" , "$sourceroot/$new_master" ;
chdir ( "$sourceroot/$new_master" ) if ( cwd ( ) eq "$sourceroot" ) ;
2008-02-18 02:12:35 -06:00
} else {
my $ push_return = $ cws - > milestone ( $ milestone ) ;
if ( $ push_return ne $ milestone ) {
print_error ( "Couldn't push new milestone to database" ) ;
} else {
print_message ( "Successfully pushed new milestone to database" ) ;
}
2004-06-25 18:23:20 -05:00
}
# resync done. now remove all $platform_resynced_flag
my @ completelist = glob ( "$sourceroot/$new_master/*/inc.$milestone/$platform_resynced_flag" ) ;
unlink ( @ completelist ) ;
return ;
}
# Low level merge file routine:
# Merge changes on master copy into the child copy of the file.
2007-08-27 07:31:52 -05:00
sub merge_files
2004-06-25 18:23:20 -05:00
{
2007-08-27 07:31:52 -05:00
my $ cws_anchor_tag = shift ;
my $ milestone_tag = shift ;
my $ changes_ref = shift ;
my $ cvs_handle = shift ;
my $ module = shift ; # needed for proper logging
my @ new_files ;
my @ removed_files ;
my @ move_tags_files ;
my @ merge_candidates ;
my % module_stats = ( 'new' = > 0 ,
'removed' = > 0 ,
'merged' = > 0 ,
'moved' = > 0 ,
'anchor' = > 0 ,
'conflict' = > 0 ,
'alert' = > 0 ,
'ignored' = > 0
) ;
foreach ( @$ { changes_ref } ) {
my $ file = $ _ - > [ 0 ] ;
my $ old_rev = $ _ - > [ 1 ] ;
my $ new_rev = $ _ - > [ 2 ] ;
if ( exists $ resync_silent_ignore_files { basename ( $ file ) } ) {
# skip it without any comment at all
next ;
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
# sort by type of merge action
if ( ! $ old_rev && ! $ new_rev ) {
push ( @ removed_files , $ file ) ;
}
elsif ( ! $ old_rev ) {
push ( @ new_files , [ $ file , $ new_rev ] ) ;
2004-06-25 18:23:20 -05:00
}
else {
2007-08-27 07:31:52 -05:00
push ( @ merge_candidates , [ $ file , $ old_rev , $ new_rev ] ) ;
2004-06-25 18:23:20 -05:00
}
}
2007-08-27 07:31:52 -05:00
# Handle files which have recently been added on the MWS.
# For new files we don't need to check the status of the
# file in the CWS, just do a simple existence check.
my $ n_new_files = @ new_files ;
if ( $ n_new_files ) {
print " ... processing $n_new_files new file(s) ...\n" ;
foreach ( @ new_files ) {
my $ file = $ _ - > [ 0 ] ;
my $ new_rev = $ _ - > [ 1 ] ;
# Check if file has been added on two CWSs, once in this CWS
# and once in an already integrated CWS.
if ( - e $ file ) {
# We alert the user and skip the file.
print "\tA\t$file: has been added independently in MWS and CWS. Skipping. Please check!\n" ;
plog ( "A\t$module/$file: has been added independently in MWS and CWS. Skipping. Please check!" ) ;
$ module_stats { 'alert' } + + ;
$ module_stats { 'skipped' } + + ;
next ;
}
write_resync_comment ( $ file , 'new' , $ milestone_tag , undef , $ new_rev ) ;
print "\tN\t$file: added, schedule move tag\n" ;
$ module_stats { 'new' } + + ;
2004-06-25 18:23:20 -05:00
}
}
2007-08-27 07:31:52 -05:00
# Handle files which have recently been removed on the MWS.
# We check the status of these files in the CWS to be able to warn
# if a file which to be removed which has been changed in the MWS
my $ n_removed_files = @ removed_files ;
if ( $ n_removed_files ) {
print " ... processing $n_removed_files removed file(s) ...\n" ;
my $ stati_ref = $ cvs_handle - > stati ( \ @ removed_files ) ;
# sanity check
my $ n_stati_ref = @ { $ stati_ref } ;
if ( $ n_stati_ref != $ n_removed_files ) {
print_error ( "INTERNAL ERROR: can't fetch the status for all to be removed files" , 8 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my @ rfiles ;
for ( my $ i = 0 ; $ i < $ n_removed_files ; $ i + + ) {
my $ file = $ removed_files [ $ i ] ;
my $ working_rev = $ stati_ref - > [ $ i ] [ 2 ] ;
my $ branch_rev = $ stati_ref - > [ $ i ] [ 4 ] ;
if ( ! defined ( $ working_rev ) ) {
# File has already been removed on CWS, ignore.
print "\tI\t$file: file already removed on CWS, ignored.\n" ;
$ module_stats { 'ignored' } + + ;
next ;
}
if ( $ working_rev =~ /$branch_rev\.\d+/ ) {
# Example: working rev 1.5.260.1, branch rev 1.5.260
print "\tA\t$file: has been removed on MWS but is changed on CWS. Will remove file. Please check!\n" ;
plog ( "A\t$module/$file: has been removed on MWS but is changed on CWS. Will remove file. Please check!" ) ;
# Note: we still procceed with removing this file. Thus this file is counted
# as alerted and removed.
$ module_stats { 'alert' } + + ;
}
push ( @ rfiles , $ file ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ n_rfiles = @ rfiles ;
if ( $ n_rfiles ) {
$ cvs_handle - > remove_files ( \ @ rfiles ) ;
foreach my $ file ( @ rfiles ) {
write_resync_comment ( $ file , 'removed' , $ milestone_tag , undef , undef , ) ;
print "\tR\t$file: removed, schedule commit\n" ;
$ module_stats { 'removed' } + + ;
}
2004-06-25 18:23:20 -05:00
}
}
2007-08-27 07:31:52 -05:00
# Handle files in the merge list. Fetch status first to check if we get
# away with "move tag". We also need to check for binary files and
# files which have been removed in the CWS.
my $ n_merge_candidates = @ merge_candidates ;
if ( $ n_merge_candidates ) {
print " ... processing $n_merge_candidates merge candidate(s) ...\n" ;
my @ stati_lists = ( ) ;
foreach ( @ merge_candidates ) {
push ( @ stati_lists , $ _ - > [ 0 ] ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ stati_ref = $ cvs_handle - > stati ( \ @ stati_lists ) ;
# sanity check
my $ n_stati_ref = @ { $ stati_ref } ;
if ( $ n_stati_ref != $ n_merge_candidates ) {
print_error ( "INTERNAL ERROR: can't fetch the status for all to be merged files" , 8 ) ;
}
my @ mfiles ;
foreach ( my $ i = 0 ; $ i < $ n_merge_candidates ; $ i + + ) {
my $ file = $ merge_candidates [ $ i ] [ 0 ] ;
my $ old_rev = $ merge_candidates [ $ i ] [ 1 ] ;
my $ new_rev = $ merge_candidates [ $ i ] [ 2 ] ;
my $ status = $ stati_ref - > [ $ i ] [ 1 ] ;
my $ working_rev = $ stati_ref - > [ $ i ] [ 2 ] ;
my $ branch_rev = $ stati_ref - > [ $ i ] [ 4 ] ;
my $ is_binary = ( defined ( $ stati_ref - > [ $ i ] [ 5 ] ) && $ stati_ref - > [ $ i ] [ 5 ] =~ /kb/ ) ? 1 : 0 ;
if ( ( $ status eq 'Up-to-date' || $ status eq 'Needs Checkout' ) && ! defined ( $ working_rev ) ) {
# Special case: file has been removed in CWS but there
# were changes between old and new MWS milestones.
# Resolution: Do nothing, skip this file. The file
# remains being removed on this CWS.
print "\tA\t$file: has been removed in CWS, but changes in MWS are pending. Skipping. Please check!\n" ;
plog ( "A\t$module/$file: has been removed in CWS, but changes in MWS are pending. Skipping. Please check!" ) ;
$ module_stats { 'alert' } + + ;
$ module_stats { 'skipped' } + + ;
next ;
}
# Sanity check
if ( ! defined ( $ branch_rev ) || ! defined ( $ working_rev ) ) {
print_error ( "Internal Error: merge_files(): branch_rev or working_rev undefined $file\n" , 77 ) ;
}
if ( exists $ resync_always_move_tags { basename ( $ file ) } ) {
# Incredible HACK, always move both tags to the milestone for these files,
# REMOVE_ME: as soon we get rid of defs files on trunk this should be removed
write_resync_comment ( $ file , 'moved' , $ milestone_tag , $ old_rev , $ new_rev ) ;
print "\tT\t$file: schedule move tag.\n" ;
$ module_stats { 'moved' } + + ;
next ;
}
if ( $ branch_rev =~ /$working_rev\.\d+/ ) {
# Example: branch rev 1.5.260, working rev 1.5
# Joy, we get away with just a "move tag".
write_resync_comment ( $ file , 'moved' , $ milestone_tag , $ old_rev , $ new_rev ) ;
print "\tT\t$file: schedule move tag.\n" ;
$ module_stats { 'moved' } + + ;
next ;
}
if ( $ is_binary ) {
# We got changes pending in the MWS and we have changes in the CWS.
# Since we can't merge binary files we give up here. Sure, we could
# either favor the MWS or the CWS version, but there is no way to decide
# which one is better. We alert the user and skip the file.
print "\tA\t$file: binary file has been changed in CWS and in MWS. Skipping. Please check!\n" ;
plog ( "A\t$file: binary file has been changed in CWS and in MWS. Skipping. Please check!" ) ;
$ module_stats { 'alert' } + + ;
$ module_stats { 'skipped' } + + ;
next ;
}
push ( @ mfiles , [ $ file , $ old_rev , $ new_rev ] ) ;
}
my $ n_mfiles = @ mfiles ;
if ( $ n_mfiles ) {
print " ... do $n_mfiles actual merge(s) ...\n" ;
# the merge_files() API wants a reference to a plain list
my @ to_be_merged_files ;
foreach ( @ mfiles ) {
push ( @ to_be_merged_files , $ _ - > [ 0 ] ) ;
}
my ( $ conflicts_ref , $ already_merged_ref )
= $ cvs_handle - > merge_files ( \ @ to_be_merged_files , $ cws_anchor_tag , $ milestone_tag ) ;
# for easier searching
my % conflicts_hash ;
foreach ( @ { $ conflicts_ref } ) {
$ conflicts_hash { $ _ } + + ;
}
my % already_merged_hash ;
foreach ( @ { $ already_merged_ref } ) {
$ already_merged_hash { $ _ } + + ;
}
foreach ( @ mfiles ) {
my $ file = $ _ - > [ 0 ] ;
my $ old_rev = $ _ - > [ 1 ] ;
my $ new_rev = $ _ - > [ 2 ] ;
if ( exists $ already_merged_hash { $ file } ) {
print "\tT\t$file: contains differences, schedule move anchor\n" ;
$ module_stats { 'anchor' } + + ;
write_resync_comment ( $ file , 'anchor' , $ milestone_tag , $ old_rev , $ new_rev ) ;
}
elsif ( exists $ conflicts_hash { $ file } ) {
print "\tC\t$file: conflict, schedule commit after resolution.\n" ;
plog ( "C\t$module/$file: conflict, schedule commit after resolution." ) ;
write_resync_comment ( $ file , 'merged' , $ milestone_tag , $ old_rev , $ new_rev ) ;
$ module_stats { 'conflict' } + + ;
}
else {
print "\tM\t$file: merged, schedule commit.\n" ;
$ module_stats { 'merged' } + + ;
write_resync_comment ( $ file , 'merged' , $ milestone_tag , $ old_rev , $ new_rev ) ;
}
2004-06-25 18:23:20 -05:00
}
}
}
2007-08-27 07:31:52 -05:00
return \ % module_stats ;
}
# Low level commit_files routine:
# Commits files to the childworkspace or move tags.
# Requires a valid .resync files next to the CVS files
sub commit_files
{
my $ cws = shift ;
my $ files_ref = shift ;
my $ cvs_dir = shift ;
my % module_stats = (
'merged' = > 0 , # aka commit
'moved' = > 0 ,
'anchor' = > 0
) ;
my @ ci_files ;
my @ remove_files ;
my @ move_both_tags_files ;
my @ move_anchor_tag_files ;
my @ move_anchor_to_master_head_files ;
my @ possible_conflict_files ;
my $ milestone_tag ;
my $ master_head ;
# collect all *.resync files
foreach ( @ { $ files_ref } ) {
if ( ! open ( CHECKIN , "<$_.resync" ) ) {
print_error ( "can't open $_.resync: $!" , 7 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my @ resync_comment = <CHECKIN> ;
close ( CHECKIN ) ;
my $ type_line = shift ( @ resync_comment ) ;
my ( $ type , $ old_rev , $ tag , $ new_rev ) ;
if ( $ type_line =~ /^RESYNC (\w+) (\w+) ([\w\.]+) ([\w\.]+)/ ) {
$ type = lc ( $ 1 ) ;
$ tag = $ 2 ;
$ old_rev = $ 3 ;
$ new_rev = $ 4 ;
2004-06-25 18:23:20 -05:00
}
else {
2007-08-27 07:31:52 -05:00
print_error ( "$_.resync has an invalid format" , 8 ) ;
2004-06-25 18:23:20 -05:00
return 'failure' ;
}
2007-08-27 07:31:52 -05:00
# shift the line with "Everything below this line will be added to the revision comment."
shift ( @ resync_comment ) ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
# sanity checks to guard against a mix of resyncs targets
if ( $ type ne 'dead' && defined ( $ milestone_tag ) && $ tag ne $ milestone_tag ) {
print_error ( "detected more than one resync milestone tag: '$milestone_tag' and '$tag'" , 9 ) ;
}
if ( $ type eq 'dead' && defined ( $ master_head ) && $ tag ne $ master_head ) {
print_error ( "detected more than one resync at master tags: '$master_head and '$tag'" , 9 ) ;
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
# set target
if ( $ type ne 'dead' && ! defined ( $ milestone_tag ) ) {
$ milestone_tag = $ tag ;
}
if ( $ type eq 'dead' && ! defined ( $ master_head ) ) {
$ master_head = $ tag ;
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
if ( $ type eq 'moved' || $ type eq 'new' ) {
# just move both tags
push ( @ move_both_tags_files , $ _ ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
elsif ( $ type eq 'anchor' ) {
# just move the anchor tag
push ( @ move_anchor_tag_files , $ _ ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
elsif ( $ type eq 'merged' ) {
# commit and move anchor tags
push ( @ ci_files , [ $ _ , $ type , $ old_rev , $ new_rev , \ @ resync_comment ] ) ;
# these files need to be checked for conflict markers
push ( @ possible_conflict_files , $ _ ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
elsif ( $ type eq 'removed' ) {
# remove, commit and move anchor tags
push ( @ remove_files , $ _ ) ;
push ( @ ci_files , [ $ _ , $ type , $ old_rev , $ new_rev , \ @ resync_comment ] ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
elsif ( $ type eq 'dead' ) {
# can occur here only if there has been an interruption
# between the commit of removed files and the move
# of the anchor tag to the master head
push ( @ move_anchor_to_master_head_files , $ _ ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
check_for_conflict_markers ( \ @ possible_conflict_files ) ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my $ cvs_handle = get_cvs_handle ( $ cws , 'directory' , $ cvs_dir ) ;
my $ n_remove_files = @ remove_files ;
if ( $ n_remove_files ) {
print " ... preparing removal of $n_remove_files file(s) ...\n" ;
my $ n = unlink ( @ remove_files ) ;
if ( $ n != $ n_remove_files ) {
print_error ( "can't unlink() files scheduled for removal." , 22 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
$ cvs_handle - > remove_files ( \ @ remove_files ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
# commit files
# we do single commits, because the comments are differing for each file
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my $ n_ci_files = @ ci_files ;
2004-06-25 18:23:20 -05:00
my ( $ master_branch_tag , $ cws_branch_tag , $ cws_anchor_tag ) = $ cws - > get_tags ( ) ;
2007-08-27 07:31:52 -05:00
if ( ! defined ( $ master_head ) ) {
2007-09-05 11:37:29 -05:00
# Determine new master from milestone_tag. We can't use $master_branch_tag
# here because after resyncing we might have a new master due to
# a cross master resync and the CWS itself is not yet updated
# to the new master.
my ( $ master ) = split ( /_/ , $ milestone_tag ) ;
my $ new_master_branch_tag = $ cws - > get_master_branch_tag ( $ master ) ;
$ master_head = $ new_master_branch_tag ? $ new_master_branch_tag : 'HEAD' ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
if ( $ n_ci_files ) {
print " ... commit $n_ci_files file(s) ...\n" ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
foreach ( @ ci_files ) {
my ( $ file , $ type , $ old_rev , $ new_rev , $ resync_comment_ref ) = @ { $ _ } ;
my @ comment ;
if ( $ type eq 'merged' ) {
@ comment = ( "RESYNC: ($old_rev-$new_rev); FILE MERGED" , @ { $ resync_comment_ref } ) ;
}
elsif ( $ type eq 'removed' ) {
@ comment = ( "RESYNC:; FILE REMOVED" ) ;
}
else {
print_error ( "INTERNAL ERROR: unknown commit type" , 11 ) ;
}
print "\t $file: commit ...\n" ;
$ cvs_handle - > commit_files ( [ $ file ] , \ @ comment ) ;
if ( $ type eq 'removed' ) {
# Uh oh, file has been removed in master workspace.
# We can't place the anchor tag on the milestone tag
# because it's simply not there. but we know that
# it must be the top level revision of the master branch.
# In this case we can set the Anchor tag to the revision
# which corresponds to the head of the master branch.
# overwrite .resync file with a 'dead' style request, in case
# of an interruption between commit and the move anchor tag step.
# $old_rev and $new_rev are just dummies, the $master_head is relevant
write_resync_comment ( $ file , 'dead' , $ master_head , '0.0' , '0.0' ) ;
push ( @ move_anchor_to_master_head_files , $ file ) ;
}
else {
# overwrite .resync file with a move anchor style request, in case
# of an interruption between commit and move anchor tag step.
# $old_rev and $new_rev are just dummies, the $milestone_tag is relevant
write_resync_comment ( $ file , 'anchor' , $ milestone_tag , '0.0' , '0.0' ) ;
push ( @ move_anchor_tag_files , $ file ) ;
}
$ module_stats { 'merged' } + + ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ n_move_both_tags_files = @ move_both_tags_files ;
if ( $ n_move_both_tags_files ) {
print " ... move branch tag for $n_move_both_tags_files file(s) ...\n" ;
my $ tagged_files_ref = $ cvs_handle - > tag_files ( \ @ move_both_tags_files , $ cws_branch_tag , 1 ,
$ milestone_tag ) ;
my $ n_tagged_files = @ { $ tagged_files_ref } ;
if ( $ n_move_both_tags_files != $ n_tagged_files ) {
print_warning ( "expected $n_move_both_tags_files tag operations, got $n_tagged_files." , 0 ) ;
plog ( "A\t $cvs_dir: expected $n_move_both_tags_files tag operations, got $n_tagged_files." ) ;
}
# overwrite .resync file with a move anchor style request, in case
# of an interruption between commit and move anchor tag step.
foreach ( @ move_both_tags_files ) {
write_resync_comment ( $ _ , 'anchor' , $ milestone_tag , '0.0' , '0.0' ) ;
}
push ( @ move_anchor_tag_files , @ move_both_tags_files ) ;
$ module_stats { 'moved' } += $ n_move_both_tags_files ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ n_move_anchor_to_master_head_files = @ move_anchor_to_master_head_files ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
if ( $ n_move_anchor_to_master_head_files ) {
print " ... move anchor tag of removed files to to branch head '$master_head' for $n_move_anchor_to_master_head_files file(s) ...\n" ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my $ tagged_files_ref = $ cvs_handle - > tag_files ( \ @ move_anchor_to_master_head_files ,
$ cws_anchor_tag , 0 , $ master_head ) ;
my $ n_tagged_files = @ { $ tagged_files_ref } ;
if ( $ n_move_anchor_to_master_head_files != $ n_tagged_files ) {
print_warning ( "expected $n_move_anchor_to_master_head_files tag operations, got $n_tagged_files." , 0 ) ;
plog ( "A\t $cvs_dir: expected $n_move_anchor_to_master_head_files tag operations, got $n_tagged_files." ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
$ module_stats { 'anchor' } += $ n_move_anchor_to_master_head_files ;
unlink_resync_comment_files ( \ @ move_anchor_to_master_head_files ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
my $ n_move_anchor_tag_files = @ move_anchor_tag_files ;
if ( $ n_move_anchor_tag_files ) {
print " ... move anchor tag to milestone '$milestone_tag' for $n_move_anchor_tag_files file(s) ...\n" ;
my $ tagged_files_ref = $ cvs_handle - > tag_files ( \ @ move_anchor_tag_files , $ cws_anchor_tag , 0 ,
$ milestone_tag ) ;
my $ n_tagged_files = @ { $ tagged_files_ref } ;
if ( $ n_move_anchor_tag_files != $ n_tagged_files ) {
print_warning ( "expected $n_move_anchor_tag_files tag operations, got $n_tagged_files." , 0 ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
$ module_stats { 'anchor' } += $ n_move_anchor_tag_files ;
unlink_resync_comment_files ( \ @ move_anchor_tag_files ) ;
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
return \ % module_stats ;
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
sub check_for_conflict_markers
{
my $ files_ref = shift ;
foreach my $ file ( @ { $ files_ref } ) {
my $ conflict = 0 ;
my $ basename = basename ( $ file ) ;
open ( MERGED_FILE , "<$file" ) or print_error ( "can't open '$file' for reading: $!." , 40 ) ;
while ( <MERGED_FILE> ) {
chomp ;
if ( /^<<<<<<< $basename$/ ) {
$ conflict + + ;
}
if ( /^>>>>>>> 1\.\d[\d\.]*$/ ) {
$ conflict + + ;
}
}
close ( MERGED_FILE ) ;
if ( $ conflict ) {
print_error ( "found conflict marker in file '$file'" , 99 ) ;
}
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
}
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
sub unlink_resync_comment_files
{
my $ comment_files_ref = shift ;
foreach ( @ { $ comment_files_ref } ) {
if ( ! unlink ( "$_.resync" ) ) {
print_error ( "can't unlink $_.cwsresync!" , 30 ) ;
}
2004-06-25 18:23:20 -05:00
}
2007-08-27 07:31:52 -05:00
2004-06-25 18:23:20 -05:00
}
sub write_resync_comment
{
2007-08-27 07:31:52 -05:00
my $ file = shift ;
my $ type = shift ;
my $ milestone_tag = shift ;
my $ old_rev = shift ;
my $ new_rev = shift ;
2004-06-25 18:23:20 -05:00
if ( ! open ( RESYNC_COMMENT , ">$file.resync" ) ) {
print_error ( "can't open file '$file.resync'" , 7 ) ;
}
my $ uctype = uc ( $ type ) ;
2007-08-27 07:31:52 -05:00
$ old_rev = 'none' if ! defined ( $ old_rev ) ;
$ new_rev = 'none' if ! defined ( $ new_rev ) ;
print RESYNC_COMMENT "RESYNC $uctype $milestone_tag $old_rev $new_rev\n" ;
if ( $ type eq 'removed' && $ type eq 'merged' ) {
2004-06-25 18:23:20 -05:00
print RESYNC_COMMENT "Everything below this line will be added to the revision comment.\n" ;
}
close ( RESYNC_COMMENT ) ;
}
sub wanted {
my $ file = $ _ ;
my ( $ name , $ path , $ suffix ) = fileparse ( $ file , '\.\w+' ) if - f $ file ;
if ( defined ( $ suffix ) && $ suffix eq '.resync' ) {
my $ cvs_file ;
if ( length ( $ File:: Find:: dir ) > 2 ) {
my $ dir = substr ( $ File:: Find:: dir , 2 ) ;
$ cvs_file = "$dir/$name" ;
}
else {
$ cvs_file = $ name ;
}
push ( @ main:: changed_files , $ cvs_file ) ;
}
}
sub check_sticky_tag
{
my $ cws = shift ;
my $ cvs_dir = shift ;
my ( $ master_branch_tag , $ cws_branch_tag , $ cws_anchor_tag ) = $ cws - > get_tags ( ) ;
if ( ! open ( CVSTAG , "<$cvs_dir/CVS/Tag" ) ) {
print_error ( "'$cvs_dir': can't determine sticky tag." , 0 ) ;
return 0 ;
}
my @ lines = <CVSTAG> ;
close ( CVSTAG ) ;
if ( $ lines [ 0 ] =~ /^T$cws_branch_tag/ ) {
return 1 ;
}
else {
print_error ( "'$cvs_dir': wrong sticky tag, need '$cws_branch_tag'" , 0 ) ;
return 0 ;
}
}
2004-08-23 05:26:52 -05:00
# Checks specified milestone.
sub verify_milestone_or_exit
2004-06-25 18:23:20 -05:00
{
2004-08-23 05:26:52 -05:00
my $ cws = shift ;
2004-06-25 18:23:20 -05:00
my $ qualified_milestone = shift ;
2005-04-22 07:35:09 -05:00
# HEAD is not a milestone but a valid resync target for single files.
# This is useful if you want to resync a single file against the latest
# version on a MWS even if that file is not yet part of a valid milestone.
return if $ qualified_milestone eq 'HEAD' ;
2004-08-23 05:26:52 -05:00
my ( $ master , $ milestone ) ;
my $ invalid = 0 ;
$ invalid + + if $ qualified_milestone =~ /-/ ;
2004-06-25 18:23:20 -05:00
if ( $ qualified_milestone =~ /:/ ) {
2004-08-23 05:26:52 -05:00
( $ master , $ milestone ) = split ( /:/ , $ qualified_milestone ) ;
$ invalid + + unless ( $ master && $ milestone ) ;
}
else {
$ milestone = $ qualified_milestone ;
}
if ( $ invalid ) {
print_error ( "Invalid milestone" , 0 ) ;
usage ( ) ;
exit ( 1 ) ;
}
$ master = $ cws - > master ( ) if ! $ master ;
if ( ! $ cws - > is_milestone ( $ master , $ milestone ) ) {
print_error ( "Milestone '$milestone' is not registered with master workspace '$master'." , 2 ) ;
2004-06-25 18:23:20 -05:00
}
}
# Returns milestone tag determined from the
# full qualified milestone name.
sub get_milestone_tag
{
my $ cws = shift ;
my $ qualified_milestone = shift ;
if ( $ qualified_milestone =~ /:/ ) {
my ( $ master , $ milestone ) = split ( /:/ , $ qualified_milestone ) ;
return uc ( $ master ) . "_$milestone" ;
}
else {
return $ cws - > master ( ) . "_$milestone" ;
}
}
# Retrieve CvsModule object for passed module.
sub get_cvs_module
{
my $ cws = shift ;
my $ module = shift ;
my $ cvs_module = CvsModule - > new ( ) ;
my ( $ method , $ vcsid , $ server , $ repository ) ;
if ( defined ( $ log ) ) {
( $ method , $ vcsid , $ server , $ repository ) = get_cvs_root ( $ cws , $ module ) ;
}
else {
# For now just take the configured OOo sever. Later we might implement a mechanism were
# only known OOo modules are fetched from the OOo server, the rest from a local
# server
my $ config = CwsConfig:: get_config ( ) ;
( $ method , $ vcsid , $ server , $ repository ) = ( $ config - > get_cvs_server_method ( ) ,
$ config - > get_cvs_server_id ( ) ,
$ config - > get_cvs_server ( ) ,
$ config - > get_cvs_server_repository ( ) ) ;
}
return undef if ! ( $ method && $ vcsid && $ server && $ repository ) ;
$ cvs_module - > module ( $ module ) ;
$ cvs_module - > cvs_method ( $ method ) ;
$ cvs_module - > vcsid ( $ vcsid ) ;
$ cvs_module - > cvs_server ( $ server ) ;
$ cvs_module - > cvs_repository ( $ repository ) ;
return $ cvs_module ;
}
2007-08-27 07:31:52 -05:00
# Retrieve CwsCvsOps object for passed module.
sub get_cvs_handle
2004-06-25 18:23:20 -05:00
{
2007-08-27 07:31:52 -05:00
my $ cws = shift ;
my $ from_config = shift ; # from config or from disk directory?
my $ module_or_dir = shift ;
my $ server_type ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
my $ config = CwsConfig:: get_config ( ) ;
2004-06-25 18:23:20 -05:00
2007-08-27 07:31:52 -05:00
if ( $ from_config eq 'config' ) {
if ( defined ( $ log ) ) {
my ( $ method , $ vcsid , $ server , $ repository ) = get_cvs_root ( $ cws , $ module_or_dir ) ;
my @ elem = split ( /\./ , $ server ) ;
$ server = $ elem [ 0 ] ;
my $ local_server = $ config - > cvs_local_root ( ) ;
if ( $ local_server =~ /$server/ ) {
$ server_type = 'local' ;
}
else {
$ server_type = 'remote' ;
}
}
else {
# For now just take the configured OOo sever. Later we might implement a mechanism were
# only known OOo modules are fetched from the OOo server, the rest from a local
# server
$ server_type = 'remote' ;
}
}
else {
$ server_type = 'directory' ;
}
return undef if ! $ server_type ;
if ( $ opt_debug ) {
my $ log_file = IO::File - > new ( '>>cwsresync.debug.log' ) ;
my $ time = localtime ( ) ;
$ log_file - > print ( "===== $time =====\n" ) ;
return CwsCvsOps - > new ( $ config , $ server_type , $ module_or_dir , $ log_file ) ;
}
else {
return CwsCvsOps - > new ( $ config , $ server_type , $ module_or_dir ) ;
}
2004-06-25 18:23:20 -05:00
}
# Find out which CVS server holds the module, returns
# the elements of CVSROOT.
2007-08-27 07:31:52 -05:00
# TODO: simplify as soon get_cvs_module is gone
2004-06-25 18:23:20 -05:00
sub get_cvs_root
{
my $ cws = shift ;
my $ module = shift ;
my $ master = $ cws - > master ( ) ;
my $ vcsid = $ ENV { VCSID } ;
if ( ! $ vcsid ) {
print_error ( "Can't determine VCSID. Please use setsolar." , 5 ) ;
}
my $ workspace_lst = EnvHelper:: get_workspace_lst ( ) ;
my $ workspace_db = GenInfoParser - > new ( ) ;
my $ success = $ workspace_db - > load_list ( $ workspace_lst ) ;
if ( ! $ success ) {
print_error ( "Can't load workspace list '$workspace_lst'." , 4 ) ;
}
my $ key = "$master/drives/o:/projects/$module/scs" ;
my $ cvsroot = $ workspace_db - > get_value ( $ key ) ;
if ( ! $ cvsroot ) {
2004-12-13 10:26:41 -06:00
print_warning ( "No such module '$module' for '$master' in workspace database." ) ;
2004-06-25 18:23:20 -05:00
return ( undef , undef , undef , undef ) ;
}
my ( $ dummy1 , $ method , $ user_at_server , $ repository ) = split ( /:/ , $ cvsroot ) ;
2004-10-11 07:45:37 -05:00
$ repository =~ s/^\d*// ;
2004-06-25 18:23:20 -05:00
my ( $ dummy2 , $ server ) = split ( /@/ , $ user_at_server ) ;
if ( ! ( $ method && $ server && $ repository ) ) {
print_error ( "Can't determine CVS server for module '$module'." , 0 ) ;
return ( undef , undef , undef , undef ) ;
}
return ( $ method , $ vcsid , $ server , $ repository ) ;
}
sub print_message
{
my $ message = shift ;
print "$script_name: " ;
print "$message\n" ;
return ;
}
sub print_warning
{
my $ message = shift ;
print STDERR "$script_name: " ;
2004-12-13 10:26:41 -06:00
print STDERR "WARNING: $message\n" ;
2004-06-25 18:23:20 -05:00
return ;
}
sub print_error
{
my $ message = shift ;
my $ error_code = shift ;
print STDERR "$script_name: " ;
print STDERR "ERROR: $message\n" ;
if ( $ error_code ) {
print STDERR "\nFAILURE: $script_name aborted.\n" ;
$ log - > end_log_extended ( $ script_name , "unknown" , $ message ) if ( defined $ log ) ;
exit ( $ error_code ) ;
}
return ;
}
2007-08-27 07:31:52 -05:00
sub plog
{
my $ message = shift ;
push ( @ problem_log , $ message ) ;
}
sub print_plog
{
if ( @ problem_log ) {
print_message ( "========== Problem Log ==========" ) ;
foreach ( @ problem_log ) {
print "\t$_\n" ;
}
print_message ( "========== End Problem Log ==========" ) ;
}
}
2004-06-25 18:23:20 -05:00
sub usage
{
2004-12-13 10:26:41 -06:00
my $ sw_skip_checkout = ! defined ( $ log ) ? " [-f] " : " " ;
2004-06-25 18:23:20 -05:00
print STDERR "Usage:\n" ;
2007-08-27 07:31:52 -05:00
print STDERR "cwsresync [-h] [-d dir] [-F] -m <milest.> <all|mod.|dir|file> [mod.|dir|file ...]\n" ;
print STDERR "cwsresync [-h] [-d dir] -m HEAD <file> [file ...]\n" ;
2004-06-25 18:23:20 -05:00
print STDERR "cwsresync [-h] [-d dir] -r|-c <all|module|dir|file> [module|dir|file ...]\n" ;
2004-12-13 10:26:41 -06:00
print STDERR "cwsresync [-h]" . $ sw_skip_checkout . "-l <milestone>\n" ;
2004-06-25 18:23:20 -05:00
print STDERR "Synchronize child workspace mod./dirs/files " ;
print STDERR "with the latest master workspace changes \n" ;
print STDERR "Options:\n" ;
print STDERR "\t-h\t\thelp\n" ;
print STDERR "\t-d dir\t\toperate in directory dir\n" ;
2007-08-27 07:31:52 -05:00
print STDERR "\t-F\t\tforce checkout of complete modules\n" ;
2004-06-25 18:23:20 -05:00
print STDERR "\t-m milestone\tmerge changes from MWS into CWS\n" ;
print STDERR "\t-c\t\tcommit the merged files to CWS\n" ;
print STDERR "\t-l milestone\trenew solver, relink modules to new milestone\n" if defined ( $ log ) ;
print STDERR "\t-l milestone\tregister new milestone with database\n" if ! defined ( $ log ) ;
print STDERR "\t-r\t\tremove solver and module output trees, update milestone information\n" if ! defined ( $ log ) ;
2004-12-13 10:26:41 -06:00
print STDERR "\t-f\t\tavoid updating entire tree\n" if ! defined ( $ log ) ;
2004-06-25 18:23:20 -05:00
print STDERR "Notes:\n" ;
print STDERR "\tA Milestone on a different MWS can be specified as <MWS:milestone>.\n" ;
print STDERR "Examples:\n" ;
print STDERR "\tcwsresync -m SRX645:m1 all \n" ;
print STDERR "\tcwsresync -c all \n" ;
print STDERR "\tcwsresync -l SRX645:m1 \n" if defined ( $ log ) ;
print STDERR "\tcwsresync -r\n" if ! defined ( $ log ) ;
}
2007-08-27 07:31:52 -05:00
# vim: set ts=4 shiftwidth=4 expandtab syntax=perl: