ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/util/scripts/dlsource.pl
Revision: 1.34
Committed: Tue Sep 1 16:34:14 2015 UTC (8 years ago) by arta
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_8-10, Ver_8-11
Changes since 1.33: +40 -4 lines
Log Message:
Do not attempt to update files that do not exist.

File Contents

# Content
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__