1 |
#!/home/jsoc/bin/linux_x86_64/activeperl -w |
2 |
|
3 |
|
4 |
# This script takes at least one argument which specifies which of three types of checkouts to perform: |
5 |
# 1. A NetDRMS checkout (-net). If present, all other arguments are ignored. |
6 |
# 2. A JSOC_SDP checkout (-sdp). If present, all other arugments are ignored. |
7 |
# 3. A custom checkout (-custom). To perform a custom checkout, the caller must follow this argument |
8 |
# with the full path to a configuration file specifying the project directories the caller would |
9 |
# like to check-out. |
10 |
|
11 |
# Each type of checkout contains a different subset of files that reside in the JSOC CVS module. To specify |
12 |
# that subset, we maintain one "file specification" for each checkout type. A file specification is |
13 |
# a list of file and directory paths relative to the CVS code-tree root. It turns out that you |
14 |
# can use the CVS checkout or export command with these relative paths. So, for example, to check-out |
15 |
# the sdp files, you can run "cvs checkout <relpath1> <relpath2> ... <relpathN>. This script maintains |
16 |
# the file specification for each type of checkout, then performs the desired checkout or export. |
17 |
|
18 |
# In order to determine the complete set of file names of the files that reside in a checkout file set, |
19 |
# you must download the files in that file set from the CVS repository. There is no CVS command that |
20 |
# will print out all files in the repository or a subtree of the repository. |
21 |
# And it is not desirable to use the checkout command to download the files, because |
22 |
# the checkout command creates additional CVS "state" files and places them in every node of the |
23 |
# downloaded code tree. These intermingled state files make it difficult to isolate all the source files |
24 |
# that comprise the checkout. To cope with these CVS deficiencies, when printing the list of files in a file set, |
25 |
# this script first EXPORTS all files in the JSOC module into a |
26 |
# temporary directory. When an export is performed, CVS does not introduce these extra state files. |
27 |
|
28 |
# It is important to use this script to update the files in your working directory after the initial |
29 |
# checkout. Using the cvs update command directly can result in the download of files outside of the file set. |
30 |
# And once that happens, 'make' may not work properly. |
31 |
|
32 |
# NOTE: You cannot check-out the entire JSOC module, then delete the files not needed. If you do that, then CVS |
33 |
# will think that the checkout is incomplete - cvsstatus.pl will indicate that the deleted files are |
34 |
# missing. The CVS state files, which list all files that were downloaded, including the the deleted files, |
35 |
# indicate to the CVS server that those deleted files are expected to be present in the working directory. If |
36 |
# they are missing, various cvs commands will complain. |
37 |
|
38 |
# flags: |
39 |
# -o The operation to perform, which includes: |
40 |
# checkout - The current directory must be the parent directory of the CVS working directory root. |
41 |
# export - The current directory must be the parent directory of the CVS working directory root. |
42 |
# update - update the set of files with changes committed to the CVS repository since the initial |
43 |
# checkout. The current directory may be either the CVS working directory root, or its parent |
44 |
# directory. The -f flag is ignored during an update - the checkout type is read from the |
45 |
# configuration file. If the checkout type is sdp or net, then the file specification |
46 |
# for that checkout type is obtained from this script (not from the state file), since the |
47 |
# file specification for that checkout type may have changed since the original checkout. |
48 |
# For a custom checkout, the file specification is re-generated. If the caller |
49 |
# provides a -f <config file> argument, then the file specification for the proj directories |
50 |
# is derived from <config file>. Otherwise, the proj directories file specification |
51 |
# is obtained from the state file. Regardless, the file specification for the "core" |
52 |
# directories is obtained from this script. |
53 |
# tag - tag the set of files in the CVS respository implied by the -f flag. |
54 |
# untag - remove the tag on the set of files in the CVS respository implied by the -f flag. |
55 |
# print - print the set of files in the CVS repository implied by the -f flag. |
56 |
# printrel - print the set of files in the CVS repostiroy implied by the -f flag (but stripped |
57 |
# of files that need to be filtered out for releases). |
58 |
# -f The type of file set to operate on, which includes: |
59 |
# sdp (all files in the repository, aka the "full JSOC" source tree). |
60 |
# net (the set of files that compose the NetDRMS release). |
61 |
# <configuration file> (the set of files is specified by <configuration file>). |
62 |
# -r For the checkout, export, and update operations, this parameter is the CVS tag that identifies |
63 |
# the revision of each file to download. For the sdp and net file-sets, this tag is applied to |
64 |
# all files. For the custom file-set, this tag is applied to only the NetDRMS subset of files. |
65 |
# -R Applies to the custom file-set only. For the checkout, export, and update operations, this parameter is |
66 |
# the CVS tag that identifies the revision of each non-NetDRMS project file to download. |
67 |
# -t For the tag and untag operations, the CVS tag to apply or delete. |
68 |
# -l A log file (for the output of CVS commands for now). |
69 |
# -F If a tagged checkout occurs as a result of other options, then tell CVS to retrieve the most recent |
70 |
# file version of any file that is part of the file-set, but is not tagged with the tag provided |
71 |
# by the -r or -R option. |
72 |
# -s This argument can only be provided if the -o flag is update, tag, or untag. This argument contains |
73 |
# a comma-separated list of file specifications. The files specified by this list must exist in the |
74 |
# working directory. |
75 |
# -d (optional) The root dir of the workspace CVS tree, which defaults to "JSOC". |
76 |
# -D (optional) The root dir of the repository CVS tree, which defaults to "JSOC". |
77 |
|
78 |
use XML::Simple; |
79 |
use IO::Dir; |
80 |
use File::Copy; |
81 |
use File::Basename; |
82 |
use File::Path qw(mkpath remove_tree); |
83 |
use File::Spec; |
84 |
use Cwd qw(chdir getcwd realpath); # need to override chdir so that $ENV{'PWD'} is changed when chdir is called. |
85 |
use Data::Dumper; |
86 |
use FindBin qw($RealBin); |
87 |
use lib "$RealBin/../../../base/libs/perl"; |
88 |
use drmsLocks; |
89 |
|
90 |
use constant kLockFile => "/home/jsoc/locks/prodbuildlck.txt"; |
91 |
|
92 |
use constant kMakeDiv => "__MAKE__"; |
93 |
use constant kProjDiv => "__PROJ__"; |
94 |
use constant kFspecDev => "__FSPEC__"; |
95 |
use constant kEndDiv => "__END__"; |
96 |
use constant kStUnk => 0; |
97 |
use constant kStMake => 1; |
98 |
use constant kStProj => 2; |
99 |
|
100 |
use constant kCoUnk => "unk"; |
101 |
use constant kCoNetDRMS => "net"; |
102 |
use constant kCoSdp => "sdp"; |
103 |
use constant kCoCustom => "custom"; |
104 |
|
105 |
use constant kDlCheckout => "checkout"; |
106 |
use constant kDlExport => "export"; |
107 |
use constant kDlUpdate => "update"; |
108 |
use constant kDlTag => "tag"; |
109 |
use constant kDlUntag => "untag"; |
110 |
use constant kDlPrint => "print"; |
111 |
use constant kDlPrintRelease => "printrel"; |
112 |
|
113 |
use constant kStrproj => "proj"; |
114 |
use constant kStrname => "name"; |
115 |
|
116 |
# Assume a localization directory of "localization" right in the root of the CVS tree. |
117 |
use constant kDefRootDir => "JSOC/"; # default root dir, overridable by the -d argument |
118 |
use constant kDefRepRootDir => "JSOC/"; # default repository root dir, overridable by the - |
119 |
use constant kLocDir => "localization/"; |
120 |
use constant kProjSubdir => "proj"; |
121 |
use constant kTmpDir => "/tmp/chkout/"; |
122 |
use constant kTypeFile => "dlset.txt"; |
123 |
use constant kSuFlagFile => "suflag.txt"; |
124 |
|
125 |
use constant kMaxFileSpecs => 50; |
126 |
|
127 |
|
128 |
my($arg); |
129 |
my($cotype); |
130 |
my($cfgfile); |
131 |
my($logfile); |
132 |
my($cmd); |
133 |
my($err); |
134 |
my(@core); |
135 |
my(@netonly); |
136 |
my(@sdponly); |
137 |
my(@netfilter); |
138 |
my(@sdpfilter); |
139 |
my(@netco); |
140 |
my(@sdbco); |
141 |
my($curdir); |
142 |
my($xmldata); # reference to hash array |
143 |
my($dltype); |
144 |
my($version); |
145 |
my($pversion); # version of project files (when for net and custom file-set types) |
146 |
my($cvstag); |
147 |
my($stfile); |
148 |
my($stfileold); |
149 |
my($stcotype); |
150 |
my($stfspec); |
151 |
my($compatmode); |
152 |
my($forceco); |
153 |
my(@filespec); # the complete file spec for all types of file-sets |
154 |
my(@pfilespec); # for custom file-set types, the file spec of the files in the configuration file |
155 |
my(@bfilespec); # for custom file-set types, the file spec of the files NOT in the configuration file |
156 |
my(@cmdlspec); # can specify file specifications on the cmd-line. |
157 |
my($actcvs); # if the user provided a cmdlspec, then this var holds the cvs command used to update |
158 |
# the files specified by $cmdlspec. |
159 |
my(@actspec); # The actual file specification that was used to download files from the repository. |
160 |
my($rdir); # root dir (either specified by -d flag, or default root dir of JSOC) |
161 |
my($reprdir); # root dir (either specified by -D flag, or default root dir of JSOC) |
162 |
|
163 |
|
164 |
# Don't allow more than one version of this file to run concurrently to avoid race conditions. |
165 |
$lock = new drmsNetLocks(&kLockFile); |
166 |
|
167 |
if (!defined($lock)) |
168 |
{ |
169 |
print "$0 is already running. Exiting.\n"; |
170 |
exit(1); |
171 |
} |
172 |
|
173 |
@core = qw(base/cfortran.h base/foundation.h base/jsoc.h base/jsoc_version.h base/mypng.h base/Rules.mk base/export base/drms base/libs base/sums base/util localize.py configure doc make_basic.mk Makefile make_jsoc.pl README Rules.mk target.mk build CM); |
174 |
@coreDel = qw(configproj.pl customizemake.pl moreconfigure.pl getmachtype.pl); |
175 |
|
176 |
@netonly = qw(config.local.template config.local.map seed_sums.c netdrms_setup.pl proj/example proj/myproj proj/cookbook); |
177 |
@netDel = qw(gen_init.csh getuid.c); |
178 |
|
179 |
@sdponly = qw(base/local proj configsdp.txt); |
180 |
@sdpDel = qw(customizedefs.pl config.local.sutemplate); |
181 |
|
182 |
# My botched attempt to remove tape files from NetDRMS sites that will never use our tape code |
183 |
#@netfilter = qw(base/drms/doc base/drms/libs/api/test base/sums/libs/api/perl base/sums/libs/api/tape.h base/sums/libs/pg/SUMLIB_DS_DataRequest_Tst.pgc base/sums/libs/pg/SUMLIB_NC_PaRequest_AP_60d.pgc base/sums/libs/pg/SUMLIB_TapeClose.pgc base/sums/libs/pg/SUMLIB_TapeFindGroup.pgc base/sums/libs/pg/SUMLIB_TapeUpdate.pgc base/sums/apps/main.c base/sums/apps/main2.c base/sums/apps/main3.c base/sums/apps/main4.c base/sums/apps/main5.c base/sums/apps/robotn_svc.c base/sums/apps/sum_forker.c base/sums/apps/sum_test.c base/sums/apps/sum_test.pl base/sums/apps/tapearc.c base/sums/apps/tapearc0.c base/sums/apps/tapearc1.c base/sums/apps/tapearc2.c base/sums/apps/tapearc3.c base/sums/apps/tapearc4.c base/sums/apps/tapearc5.c base/sums/apps/tapearc6.c base/sums/apps/tapearc7.c base/sums/apps/tapearc8.c base/sums/apps/tapearcinfo.c base/sums/apps/tapearcX.c base/sums/apps/tape_inventory.c base/sums/apps/tapeonoff.c base/sums/apps/tape_svc.c base/sums/apps/tape_svc_proc.c base/sums/apps/tapeutil.c base/sums/apps/xsum_svc.c base/sums/apps/xsum_svc_proc.c base/sums/apps/xtape_svc.c base/sums/scripts/build_parc_file.pl base/sums/scripts/find_dir_sum_partn_alloc_dc base/sums/scripts/fixportm.pl base/sums/scripts/get_dcs_times.csh base/sums/scripts/GRAD_BLUE_LINE.gif base/sums/scripts/lev1_def_gui base/sums/scripts/lev1_def_gui_aia base/sums/scripts/lev1_def_gui_called base/sums/scripts/lev1_def_gui_called_PZT_FSN base/sums/scripts/lev1_def_gui_hmi base/sums/scripts/rsync_scr111.pl base/sums/scripts/SDO_Badge.gif base/sums/scripts/SDO_HSB_CCSDS_Data_Structures.gif base/sums/scripts/ssh_rsync.source base/sums/scripts/sum_bad_permissions.pl base/sums/scripts/sumck base/sums/scripts/sumck_j1 base/sums/scripts/sumck_j1M base/sums/scripts/sumck_n02_jim base/sums/scripts/sumlookgroup.pl base/sums/scripts/sumlook.pl base/sums/scripts/sum_start base/sums/scripts/sum_start_d00_jim base/sums/scripts/sum_start_d02 base/sums/scripts/sum_start_d02_auto base/sums/scripts/sum_start_dc base/sums/scripts/sum_start_j1 base/sums/scripts/sum_start_j1_auto base/sums/scripts/sum_start_j1_auto.MULTI base/sums/scripts/sum_start_j1.MULTI base/sums/scripts/sum_start_n02_jim base/sums/scripts/sum_start_n02_jim_auto base/sums/scripts/sum_start_xim.MULTI base/sums/scripts/sum_stop base/sums/scripts/sum_stop_d00_jim base/sums/scripts/sum_stop_d02 base/sums/scripts/sum_stop_d02_auto base/sums/scripts/sum_stop_d02_tape base/sums/scripts/sum_stop_dc base/sums/scripts/sum_stop_j1 base/sums/scripts/sum_stop_j1_auto base/sums/scripts/sum_stop_j1_auto.MULTI base/sums/scripts/sum_stop_j1.MULTI base/sums/scripts/sum_stop_n02_jim base/sums/scripts/sum_stop_n02_jim_auto base/sums/scripts/sum_stop_xim.MULTI base/sums/scripts/sum_tape_catchup_update.pl base/sums/scripts/sum_tape_insert.pl base/sums/scripts/sum_tape_insert_t50.pl base/sums/scripts/sum_tape_insert_t950.pl base/sums/scripts/t120_reachive.pl base/sums/scripts/t120stageall.pl base/sums/scripts/t120view base/sums/scripts/t50view base/sums/scripts/t950view base/sums/scripts/tapearc_do base/sums/scripts/tapearc_do_dcs1 base/sums/scripts/tape_do_0.pl base/sums/scripts/tape_do_1.pl base/sums/scripts/tape_do_2.pl base/sums/scripts/tape_do_3.pl base/sums/scripts/tape_do_4.pl base/sums/scripts/tape_do_7.pl base/sums/scripts/tape_do_8.pl base/sums/scripts/tape_do_archive.pl base/sums/scripts/tape_do.pl base/sums/scripts/tapeid.list base/sums/scripts/tapeid_t50.list base/sums/scripts/tape_verify.pl base/sums/scripts/test base/sums/scripts/tmp.pl doc/dcs2_convert_to_0_or_1.txt doc/dcs3_name_change.txt doc/dcs_warmstandby.txt doc/dsc0_just_rebooted.txt doc/HK_Level0_Debug_Guide.odt doc/HK_Level0_Debug_Guide.pdf doc/whattodo_aia_lev1.txt doc/whattodo_dcs.txt doc/whattodolev0.txt doc/whattodo_start_stop_lev1_0_sums.txt); |
184 |
|
185 |
@netfilter = qw(base/drms/doc base/drms/libs/api/test base/sums/libs/api/perl base/sums/libs/pg/SUMLIB_DS_DataRequest_Tst.pgc base/sums/libs/pg/SUMLIB_NC_PaRequest_AP_60d.pgc base/sums/apps/main.c base/sums/apps/main2.c base/sums/apps/main3.c base/sums/apps/main4.c base/sums/apps/main5.c base/sums/apps/sum_test.c base/sums/apps/sum_test.pl base/sums/apps/xsum_svc.c base/sums/apps/xsum_svc_proc.c base/sums/apps/xtape_svc.c base/sums/scripts/build_parc_file.pl base/sums/scripts/find_dir_sum_partn_alloc_dc base/sums/scripts/fixportm.pl base/sums/scripts/get_dcs_times.csh base/sums/scripts/GRAD_BLUE_LINE.gif base/sums/scripts/lev1_def_gui base/sums/scripts/lev1_def_gui_aia base/sums/scripts/lev1_def_gui_called base/sums/scripts/lev1_def_gui_called_PZT_FSN base/sums/scripts/lev1_def_gui_hmi base/sums/scripts/rsync_scr111.pl base/sums/scripts/SDO_Badge.gif base/sums/scripts/SDO_HSB_CCSDS_Data_Structures.gif base/sums/scripts/ssh_rsync.source base/sums/scripts/sum_bad_permissions.pl base/sums/scripts/sumck base/sums/scripts/sumck_j1 base/sums/scripts/sumck_j1M base/sums/scripts/sumck_n02_jim base/sums/scripts/sumlookgroup.pl base/sums/scripts/sumlook.pl base/sums/scripts/sum_start base/sums/scripts/sum_start_d00_jim base/sums/scripts/sum_start_d02 base/sums/scripts/sum_start_d02_auto base/sums/scripts/sum_start_dc base/sums/scripts/sum_start_j1 base/sums/scripts/sum_start_j1_auto base/sums/scripts/sum_start_j1_auto.MULTI base/sums/scripts/sum_start_j1.MULTI base/sums/scripts/sum_start_n02_jim base/sums/scripts/sum_start_n02_jim_auto base/sums/scripts/sum_start_xim.MULTI base/sums/scripts/sum_stop base/sums/scripts/sum_stop_d00_jim base/sums/scripts/sum_stop_d02 base/sums/scripts/sum_stop_d02_auto base/sums/scripts/sum_stop_d02_tape base/sums/scripts/sum_stop_dc base/sums/scripts/sum_stop_j1 base/sums/scripts/sum_stop_j1_auto base/sums/scripts/sum_stop_j1_auto.MULTI base/sums/scripts/sum_stop_j1.MULTI base/sums/scripts/sum_stop_n02_jim base/sums/scripts/sum_stop_n02_jim_auto base/sums/scripts/sum_stop_xim.MULTI base/sums/scripts/sum_tape_catchup_update.pl base/sums/scripts/sum_tape_insert.pl base/sums/scripts/sum_tape_insert_t50.pl base/sums/scripts/sum_tape_insert_t950.pl base/sums/scripts/t120_reachive.pl base/sums/scripts/t120stageall.pl base/sums/scripts/t120view base/sums/scripts/t50view base/sums/scripts/t950view base/sums/scripts/tapearc_do base/sums/scripts/tapearc_do_dcs1 base/sums/scripts/tape_do_0.pl base/sums/scripts/tape_do_1.pl base/sums/scripts/tape_do_2.pl base/sums/scripts/tape_do_3.pl base/sums/scripts/tape_do_4.pl base/sums/scripts/tape_do_7.pl base/sums/scripts/tape_do_8.pl base/sums/scripts/tape_do_archive.pl base/sums/scripts/tape_do.pl base/sums/scripts/tapeid.list base/sums/scripts/tapeid_t50.list base/sums/scripts/tape_verify.pl base/sums/scripts/test base/sums/scripts/tmp.pl doc/dcs2_convert_to_0_or_1.txt doc/dcs3_name_change.txt doc/dcs_warmstandby.txt doc/dsc0_just_rebooted.txt doc/HK_Level0_Debug_Guide.odt doc/HK_Level0_Debug_Guide.pdf doc/whattodo_aia_lev1.txt doc/whattodo_dcs.txt doc/whattodolev0.txt doc/whattodo_start_stop_lev1_0_sums.txt); |
186 |
|
187 |
@sdpfilter = qw(base/drms/doc base/drms/libs/api/test base/sums/libs/api/perl base/sums/libs/pg/SUMLIB_DS_DataRequest_Tst.pgc base/sums/libs/pg/SUMLIB_NC_PaRequest_AP_60d.pgc base/sums/apps/main.c base/sums/apps/main2.c base/sums/apps/main3.c base/sums/apps/main4.c base/sums/apps/main5.c base/sums/apps/sum_test.c base/sums/apps/sum_test.pl base/sums/apps/tapearcX.c base/sums/apps/xsum_svc.c base/sums/apps/xsum_svc_proc.c base/sums/apps/xtape_svc.c base/sums/scripts/fixportm.pl base/sums/scripts/get_dcs_times.csh base/sums/scripts/GRAD_BLUE_LINE.gif base/sums/scripts/lev1_def_gui base/sums/scripts/lev1_def_gui_aia base/sums/scripts/lev1_def_gui_called base/sums/scripts/lev1_def_gui_called_PZT_FSN base/sums/scripts/lev1_def_gui_hmi base/sums/scripts/rsync_scr111.pl base/sums/scripts/SDO_Badge.gif base/sums/scripts/SDO_HSB_CCSDS_Data_Structures.gif base/sums/scripts/ssh_rsync.source base/sums/scripts/sum_bad_permissions.pl base/sums/scripts/sumck base/sums/scripts/sumck_j1 base/sums/scripts/sumck_j1M base/sums/scripts/sumck_n02_jim base/sums/scripts/sumlookgroup.pl base/sums/scripts/sumlook.pl base/sums/scripts/sum_start base/sums/scripts/sum_start_d00_jim base/sums/scripts/sum_start_d02 base/sums/scripts/sum_start_d02_auto base/sums/scripts/sum_start_dc base/sums/scripts/sum_start_j1 base/sums/scripts/sum_start_j1_auto base/sums/scripts/sum_start_j1_auto.MULTI base/sums/scripts/sum_start_j1.MULTI base/sums/scripts/sum_start_n02_jim base/sums/scripts/sum_start_n02_jim_auto base/sums/scripts/sum_start_xim.MULTI base/sums/scripts/sum_stop base/sums/scripts/sum_stop_d00_jim base/sums/scripts/sum_stop_d02 base/sums/scripts/sum_stop_d02_auto base/sums/scripts/sum_stop_d02_tape base/sums/scripts/sum_stop_dc base/sums/scripts/sum_stop_j1 base/sums/scripts/sum_stop_j1_auto base/sums/scripts/sum_stop_j1_auto.MULTI base/sums/scripts/sum_stop_j1.MULTI base/sums/scripts/sum_stop_n02_jim base/sums/scripts/sum_stop_n02_jim_auto base/sums/scripts/sum_stop_xim.MULTI base/sums/scripts/sum_tape_catchup_update.pl base/sums/scripts/sum_tape_insert.pl base/sums/scripts/sum_tape_insert_t50.pl base/sums/scripts/sum_tape_insert_t950.pl base/sums/scripts/t120_reachive.pl base/sums/scripts/t120stageall.pl base/sums/scripts/t120view base/sums/scripts/t50view base/sums/scripts/t950view base/sums/scripts/tapearc_do base/sums/scripts/tapearc_do_dcs1 base/sums/scripts/tape_do_0.pl base/sums/scripts/tape_do_1.pl base/sums/scripts/tape_do_2.pl base/sums/scripts/tape_do_3.pl base/sums/scripts/tape_do_4.pl base/sums/scripts/tape_do_7.pl base/sums/scripts/tape_do_8.pl base/sums/scripts/tape_do_archive.pl base/sums/scripts/tape_do.pl base/sums/scripts/tapeid.list base/sums/scripts/tapeid_t50.list base/sums/scripts/tape_verify.pl base/sums/scripts/test base/sums/scripts/tmp.pl doc/dcs2_convert_to_0_or_1.txt doc/dcs3_name_change.txt doc/dcs_warmstandby.txt doc/dsc0_just_rebooted.txt doc/HK_Level0_Debug_Guide.odt doc/HK_Level0_Debug_Guide.pdf doc/whattodo_aia_lev1.txt doc/whattodo_dcs.txt doc/whattodolev0.txt doc/whattodo_start_stop_lev1_0_sums.txt); |
188 |
|
189 |
$err = 0; |
190 |
$cotype = kCoSdp; |
191 |
$dltype = kDlCheckout; |
192 |
$version = ""; |
193 |
$cvstag = ""; |
194 |
$compatmode = 0; |
195 |
$forceco = 0; |
196 |
$rdir = &kDefRootDir; |
197 |
$reprdir = &kDefRepRootDir; |
198 |
|
199 |
while ($arg = shift(@ARGV)) |
200 |
{ |
201 |
if ($arg eq "-o") |
202 |
{ |
203 |
# download type |
204 |
$arg = shift(@ARGV); |
205 |
if ($arg eq kDlCheckout || |
206 |
$arg eq kDlExport || |
207 |
$arg eq kDlUpdate || |
208 |
$arg eq kDlTag || |
209 |
$arg eq kDlUntag || |
210 |
$arg eq kDlPrint || |
211 |
$arg eq kDlPrintRelease) |
212 |
{ |
213 |
$dltype = $arg; |
214 |
} |
215 |
else |
216 |
{ |
217 |
print STDERR "Invalid download type - please choose from 'checkout', 'export', 'update', 'tag', 'untag', 'print', or 'printrel'.\n"; |
218 |
$err = 1; |
219 |
last; |
220 |
} |
221 |
} |
222 |
elsif ($arg eq "-r") |
223 |
{ |
224 |
# revision (version) |
225 |
$arg = shift(@ARGV); |
226 |
$version = $arg; |
227 |
} |
228 |
elsif ($arg eq "-R") |
229 |
{ |
230 |
$arg = shift(@ARGV); |
231 |
$pversion = $arg; |
232 |
} |
233 |
elsif ($arg eq "-t") |
234 |
{ |
235 |
# CVS tag to set/remove |
236 |
$arg = shift(@ARGV); |
237 |
$cvstag = $arg; |
238 |
} |
239 |
elsif ($arg eq "-l") |
240 |
{ |
241 |
$arg = shift(@ARGV); |
242 |
$logfile = $arg; |
243 |
} |
244 |
elsif ($arg eq "-f") |
245 |
{ |
246 |
# file set |
247 |
$arg = shift(@ARGV); |
248 |
|
249 |
if ($arg eq kCoSdp) |
250 |
{ |
251 |
$cotype = kCoSdp; |
252 |
} |
253 |
elsif ($arg eq kCoNetDRMS) |
254 |
{ |
255 |
$cotype = kCoNetDRMS; |
256 |
} |
257 |
else |
258 |
{ |
259 |
# custom - argument must be a configuration file |
260 |
if (-f $arg) |
261 |
{ |
262 |
$cotype = kCoCustom; |
263 |
$cfgfile = $arg; |
264 |
} |
265 |
else |
266 |
{ |
267 |
print STDERR "Invalid custom-download configuration file $arg.\n"; |
268 |
$err = 1; |
269 |
} |
270 |
} |
271 |
} |
272 |
elsif ($arg eq "-F") |
273 |
{ |
274 |
$forceco = 1; |
275 |
} |
276 |
elsif ($arg eq "-s") |
277 |
{ |
278 |
$arg = shift(@ARGV); |
279 |
@cmdlspec = split(/,/, $arg); |
280 |
} |
281 |
elsif ($arg eq "-d") |
282 |
{ |
283 |
$arg = shift(@ARGV); |
284 |
$rdir = $arg; |
285 |
} |
286 |
elsif ($arg eq "-D") |
287 |
{ |
288 |
$arg = shift(@ARGV); |
289 |
$reprdir = $arg; |
290 |
} |
291 |
} |
292 |
|
293 |
if (!$err) |
294 |
{ |
295 |
my($inparent); # if 1, curr dir is the parent of JSOC root dir. |
296 |
my($crootdir); # canonical root dir |
297 |
my($creprootdir); # canonical repository root dir (i.e., JSOC) |
298 |
|
299 |
$inparent = 0; |
300 |
if (defined($cfgfile)) |
301 |
{ |
302 |
# Custom checkout - if the user is performing an update, then use the file spec saved |
303 |
# in the TYPEFILE (no need to re-read a config file). |
304 |
my($xml); |
305 |
my($xmlobj) = new XML::Simple; |
306 |
|
307 |
# Read in the configuration file to obtain the set of project files that will reside |
308 |
# in the custom checkout set. |
309 |
if (!ReadCfg($cfgfile, \$xml) && defined($xml)) |
310 |
{ |
311 |
$xmldata = $xmlobj->XMLin($xml, ForceArray => 1); |
312 |
} |
313 |
else |
314 |
{ |
315 |
print STDERR "Unable to read or parse configuration file $cfgfile.\n"; |
316 |
$err = 1; |
317 |
} |
318 |
} |
319 |
|
320 |
if ($dltype eq kDlCheckout || $dltype eq kDlExport || $dltype eq kDlUpdate) |
321 |
{ |
322 |
# Set the state file path. |
323 |
$crootdir = File::Spec->catdir($rdir); |
324 |
$creprootdir = File::Spec->catdir($reprdir); |
325 |
#my($cdir) = File::Spec->catdir($ENV{'PWD'}); |
326 |
my($cdir) = realpath($ENV{'PWD'}); |
327 |
|
328 |
$stfile = kLocDir . kTypeFile; |
329 |
$stfileold = kSuFlagFile; |
330 |
|
331 |
if ($cdir !~ /$crootdir\s*$/) |
332 |
{ |
333 |
# Assume that the current directory is the parent of the JSOC code tree. |
334 |
$stfile = $rdir . $stfile; |
335 |
$stfileold = $rdir . $stfileold; |
336 |
$inparent = 1; |
337 |
} |
338 |
} |
339 |
|
340 |
if ($dltype eq kDlUpdate) |
341 |
{ |
342 |
# If this is an update, obtain the checkout type from the statefile. The |
343 |
# state file will exist at this point only for kDlUpdate. |
344 |
if (open(STFILE, "<$stfile")) |
345 |
{ |
346 |
# Modify $cotype - should be determined by the first line of the state file. |
347 |
my($line); |
348 |
|
349 |
$line = <STFILE>; |
350 |
chomp($line); |
351 |
$stcotype = $line; |
352 |
$cotype = $stcotype; |
353 |
$line = <STFILE>; |
354 |
chomp($line); |
355 |
$stfspec = $line; |
356 |
|
357 |
close(STFILE); |
358 |
} |
359 |
elsif (!(-e $stfile)) |
360 |
{ |
361 |
# Backward compatibility for previous versions of the cvs tree. |
362 |
if (-e $stfileold) |
363 |
{ |
364 |
# Assume old sdp tree. |
365 |
$cotype = kCoSdp; |
366 |
} |
367 |
else |
368 |
{ |
369 |
# Assume old net tree. |
370 |
$cotype = kCoNetDRMS; |
371 |
} |
372 |
|
373 |
$compatmode = 1; |
374 |
} |
375 |
else |
376 |
{ |
377 |
print STDERR "Unable to open state file '$stfile' for reading.\n"; |
378 |
$err = 1; |
379 |
} |
380 |
} |
381 |
|
382 |
if ($err) |
383 |
{ |
384 |
# Do nothing - this will essentially cause this script to exit. |
385 |
} |
386 |
elsif ($cotype ne kCoSdp && $cotype ne kCoNetDRMS && $cotype ne kCoCustom) |
387 |
{ |
388 |
print STDERR "Invalid file set identifier '$cotype'.\n"; |
389 |
$err = 1; |
390 |
} |
391 |
elsif ($dltype ne kDlCheckout && $dltype ne kDlExport && $dltype ne kDlUpdate && |
392 |
$dltype ne kDlTag && $dltype ne kDlUntag && $dltype ne kDlPrint && $dltype ne kDlPrintRelease) |
393 |
{ |
394 |
print STDERR "Invalid operation '$dltype'.\n"; |
395 |
$err = 1; |
396 |
} |
397 |
else |
398 |
{ |
399 |
my(@cmdlspecrel); |
400 |
|
401 |
if ($#cmdlspec >= 0) |
402 |
{ |
403 |
if ($inparent) |
404 |
{ |
405 |
# Prepend each spec with the $rootdir |
406 |
@cmdlspecrel = map({($creprootdir . $_)} @cmdlspec); |
407 |
} |
408 |
else |
409 |
{ |
410 |
@cmdlspecrel = @cmdlspec; |
411 |
} |
412 |
} |
413 |
|
414 |
if (BuildFilespec($cotype, $dltype, $stfspec, $xmldata, \@core, \@netonly, \@sdponly, \@filespec, \@bfilespec, \@pfilespec, \@cmdlspecrel, \@coreDel, \@netDel, \@sdpDel)) |
415 |
{ |
416 |
print STDERR "Unable to build filespec.\n"; |
417 |
$err = 1; |
418 |
} |
419 |
else |
420 |
{ |
421 |
undef($curdir); |
422 |
|
423 |
if ($dltype eq kDlTag || $dltype eq kDlUntag || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
424 |
{ |
425 |
# cd to tmp directory for these commands |
426 |
if (!(-d kTmpDir)) |
427 |
{ |
428 |
# no need to check this call, because the chdir() cmd is being checked. |
429 |
mkpath(kTmpDir); |
430 |
} |
431 |
|
432 |
$curdir = $ENV{'PWD'}; |
433 |
$err = (chdir(kTmpDir) == 0); |
434 |
if ($err) |
435 |
{ |
436 |
print STDERR "Unable to cd to " . kTmpDir . ".\n"; |
437 |
} |
438 |
} |
439 |
elsif ($dltype eq kDlUpdate) |
440 |
{ |
441 |
# If the current directory is the root directory of the CVS working directory, then |
442 |
# cd up to the parent directory (DownloadTree assumes the current directory is the |
443 |
# parent of the CVS working directory). |
444 |
my($crootdir) = File::Spec->catdir($rdir); |
445 |
my($creprootdir) = File::Spec->catdir($reprdir); |
446 |
#my($cdir) = File::Spec->catdir($ENV{'PWD'}); |
447 |
my($cdir) = realpath($ENV{'PWD'}); |
448 |
|
449 |
print "dlsource.pl: rootdir == $crootdir, cdir == $cdir.\n"; |
450 |
if ($cdir =~ /$crootdir\s*$/) |
451 |
{ |
452 |
# The current directory is the CVS working directory. |
453 |
$curdir = $ENV{'PWD'}; |
454 |
$err = (chdir('..') == 0) ? 1 : 0; |
455 |
} |
456 |
} |
457 |
|
458 |
# Do a cvs checkout, export, or update into the current directory |
459 |
if (!$err) |
460 |
{ |
461 |
# @filespec - the complete set of files that reside on the server for the current check-out type. |
462 |
# @bfilespec - for non-custom check-out, the set of files to update or checkout. For |
463 |
# custom check-out, the set of files in the base dir to update or checkout. |
464 |
# @pfilespec - for custom check-out, the set of files in the proj dir to update or checkout. |
465 |
# @actspec - the spec actually used with the cvs command. Might differ from the others if |
466 |
# an export was done and undesirable files were filtered out. |
467 |
$err = DownloadTree($cotype, $dltype, $version, $pversion, \@filespec, \@bfilespec, \@pfilespec, \@cmdlspec, $logfile, $forceco, \@netfilter, \@sdpfilter, \$actcvs, \@actspec); |
468 |
|
469 |
if ($err) |
470 |
{ |
471 |
print STDERR "Unable to $dltype CVS tree.\n"; |
472 |
} |
473 |
elsif ($compatmode) |
474 |
{ |
475 |
# Must remove kSuFlagFile if it was present. |
476 |
# compatmode is used only during an update, so the current |
477 |
# directory is the parent of the code root directory. |
478 |
if (-e $rdir . kSuFlagFile) |
479 |
{ |
480 |
my($cvscmd) = "cvs update -A " . $rdir . kSuFlagFile . " " . $rdir . "jsoc_sync.pl " . $rdir . "jsoc_update.pl"; |
481 |
|
482 |
if (CallCVS($cvscmd, $logfile, undef, 0)) |
483 |
{ |
484 |
print STDERR "Unable to run $cvscmd.\n"; |
485 |
$err = 1; |
486 |
} |
487 |
elsif (-e $rdir . kSuFlagFile || -e $rdir . "jsoc_sync.pl" || -e $rdir . "jsoc_update.pl") |
488 |
{ |
489 |
print STDERR "Unable to delete old suflag.txt, jsoc_sync.pl, or jsoc_update.pl\n"; |
490 |
$err = 1; |
491 |
} |
492 |
} |
493 |
} |
494 |
} |
495 |
|
496 |
if (!$err) |
497 |
{ |
498 |
# Assumes that the cdir is the one containing kRootDir |
499 |
if ($dltype eq kDlCheckout || $dltype eq kDlExport || $dltype eq kDlUpdate) |
500 |
{ |
501 |
my($typefile); |
502 |
my($tmptypefile); |
503 |
my($ierr) = 0; |
504 |
|
505 |
$typefile = $rdir . &kLocDir . &kTypeFile; |
506 |
$tmptypefile = $rdir . &kLocDir . "." . &kTypeFile . ".tmp"; |
507 |
if (!(-d $rdir . kLocDir)) |
508 |
{ |
509 |
mkpath($rdir . kLocDir); |
510 |
} |
511 |
|
512 |
# Copy original version of TYPEFILE |
513 |
if (-e $typefile) |
514 |
{ |
515 |
copy($typefile, $tmptypefile); |
516 |
} |
517 |
|
518 |
# save state file |
519 |
if (open(TYPEFILE, ">" . $typefile)) |
520 |
{ |
521 |
# save check-out type |
522 |
print TYPEFILE "$cotype\n"; |
523 |
|
524 |
# print file spec used during checkout |
525 |
my($fs) = join(' ', @filespec); |
526 |
print TYPEFILE "$fs\n"; |
527 |
|
528 |
# Now print list of files that compose the file set. |
529 |
if ($dltype eq kDlUpdate) |
530 |
{ |
531 |
# Must print each tree in file specification, since |
532 |
# the tree rooted at kRootDir may contain |
533 |
# files other than the files originally downloaded |
534 |
# from CVS (e.g., running make will create new |
535 |
# files). |
536 |
|
537 |
# The update may have downloaded additional files that were not |
538 |
# in the original check-out set. And, only a subset of files |
539 |
# may have been updated. So, read in the previous set of |
540 |
# files in the TYPEFILE, then add to this list files new files |
541 |
# that were downloaded by the update. |
542 |
my(@combined); |
543 |
my(@sorted); |
544 |
my(@listf); |
545 |
my($sdir); |
546 |
my(@oldflist); |
547 |
my(@dlist); |
548 |
my(%seen); |
549 |
my($lastindx); |
550 |
|
551 |
# Read-in the list of files in the old TYPEFILE. |
552 |
if (open(OLDTYPEFILE, "<" . $tmptypefile)) |
553 |
{ |
554 |
@oldflist = <OLDTYPEFILE>; |
555 |
$lastindx = $#oldflist; |
556 |
push(@combined, @oldflist[2..$lastindx]); |
557 |
close(OLDTYPEFILE); |
558 |
|
559 |
# Export-download the update filespec into the tmp directory. The |
560 |
# user may have provided a cmd-line spec, in which case it should |
561 |
# be used for the download, and not the full file spec. The previous |
562 |
# DownloadTree() did perform this logic, and saved the cvs command |
563 |
# used in $actcvs. |
564 |
if (!(-d kTmpDir)) |
565 |
{ |
566 |
# no need to check this call, because the chdir() cmd is being checked. |
567 |
mkpath(kTmpDir); |
568 |
} |
569 |
|
570 |
$sdir = $ENV{'PWD'}; |
571 |
if (chdir(kTmpDir) == 0) |
572 |
{ |
573 |
print STDERR "Unable to cd to " . kTmpDir . ".\n"; |
574 |
$ierr = 1; |
575 |
} |
576 |
else |
577 |
{ |
578 |
# The $actcvs command won't be quite right. We need to change the |
579 |
# word 'update -APd' to export, and if there is no '-r' flag, we need to |
580 |
# add '-r HEAD' after update. |
581 |
$actcvs =~ s/update\s+-APd\s+/export /; |
582 |
if ($actcvs !~ /-r\s/) |
583 |
{ |
584 |
$actcvs =~ s/export\s/export -r HEAD /; |
585 |
} |
586 |
|
587 |
unless (CallCVSInChunks($actcvs, \@actspec, undef, undef, 1)) |
588 |
{ |
589 |
unless (GetFileList(&kTmpDir . $rdir, "", \@dlist)) |
590 |
{ |
591 |
# Combine the list of files in the downloaded tree with the list of |
592 |
# files in @combined. |
593 |
my($tmpdiri) = &kTmpDir; |
594 |
foreach my $afile (@dlist) |
595 |
{ |
596 |
# remove &kTmpDir |
597 |
$afile =~ s/$tmpdiri//; |
598 |
push(@combined, "$afile\n"); |
599 |
} |
600 |
|
601 |
# Sort and extract list of unique file names. |
602 |
@sorted = sort(@combined); |
603 |
@listf = map({ unless ($seen{$_}++){($_)}else{()} } @sorted); |
604 |
|
605 |
# Finally, print list. |
606 |
foreach my $afile (@listf) |
607 |
{ |
608 |
print TYPEFILE $afile; |
609 |
} |
610 |
} |
611 |
else |
612 |
{ |
613 |
$ierr = 1; |
614 |
} |
615 |
|
616 |
remove_tree(&kTmpDir); |
617 |
} |
618 |
else |
619 |
{ |
620 |
$ierr = 1; |
621 |
} |
622 |
|
623 |
chdir($sdir); |
624 |
} |
625 |
} |
626 |
else |
627 |
{ |
628 |
print STDERR "Unable to open $tmptypefile for reading.\n"; |
629 |
$ierr = 1; |
630 |
} |
631 |
} |
632 |
else |
633 |
{ |
634 |
if (PrintFilenames(*TYPEFILE, $rdir, 1, qr(\/CVS\/))) |
635 |
{ |
636 |
print STDERR "Unable to print file-set file names.\n"; |
637 |
$ierr = 1; |
638 |
} |
639 |
} |
640 |
|
641 |
close(TYPEFILE); |
642 |
} |
643 |
else |
644 |
{ |
645 |
print STDERR "Unable to open file " . $rdir . kLocDir . kTypeFile . " for writing.\n"; |
646 |
$ierr = 1; |
647 |
} |
648 |
|
649 |
if (!$ierr && -e $tmptypefile) |
650 |
{ |
651 |
unlink($tmptypefile); |
652 |
} |
653 |
|
654 |
# Copy the cvs update log, if it exists, back to the kRootDir (programs calling this script) |
655 |
# expect it in kRootDir. |
656 |
if (defined($logfile) && -e $logfile) |
657 |
{ |
658 |
# cp $logfile kRootDir |
659 |
if (!copy($logfile, $rdir)) |
660 |
{ |
661 |
# copy failure |
662 |
print STDERR "Unable to copy log file $logfile to " . $rdir . ".\n"; |
663 |
$err = 1; |
664 |
} |
665 |
} |
666 |
} |
667 |
elsif ($dltype eq kDlTag || $dltype eq kDlUntag) |
668 |
{ |
669 |
# Can only use the tag/untag command to tag/untag releases, |
670 |
# which can only be done on either the sdp or netdrms checkouts types. |
671 |
if ($cotype eq kCoSdp || $cotype eq kCoNetDRMS) |
672 |
{ |
673 |
my($curdirin) = $ENV{'PWD'}; |
674 |
$err = (chdir(kTmpDir . $rdir) == 0); |
675 |
if ($err) |
676 |
{ |
677 |
print STDERR "Unable to cd to " . kTmpDir . $rdir . ".\n"; |
678 |
} |
679 |
else |
680 |
{ |
681 |
if (TagFiles($cvstag, $dltype, $logfile)) |
682 |
{ |
683 |
print STDERR "Unable to tag/untag files in file specification.\n"; |
684 |
$err = 1; |
685 |
} |
686 |
} |
687 |
|
688 |
if (chdir($curdirin) == 0) |
689 |
{ |
690 |
print STDERR "Unable to cd to $curdir.\n"; |
691 |
if (!$err) |
692 |
{ |
693 |
$err = 1; |
694 |
} |
695 |
} |
696 |
} |
697 |
else |
698 |
{ |
699 |
print STDERR "Checkout type $cotype not compatible with tag command.\n"; |
700 |
$err = 1; |
701 |
} |
702 |
} |
703 |
elsif ($dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
704 |
{ |
705 |
if (PrintFilenames(*STDOUT, kTmpDir . $rdir, 0)) |
706 |
{ |
707 |
print STDERR "Unable to print file set file names.\n"; |
708 |
$err = 1; |
709 |
} |
710 |
} |
711 |
} |
712 |
|
713 |
if (defined($curdir)) |
714 |
{ |
715 |
# This implies that a successful chdir was done previously. |
716 |
if (chdir($curdir) == 0) |
717 |
{ |
718 |
print STDERR "Unable to cd to $curdir.\n"; |
719 |
$err = 1; |
720 |
} |
721 |
} |
722 |
|
723 |
# Delete all files from temporary directory, but only if there were no errors |
724 |
if (!$err) |
725 |
{ |
726 |
if (-d kTmpDir) |
727 |
{ |
728 |
remove_tree(kTmpDir, {error => \my $errlist}); |
729 |
if (@{$errlist}) |
730 |
{ |
731 |
print STDERR "Unable to properly remove temporary subdirectory $tmpdir.\n"; |
732 |
$err = 1; |
733 |
} |
734 |
} |
735 |
} |
736 |
} |
737 |
} |
738 |
} |
739 |
|
740 |
exit($err); |
741 |
|
742 |
sub ReadCfg |
743 |
{ |
744 |
my($cfgfile) = $_[0]; |
745 |
my($xml) = $_[1]; # reference |
746 |
my($rv); |
747 |
|
748 |
$rv = 0; |
749 |
|
750 |
# initialize xml string variable |
751 |
$$xml = ""; |
752 |
|
753 |
if (defined($cfgfile) && -e $cfgfile) |
754 |
{ |
755 |
if (open(CFGFILE, "<$cfgfile")) |
756 |
{ |
757 |
my($projdone); |
758 |
my($line); |
759 |
|
760 |
$st = kStUnk; |
761 |
$pdiv = kProjDiv; |
762 |
$ediv = kEndDiv; |
763 |
|
764 |
$projdone = 0; |
765 |
|
766 |
while (defined($line = <CFGFILE>)) |
767 |
{ |
768 |
chomp($line); |
769 |
|
770 |
if ($line =~ /^\#/ || $line =~ /^\s*$/) |
771 |
{ |
772 |
# Skip blank lines or lines beginning with # (comment lines) |
773 |
next; |
774 |
} |
775 |
elsif ($line =~ /^$pdiv/) |
776 |
{ |
777 |
$st = kStProj; |
778 |
|
779 |
|
780 |
next; |
781 |
} |
782 |
elsif ($line =~ /^$ediv/) |
783 |
{ |
784 |
if ($st == kStProj) |
785 |
{ |
786 |
$projdone = 1; |
787 |
} |
788 |
|
789 |
$st = kStUnk; |
790 |
|
791 |
if ($projdone) |
792 |
{ |
793 |
last; |
794 |
} |
795 |
|
796 |
next; |
797 |
} |
798 |
|
799 |
if ($st == kStProj) |
800 |
{ |
801 |
# suck out xml |
802 |
$$xml = $$xml . "$line\n"; |
803 |
} |
804 |
} # loop over cfg file |
805 |
|
806 |
close(CFGFILE); |
807 |
} |
808 |
else |
809 |
{ |
810 |
print STDERR "Unable to open $cfgfile for reading.\n"; |
811 |
$rv = 1; |
812 |
} |
813 |
} |
814 |
else |
815 |
{ |
816 |
print STDERR "Unable to open $cfgfile for reading.\n"; |
817 |
$rv = 1; |
818 |
} |
819 |
|
820 |
return $rv; |
821 |
} |
822 |
|
823 |
# fsout - The full file spec for the given type of checkout. |
824 |
# bfsout - Same as fsout. Used only for custom checkouts. |
825 |
# pfsout - For custom checkouts only. This is the project-directory file spec. |
826 |
sub BuildFilespec |
827 |
{ |
828 |
my($cotype) = $_[0]; |
829 |
my($dltype) = $_[1]; |
830 |
my($stfspec) = $_[2]; |
831 |
my($xmldata) = $_[3]; # reference to hash |
832 |
my($core) = $_[4]; |
833 |
my($netonly) = $_[5]; |
834 |
my($sdponly) = $_[6]; |
835 |
my($fsout) = $_[7]; |
836 |
my($bfsout) = $_[8]; |
837 |
my($pfsout) = $_[9]; |
838 |
my($cmdlspec) = $_[10]; # Altenate file spec - use in place of $core, $netonly, and $sdponly. |
839 |
# Can be used only for an update, tag, or untag download type. |
840 |
my($coreDel) = $_[11]; |
841 |
my($netDel) = $_[12]; |
842 |
my($sdpDel) = $_[13]; |
843 |
|
844 |
my($rv); |
845 |
my($strproj) = &kStrproj; |
846 |
my($strname) = &kStrname; |
847 |
|
848 |
$rv = 0; |
849 |
|
850 |
if ($#cmdlspec >= 0) |
851 |
{ |
852 |
if ($cotype ne kCoCustom && ($dltype eq kDlUpdate || $dltype eq kDlTag || $dltype eq kDlTag)) |
853 |
{ |
854 |
my($compflistH); |
855 |
my(@fset); |
856 |
|
857 |
# Ensure that files specified on the cmd-line are actually part of the current |
858 |
# check-out type (net, sdp, or custom). To obtain the list of the current check-out set, |
859 |
# we need to check out everything in the appropriate definitive file spec (as an export). |
860 |
|
861 |
# This function returns a hash whose element keys are file names. If the filename-key |
862 |
# represents a regualar file, then the value for the key is 'f'. If the filename-key |
863 |
# represents a directory, then the value for this key is a hash with one element |
864 |
# per file in this directory. |
865 |
# |
866 |
# If there is a regular file in $cmdlspec, then traverse $compflistH until the |
867 |
# parent directory is found. Then verify that the regular file is in the hash |
868 |
# of this parent directory. If it is found, then add the regular file |
869 |
# to the array of file-specs returned to the caller. If there is a directory in $cmdlspec, |
870 |
# traverse $compflistH until the directory is found. Then collect ALL regular files rooted |
871 |
# at this directory and add those to the array of file-specs returned to the caller. |
872 |
if (!$rv) |
873 |
{ |
874 |
$compflistH = GetDefinitiveFileSet($cotype, $core, $netonly, $sdponly, $xmldata, $stfspec, $version, $pversion, $reprdir, $rdir); |
875 |
|
876 |
foreach my $spec (@$cmdlspec) |
877 |
{ |
878 |
@fset = CollectFiles($spec, $compflistH); |
879 |
if ($#fset >= 0) |
880 |
{ |
881 |
# ART - If this is a custom check-out, then this is wrong. We'd need to |
882 |
# sort the files into those in the proj dir, and those in the base dir, |
883 |
# then put the proj-dir ones into $fpsout. But there is too much to do, |
884 |
# so for now ignore the custom check-out case. |
885 |
push(@$bfsout, @fset); |
886 |
} |
887 |
else |
888 |
{ |
889 |
print STDERR "Warning: Invalid cmd-line file specification $spec.\n"; |
890 |
} |
891 |
} |
892 |
|
893 |
# fill in the complete set of files |
894 |
if ($cotype eq kCoNetDRMS) |
895 |
{ |
896 |
push(@$fsout, @$core); |
897 |
push(@$fsout, @$netonly); |
898 |
} |
899 |
elsif ($cotype eq kCoSdp) |
900 |
{ |
901 |
push(@$fsout, @$core); |
902 |
push(@$fsout, @$sdponly); |
903 |
} |
904 |
} |
905 |
} |
906 |
else |
907 |
{ |
908 |
print STDERR "No support for cmd-line file specification with this check-out type/operation.\n"; |
909 |
$rv = 1; |
910 |
} |
911 |
} |
912 |
else |
913 |
{ |
914 |
if ($cotype eq kCoCustom && $dltype eq kDlUpdate && (!defined($xmldata) || $#{$xmldata->{$strproj}} < 0)) |
915 |
{ |
916 |
# If this is an update of a custom checkout, and the user did not provide a config-file argument, |
917 |
# then use the file spec stored in the existing typefile |
918 |
if (defined($stfspec) && length($stfspec) > 0) |
919 |
{ |
920 |
@$fsout = qw($stfspec); |
921 |
} |
922 |
else |
923 |
{ |
924 |
print STDERR "Invalid file specification in state file.\n"; |
925 |
$rv = 1; |
926 |
} |
927 |
} |
928 |
else |
929 |
{ |
930 |
# If doing an update, add to the file set the list of deleted files. This will |
931 |
# result in removal of files in the sandbox that have already been removed from |
932 |
# the repository. This only matters for files directory in the root directory. |
933 |
# Files is subdirectories will be processed via a cvs update of the subdirectory. |
934 |
if ($cotype eq kCoNetDRMS) |
935 |
{ |
936 |
push(@$fsout, @$core); |
937 |
if ($dltype eq kDlUpdate) |
938 |
{ |
939 |
# If the user has these obsolete files in their working directory, the |
940 |
# only safe way to remove them is to run cvs update on them. But we do |
941 |
# not want to run that command if the files do not exist. |
942 |
foreach $delFile (@$coreDel) |
943 |
{ |
944 |
if (-e $delFile) |
945 |
{ |
946 |
push(@$fsout, $delFile); |
947 |
} |
948 |
} |
949 |
} |
950 |
push(@$fsout, @$netonly); |
951 |
if ($dltype eq kDlUpdate) |
952 |
{ |
953 |
# If the user has these obsolete files in their working directory, the |
954 |
# only safe way to remove them is to run cvs update on them. But we do |
955 |
# not want to run that command if the files do not exist. |
956 |
foreach $delFile (@$netDel) |
957 |
{ |
958 |
if (-e $delFile) |
959 |
{ |
960 |
push(@$fsout, $delFile); |
961 |
} |
962 |
} |
963 |
} |
964 |
push(@$bfsout, @$fsout); |
965 |
} |
966 |
elsif ($cotype eq kCoSdp) |
967 |
{ |
968 |
push(@$fsout, @$core); |
969 |
if ($dltype eq kDlUpdate) |
970 |
{ |
971 |
# If the user has these obsolete files in their working directory, the |
972 |
# only safe way to remove them is to run cvs update on them. But we do |
973 |
# not want to run that command if the files do not exist. |
974 |
foreach $delFile (@$coreDel) |
975 |
{ |
976 |
if (-e $delFile) |
977 |
{ |
978 |
push(@$fsout, $delFile); |
979 |
} |
980 |
} |
981 |
} |
982 |
push(@$fsout, @$sdponly); |
983 |
if ($dltype eq kDlUpdate) |
984 |
{ |
985 |
# If the user has these obsolete files in their working directory, the |
986 |
# only safe way to remove them is to run cvs update on them. But we do |
987 |
# not want to run that command if the files do not exist. |
988 |
foreach $delFile (@$sdpDel) |
989 |
{ |
990 |
if (-e $delFile) |
991 |
{ |
992 |
push(@$fsout, $delFile); |
993 |
} |
994 |
} |
995 |
} |
996 |
push(@$bfsout, @$fsout); |
997 |
} |
998 |
elsif ($cotype eq kCoCustom) |
999 |
{ |
1000 |
push(@$fsout, @$core); |
1001 |
push(@$fsout, @$netonly); |
1002 |
push(@$bfsout, @$fsout); |
1003 |
|
1004 |
# If there is a -R flag, then it applies only to the checkout of project directories specified in |
1005 |
# the config file - so keep these files separate from the rest. @$bfsout contains the files in base, |
1006 |
# @$pfsout contains the files in proj. |
1007 |
|
1008 |
# Use $xmldata to populate @pfsout and @fsout |
1009 |
foreach $proj (@{$xmldata->{$strproj}}) |
1010 |
{ |
1011 |
push(@$fsout, kProjSubdir . "/" . $proj->{$strname}->[0]); |
1012 |
push(@$pfsout, kProjSubdir . "/" . $proj->{$strname}->[0]); |
1013 |
} |
1014 |
} |
1015 |
else |
1016 |
{ |
1017 |
print STDERR "Unsupported checkout type $cotype.\n"; |
1018 |
$rv = 1; |
1019 |
} |
1020 |
} |
1021 |
} |
1022 |
|
1023 |
return $rv; |
1024 |
} |
1025 |
|
1026 |
sub IsBadGuy |
1027 |
{ |
1028 |
my($file) = $_[0]; |
1029 |
my($badguys) = $_[1]; |
1030 |
|
1031 |
my($dir); |
1032 |
|
1033 |
if (defined($badguys->{$file})) |
1034 |
{ |
1035 |
return 1; |
1036 |
} |
1037 |
else |
1038 |
{ |
1039 |
if (substr($file, -1, 1) eq '/') |
1040 |
{ |
1041 |
$file = substr($file, 0, length($file) - 1); |
1042 |
} |
1043 |
|
1044 |
while (1) |
1045 |
{ |
1046 |
my($fn, $dir, $sfx) = fileparse($file); |
1047 |
|
1048 |
if (substr($dir, -1, 1) eq '/') |
1049 |
{ |
1050 |
$dir = substr($dir, 0, length($dir) - 1); |
1051 |
} |
1052 |
|
1053 |
if (!defined($dir) || length($dir) == 0 || $dir eq ".") |
1054 |
{ |
1055 |
return 0; |
1056 |
} |
1057 |
|
1058 |
if (defined($badguys->{$dir})) |
1059 |
{ |
1060 |
return 1; |
1061 |
} |
1062 |
|
1063 |
if ($file ne $dir) |
1064 |
{ |
1065 |
$file = $dir; |
1066 |
} |
1067 |
else |
1068 |
{ |
1069 |
return 0; |
1070 |
} |
1071 |
} |
1072 |
} |
1073 |
|
1074 |
return 0; |
1075 |
} |
1076 |
|
1077 |
sub DownloadTree |
1078 |
{ |
1079 |
my($cotype) = $_[0]; |
1080 |
my($dltype) = $_[1]; |
1081 |
my($version) = $_[2]; |
1082 |
my($pversion) = $_[3]; |
1083 |
my($fspec) = $_[4]; |
1084 |
my($bfspec) = $_[5]; |
1085 |
my($pfspec) = $_[6]; |
1086 |
my($cmdlspec) = $_[7]; |
1087 |
my($logfile) = $_[8]; |
1088 |
my($forceco) = $_[9]; |
1089 |
my($netfilter) = $_[10]; |
1090 |
my($sdpfilter) = $_[11]; |
1091 |
my($actualcvs) = $_[12]; |
1092 |
my($actualspec) = $_[13]; |
1093 |
|
1094 |
my($rv) = 0; |
1095 |
my($curdir); |
1096 |
my($callstat); |
1097 |
my($cvscmd); |
1098 |
my($cmd); |
1099 |
my($rev); |
1100 |
my($prev); |
1101 |
my(@relpaths); |
1102 |
my($forcecostr) = $forceco ? "-f" : ""; |
1103 |
my($filterdir); |
1104 |
my(@specfiles); |
1105 |
my($filter); |
1106 |
my($log); |
1107 |
|
1108 |
if ($dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1109 |
{ |
1110 |
# Output should be a list of files only. |
1111 |
$log = "/dev/null"; |
1112 |
} |
1113 |
else |
1114 |
{ |
1115 |
$log = $logfile; |
1116 |
} |
1117 |
|
1118 |
if (length($dltype) > 0) |
1119 |
{ |
1120 |
if ($dltype eq kDlCheckout || $dltype eq kDlTag || $dltype eq kDlUntag) |
1121 |
{ |
1122 |
$cvscmd = "checkout -AP"; |
1123 |
} |
1124 |
elsif ($dltype eq kDlExport || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1125 |
{ |
1126 |
$cvscmd = "export"; |
1127 |
} |
1128 |
elsif ($dltype eq kDlUpdate) |
1129 |
{ |
1130 |
# If a new directory is added to the repository AND the new directory is added to the |
1131 |
# file specifications above, then the -d flag to cvs update will cause the new directory |
1132 |
# to be downloaded to the client. |
1133 |
$cvscmd = "update -APd"; |
1134 |
} |
1135 |
else |
1136 |
{ |
1137 |
print STDERR "Unsupported download type $dltype.\n"; |
1138 |
$rv = 1; |
1139 |
} |
1140 |
} |
1141 |
else |
1142 |
{ |
1143 |
# Default to a checkout. |
1144 |
$cvscmd = "checkout -AP"; |
1145 |
} |
1146 |
|
1147 |
if (!$rv) |
1148 |
{ |
1149 |
if (defined($version) && length($version) > 0) |
1150 |
{ |
1151 |
$rev = "-r $version"; |
1152 |
} |
1153 |
elsif ($dltype eq kDlExport || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1154 |
{ |
1155 |
# Only export requires a revision argument |
1156 |
$rev = "-r HEAD"; |
1157 |
} |
1158 |
else |
1159 |
{ |
1160 |
$rev = ""; |
1161 |
} |
1162 |
|
1163 |
if (defined($pversion) && length($pversion) > 0) |
1164 |
{ |
1165 |
$prev = "-r $pversion"; |
1166 |
} |
1167 |
elsif ($dltype eq kDlExport || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1168 |
{ |
1169 |
# Only export requires a revision argument |
1170 |
$prev = "-r HEAD"; |
1171 |
} |
1172 |
else |
1173 |
{ |
1174 |
$prev = ""; |
1175 |
} |
1176 |
} |
1177 |
|
1178 |
if (!$rv) |
1179 |
{ |
1180 |
# Check the existence of the proper directories required for each operation. |
1181 |
if ($dltype eq kDlCheckout || $dltype eq kDlExport) |
1182 |
{ |
1183 |
# If $dltype is kDlCheckout, kDlExport,then there must not be a JSOC subdirectory in the current directory. |
1184 |
if (-e $rdir) |
1185 |
{ |
1186 |
print STDERR "Root directory " . $rdir . " already exists.\n"; |
1187 |
$rv = 1; |
1188 |
} |
1189 |
} |
1190 |
elsif ($dltype eq kDlTag || $dltype eq kDlUntag || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1191 |
{ |
1192 |
# If $dltype is kDlTag, kDlUntag, kDlPrint, or kDlPrintRelease then it is okay to delete the JSOC subdirectory |
1193 |
# because these three operations create a temporary JSOC directory. |
1194 |
if (-e kTmpDir . $rdir) |
1195 |
{ |
1196 |
remove_tree(kTmpDir . $rdir, {error => \my $errlist}); |
1197 |
if (@{$errlist}) |
1198 |
{ |
1199 |
print STDERR "Unable to properly remove temporary subdirectory $tmpdir.\n"; |
1200 |
$rv = 1; |
1201 |
} |
1202 |
} |
1203 |
} |
1204 |
elsif ($dltype eq kDlUpdate) |
1205 |
{ |
1206 |
# If $dltype is kDlUpdate, then there MUST be a working directory root. |
1207 |
# The current directory is the parent of the root directory (if it exists). |
1208 |
my($rootdir) = File::Spec->catdir($rdir); |
1209 |
|
1210 |
if (!(-d $rootdir)) |
1211 |
{ |
1212 |
print STDERR "Working dir is $ENV{PWD}; expected DRMS root dir is $rootdir.\n"; |
1213 |
print STDERR "No CVS working directory exists in $ENV{'PWD'}.\n"; |
1214 |
$rv = 1; |
1215 |
} |
1216 |
} |
1217 |
else |
1218 |
{ |
1219 |
print STDERR "Unsupported download type $dltype.\n"; |
1220 |
$rv = 1; |
1221 |
} |
1222 |
} |
1223 |
|
1224 |
if (!$rv) |
1225 |
{ |
1226 |
# If this is an export or print command, download to a temporary directory, |
1227 |
# obtain the full list of files from the download directory, |
1228 |
# apply the filters to remove files from this list, then call CVS again |
1229 |
# providing this list of file paths. After obtaining this list, |
1230 |
# delete the files in the temporary directory. |
1231 |
# |
1232 |
# Must cd to the temporary directory because if this is an export, |
1233 |
# then the current directory is not the temporary directory. |
1234 |
if ($dltype eq kDlExport || $dltype eq kDlPrint || $dltype eq kDlPrintRelease) |
1235 |
{ |
1236 |
$filterdir = $ENV{'PWD'}; |
1237 |
$filter = ($cotype eq kCoSdp) ? $sdpfilter : $netfilter; |
1238 |
|
1239 |
# The temp directory may not exist if this is an export. |
1240 |
if (!(-d kTmpDir)) |
1241 |
{ |
1242 |
# no need to check this call, because the chdir() cmd is being checked. |
1243 |
mkpath(kTmpDir); |
1244 |
} |
1245 |
} |
1246 |
} |
1247 |
|
1248 |
if (!$rv) |
1249 |
{ |
1250 |
# Checkout the project files with a separate cvs command - using the version tag specific to the project |
1251 |
# files. |
1252 |
|
1253 |
# THIS SECTION CHECKS-OUT THE BASE FILES. |
1254 |
if (length($rev) > 0) |
1255 |
{ |
1256 |
$cvscmd = "$cvscmd $forcecostr"; |
1257 |
} |
1258 |
|
1259 |
@relpaths = map({$reprdir . "$_"} @{$bfspec}); |
1260 |
|
1261 |
# Filter out undesired files. $filter contains a black list. DOES NOT APPLY TO update. |
1262 |
if (defined($filterdir)) |
1263 |
{ |
1264 |
# We need to filter out undesirables - checkout into temp dir now (which we cded to above). |
1265 |
my(%badguys); |
1266 |
my($tcmd) = join(' ', "cvs", $cvscmd, $rev, @relpaths); |
1267 |
|
1268 |
$rv = (chdir(kTmpDir) == 0); |
1269 |
if ($rv) |
1270 |
{ |
1271 |
print STDERR "Unable to cd to " . kTmpDir . ".\n"; |
1272 |
} |
1273 |
else |
1274 |
{ |
1275 |
# Check-out all files from repository (will filter out the non-release files below). |
1276 |
if (CallCVS($tcmd, $log, undef, 0)) |
1277 |
{ |
1278 |
print STDERR "Unable to $dltype repository files.\n"; |
1279 |
$rv = 1; |
1280 |
} |
1281 |
else |
1282 |
{ |
1283 |
# Get a list of all files from temp dir. |
1284 |
@specfiles = (); |
1285 |
if (GetFileList($rdir, "", \@specfiles)) |
1286 |
{ |
1287 |
print STDERR "Unable to retrieve list of files rooted at " . kTmpDir . $rdir . ".\n"; |
1288 |
$rv = 1; |
1289 |
} |
1290 |
else |
1291 |
{ |
1292 |
# At long last we can filter out the bad guys. |
1293 |
foreach $guy (@{$filter}) |
1294 |
{ |
1295 |
$badguys{$rdir . $guy} = 1; |
1296 |
} |
1297 |
|
1298 |
# Since badguys might contain directories, not just plain files, we have to |
1299 |
# check ALL parent directories for existence in badguys. Blah. |
1300 |
@relpaths = map({IsBadGuy($_, \%badguys) ? () : $_;} @specfiles); |
1301 |
} |
1302 |
} |
1303 |
} |
1304 |
|
1305 |
# Back to the original working directory |
1306 |
remove_tree(kTmpDir . $rdir, {error => \my $errlist}); |
1307 |
if (@{$errlist}) |
1308 |
{ |
1309 |
print STDERR "Unable to properly remove temporary subdirectory $tmpdir.\n"; |
1310 |
$rv = 1; |
1311 |
} |
1312 |
|
1313 |
chdir($filterdir); |
1314 |
} |
1315 |
|
1316 |
$cmd = join(' ', $cvscmd, $rev); |
1317 |
|
1318 |
if (defined($actualcvs)) |
1319 |
{ |
1320 |
$$actualcvs = $cmd; |
1321 |
} |
1322 |
|
1323 |
if (defined($actualspec)) |
1324 |
{ |
1325 |
@$actualspec = @relpaths; |
1326 |
} |
1327 |
|
1328 |
if (CallCVSInChunks($cmd, \@relpaths, $log, undef, 0)) |
1329 |
{ |
1330 |
print STDERR "Unable to $dltype repository files.\n"; |
1331 |
$rv = 1; |
1332 |
} |
1333 |
else |
1334 |
{ |
1335 |
# If this is a sdp or net checkout, then $pfspec will be empty, so we can skip this second |
1336 |
# checkout. |
1337 |
|
1338 |
if (defined($pfspec) && $#{$pfspec} >= 0) |
1339 |
{ |
1340 |
# THIS SECTION CHECKS-OUT THE PROJECT FILES (if this is a custom checkout). |
1341 |
if (length($prev) > 0) |
1342 |
{ |
1343 |
$cvscmd = "$cvscmd $forcecostr"; |
1344 |
} |
1345 |
|
1346 |
@relpaths = map({$reprdir . "$_"} @{$pfspec}); |
1347 |
|
1348 |
if (defined($filterdir)) |
1349 |
{ |
1350 |
# We need to filter out undesirables - checkout into temp dir now (which we cded to above). |
1351 |
# DOES NOT APPLY TO update. |
1352 |
my(%badguys); |
1353 |
my($tcmd) = join(' ', "cvs", $cvscmd, $prev, @relpaths); |
1354 |
|
1355 |
$rv = (chdir(kTmpDir) == 0); |
1356 |
if ($rv) |
1357 |
{ |
1358 |
print STDERR "Unable to cd to " . kTmpDir . ".\n"; |
1359 |
} |
1360 |
else |
1361 |
{ |
1362 |
# Check-out all files from repository (will filter out the non-release files below). |
1363 |
if (CallCVS($tcmd, $log, undef, 0)) |
1364 |
{ |
1365 |
print STDERR "Unable to $dltype repository files.\n"; |
1366 |
$rv = 1; |
1367 |
} |
1368 |
else |
1369 |
{ |
1370 |
# Get a list of all files from temp dir. |
1371 |
@specfiles = (); |
1372 |
if (GetFileList($rdir, "", \@specfiles)) |
1373 |
{ |
1374 |
print STDERR "Unable to retrieve list of files rooted at " . kTmpDir . $rdir . ".\n"; |
1375 |
$rv = 1; |
1376 |
} |
1377 |
else |
1378 |
{ |
1379 |
# At long last we can filter out the bad guys. |
1380 |
foreach $guy (@{$filter}) |
1381 |
{ |
1382 |
$badguys{$rdir . $guy} = 1; |
1383 |
} |
1384 |
|
1385 |
@relpaths = map({IsBadGuy($_, \%badguys) ? () : $_;} @specfiles); |
1386 |
} |
1387 |
} |
1388 |
} |
1389 |
|
1390 |
remove_tree(kTmpDir . $rdir, {error => \my $errlist}); |
1391 |
if (@{$errlist}) |
1392 |
{ |
1393 |
print STDERR "Unable to properly remove temporary subdirectory $tmpdir.\n"; |
1394 |
$rv = 1; |
1395 |
} |
1396 |
|
1397 |
chdir($filterdir); |
1398 |
} |
1399 |
|
1400 |
$cmd = join(' ', "cvs", $cvscmd, $prev, @relpaths); |
1401 |
|
1402 |
if (CallCVS($cmd, $log, undef, 0)) |
1403 |
{ |
1404 |
print STDERR "Unable to $dltype repository files.\n"; |
1405 |
$rv = 1; |
1406 |
} |
1407 |
} |
1408 |
} |
1409 |
} |
1410 |
|
1411 |
if (!$rv && $dltype eq kDlUpdate) |
1412 |
{ |
1413 |
# An update will not remove files that were deleted from the repository from the sandbox. |
1414 |
# So, we must do a cvs update on every file that was deleted from the server. Shit. |
1415 |
# How do we figure out which files were deleted from the server? It's not like |
1416 |
# we can ask cvs that question? But we can run any old cvs command using the global |
1417 |
# -n flag, which will forestall any sandbox changes. Call cvs -n update on the root dir. |
1418 |
# Then parse STDERR results (for some crazy reason cvs prints this output to stderr), |
1419 |
# saving all lines with "is no longer in the repository". The text immediately before this |
1420 |
# string is the name of the file. For all these files, call cvs update. |
1421 |
my(@resp); |
1422 |
my(@orig); |
1423 |
my(@delfiles); |
1424 |
|
1425 |
# The working directory is the root directory. |
1426 |
|
1427 |
# Unfortunately, we have to call CVS twice - once for base specs and once for proj |
1428 |
# specs. Each type of spec will use a different -r flag. |
1429 |
$cmd = "-n update $rev"; |
1430 |
|
1431 |
if (length($rev) > 0) |
1432 |
{ |
1433 |
$cmd = "$cmd $forcecostr"; |
1434 |
} |
1435 |
|
1436 |
# Original file specs. |
1437 |
if ($#cmdlspec >= 0) |
1438 |
{ |
1439 |
@orig = map({$reprdir . "$_"} @{$cmdlspec}); |
1440 |
} |
1441 |
else |
1442 |
{ |
1443 |
@orig = map({$reprdir . "$_"} @{$bfspec}); |
1444 |
} |
1445 |
|
1446 |
if (CallCVSInChunks($cmd, \@orig, undef, \@resp, 1)) |
1447 |
{ |
1448 |
print STDERR "Unable to locate sandbox files that were deleted from the repository.\n"; |
1449 |
$rv = 1; |
1450 |
} |
1451 |
else |
1452 |
{ |
1453 |
push(@delfiles, @resp); |
1454 |
|
1455 |
if ($#cmdlspec < 0) |
1456 |
{ |
1457 |
# If a cmdlspec was given, then all specs are in cmdlspec. |
1458 |
$cmd = "-n update $prev"; |
1459 |
if (length($prev) > 0) |
1460 |
{ |
1461 |
$cmd = "$cmd $forcecostr"; |
1462 |
} |
1463 |
|
1464 |
if (CallCVSInChunks($cmd, \@$pfspec, undef, \@resp, 1)) |
1465 |
{ |
1466 |
print STDERR "Unable to locate sandbox files that were deleted from the repository.\n"; |
1467 |
$rv = 1; |
1468 |
} |
1469 |
else |
1470 |
{ |
1471 |
push(@delfiles, @resp); |
1472 |
} |
1473 |
} |
1474 |
} |
1475 |
|
1476 |
if (!$rv) |
1477 |
{ |
1478 |
my(@filestoud); |
1479 |
|
1480 |
foreach my $line (@delfiles) |
1481 |
{ |
1482 |
chomp($line); |
1483 |
if ($line =~ /(\S+)\s+is no longer in the repository/) |
1484 |
{ |
1485 |
push(@filestoud, $1); |
1486 |
} |
1487 |
} |
1488 |
|
1489 |
# Finally, call CVS yet again, but without the "-n" flag. This will remove from the sandbox |
1490 |
# files deleted from the repository. |
1491 |
|
1492 |
my($removecmd) = $cmd; |
1493 |
$removecmd =~ s/-n//; |
1494 |
|
1495 |
if (CallCVSInChunks($removecmd, \@filestoud, $log, undef, 0)) |
1496 |
{ |
1497 |
print STDERR "Unable to locate sandbox files that were deleted from the repository.\n"; |
1498 |
$rv = 1; |
1499 |
} |
1500 |
} |
1501 |
} |
1502 |
|
1503 |
return $rv; |
1504 |
} |
1505 |
|
1506 |
# tag all files in cwd with tag $tag |
1507 |
sub TagFiles |
1508 |
{ |
1509 |
my($tag) = $_[0]; |
1510 |
my($dltype) = $_[1]; |
1511 |
my($logfile) = $_[2]; |
1512 |
|
1513 |
my($rv) = 0; |
1514 |
my(@allfiles); |
1515 |
my($curdir) = $ENV{'PWD'}; |
1516 |
my($cmd); |
1517 |
|
1518 |
if ($dltype eq kDlTag) |
1519 |
{ |
1520 |
# call cvs tag -c <tag> |
1521 |
$cmd = "cvs tag -c $tag ." |
1522 |
} else |
1523 |
{ |
1524 |
# call cvs tag -d <tag> |
1525 |
$cmd = "cvs tag -d $tag ." |
1526 |
} |
1527 |
|
1528 |
if (CallCVS($cmd, $logfile, undef, 0)) |
1529 |
{ |
1530 |
print STDERR "Unable to tag repository files.\n"; |
1531 |
$rv = 1; |
1532 |
} |
1533 |
|
1534 |
return $rv; |
1535 |
} |
1536 |
|
1537 |
sub PrintFilenames |
1538 |
{ |
1539 |
my($fh) = $_[0]; |
1540 |
my($froot) = $_[1]; |
1541 |
my($sort) = $_[2]; |
1542 |
my($regexp) = $_[3]; |
1543 |
|
1544 |
my($rv) = 0; |
1545 |
my(@allfiles); |
1546 |
|
1547 |
if (GetFileList($froot, "", \@allfiles)) |
1548 |
{ |
1549 |
print STDERR "Unable to retrieve list of files rooted at $froot.\n"; |
1550 |
$rv = 1; |
1551 |
} |
1552 |
else |
1553 |
{ |
1554 |
my(@final); |
1555 |
|
1556 |
if ($sort) |
1557 |
{ |
1558 |
@final = sort(@allfiles); |
1559 |
} |
1560 |
else |
1561 |
{ |
1562 |
@final = @allfiles; |
1563 |
} |
1564 |
|
1565 |
foreach $afile (@final) |
1566 |
{ |
1567 |
if (defined($regexp)) |
1568 |
{ |
1569 |
if ($afile !~ $regexp) |
1570 |
{ |
1571 |
print $fh "$afile\n"; |
1572 |
} |
1573 |
} |
1574 |
else |
1575 |
{ |
1576 |
print $fh "$afile\n"; |
1577 |
} |
1578 |
} |
1579 |
} |
1580 |
|
1581 |
return $rv; |
1582 |
} |
1583 |
|
1584 |
sub SPrintFilenames |
1585 |
{ |
1586 |
my($listA) = $_[0]; |
1587 |
my($froot) = $_[1]; |
1588 |
|
1589 |
my($rv) = 0; |
1590 |
my(@allfiles); |
1591 |
|
1592 |
if (GetFileList($froot, "", \@allfiles)) |
1593 |
{ |
1594 |
print STDERR "Unable to retrieve list of files rooted at $froot.\n"; |
1595 |
$rv = 1; |
1596 |
} |
1597 |
else |
1598 |
{ |
1599 |
foreach $afile (@allfiles) |
1600 |
{ |
1601 |
push(@$listA, "$afile"); |
1602 |
} |
1603 |
} |
1604 |
|
1605 |
return $rv; |
1606 |
} |
1607 |
|
1608 |
# Returns a list of all files in the code tree rooted at $spec. The names of each file |
1609 |
# will be prefixed by $dir, unless $dir is the empty string. $listout points to the |
1610 |
# returned list of files. |
1611 |
sub GetFileList |
1612 |
{ |
1613 |
my($spec) = $_[0]; |
1614 |
my($dir) = $_[1]; # the directory to prepend to files when inserting into $listout |
1615 |
my($listout) = $_[2]; |
1616 |
|
1617 |
my($rv) = 0; |
1618 |
my($prefix); |
1619 |
|
1620 |
if (length($dir) > 0) |
1621 |
{ |
1622 |
if (substr($dir, length($dir) - 1, 1) eq "/") |
1623 |
{ |
1624 |
$prefix = $dir; |
1625 |
} |
1626 |
else |
1627 |
{ |
1628 |
$prefix = "$dir/"; |
1629 |
} |
1630 |
} |
1631 |
else |
1632 |
{ |
1633 |
$prefix = ""; |
1634 |
} |
1635 |
|
1636 |
if (!(-e $spec)) |
1637 |
{ |
1638 |
print STDERR "File $spec does not exist in $ENV{'PWD'}.\n"; |
1639 |
$rv = 1; |
1640 |
} |
1641 |
else |
1642 |
{ |
1643 |
|
1644 |
if (-f "$spec") |
1645 |
{ |
1646 |
# $spec is a file - just push onto output list |
1647 |
push(@{$listout}, "$prefix$spec"); |
1648 |
} |
1649 |
elsif (-d "$spec") |
1650 |
{ |
1651 |
my(@alltreefiles); |
1652 |
my(@treefiles); |
1653 |
my($curdir); |
1654 |
|
1655 |
# This is a directory, collect all files (excluding "." and "..") in the tree rooted at |
1656 |
# this directory. |
1657 |
$curdir = "$ENV{'PWD'}"; |
1658 |
chdir($spec); |
1659 |
tie(my(%tree), "IO::Dir", "."); |
1660 |
@alltreefiles = keys(%tree); |
1661 |
@treefiles = map({$_ !~ /^\.$/ && $_ !~ /^\.\.$/ ? $_ : ()} @alltreefiles); |
1662 |
|
1663 |
|
1664 |
# Now recursively call GetFileList() for each item in @treefiles |
1665 |
foreach $childspec (@treefiles) |
1666 |
{ |
1667 |
GetFileList($childspec, "$prefix$spec", $listout); |
1668 |
} |
1669 |
|
1670 |
chdir($curdir); |
1671 |
} |
1672 |
else |
1673 |
{ |
1674 |
print STDERR "File '$spec' is not a supported file type.\n"; |
1675 |
$rv = 1; |
1676 |
} |
1677 |
} |
1678 |
|
1679 |
return $rv; |
1680 |
} |
1681 |
|
1682 |
sub CallCVS |
1683 |
{ |
1684 |
my($cmd) = $_[0]; |
1685 |
my($log) = $_[1]; |
1686 |
my($rsp) = $_[2]; |
1687 |
my($silent) = $_[3]; |
1688 |
|
1689 |
my($rv) = 0; |
1690 |
my($callstat); |
1691 |
|
1692 |
if (defined($log) && length($log) > 0) |
1693 |
{ |
1694 |
system("$cmd 1>$log 2>&1"); |
1695 |
} |
1696 |
elsif (defined($rsp)) |
1697 |
{ |
1698 |
if (open(PIPE, "$cmd 2>&1 |")) |
1699 |
{ |
1700 |
@$rsp = <PIPE>; |
1701 |
close(PIPE); |
1702 |
} |
1703 |
else |
1704 |
{ |
1705 |
print STDERR "Could not run '$cmd'\n"; |
1706 |
$rv = 1; |
1707 |
} |
1708 |
|
1709 |
} |
1710 |
elsif ($silent) |
1711 |
{ |
1712 |
system("$cmd 1>/dev/null 2>&1"); |
1713 |
} |
1714 |
else |
1715 |
{ |
1716 |
system($cmd); |
1717 |
} |
1718 |
|
1719 |
$callstat = $?; |
1720 |
|
1721 |
if ($callstat == -1) |
1722 |
{ |
1723 |
print STDERR "Failed to execute '$cmd'.\n"; |
1724 |
$rv = 1; |
1725 |
} |
1726 |
elsif ($callstat & 127) |
1727 |
{ |
1728 |
print STDERR "cvs command terminated abnormally.\n"; |
1729 |
$rv = 1; |
1730 |
} |
1731 |
elsif ($callstat >> 8 != 0) |
1732 |
{ |
1733 |
$callstat = $callstat >> 8; |
1734 |
print STDERR "cvs command ran unsuccessfully, status == $callstat.\n"; |
1735 |
$rv = 1; |
1736 |
} |
1737 |
|
1738 |
return $rv; |
1739 |
} |
1740 |
|
1741 |
sub CallCVSInChunks |
1742 |
{ |
1743 |
my($cmd) = $_[0]; |
1744 |
my($specs) = $_[1]; |
1745 |
my($log) = $_[2]; |
1746 |
my($rsp) = $_[3]; |
1747 |
my($silent) = $_[4]; |
1748 |
|
1749 |
my(@chunk); |
1750 |
my(@checkout); |
1751 |
my($fullcmd); |
1752 |
my($rv); |
1753 |
|
1754 |
$rv = 0; |
1755 |
|
1756 |
# Submit with kMaxFileSpecs file specs at most. |
1757 |
foreach my $aspec (@$specs) |
1758 |
{ |
1759 |
# %@$&*(~ CVS! If $aspec is part of a path that does not exist in the current working directory, |
1760 |
# CVS will choke if the CVS command is not a checkout or export command. The work-around in this case is to run |
1761 |
# cvs checkout -A first. But you cannot run this command on a directory, no that would be too easy. |
1762 |
# If you do that CVS will checkout all files in the directory. We have to instead checkout a file in |
1763 |
# the directory that we want to really have in the working directory after CallCVSInChunks completes. |
1764 |
# That will result in the checkout of just the file we want to download and the creation of the path |
1765 |
# leading to the file. |
1766 |
# |
1767 |
# So, if $aspec is a file that doesn't exist, first run cvs checkout -A on that file. But only do this |
1768 |
# if $cmd is not checkout or export! |
1769 |
|
1770 |
if ($cmd !~ /^\s*checkout/ && $cmd !~ /^\s*co/ && $cmd !~ /^export/) |
1771 |
{ |
1772 |
if (!(-e $aspec)) |
1773 |
{ |
1774 |
push(@checkout, $aspec); |
1775 |
} |
1776 |
} |
1777 |
|
1778 |
push(@chunk, $aspec); |
1779 |
|
1780 |
if ($#chunk == &kMaxFileSpecs - 1) |
1781 |
{ |
1782 |
# Checkout files that do not exist first. |
1783 |
if ($#checkout >= 0) |
1784 |
{ |
1785 |
$fullcmd = join(' ', "cvs checkout -A", @checkout); |
1786 |
if (CallCVS($fullcmd, $log, $rsp, $silent)) |
1787 |
{ |
1788 |
$rv = 1; |
1789 |
last; |
1790 |
} |
1791 |
|
1792 |
# Must remove the files just checked out or else the next call to cvs might fail. But |
1793 |
# do not remove the temp dir we just downloaded files into. |
1794 |
remove_tree(&kTmpDir, {keep_root => 1}); |
1795 |
|
1796 |
@checkout = (); |
1797 |
} |
1798 |
|
1799 |
$fullcmd = join(' ', "cvs", $cmd, @chunk); |
1800 |
if (CallCVS($fullcmd, $log, $rsp, $silent)) |
1801 |
{ |
1802 |
$rv = 1; |
1803 |
last; |
1804 |
} |
1805 |
|
1806 |
@chunk = (); |
1807 |
} |
1808 |
} |
1809 |
|
1810 |
if (!$rv && $#chunk >= 0) |
1811 |
{ |
1812 |
if ($#checkout >= 0) |
1813 |
{ |
1814 |
$fullcmd = join(' ', "cvs checkout -A", @checkout); |
1815 |
if (CallCVS($fullcmd, $log, $rsp, $silent)) |
1816 |
{ |
1817 |
$rv = 1; |
1818 |
} |
1819 |
|
1820 |
# Must remove the files just checked out or else the next call to cvs might fail. But |
1821 |
# do not remove the temp dir we just downloaded files into. |
1822 |
remove_tree(&kTmpDir, {keep_root => 1}); |
1823 |
|
1824 |
@checkout = (); |
1825 |
} |
1826 |
|
1827 |
$fullcmd = join(' ', "cvs", $cmd, @chunk); |
1828 |
if (CallCVS($fullcmd, $log, $rsp, $silent)) |
1829 |
{ |
1830 |
$rv = 1; |
1831 |
} |
1832 |
|
1833 |
@chunk = (); |
1834 |
} |
1835 |
|
1836 |
return $rv; |
1837 |
} |
1838 |
|
1839 |
sub MoveFiles |
1840 |
{ |
1841 |
my($files) = $_[0]; |
1842 |
my($srcroot) = $_[1]; |
1843 |
my($tgtroot) = $_[2]; |
1844 |
|
1845 |
my($rv) = 0; |
1846 |
my($fullsrc); |
1847 |
my($fulltgt); |
1848 |
my($tgtdir); |
1849 |
|
1850 |
foreach $onefile (@{$files}) |
1851 |
{ |
1852 |
$fullsrc = "$srcroot/$onefile"; |
1853 |
$fulltgt = "$tgtroot/$onefile"; |
1854 |
$tgtdir = dirname($fulltgt); |
1855 |
|
1856 |
if (-e $fullsrc) |
1857 |
{ |
1858 |
# Make sure the tgt directory exists. |
1859 |
if (!(-d $tgtdir)) |
1860 |
{ |
1861 |
mkpath($tgtdir); |
1862 |
} |
1863 |
|
1864 |
if (-d $tgtdir) |
1865 |
{ |
1866 |
if (!move($fullsrc, $fulltgt)) |
1867 |
{ |
1868 |
print STDERR "Unable to move $fullsrc to $fulltgt; skipping.\n"; |
1869 |
} |
1870 |
} |
1871 |
else |
1872 |
{ |
1873 |
print STDERR "Unable to make target directory $tgtdir; skipping.\n"; |
1874 |
} |
1875 |
} |
1876 |
else |
1877 |
{ |
1878 |
print STDERR "File $fullsrc does not exist; skipping.\n"; |
1879 |
} |
1880 |
} |
1881 |
|
1882 |
return $rv; |
1883 |
} |
1884 |
|
1885 |
sub InsertFile |
1886 |
{ |
1887 |
my($root) = shift; |
1888 |
my($afile) = shift; |
1889 |
my($hash) = $_[0]; |
1890 |
|
1891 |
my($top); |
1892 |
my($bot); |
1893 |
|
1894 |
if ($afile =~ /^([^\/]+)\/(.+)$/) |
1895 |
{ |
1896 |
$top = $1; |
1897 |
$bot = $2; |
1898 |
|
1899 |
if (!exists($hash->{$top})) |
1900 |
{ |
1901 |
$hash->{$top} = {}; |
1902 |
} |
1903 |
|
1904 |
if (length($root) > 0) |
1905 |
{ |
1906 |
InsertFile("$root/$top", $bot, $hash->{$top}); |
1907 |
} |
1908 |
else |
1909 |
{ |
1910 |
InsertFile($top, $bot, $hash->{$top}); |
1911 |
} |
1912 |
} |
1913 |
else |
1914 |
{ |
1915 |
$hash->{$afile} = $root; |
1916 |
} |
1917 |
} |
1918 |
|
1919 |
sub GetDefinitiveFileSet |
1920 |
{ |
1921 |
my($cotype) = $_[0]; |
1922 |
my($core) = $_[1]; |
1923 |
my($netonly) = $_[2]; |
1924 |
my($sdponly) = $_[3]; |
1925 |
my($xmldata) = $_[4]; |
1926 |
my($stfspec) = $_[5]; |
1927 |
my($version) = $_[6]; |
1928 |
my($pversion) = $_[7]; |
1929 |
my($reprdir) = $_[8]; |
1930 |
my($rdir) = $_[9]; |
1931 |
|
1932 |
my($sdir); |
1933 |
my(@dlist); |
1934 |
my(@flist); |
1935 |
my(@sorted); |
1936 |
my($listf); |
1937 |
my($cmdlcvs); |
1938 |
my(%seen); |
1939 |
my($ierr); |
1940 |
my($rv); |
1941 |
|
1942 |
$rv = {}; |
1943 |
|
1944 |
if (!(-d &kTmpDir)) |
1945 |
{ |
1946 |
# no need to check this call, because the chdir() cmd is being checked. |
1947 |
mkpath(kTmpDir); |
1948 |
} |
1949 |
|
1950 |
$sdir = $ENV{'PWD'}; |
1951 |
if (chdir(kTmpDir) == 0) |
1952 |
{ |
1953 |
print STDERR "Unable to cd to " . kTmpDir . ".\n"; |
1954 |
$ierr = 1; |
1955 |
} |
1956 |
else |
1957 |
{ |
1958 |
my(@allspecs); |
1959 |
my(@wroot); |
1960 |
|
1961 |
$cmdlcvs = "cvs export "; |
1962 |
|
1963 |
if ($cotype eq &kCoSdp || $cotype eq &kCoNetDRMS) |
1964 |
{ |
1965 |
if (length($version) > 0) |
1966 |
{ |
1967 |
$cmdlcvs = $cmdlcvs . "-r $version "; |
1968 |
} |
1969 |
else |
1970 |
{ |
1971 |
$cmdlcvs = $cmdlcvs . "-r HEAD "; |
1972 |
} |
1973 |
|
1974 |
if ($cotype eq &kCoSdp) |
1975 |
{ |
1976 |
@wroot = map({$reprdir . "$_"} @{$core}); |
1977 |
push(@allspecs, @wroot); |
1978 |
@wroot = map({$reprdir . "$_"} @{$sdponly}); |
1979 |
push(@allspecs, @wroot); |
1980 |
|
1981 |
$cmdlcvs = join(' ', $cmdlcvs, @allspecs); |
1982 |
|
1983 |
} |
1984 |
else |
1985 |
{ |
1986 |
@wroot = map({$reprdir . "$_"} @{$core}); |
1987 |
push(@allspecs, @wroot); |
1988 |
@wroot = map({$reprdir . "$_"} @{$sdponly}); |
1989 |
push(@allspecs, @wroot); |
1990 |
|
1991 |
$cmdlcvs = join(' ', $cmdlcvs, @allspecs); |
1992 |
} |
1993 |
} |
1994 |
else |
1995 |
{ |
1996 |
# ?? |
1997 |
print STDERR "Can't specify cmd-line file spec for custom check-out type.\n"; |
1998 |
$ierr = 1; |
1999 |
} |
2000 |
|
2001 |
if (!$ierr) |
2002 |
{ |
2003 |
unless (CallCVS($cmdlcvs, undef, undef, 1)) |
2004 |
{ |
2005 |
unless (GetFileList(&kTmpDir . $rdir, "", \@dlist)) |
2006 |
{ |
2007 |
my($prefdiri) = &kTmpDir . $rdir; |
2008 |
|
2009 |
foreach my $afile (@dlist) |
2010 |
{ |
2011 |
# remove &kTmpDir . &kRootDir |
2012 |
$afile =~ s/$prefdiri//; |
2013 |
push(@flist, "$afile"); |
2014 |
} |
2015 |
|
2016 |
# Sort and extract list of unique file names. |
2017 |
@sorted = sort(@flist); |
2018 |
@listf = map({ unless ($seen{$_}++){($_)}else{()} } @sorted); |
2019 |
|
2020 |
foreach my $afile (@listf) |
2021 |
{ |
2022 |
# Insert into $rv. |
2023 |
InsertFile("", $afile, $rv); |
2024 |
} |
2025 |
} |
2026 |
else |
2027 |
{ |
2028 |
$ierr = 1; |
2029 |
} |
2030 |
|
2031 |
remove_tree(&kTmpDir); |
2032 |
} |
2033 |
else |
2034 |
{ |
2035 |
$ierr = 1; |
2036 |
} |
2037 |
|
2038 |
chdir($sdir); |
2039 |
} |
2040 |
} |
2041 |
|
2042 |
return $rv; |
2043 |
} |
2044 |
|
2045 |
sub CollectFiles |
2046 |
{ |
2047 |
my($spec) = $_[0]; |
2048 |
my($deflistH) = $_[1]; |
2049 |
|
2050 |
my($ierr); |
2051 |
my(@rv); |
2052 |
|
2053 |
$ierr = 0; |
2054 |
|
2055 |
# Peel off the top directory name (must be relative to jsocroot). |
2056 |
if ($spec =~ /^([^\/]+)\/(.+)$/) |
2057 |
{ |
2058 |
my($top) = $1; |
2059 |
my($bottom) = $2; |
2060 |
my($listH) = $deflistH->{$top}; |
2061 |
|
2062 |
if (ref($listH)) |
2063 |
{ |
2064 |
@rv = CollectFiles($bottom, $listH); |
2065 |
} |
2066 |
else |
2067 |
{ |
2068 |
print STDERR "The directory $top should have a hash array associated with it.\n"; |
2069 |
$ierr = 1; |
2070 |
} |
2071 |
} |
2072 |
else |
2073 |
{ |
2074 |
my($listH); |
2075 |
|
2076 |
# $spec could have a trailing '/'. |
2077 |
if ($spec =~ /\s*(.+)\/\s*$/) |
2078 |
{ |
2079 |
$spec = $1; |
2080 |
} |
2081 |
|
2082 |
# This is a node - either a directory or a regular file. |
2083 |
$listH = $deflistH->{$spec}; |
2084 |
|
2085 |
if (!defined($listH)) |
2086 |
{ |
2087 |
print STDERR "Unknown file $spec.\n"; |
2088 |
$ierr = 1; |
2089 |
} |
2090 |
else |
2091 |
{ |
2092 |
if (ref($listH)) |
2093 |
{ |
2094 |
# Directory. |
2095 |
my(@dirfiles); |
2096 |
|
2097 |
foreach my $elem (keys(%$listH)) |
2098 |
{ |
2099 |
@dirfiles = CollectFiles($elem, $listH); |
2100 |
push(@rv, @dirfiles); |
2101 |
} |
2102 |
} |
2103 |
else |
2104 |
{ |
2105 |
# Regular file. |
2106 |
@rv = $listH . "/" . $spec; |
2107 |
} |
2108 |
} |
2109 |
} |
2110 |
|
2111 |
return @rv; |
2112 |
} |
2113 |
|
2114 |
|
2115 |
__DATA__ |
2116 |
I think we need data here in avx. |
2117 |
__END__ |