source: release-kits/lirk3/resources/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java@ 14982

Last change on this file since 14982 was 14982, checked in by oranfry, 16 years ago

initial import of LiRK3

File size: 23.3 KB
Line 
1/*
2 * Copyright 2001-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17package org.apache.tools.ant.taskdefs.optional.starteam;
18
19import com.starbase.starteam.Folder;
20import com.starbase.starteam.Item;
21import com.starbase.starteam.Status;
22import com.starbase.starteam.View;
23import com.starbase.starteam.ViewConfiguration;
24import java.io.IOException;
25import java.io.File;
26import java.util.Enumeration;
27import java.util.Hashtable;
28import org.apache.tools.ant.BuildException;
29import org.apache.tools.ant.Project;
30
31
32/**
33 * Checks out files from a StarTeam project.
34 * It also creates all working directories on the
35 * local directory if appropriate. Ant Usage:
36 * <pre>
37 * &lt;taskdef name="starteamcheckout"
38 * classname="org.apache.tools.ant.taskdefs.StarTeamCheckout"/&gt;
39 * &lt;starteamcheckout username="BuildMaster" password="ant" starteamFolder="Source"
40 * starteamurl="servername:portnum/project/view"
41 * createworkingdirectories="true"/&gt;
42 * </pre>
43 *
44 * @version 1.1
45 * @see <A HREF="http://www.starbase.com/">StarBase Web Site</A>
46 *
47 * @ant.task name="stcheckout" category="scm"
48 */
49public class StarTeamCheckout extends TreeBasedTask {
50
51 /**
52 * holder for the createDirs attribute
53 */
54 private boolean createDirs = true;
55
56 /**
57 * holder for the deleteUncontrolled attribute. If true,
58 * all local files not in StarTeam will be deleted.
59 */
60 private boolean deleteUncontrolled = true;
61
62 /**
63 * holder for the deleteUncontrolled attribute. If true,
64 * (default) local non-binary files will be checked out using the local
65 * platform's EOL convention. If false, checkouts will preserve the
66 * server's EOL convention.
67 */
68 private boolean convertEOL = true;
69
70
71 /**
72 * flag (defaults to true) to create all directories
73 * that are in the Starteam repository even if they are empty.
74 *
75 * @param value the value to set the attribute to.
76 */
77 public void setCreateWorkingDirs(boolean value) {
78 this.createDirs = value;
79 }
80
81 /**
82 * Whether or not all local files <i>not<i> in StarTeam should be deleted.
83 * Optional, defaults to <code>true</code>.
84 * @param value the value to set the attribute to.
85 */
86 public void setDeleteUncontrolled(boolean value) {
87 this.deleteUncontrolled = value;
88 }
89
90 /**
91 * Set whether or not files should be checked out using the
92 * local machine's EOL convention.
93 * Optional, defaults to <code>true</code>.
94 * @param value the value to set the attribute to.
95 */
96 public void setConvertEOL(boolean value) {
97 this.convertEOL = value;
98 }
99
100 /**
101 * Sets the label StarTeam is to use for checkout; defaults to the most recent file.
102 * The label must exist in starteam or an exception will be thrown.
103 * @param label the label to be used
104 */
105 public void setLabel(String label) {
106 _setLabel(label);
107 }
108
109 /**
110 * This attribute tells whether to do a locked checkout, an unlocked
111 * checkout or to leave the checkout status alone (default). A locked
112 * checkout locks all other users out from making changes. An unlocked
113 * checkout reverts all local files to their previous repository status
114 * and removes the lock.
115 * @see #setLocked(boolean)
116 * @see #setUnlocked(boolean)
117 */
118 private int lockStatus = Item.LockType.UNCHANGED;
119
120 /**
121 * Set to do a locked checkout; optional default is false.
122 * @param v True to do a locked checkout, false to checkout without
123 * changing status/.
124 * @exception BuildException if both locked and unlocked are set true
125 */
126 public void setLocked(boolean v) throws BuildException {
127 setLockStatus(v, Item.LockType.EXCLUSIVE);
128 }
129
130
131 /**
132 * Set to do an unlocked checkout. Default is false;
133 * @param v True to do an unlocked checkout, false to checkout without
134 * changing status.
135 * @exception BuildException if both locked and unlocked are set true
136 */
137 public void setUnlocked(boolean v) throws BuildException {
138 setLockStatus(v, Item.LockType.UNLOCKED);
139 }
140
141 private void setLockStatus(boolean v, int newStatus)
142 throws BuildException {
143 if (v) {
144 if (this.lockStatus == Item.LockType.UNCHANGED) {
145 this.lockStatus = newStatus;
146 } else if (this.lockStatus != newStatus) {
147 throw new BuildException(
148 "Error: cannot set locked and unlocked both true.");
149 }
150 }
151 }
152
153 /**
154 * should checked out files get the timestamp from the repository
155 * or the time they are checked out. True means use the repository
156 * timestamp.
157 */
158 private boolean useRepositoryTimeStamp = false;
159
160 /**
161 * sets the useRepositoryTimestmp member.
162 *
163 * @param useRepositoryTimeStamp
164 * true means checked out files will get the repository timestamp.
165 * false means the checked out files will be timestamped at the time
166 * of checkout.
167 */
168 public void setUseRepositoryTimeStamp(boolean useRepositoryTimeStamp) {
169 this.useRepositoryTimeStamp = useRepositoryTimeStamp;
170 }
171
172 /**
173 * returns the value of the useRepositoryTimestamp member
174 *
175 * @return the value of the useRepositoryTimestamp member
176 */
177 public boolean getUseRepositoryTimeStamp() {
178 return this.useRepositoryTimeStamp;
179 }
180
181 /**
182 * List files, dates, and statuses as of this date; optional.
183 * If not specified, the most recent version of each file will be listed.
184 *
185 * @param asOfDateParam the date as of which the listing to be made
186 * @since Ant 1.6
187 */
188 public void setAsOfDate(String asOfDateParam) {
189 _setAsOfDate(asOfDateParam);
190 }
191
192 /**
193 * Date Format with which asOfDate parameter to be parsed; optional.
194 * Must be a SimpleDateFormat compatible string.
195 * If not specified, and asOfDateParam is specified, parse will use ISO8601
196 * datetime and date formats.
197 *
198 * @param asOfDateFormat the SimpleDateFormat-compatible format string
199 * @since Ant 1.6
200 */
201 public void setAsOfDateFormat(String asOfDateFormat) {
202 _setAsOfDateFormat(asOfDateFormat);
203 }
204
205 /**
206 * Override of base-class abstract function creates an
207 * appropriately configured view for checkouts - either
208 * the current view or a view from this.label or the raw
209 * view itself in the case of a revision label.
210 *
211 * @param raw the unconfigured <code>View</code>
212 *
213 * @return the snapshot <code>View</code> appropriately configured.
214 * @exception BuildException on error
215 */
216 protected View createSnapshotView(View raw) throws BuildException {
217
218 int labelID = getLabelID(raw);
219
220 // if a label has been supplied and it is a view label, use it
221 // to configure the view
222 if (this.isUsingViewLabel()) {
223 return new View(raw, ViewConfiguration.createFromLabel(labelID));
224 }
225 // if a label has been supplied and it is a revision label, use the raw
226 // the view as the snapshot
227 else if (this.isUsingRevisionLabel()) {
228 return raw;
229 }
230 // if a date has been supplied use a view configured to the date.
231 View view = getViewConfiguredByDate(raw);
232 if (view != null) {
233 return view;
234 }
235 // otherwise, use this view configured as the tip.
236 else {
237 return new View(raw, ViewConfiguration.createTip());
238 }
239 }
240
241
242 /**
243 * Implements base-class abstract function to define tests for
244 * any preconditons required by the task.
245 *
246 * @exception BuildException thrown if both rootLocalFolder
247 * and viewRootLocalFolder are defined
248 */
249 protected void testPreconditions() throws BuildException {
250 if (this.isUsingRevisionLabel() && this.createDirs) {
251 log("Ignoring createworkingdirs while using a revision label."
252 + " Folders will be created only as needed.",
253 Project.MSG_WARN);
254 this.createDirs = false;
255 }
256 if (lockStatus != Item.LockType.UNCHANGED) {
257 boolean lockStatusBad = false;
258 if (null != getLabel()) {
259 log("Neither locked nor unlocked may be true"
260 + " when checking out a labeled version.",
261 Project.MSG_ERR);
262 lockStatusBad = true;
263 } else if (null != getAsOfDate()) {
264 log("Neither locked nor unlocked may be true"
265 + " when checking out by date.",
266 Project.MSG_ERR);
267 lockStatusBad = true;
268 }
269 if (lockStatusBad) {
270 throw new BuildException(
271 "Lock status may not be changed"
272 + " when checking out a non-current version.");
273 }
274 }
275 if (null != getLabel() && null != getAsOfDate()) {
276 throw new BuildException(
277 "Both label and asOfDate specified. "
278 + "Unable to process request.");
279 }
280
281 }
282
283 /**
284 * extenders should emit to the log an entry describing the parameters
285 * that will be used by this operation.
286 *
287 * @param starteamrootFolder
288 * root folder in StarTeam for the operation
289 * @param targetrootFolder
290 * root local folder for the operation (whether specified
291 * by the user or not.
292 */
293
294 protected void logOperationDescription(
295 Folder starteamrootFolder, java.io.File targetrootFolder) {
296 log((this.isRecursive() ? "Recursive" : "Non-recursive")
297 + " Checkout from: " + starteamrootFolder.getFolderHierarchy());
298
299 log(" Checking out to"
300 + (null == getRootLocalFolder() ? "(default): " : ": ")
301 + targetrootFolder.getAbsolutePath());
302
303
304 logLabel();
305 logAsOfDate();
306 logIncludes();
307 logExcludes();
308
309 if (this.lockStatus == Item.LockType.EXCLUSIVE) {
310 log(" Items will be checked out with Exclusive locks.");
311 } else if (this.lockStatus == Item.LockType.UNLOCKED) {
312 log(" Items will be checked out unlocked "
313 + "(even if presently locked).");
314 } else {
315 log(" Items will be checked out with no change in lock status.");
316 }
317 log(" Items will be checked out with "
318 + (this.useRepositoryTimeStamp ? "repository timestamps."
319 : "the current timestamp."));
320 log(" Items will be checked out "
321 + (this.isForced() ? "regardless of" : "in accordance with")
322 + " repository status.");
323 if (this.deleteUncontrolled) {
324 log(" Local items not found in the repository will be deleted.");
325 }
326 log(" Items will be checked out "
327 + (this.convertEOL ? "using the local machine's EOL convention"
328 : "without changing the EOL convention used on the server"));
329 log(" Directories will be created"
330 + (this.createDirs ? " wherever they exist in the repository, even if empty."
331 : " only where needed to check out files."));
332
333 }
334
335
336 /**
337 * Implements base-class abstract function to perform the checkout
338 * operation on the files in each folder of the tree.
339 *
340 * @param starteamFolder the StarTeam folder from which files to be
341 * checked out
342 * @param targetFolder the local mapping of rootStarteamFolder
343 * @exception BuildException if any error occurs
344 */
345 protected void visit(Folder starteamFolder, java.io.File targetFolder)
346 throws BuildException {
347 try {
348
349
350 if (null != getRootLocalFolder()) {
351 starteamFolder.setAlternatePathFragment(
352 targetFolder.getAbsolutePath());
353 }
354
355 if (!targetFolder.exists()) {
356 if (!this.isUsingRevisionLabel()) {
357 if (this.createDirs) {
358 if (targetFolder.mkdirs()) {
359 log("Creating folder: " + targetFolder);
360 } else {
361 throw new BuildException(
362 "Failed to create local folder " + targetFolder);
363 }
364 }
365 }
366 }
367
368
369 Folder[] foldersList = starteamFolder.getSubFolders();
370 Item[] filesList = starteamFolder.getItems(getTypeNames().FILE);
371
372 if (this.isUsingRevisionLabel()) {
373
374 // prune away any files not belonging to the revision label
375 // this is one ugly API from Starteam SDK
376
377 Hashtable labelItems = new Hashtable(filesList.length);
378 int s = filesList.length;
379 int[] ids = new int[s];
380 for (int i = 0; i < s; i++) {
381 ids[i] = filesList[i].getItemID();
382 labelItems.put(new Integer(ids[i]), new Integer(i));
383 }
384 int[] foundIds = getLabelInUse().getLabeledItemIDs(ids);
385 s = foundIds.length;
386 Item[] labeledFiles = new Item[s];
387 for (int i = 0; i < s; i++) {
388 Integer id = new Integer(foundIds[i]);
389 labeledFiles[i] =
390 filesList[((Integer) labelItems.get(id)).intValue()];
391 }
392 filesList = labeledFiles;
393 }
394
395
396 // note, it's important to scan the items BEFORE we make the
397 // Unmatched file map because that creates a bunch of NEW
398 // folders and files (unattached to repository) and we
399 // don't want to include those in our traversal.
400
401 UnmatchedFileMap ufm =
402 new CheckoutMap().
403 init(targetFolder.getAbsoluteFile(), starteamFolder);
404
405
406
407 for (int i = 0; i < foldersList.length; i++) {
408 Folder stFolder = foldersList[i];
409
410 java.io.File subfolder =
411 new java.io.File(targetFolder, stFolder.getName());
412
413 ufm.removeControlledItem(subfolder);
414
415 if (isRecursive()) {
416 visit(stFolder, subfolder);
417 }
418 }
419
420 for (int i = 0; i < filesList.length; i++) {
421 com.starbase.starteam.File stFile =
422 (com.starbase.starteam.File) filesList[i];
423 processFile(stFile, targetFolder);
424
425 ufm.removeControlledItem(
426 new java.io.File(targetFolder, stFile.getName()));
427 }
428 if (this.deleteUncontrolled) {
429 ufm.processUncontrolledItems();
430 }
431 } catch (IOException e) {
432 throw new BuildException(e);
433 }
434 }
435
436
437 /**
438 * provides a string showing from and to full paths for logging
439 *
440 * @param remotefile the Star Team file being processed.
441 *
442 * @return a string showing from and to full paths
443 */
444 private String describeCheckout(com.starbase.starteam.File remotefile,
445 java.io.File localFile) {
446 StringBuffer sb = new StringBuffer();
447 sb.append(getFullRepositoryPath(remotefile))
448 .append(" --> ");
449 if (null == localFile) {
450 sb.append(remotefile.getFullName());
451 } else {
452 sb.append(localFile);
453 }
454 return sb.toString();
455 }
456 private String describeCheckout(com.starbase.starteam.File remotefile) {
457 return describeCheckout(remotefile, null);
458 }
459 /**
460 * Processes (checks out) <code>stFiles</code>files from StarTeam folder.
461 *
462 * @param eachFile repository file to process
463 * @param targetFolder a java.io.File (Folder) to work
464 * @throws IOException when StarTeam API fails to work with files
465 */
466 private void processFile(com.starbase.starteam.File eachFile,
467 File targetFolder)
468 throws IOException {
469 String filename = eachFile.getName();
470
471 java.io.File localFile = new java.io.File(targetFolder, filename);
472
473 // If the file doesn't pass the include/exclude tests, skip it.
474 if (!shouldProcess(filename)) {
475 log("Excluding " + getFullRepositoryPath(eachFile),
476 Project.MSG_INFO);
477 return;
478 }
479
480 if (this.isUsingRevisionLabel()) {
481 if (!targetFolder.exists()) {
482 if (targetFolder.mkdirs()) {
483 log("Creating folder: " + targetFolder);
484 } else {
485 throw new BuildException(
486 "Failed to create local folder " + targetFolder);
487 }
488 }
489 boolean success = eachFile.checkoutByLabelID(
490 localFile,
491 getIDofLabelInUse(),
492 this.lockStatus,
493 !this.useRepositoryTimeStamp,
494 true,
495 false);
496 if (success) {
497 log("Checked out " + describeCheckout(eachFile, localFile));
498 }
499 } else {
500 boolean checkout = true;
501
502 // Just a note: StarTeam has a status for NEW which implies
503 // that there is an item on your local machine that is not
504 // in the repository. These are the items that show up as
505 // NOT IN VIEW in the Starteam GUI.
506 // One would think that we would want to perhaps checkin the
507 // NEW items (not in all cases! - Steve Cohen 15 Dec 2001)
508 // Unfortunately, the sdk doesn't really work, and we can't
509 // actually see anything with a status of NEW. That is why
510 // we can just check out everything here without worrying
511 // about losing anything.
512
513 int fileStatus = (eachFile.getStatus());
514
515 // We try to update the status once to give StarTeam
516 // another chance.
517
518 if (fileStatus == Status.MERGE
519 || fileStatus == Status.UNKNOWN) {
520 eachFile.updateStatus(true, true);
521 fileStatus = (eachFile.getStatus());
522 }
523
524 log(eachFile.toString() + " has status of "
525 + Status.name(fileStatus), Project.MSG_DEBUG);
526
527
528 switch (fileStatus) {
529 case Status.OUTOFDATE:
530 case Status.MISSING:
531 log("Checking out: " + describeCheckout(eachFile));
532 break;
533 default:
534 if (isForced()) {
535 log("Forced checkout of "
536 + describeCheckout(eachFile)
537 + " over status " + Status.name(fileStatus));
538 } else {
539 log("Skipping: " + getFullRepositoryPath(eachFile)
540 + " - status: " + Status.name(fileStatus));
541 checkout = false;
542 }
543 }
544
545 if (checkout) {
546 if (!targetFolder.exists()) {
547 if (targetFolder.mkdirs()) {
548 log("Creating folder: " + targetFolder);
549 } else {
550 throw new BuildException(
551 "Failed to create local folder " + targetFolder);
552 }
553 }
554 eachFile.checkout(this.lockStatus,
555 !this.useRepositoryTimeStamp, this.convertEOL, true);
556 }
557 }
558 }
559 /**
560 * handles the deletion of uncontrolled items
561 */
562 private class CheckoutMap extends UnmatchedFileMap {
563 protected boolean isActive() {
564 return StarTeamCheckout.this.deleteUncontrolled;
565 }
566
567 /**
568 * override of the base class init. It can be much simpler, since
569 * the action to be taken is simply to delete the local files. No
570 * further interaction with the repository is necessary.
571 *
572 * @param localFolder
573 * the local folder from which the mappings will be made.
574 * @param remoteFolder
575 * not used in this implementation
576 */
577 UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) {
578 if (!localFolder.exists()) {
579 return this;
580 }
581
582 String[] localFiles = localFolder.list();
583
584 for (int i = 0; i < localFiles.length; i++) {
585 java.io.File localFile =
586 new java.io.File(localFolder, localFiles[i]).getAbsoluteFile();
587
588 log("adding " + localFile + " to UnmatchedFileMap",
589 Project.MSG_DEBUG);
590
591 if (localFile.isDirectory()) {
592 this.put(localFile, "");
593 } else {
594 this.put(localFile, "");
595 }
596 }
597 return this;
598 }
599
600
601
602 /**
603 * deletes uncontrolled items from the local tree. It is assumed
604 * that this method will not be called until all the items in the
605 * corresponding folder have been processed, and that the internal map
606 * will contain only uncontrolled items.
607 */
608 void processUncontrolledItems() throws BuildException {
609 if (this.isActive()) {
610 Enumeration e = this.keys();
611 while (e.hasMoreElements()) {
612 java.io.File local = (java.io.File) e.nextElement();
613 delete(local);
614 }
615 }
616 }
617
618 /**
619 * deletes all files and if the file is a folder recursively deletes
620 * everything in it.
621 *
622 * @param local The local file or folder to be deleted.
623 */
624 void delete(java.io.File local) {
625 // once we find a folder that isn't in the repository,
626 // anything below it can be deleted.
627 if (local.isDirectory() && isRecursive()) {
628 String[] contents = local.list();
629 for (int i = 0; i < contents.length; i++) {
630 java.io.File file = new java.io.File(local, contents[i]);
631 delete(file);
632 }
633 }
634 local.delete();
635 log("Deleted uncontrolled item " + local.getAbsolutePath());
636 }
637 }
638
639
640}
Note: See TracBrowser for help on using the repository browser.