git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@579316 13f79535-47bb-0310-9956-ffa450edef68master
@@ -1,361 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.Folder; | |||
import com.starbase.starteam.Item; | |||
import com.starbase.starteam.Status; | |||
import com.starbase.starteam.View; | |||
import com.starbase.starteam.ViewConfiguration; | |||
import java.io.IOException; | |||
import java.util.Enumeration; | |||
import org.apache.tools.ant.BuildException; | |||
/** | |||
* Checks files into a StarTeam project. | |||
* Optionally adds files and in the local tree that | |||
* are not managed by the repository to its control. | |||
* Created: Sat Dec 15 20:26:07 2001 | |||
* | |||
* @version 1.0 | |||
* | |||
* @ant.task name="stcheckin" category="scm" product="Starteam" | |||
*/ | |||
public class StarTeamCheckin extends TreeBasedTask { | |||
/** | |||
* Constructor for StarTeamCheckin. | |||
*/ | |||
public StarTeamCheckin() { | |||
// we want this to have a false default, unlike for Checkin. | |||
setRecursive(false); | |||
} | |||
private boolean createFolders = true; | |||
/** | |||
* The comment which will be stored with the checkin. | |||
*/ | |||
private String comment = null; | |||
/** | |||
* holder for the add Uncontrolled attribute. If true, all | |||
* local files not in StarTeam will be added to the repository. | |||
*/ | |||
private boolean addUncontrolled = false; | |||
/** | |||
* Sets the value of createFolders | |||
* | |||
* @param argCreateFolders Value to assign to this.createFolders | |||
*/ | |||
public void setCreateFolders(boolean argCreateFolders) { | |||
this.createFolders = argCreateFolders; | |||
} | |||
/** | |||
* Get the comment attribute for this operation | |||
* @return value of comment. | |||
*/ | |||
public String getComment() { | |||
return this.comment; | |||
} | |||
/** | |||
* Optional checkin comment to be saved with the file. | |||
* @param comment Value to assign to comment. | |||
*/ | |||
public void setComment(String comment) { | |||
this.comment = comment; | |||
} | |||
/** | |||
* Get the value of addUncontrolled. | |||
* @return value of addUncontrolled. | |||
*/ | |||
public boolean isAddUncontrolled() { | |||
return this.addUncontrolled; | |||
} | |||
/** | |||
* if true, any files or folders NOT in StarTeam will be | |||
* added to the repository. Defaults to "false". | |||
* @param addUncontrolled Value to assign to addUncontrolled. | |||
*/ | |||
public void setAddUncontrolled(boolean addUncontrolled) { | |||
this.addUncontrolled = addUncontrolled; | |||
} | |||
/** | |||
* This attribute tells whether unlocked files on checkin (so that | |||
* other users may access them) checkout or to leave the checkout status | |||
* alone (default). | |||
* @see #setUnlocked(boolean) | |||
*/ | |||
private int lockStatus = Item.LockType.UNCHANGED; | |||
/** | |||
* Set to do an unlocked checkout; optional, default is false; | |||
* If true, file will be unlocked so that other users may | |||
* change it. If false, lock status will not change. | |||
* @param v true means do an unlocked checkout | |||
* false means leave status alone. | |||
*/ | |||
public void setUnlocked(boolean v) { | |||
if (v) { | |||
this.lockStatus = Item.LockType.UNLOCKED; | |||
} else { | |||
this.lockStatus = Item.LockType.UNCHANGED; | |||
} | |||
} | |||
/** | |||
* Override of base-class abstract function creates an | |||
* appropriately configured view. For checkins this is | |||
* always the current or "tip" view. | |||
* | |||
* @param raw the unconfigured <code>View</code> | |||
* @return the snapshot <code>View</code> appropriately configured. | |||
*/ | |||
protected View createSnapshotView(View raw) { | |||
return new View(raw, ViewConfiguration.createTip()); | |||
} | |||
/** | |||
* Implements base-class abstract function to define tests for | |||
* any preconditons required by the task. | |||
* | |||
* @exception BuildException thrown if both rootLocalFolder | |||
* and viewRootLocalFolder are defined | |||
*/ | |||
protected void testPreconditions() throws BuildException { | |||
} | |||
/** | |||
* Implements base-class abstract function to emit to the log an | |||
* entry describing the parameters that will be used by this operation. | |||
* | |||
* @param starteamrootFolder | |||
* root folder in StarTeam for the operation | |||
* @param targetrootFolder | |||
* root local folder for the operation | |||
* (whether specified by the user or not). | |||
*/ | |||
protected void logOperationDescription( | |||
Folder starteamrootFolder, java.io.File targetrootFolder) { | |||
log((this.isRecursive() ? "Recursive" : "Non-recursive") | |||
+ " Checkin from" | |||
+ (null == getRootLocalFolder() ? " (default): " : ": ") | |||
+ targetrootFolder.getAbsolutePath()); | |||
log("Checking in to: " + starteamrootFolder.getFolderHierarchy()); | |||
logIncludes(); | |||
logExcludes(); | |||
if (this.lockStatus == Item.LockType.UNLOCKED) { | |||
log(" Items will be checked in unlocked."); | |||
} else { | |||
log(" Items will be checked in with no change in lock status."); | |||
} | |||
if (this.isForced()) { | |||
log(" Items will be checked in in accordance with repository " | |||
+ "status and regardless of lock status."); | |||
} else { | |||
log(" Items will be checked in regardless of repository status " | |||
+ "only if locked."); | |||
} | |||
} | |||
/** | |||
* Implements base-class abstract function to perform the checkout | |||
* operation on the files in each folder of the tree. | |||
* | |||
* @param starteamFolder the StarTeam folder to which files | |||
* will be checked in | |||
* @param targetFolder local folder from which files will be checked in | |||
* @exception BuildException if any error occurs | |||
*/ | |||
protected void visit(Folder starteamFolder, java.io.File targetFolder) | |||
throws BuildException { | |||
try { | |||
if (null != getRootLocalFolder()) { | |||
starteamFolder.setAlternatePathFragment( | |||
targetFolder.getAbsolutePath()); | |||
} | |||
Folder[] foldersList = starteamFolder.getSubFolders(); | |||
Item[] stFiles = starteamFolder.getItems(getTypeNames().FILE); | |||
// note, it's important to scan the items BEFORE we make the | |||
// UnmatchedFileMap because that creates a bunch of NEW | |||
// folders and files (unattached to repository) and we | |||
// don't want to include those in our traversal. | |||
UnmatchedFileMap ufm = | |||
new CheckinMap().init( | |||
targetFolder.getAbsoluteFile(), starteamFolder); | |||
for (int i = 0, size = foldersList.length; i < size; i++) { | |||
Folder stFolder = foldersList[i]; | |||
java.io.File subfolder = | |||
new java.io.File(targetFolder, stFolder.getName()); | |||
ufm.removeControlledItem(subfolder); | |||
if (isRecursive()) { | |||
visit(stFolder, subfolder); | |||
} | |||
} | |||
for (int i = 0, size = stFiles.length; i < size; i++) { | |||
com.starbase.starteam.File stFile = | |||
(com.starbase.starteam.File) stFiles[i]; | |||
processFile(stFile); | |||
ufm.removeControlledItem( | |||
new java.io.File(targetFolder, stFile.getName())); | |||
} | |||
if (this.addUncontrolled) { | |||
ufm.processUncontrolledItems(); | |||
} | |||
} catch (IOException e) { | |||
throw new BuildException(e); | |||
} | |||
} | |||
/** | |||
* provides a string showing from and to full paths for logging | |||
* | |||
* @param remotefile the Star Team file being processed. | |||
* | |||
* @return a string showing from and to full paths | |||
*/ | |||
private String describeCheckin(com.starbase.starteam.File remotefile) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(remotefile.getFullName()) | |||
.append(" --> ") | |||
.append(getFullRepositoryPath(remotefile)); | |||
return sb.toString(); | |||
} | |||
/** | |||
* Processes (checks-out) <code>stFiles</code>files from StarTeam folder. | |||
* | |||
* @param eachFile repository file to process | |||
* @param targetFolder a java.io.File (Folder) to work | |||
* @throws IOException when StarTeam API fails to work with files | |||
*/ | |||
private void processFile(com.starbase.starteam.File eachFile) | |||
throws IOException { | |||
String filename = eachFile.getName(); | |||
// If the file doesn't pass the include/exclude tests, skip it. | |||
if (!shouldProcess(filename)) { | |||
log("Excluding " + getFullRepositoryPath(eachFile)); | |||
return; | |||
} | |||
boolean checkin = true; | |||
int fileStatus = (eachFile.getStatus()); | |||
// We try to update the status once to give StarTeam | |||
// another chance. | |||
if (fileStatus == Status.MERGE || fileStatus == Status.UNKNOWN) { | |||
eachFile.updateStatus(true, true); | |||
fileStatus = (eachFile.getStatus()); | |||
} | |||
if (fileStatus == Status.MODIFIED) { | |||
log("Checking in: " + describeCheckin(eachFile)); | |||
} else if (fileStatus == Status.MISSING) { | |||
log("Local file missing: " + describeCheckin(eachFile)); | |||
checkin = false; | |||
} else { | |||
if (isForced()) { | |||
log("Forced checkin of " + describeCheckin(eachFile) | |||
+ " over status " + Status.name(fileStatus)); | |||
} else { | |||
log("Skipping: " + getFullRepositoryPath(eachFile) | |||
+ " - status: " + Status.name(fileStatus)); | |||
checkin = false; | |||
} | |||
} | |||
if (checkin) { | |||
eachFile.checkin(this.comment, this.lockStatus, | |||
this.isForced(), true, true); | |||
} | |||
} | |||
/** | |||
* handles the deletion of uncontrolled items | |||
*/ | |||
private class CheckinMap extends UnmatchedFileMap { | |||
protected boolean isActive() { | |||
return StarTeamCheckin.this.addUncontrolled; | |||
} | |||
/** | |||
* This override adds all its members to the repository. It is assumed | |||
* that this method will not be called until all the items in the | |||
* corresponding folder have been processed, and that the internal map | |||
* will contain only uncontrolled items. | |||
*/ | |||
void processUncontrolledItems() throws BuildException { | |||
if (this.isActive()) { | |||
Enumeration e = this.keys(); | |||
while (e.hasMoreElements()) { | |||
java.io.File local = (java.io.File) e.nextElement(); | |||
Item remoteItem = (Item) this.get(local); | |||
remoteItem.update(); | |||
// once we find a folder that isn't in the repository, | |||
// we know we can add it. | |||
if (local.isDirectory()) { | |||
Folder folder = (Folder) remoteItem; | |||
log("Added uncontrolled folder " | |||
+ folder.getFolderHierarchy() | |||
+ " from " + local.getAbsoluteFile()); | |||
if (isRecursive()) { | |||
UnmatchedFileMap submap = | |||
new CheckinMap().init(local, folder); | |||
submap.processUncontrolledItems(); | |||
} | |||
} else { | |||
com.starbase.starteam.File remoteFile = | |||
(com.starbase.starteam.File) remoteItem; | |||
log("Added uncontrolled file " | |||
+ TreeBasedTask.getFullRepositoryPath(remoteFile) | |||
+ " from " + local.getAbsoluteFile()); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,643 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.Folder; | |||
import com.starbase.starteam.Item; | |||
import com.starbase.starteam.Status; | |||
import com.starbase.starteam.View; | |||
import com.starbase.starteam.ViewConfiguration; | |||
import java.io.IOException; | |||
import java.io.File; | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* Checks out files from a StarTeam project. | |||
* It also creates all working directories on the | |||
* local directory if appropriate. Ant Usage: | |||
* <pre> | |||
* <taskdef name="starteamcheckout" | |||
* classname="org.apache.tools.ant.taskdefs.StarTeamCheckout"/> | |||
* <starteamcheckout username="BuildMaster" password="ant" starteamFolder="Source" | |||
* starteamurl="servername:portnum/project/view" | |||
* createworkingdirectories="true"/> | |||
* </pre> | |||
* | |||
* @version 1.1 | |||
* @see <a href="http://www.borland.com/us/products/starteam/index.html" | |||
* >borland StarTeam Web Site</a> | |||
* | |||
* @ant.task name="stcheckout" category="scm" | |||
*/ | |||
public class StarTeamCheckout extends TreeBasedTask { | |||
/** | |||
* holder for the createDirs attribute | |||
*/ | |||
private boolean createDirs = true; | |||
/** | |||
* holder for the deleteUncontrolled attribute. If true, | |||
* all local files not in StarTeam will be deleted. | |||
*/ | |||
private boolean deleteUncontrolled = true; | |||
/** | |||
* holder for the deleteUncontrolled attribute. If true, | |||
* (default) local non-binary files will be checked out using the local | |||
* platform's EOL convention. If false, checkouts will preserve the | |||
* server's EOL convention. | |||
*/ | |||
private boolean convertEOL = true; | |||
/** | |||
* flag (defaults to true) to create all directories | |||
* that are in the Starteam repository even if they are empty. | |||
* | |||
* @param value the value to set the attribute to. | |||
*/ | |||
public void setCreateWorkingDirs(boolean value) { | |||
this.createDirs = value; | |||
} | |||
/** | |||
* Whether or not all local files <i>not<i> in StarTeam should be deleted. | |||
* Optional, defaults to <code>true</code>. | |||
* @param value the value to set the attribute to. | |||
*/ | |||
public void setDeleteUncontrolled(boolean value) { | |||
this.deleteUncontrolled = value; | |||
} | |||
/** | |||
* Set whether or not files should be checked out using the | |||
* local machine's EOL convention. | |||
* Optional, defaults to <code>true</code>. | |||
* @param value the value to set the attribute to. | |||
*/ | |||
public void setConvertEOL(boolean value) { | |||
this.convertEOL = value; | |||
} | |||
/** | |||
* Sets the label StarTeam is to use for checkout; defaults to the most recent file. | |||
* The label must exist in starteam or an exception will be thrown. | |||
* @param label the label to be used | |||
*/ | |||
public void setLabel(String label) { | |||
_setLabel(label); | |||
} | |||
/** | |||
* This attribute tells whether to do a locked checkout, an unlocked | |||
* checkout or to leave the checkout status alone (default). A locked | |||
* checkout locks all other users out from making changes. An unlocked | |||
* checkout reverts all local files to their previous repository status | |||
* and removes the lock. | |||
* @see #setLocked(boolean) | |||
* @see #setUnlocked(boolean) | |||
*/ | |||
private int lockStatus = Item.LockType.UNCHANGED; | |||
/** | |||
* Set to do a locked checkout; optional default is false. | |||
* @param v True to do a locked checkout, false to checkout without | |||
* changing status/. | |||
* @exception BuildException if both locked and unlocked are set true | |||
*/ | |||
public void setLocked(boolean v) throws BuildException { | |||
setLockStatus(v, Item.LockType.EXCLUSIVE); | |||
} | |||
/** | |||
* Set to do an unlocked checkout. Default is false; | |||
* @param v True to do an unlocked checkout, false to checkout without | |||
* changing status. | |||
* @exception BuildException if both locked and unlocked are set true | |||
*/ | |||
public void setUnlocked(boolean v) throws BuildException { | |||
setLockStatus(v, Item.LockType.UNLOCKED); | |||
} | |||
private void setLockStatus(boolean v, int newStatus) | |||
throws BuildException { | |||
if (v) { | |||
if (this.lockStatus == Item.LockType.UNCHANGED) { | |||
this.lockStatus = newStatus; | |||
} else if (this.lockStatus != newStatus) { | |||
throw new BuildException( | |||
"Error: cannot set locked and unlocked both true."); | |||
} | |||
} | |||
} | |||
/** | |||
* should checked out files get the timestamp from the repository | |||
* or the time they are checked out. True means use the repository | |||
* timestamp. | |||
*/ | |||
private boolean useRepositoryTimeStamp = false; | |||
/** | |||
* sets the useRepositoryTimestmp member. | |||
* | |||
* @param useRepositoryTimeStamp | |||
* true means checked out files will get the repository timestamp. | |||
* false means the checked out files will be timestamped at the time | |||
* of checkout. | |||
*/ | |||
public void setUseRepositoryTimeStamp(boolean useRepositoryTimeStamp) { | |||
this.useRepositoryTimeStamp = useRepositoryTimeStamp; | |||
} | |||
/** | |||
* returns the value of the useRepositoryTimestamp member | |||
* | |||
* @return the value of the useRepositoryTimestamp member | |||
*/ | |||
public boolean getUseRepositoryTimeStamp() { | |||
return this.useRepositoryTimeStamp; | |||
} | |||
/** | |||
* List files, dates, and statuses as of this date; optional. | |||
* If not specified, the most recent version of each file will be listed. | |||
* | |||
* @param asOfDateParam the date as of which the listing to be made | |||
* @since Ant 1.6 | |||
*/ | |||
public void setAsOfDate(String asOfDateParam) { | |||
_setAsOfDate(asOfDateParam); | |||
} | |||
/** | |||
* Date Format with which asOfDate parameter to be parsed; optional. | |||
* Must be a SimpleDateFormat compatible string. | |||
* If not specified, and asOfDateParam is specified, parse will use ISO8601 | |||
* datetime and date formats. | |||
* | |||
* @param asOfDateFormat the SimpleDateFormat-compatible format string | |||
* @since Ant 1.6 | |||
*/ | |||
public void setAsOfDateFormat(String asOfDateFormat) { | |||
_setAsOfDateFormat(asOfDateFormat); | |||
} | |||
/** | |||
* Override of base-class abstract function creates an | |||
* appropriately configured view for checkouts - either | |||
* the current view or a view from this.label or the raw | |||
* view itself in the case of a revision label. | |||
* | |||
* @param raw the unconfigured <code>View</code> | |||
* | |||
* @return the snapshot <code>View</code> appropriately configured. | |||
* @exception BuildException on error | |||
*/ | |||
protected View createSnapshotView(View raw) throws BuildException { | |||
int labelID = getLabelID(raw); | |||
// if a label has been supplied and it is a view label, use it | |||
// to configure the view | |||
if (this.isUsingViewLabel()) { | |||
return new View(raw, ViewConfiguration.createFromLabel(labelID)); | |||
// if a label has been supplied and it is a revision label, use the raw | |||
// the view as the snapshot | |||
} else if (this.isUsingRevisionLabel()) { | |||
return raw; | |||
} | |||
// if a date has been supplied use a view configured to the date. | |||
View view = getViewConfiguredByDate(raw); | |||
if (view != null) { | |||
return view; | |||
// otherwise, use this view configured as the tip. | |||
} else { | |||
return new View(raw, ViewConfiguration.createTip()); | |||
} | |||
} | |||
/** | |||
* Implements base-class abstract function to define tests for | |||
* any preconditons required by the task. | |||
* | |||
* @exception BuildException thrown if both rootLocalFolder | |||
* and viewRootLocalFolder are defined | |||
*/ | |||
protected void testPreconditions() throws BuildException { | |||
if (this.isUsingRevisionLabel() && this.createDirs) { | |||
log("Ignoring createworkingdirs while using a revision label." | |||
+ " Folders will be created only as needed.", | |||
Project.MSG_WARN); | |||
this.createDirs = false; | |||
} | |||
if (lockStatus != Item.LockType.UNCHANGED) { | |||
boolean lockStatusBad = false; | |||
if (null != getLabel()) { | |||
log("Neither locked nor unlocked may be true" | |||
+ " when checking out a labeled version.", | |||
Project.MSG_ERR); | |||
lockStatusBad = true; | |||
} else if (null != getAsOfDate()) { | |||
log("Neither locked nor unlocked may be true" | |||
+ " when checking out by date.", | |||
Project.MSG_ERR); | |||
lockStatusBad = true; | |||
} | |||
if (lockStatusBad) { | |||
throw new BuildException( | |||
"Lock status may not be changed" | |||
+ " when checking out a non-current version."); | |||
} | |||
} | |||
if (null != getLabel() && null != getAsOfDate()) { | |||
throw new BuildException( | |||
"Both label and asOfDate specified. " | |||
+ "Unable to process request."); | |||
} | |||
} | |||
/** | |||
* extenders should emit to the log an entry describing the parameters | |||
* that will be used by this operation. | |||
* | |||
* @param starteamrootFolder | |||
* root folder in StarTeam for the operation | |||
* @param targetrootFolder | |||
* root local folder for the operation (whether specified | |||
* by the user or not. | |||
*/ | |||
protected void logOperationDescription( | |||
Folder starteamrootFolder, java.io.File targetrootFolder) { | |||
log((this.isRecursive() ? "Recursive" : "Non-recursive") | |||
+ " Checkout from: " + starteamrootFolder.getFolderHierarchy()); | |||
log(" Checking out to" | |||
+ (null == getRootLocalFolder() ? "(default): " : ": ") | |||
+ targetrootFolder.getAbsolutePath()); | |||
logLabel(); | |||
logAsOfDate(); | |||
logIncludes(); | |||
logExcludes(); | |||
if (this.lockStatus == Item.LockType.EXCLUSIVE) { | |||
log(" Items will be checked out with Exclusive locks."); | |||
} else if (this.lockStatus == Item.LockType.UNLOCKED) { | |||
log(" Items will be checked out unlocked " | |||
+ "(even if presently locked)."); | |||
} else { | |||
log(" Items will be checked out with no change in lock status."); | |||
} | |||
log(" Items will be checked out with " | |||
+ (this.useRepositoryTimeStamp ? "repository timestamps." | |||
: "the current timestamp.")); | |||
log(" Items will be checked out " | |||
+ (this.isForced() ? "regardless of" : "in accordance with") | |||
+ " repository status."); | |||
if (this.deleteUncontrolled) { | |||
log(" Local items not found in the repository will be deleted."); | |||
} | |||
log(" Items will be checked out " | |||
+ (this.convertEOL ? "using the local machine's EOL convention" | |||
: "without changing the EOL convention used on the server")); | |||
log(" Directories will be created" | |||
+ (this.createDirs ? " wherever they exist in the repository, even if empty." | |||
: " only where needed to check out files.")); | |||
} | |||
/** | |||
* Implements base-class abstract function to perform the checkout | |||
* operation on the files in each folder of the tree. | |||
* | |||
* @param starteamFolder the StarTeam folder from which files to be | |||
* checked out | |||
* @param targetFolder the local mapping of rootStarteamFolder | |||
* @exception BuildException if any error occurs | |||
*/ | |||
protected void visit(Folder starteamFolder, java.io.File targetFolder) | |||
throws BuildException { | |||
try { | |||
if (null != getRootLocalFolder()) { | |||
starteamFolder.setAlternatePathFragment( | |||
targetFolder.getAbsolutePath()); | |||
} | |||
if (!targetFolder.exists()) { | |||
if (!this.isUsingRevisionLabel()) { | |||
if (this.createDirs) { | |||
if (targetFolder.mkdirs()) { | |||
log("Creating folder: " + targetFolder); | |||
} else { | |||
throw new BuildException( | |||
"Failed to create local folder " + targetFolder); | |||
} | |||
} | |||
} | |||
} | |||
Folder[] foldersList = starteamFolder.getSubFolders(); | |||
Item[] filesList = starteamFolder.getItems(getTypeNames().FILE); | |||
if (this.isUsingRevisionLabel()) { | |||
// prune away any files not belonging to the revision label | |||
// this is one ugly API from Starteam SDK | |||
Hashtable labelItems = new Hashtable(filesList.length); | |||
int s = filesList.length; | |||
int[] ids = new int[s]; | |||
for (int i = 0; i < s; i++) { | |||
ids[i] = filesList[i].getItemID(); | |||
labelItems.put(new Integer(ids[i]), new Integer(i)); | |||
} | |||
int[] foundIds = getLabelInUse().getLabeledItemIDs(ids); | |||
s = foundIds.length; | |||
Item[] labeledFiles = new Item[s]; | |||
for (int i = 0; i < s; i++) { | |||
Integer id = new Integer(foundIds[i]); | |||
labeledFiles[i] = | |||
filesList[((Integer) labelItems.get(id)).intValue()]; | |||
} | |||
filesList = labeledFiles; | |||
} | |||
// note, it's important to scan the items BEFORE we make the | |||
// Unmatched file map because that creates a bunch of NEW | |||
// folders and files (unattached to repository) and we | |||
// don't want to include those in our traversal. | |||
UnmatchedFileMap ufm = | |||
new CheckoutMap(). | |||
init(targetFolder.getAbsoluteFile(), starteamFolder); | |||
for (int i = 0; i < foldersList.length; i++) { | |||
Folder stFolder = foldersList[i]; | |||
java.io.File subfolder = | |||
new java.io.File(targetFolder, stFolder.getName()); | |||
ufm.removeControlledItem(subfolder); | |||
if (isRecursive()) { | |||
visit(stFolder, subfolder); | |||
} | |||
} | |||
for (int i = 0; i < filesList.length; i++) { | |||
com.starbase.starteam.File stFile = | |||
(com.starbase.starteam.File) filesList[i]; | |||
processFile(stFile, targetFolder); | |||
ufm.removeControlledItem( | |||
new java.io.File(targetFolder, stFile.getName())); | |||
} | |||
if (this.deleteUncontrolled) { | |||
ufm.processUncontrolledItems(); | |||
} | |||
} catch (IOException e) { | |||
throw new BuildException(e); | |||
} | |||
} | |||
/** | |||
* provides a string showing from and to full paths for logging | |||
* | |||
* @param remotefile the Star Team file being processed. | |||
* | |||
* @return a string showing from and to full paths | |||
*/ | |||
private String describeCheckout(com.starbase.starteam.File remotefile, | |||
java.io.File localFile) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(getFullRepositoryPath(remotefile)) | |||
.append(" --> "); | |||
if (null == localFile) { | |||
sb.append(remotefile.getFullName()); | |||
} else { | |||
sb.append(localFile); | |||
} | |||
return sb.toString(); | |||
} | |||
private String describeCheckout(com.starbase.starteam.File remotefile) { | |||
return describeCheckout(remotefile, null); | |||
} | |||
/** | |||
* Processes (checks out) <code>stFiles</code>files from StarTeam folder. | |||
* | |||
* @param eachFile repository file to process | |||
* @param targetFolder a java.io.File (Folder) to work | |||
* @throws IOException when StarTeam API fails to work with files | |||
*/ | |||
private void processFile(com.starbase.starteam.File eachFile, | |||
File targetFolder) | |||
throws IOException { | |||
String filename = eachFile.getName(); | |||
java.io.File localFile = new java.io.File(targetFolder, filename); | |||
// If the file doesn't pass the include/exclude tests, skip it. | |||
if (!shouldProcess(filename)) { | |||
log("Excluding " + getFullRepositoryPath(eachFile), | |||
Project.MSG_INFO); | |||
return; | |||
} | |||
if (this.isUsingRevisionLabel()) { | |||
if (!targetFolder.exists()) { | |||
if (targetFolder.mkdirs()) { | |||
log("Creating folder: " + targetFolder); | |||
} else { | |||
throw new BuildException( | |||
"Failed to create local folder " + targetFolder); | |||
} | |||
} | |||
boolean success = eachFile.checkoutByLabelID( | |||
localFile, | |||
getIDofLabelInUse(), | |||
this.lockStatus, | |||
!this.useRepositoryTimeStamp, | |||
true, | |||
false); | |||
if (success) { | |||
log("Checked out " + describeCheckout(eachFile, localFile)); | |||
} | |||
} else { | |||
boolean checkout = true; | |||
// Just a note: StarTeam has a status for NEW which implies | |||
// that there is an item on your local machine that is not | |||
// in the repository. These are the items that show up as | |||
// NOT IN VIEW in the Starteam GUI. | |||
// One would think that we would want to perhaps checkin the | |||
// NEW items (not in all cases! - Steve Cohen 15 Dec 2001) | |||
// Unfortunately, the sdk doesn't really work, and we can't | |||
// actually see anything with a status of NEW. That is why | |||
// we can just check out everything here without worrying | |||
// about losing anything. | |||
int fileStatus = (eachFile.getStatus()); | |||
// We try to update the status once to give StarTeam | |||
// another chance. | |||
if (fileStatus == Status.MERGE | |||
|| fileStatus == Status.UNKNOWN) { | |||
eachFile.updateStatus(true, true); | |||
fileStatus = (eachFile.getStatus()); | |||
} | |||
log(eachFile.toString() + " has status of " | |||
+ Status.name(fileStatus), Project.MSG_DEBUG); | |||
switch (fileStatus) { | |||
case Status.OUTOFDATE: | |||
case Status.MISSING: | |||
log("Checking out: " + describeCheckout(eachFile)); | |||
break; | |||
default: | |||
if (isForced() && fileStatus != Status.CURRENT) { | |||
log("Forced checkout of " | |||
+ describeCheckout(eachFile) | |||
+ " over status " + Status.name(fileStatus)); | |||
} else { | |||
log("Skipping: " + getFullRepositoryPath(eachFile) | |||
+ " - status: " + Status.name(fileStatus)); | |||
checkout = false; | |||
} | |||
} | |||
if (checkout) { | |||
if (!targetFolder.exists()) { | |||
if (targetFolder.mkdirs()) { | |||
log("Creating folder: " + targetFolder); | |||
} else { | |||
throw new BuildException( | |||
"Failed to create local folder " + targetFolder); | |||
} | |||
} | |||
eachFile.checkout(this.lockStatus, | |||
!this.useRepositoryTimeStamp, this.convertEOL, false); | |||
} | |||
} | |||
} | |||
/** | |||
* handles the deletion of uncontrolled items | |||
*/ | |||
private class CheckoutMap extends UnmatchedFileMap { | |||
protected boolean isActive() { | |||
return StarTeamCheckout.this.deleteUncontrolled; | |||
} | |||
/** | |||
* override of the base class init. It can be much simpler, since | |||
* the action to be taken is simply to delete the local files. No | |||
* further interaction with the repository is necessary. | |||
* | |||
* @param localFolder | |||
* the local folder from which the mappings will be made. | |||
* @param remoteFolder | |||
* not used in this implementation | |||
*/ | |||
UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) { | |||
if (!localFolder.exists()) { | |||
return this; | |||
} | |||
String[] localFiles = localFolder.list(); | |||
// PR 31965 says that it can return null | |||
if (localFiles == null) { | |||
return this; | |||
} | |||
for (int i = 0; i < localFiles.length; i++) { | |||
java.io.File localFile = | |||
new java.io.File(localFolder, localFiles[i]).getAbsoluteFile(); | |||
log("adding " + localFile + " to UnmatchedFileMap", | |||
Project.MSG_DEBUG); | |||
if (localFile.isDirectory()) { | |||
this.put(localFile, ""); | |||
} else { | |||
this.put(localFile, ""); | |||
} | |||
} | |||
return this; | |||
} | |||
/** | |||
* deletes uncontrolled items from the local tree. It is assumed | |||
* that this method will not be called until all the items in the | |||
* corresponding folder have been processed, and that the internal map | |||
* will contain only uncontrolled items. | |||
*/ | |||
void processUncontrolledItems() throws BuildException { | |||
if (this.isActive()) { | |||
Enumeration e = this.keys(); | |||
while (e.hasMoreElements()) { | |||
java.io.File local = (java.io.File) e.nextElement(); | |||
delete(local); | |||
} | |||
} | |||
} | |||
/** | |||
* deletes all files and if the file is a folder recursively deletes | |||
* everything in it. | |||
* | |||
* @param local The local file or folder to be deleted. | |||
*/ | |||
void delete(java.io.File local) { | |||
// once we find a folder that isn't in the repository, | |||
// anything below it can be deleted. | |||
if (local.isDirectory() && isRecursive()) { | |||
String[] contents = local.list(); | |||
for (int i = 0; i < contents.length; i++) { | |||
java.io.File file = new java.io.File(local, contents[i]); | |||
delete(file); | |||
} | |||
} | |||
local.delete(); | |||
log("Deleted uncontrolled item " + local.getAbsolutePath()); | |||
} | |||
} | |||
} |
@@ -1,196 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.Label; | |||
import com.starbase.starteam.View; | |||
import com.starbase.util.OLEDate; | |||
import java.text.ParseException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import org.apache.tools.ant.BuildException; | |||
/** | |||
* Creates a view label in StarTeam at the specified view. | |||
* | |||
* Ant Usage: | |||
* <pre> | |||
* <taskdef name="stlabel" | |||
* classname="org.apache.tools.ant.taskdefs.optional.starteam.StarTeamLabel"/< | |||
* <stlabel | |||
* label="1.0" lastbuild="20011514100000" description="Successful Build" | |||
* username="BuildMaster" password="ant" | |||
* starteamurl="server:port/project/view"/> | |||
* </pre> | |||
* | |||
* @see <a href="http://www.borland.com/us/products/starteam/index.html" | |||
* >borland StarTeam Web Site</a> | |||
* | |||
* @ant.task name="stlabel" category="scm" | |||
*/ | |||
public class StarTeamLabel extends StarTeamTask { | |||
/** | |||
* The name of the label to be set in Starteam. | |||
*/ | |||
private String labelName; | |||
/** | |||
* The label description to be set in Starteam. | |||
*/ | |||
private String description; | |||
/** | |||
* If true, this will be a build label. If false, it will be a non-build | |||
* label. The default is false. Has no effect if revision label is | |||
* true. | |||
*/ | |||
private boolean buildlabel = false; | |||
/** | |||
* If true, this will be a revision label. If false, it will be a build | |||
* label. The default is false. | |||
*/ | |||
private boolean revisionlabel = false; | |||
/** | |||
* The time of the last successful. The new label will be a snapshot of the | |||
* repository at this time. String should be formatted as "yyyyMMddHHmmss" | |||
*/ | |||
private OLEDate lastBuild = null; | |||
private static final SimpleDateFormat DATE_FORMAT = | |||
new SimpleDateFormat("yyyyMMddHHmmss"); | |||
/** | |||
* The name to be given to the label; required. | |||
* @param label the name to be used | |||
*/ | |||
public void setLabel(String label) { | |||
this.labelName = label; | |||
} | |||
/** | |||
* Description of the label to be stored in the StarTeam project. | |||
* @param description the description to be used | |||
*/ | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
/** | |||
* set the type of label based on the supplied value - if true, this | |||
* label will be a revision label, if false, a build label. | |||
* | |||
* @param buildlabel If true this will be a revision label; if false, | |||
* a build label | |||
*/ | |||
public void setBuildLabel(boolean buildlabel) { | |||
this.buildlabel = buildlabel; | |||
} | |||
/** | |||
* set the type of label based on the supplied value - if true, this | |||
* label will be a revision label, if false, a build label. | |||
* | |||
* @param revisionlabel If true this will be a revision label; if false, | |||
* a build label | |||
*/ | |||
public void setRevisionLabel(boolean revisionlabel) { | |||
this.revisionlabel = revisionlabel; | |||
} | |||
/** | |||
* The timestamp of the build that will be stored with the label; required. | |||
* Must be formatted <code>yyyyMMddHHmmss</code> | |||
* @param lastbuild the timestamp of the last build | |||
* @throws BuildException on error | |||
*/ | |||
public void setLastBuild(String lastbuild) throws BuildException { | |||
try { | |||
Date lastBuildTime = DATE_FORMAT.parse(lastbuild); | |||
this.lastBuild = new OLEDate(lastBuildTime); | |||
} catch (ParseException e) { | |||
throw new BuildException("Unable to parse the date '" | |||
+ lastbuild + "'", e); | |||
} | |||
} | |||
/** | |||
* This method does the work of creating the new view and checking it into | |||
* Starteam. | |||
* @throws BuildException on error | |||
*/ | |||
public void execute() throws BuildException { | |||
if (this.revisionlabel && this.buildlabel) { | |||
throw new BuildException("'revisionlabel' and 'buildlabel' " | |||
+ "both specified. A revision label cannot be a build label."); | |||
} | |||
try { | |||
View snapshot = openView(); | |||
// Create the new label and update the repository | |||
if (this.revisionlabel) { | |||
new Label(snapshot, this.labelName, this.description).update(); | |||
log("Created Revision Label " + this.labelName); | |||
} else if (null != lastBuild) { | |||
new Label(snapshot, this.labelName, this.description, this.lastBuild, | |||
this.buildlabel).update(); | |||
log("Created View Label (" | |||
+ (this.buildlabel ? "" : "non-") + "build) " + this.labelName | |||
+ " as of " + this.lastBuild.toString()); | |||
} else { | |||
new Label(snapshot, this.labelName, this.description, | |||
this.buildlabel).update(); | |||
log("Created View Label (" | |||
+ (this.buildlabel ? "" : "non-") + "build) " + this.labelName); | |||
} | |||
} catch (Exception e) { | |||
throw new BuildException(e); | |||
} finally { | |||
disconnectFromServer(); | |||
} | |||
} | |||
/** | |||
* Override of base-class abstract function creates an | |||
* appropriately configured view. For labels this a view | |||
* configured as of this.lastBuild. | |||
* | |||
* @param raw the unconfigured <code>View</code> | |||
* @return the snapshot <code>View</code> appropriately configured. | |||
*/ | |||
protected View createSnapshotView(View raw) { | |||
/* | |||
if (this.revisionlabel) { | |||
return raw; | |||
} | |||
return new View(raw, ViewConfiguration.createFromTime(this.lastBuild)); | |||
*/ | |||
return raw; | |||
} | |||
} | |||
@@ -1,338 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.File; | |||
import com.starbase.starteam.Folder; | |||
import com.starbase.starteam.Item; | |||
import com.starbase.starteam.Status; | |||
import com.starbase.starteam.View; | |||
import com.starbase.starteam.ViewConfiguration; | |||
import java.io.IOException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Enumeration; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* Produces a listing of the contents of the StarTeam repository | |||
* at the specified view and StarTeamFolder. | |||
* | |||
* Created: Tue Dec 25 06:51:14 2001 | |||
* | |||
* @version 1.0 | |||
* | |||
* @ant.task name="stlist" category="scm" | |||
*/ | |||
public class StarTeamList extends TreeBasedTask { | |||
private boolean listUncontrolled = true; | |||
/** | |||
* List files, dates, and statuses as of this label; optional. | |||
* The label must exist in starteam or an exception will be thrown. | |||
* If not specified, the most recent version of each file will be listed. | |||
* | |||
* @param label the label to be listed | |||
*/ | |||
public void setLabel(String label) { | |||
_setLabel(label); | |||
} | |||
/** | |||
* List files, dates, and statuses as of this date; optional. | |||
* If not specified, the most recent version of each file will be listed. | |||
* | |||
* @param asOfDateParam the date as of which the listing to be made | |||
* @since Ant 1.6 | |||
*/ | |||
public void setAsOfDate(String asOfDateParam) { | |||
_setAsOfDate(asOfDateParam); | |||
} | |||
/** | |||
* Date Format with which asOfDate parameter to be parsed; optional. | |||
* Must be a SimpleDateFormat compatible string. | |||
* If not specified, and asOfDateParam is specified, parse will use ISO8601 | |||
* datetime and date formats. | |||
* | |||
* @param asOfDateFormat the SimpleDateFormat-compatible format string | |||
* @since Ant 1.6 | |||
*/ | |||
public void setAsOfDateFormat(String asOfDateFormat) { | |||
_setAsOfDateFormat(asOfDateFormat); | |||
} | |||
/** | |||
* Override of base-class abstract function creates an | |||
* appropriately configured view for checkoutlists - either | |||
* the current view or a view from this.label. | |||
* | |||
* @param raw the unconfigured <code>View</code> | |||
* @return the snapshot <code>View</code> appropriately configured. | |||
*/ | |||
protected View createSnapshotView(View raw) { | |||
int labelID = getLabelID(raw); | |||
// if a label has been supplied, use it to configure the view | |||
// otherwise use current view | |||
if (labelID >= 0) { | |||
return new View(raw, ViewConfiguration.createFromLabel(labelID)); | |||
} | |||
// if a date has been supplied use a view configured to the date. | |||
View view = getViewConfiguredByDate(raw); | |||
if (view != null) { | |||
return view; | |||
// otherwise, use this view configured as the tip. | |||
} else { | |||
return new View(raw, ViewConfiguration.createTip()); | |||
} | |||
} | |||
/** | |||
* Required base-class abstract function implementation checks for | |||
* incompatible parameters. | |||
* | |||
* @exception BuildException thrown on incompatible params specified | |||
*/ | |||
protected void testPreconditions() throws BuildException { | |||
if (null != getLabel() && null != getAsOfDate()) { | |||
throw new BuildException( | |||
"Both label and asOfDate specified. " | |||
+ "Unable to process request."); | |||
} | |||
} | |||
/** | |||
* extenders should emit to the log an entry describing the parameters | |||
* that will be used by this operation. | |||
* | |||
* @param starteamrootFolder | |||
* root folder in StarTeam for the operation | |||
* @param targetrootFolder | |||
* root local folder for the operation (whether specified by the user or not. | |||
*/ | |||
protected void logOperationDescription(Folder starteamrootFolder, | |||
java.io.File targetrootFolder) { | |||
log((this.isRecursive() ? "Recursive" : "Non-recursive") | |||
+ " Listing of: " + starteamrootFolder.getFolderHierarchy()); | |||
log("Listing against local folder" | |||
+ (null == getRootLocalFolder() ? " (default): " : ": ") | |||
+ targetrootFolder.getAbsolutePath(), | |||
Project.MSG_INFO); | |||
logLabel(); | |||
logAsOfDate(); | |||
logIncludes(); | |||
logExcludes(); | |||
} | |||
/** | |||
* Implements base-class abstract function to perform the checkout | |||
* operation on the files in each folder of the tree. | |||
* | |||
* @param starteamFolder the StarTeam folder from which files to be | |||
* checked out | |||
* @param targetFolder the local mapping of rootStarteamFolder | |||
* @throws BuildException on error | |||
*/ | |||
protected void visit(Folder starteamFolder, java.io.File targetFolder) | |||
throws BuildException { | |||
try { | |||
if (null != getRootLocalFolder()) { | |||
starteamFolder.setAlternatePathFragment( | |||
targetFolder.getAbsolutePath()); | |||
} | |||
Folder[] subFolders = starteamFolder.getSubFolders(); | |||
Item[] files = starteamFolder.getItems(getTypeNames().FILE); | |||
UnmatchedFileMap ufm = | |||
new UnmatchedListingMap().init( | |||
targetFolder.getAbsoluteFile(), starteamFolder); | |||
log(""); | |||
log("Listing StarTeam folder " | |||
+ starteamFolder.getFolderHierarchy()); | |||
log(" against local folder " + targetFolder.getAbsolutePath()); | |||
// For all Files in this folder, we need to check | |||
// if there have been modifications. | |||
for (int i = 0; i < files.length; i++) { | |||
File eachFile = (File) files[i]; | |||
String filename = eachFile.getName(); | |||
java.io.File localFile = | |||
new java.io.File(targetFolder, filename); | |||
ufm.removeControlledItem(localFile); | |||
// If the file doesn't pass the include/exclude tests, skip it. | |||
if (!shouldProcess(filename)) { | |||
continue; | |||
} | |||
list(eachFile, localFile); | |||
} | |||
// Now we recursively call this method on all sub folders in this | |||
// folder unless recursive attribute is off. | |||
for (int i = 0; i < subFolders.length; i++) { | |||
java.io.File targetSubfolder = | |||
new java.io.File(targetFolder, subFolders[i].getName()); | |||
ufm.removeControlledItem(targetSubfolder); | |||
if (isRecursive()) { | |||
visit(subFolders[i], targetSubfolder); | |||
} | |||
} | |||
if (this.listUncontrolled) { | |||
ufm.processUncontrolledItems(); | |||
} | |||
} catch (IOException e) { | |||
throw new BuildException(e); | |||
} | |||
} | |||
private static final SimpleDateFormat SDF = | |||
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss zzz"); | |||
/** | |||
* Log a repositary file and it's corresponding local file. | |||
* @param reposFile the repositary file to log | |||
* @param localFile the corresponding local file | |||
* @throws IOException on error getting information from files | |||
*/ | |||
protected void list(File reposFile, java.io.File localFile) | |||
throws IOException { | |||
StringBuffer b = new StringBuffer(); | |||
int status = reposFile.getStatus(); | |||
java.util.Date displayDate = null; | |||
if (status == Status.NEW) { | |||
displayDate = new java.util.Date(localFile.lastModified()); | |||
} else { | |||
displayDate = reposFile.getModifiedTime().createDate(); | |||
} | |||
b.append(pad(Status.name(status), 12)).append(' '); | |||
b.append(pad(getUserName(reposFile.getLocker()), 20)) | |||
.append(' ') | |||
.append(SDF.format(displayDate)) | |||
.append(rpad(String.valueOf(reposFile.getSize()), 9)) | |||
.append(' ') | |||
.append(reposFile.getName()); | |||
log(b.toString()); | |||
} | |||
private static final String BLANK_STRING = blanks(30); | |||
private static String blanks(int len) { | |||
StringBuffer b = new StringBuffer(); | |||
for (int i = 0; i < len; i++) { | |||
b.append(' '); | |||
} | |||
return b.toString(); | |||
} | |||
/** | |||
* Return a padded string. | |||
* @param s the string to pad | |||
* @param padlen the size of the padded string | |||
* @return the padded string | |||
*/ | |||
protected static String pad(String s, int padlen) { | |||
return (s + BLANK_STRING).substring(0, padlen); | |||
} | |||
/** | |||
* Return a right padded string. | |||
* @param s the string to pad | |||
* @param padlen the size of the padded string | |||
* @return the padded string | |||
*/ | |||
protected static String rpad(String s, int padlen) { | |||
s = BLANK_STRING + s; | |||
return s.substring(s.length() - padlen); | |||
} | |||
/** | |||
* handles the list of uncontrolled items | |||
*/ | |||
private class UnmatchedListingMap extends UnmatchedFileMap { | |||
protected boolean isActive() { | |||
return StarTeamList.this.listUncontrolled; | |||
} | |||
/** | |||
* lists uncontrolled items from the local tree. It is assumed | |||
* that this method will not be called until all the items in the | |||
* corresponding folder have been processed, and that the internal map | |||
* will contain only uncontrolled items. | |||
*/ | |||
void processUncontrolledItems() throws BuildException { | |||
if (this.isActive()) { | |||
Enumeration e = this.keys(); | |||
// handle the files so they appear first | |||
while (e.hasMoreElements()) { | |||
java.io.File local = (java.io.File) e.nextElement(); | |||
Item remoteItem = (Item) this.get(local); | |||
// once we find a folder that isn't in the repository, | |||
// we know we can add it. | |||
if (local.isFile()) { | |||
com.starbase.starteam.File remoteFile = | |||
(com.starbase.starteam.File) remoteItem; | |||
try { | |||
list(remoteFile, local); | |||
} catch (IOException ie) { | |||
throw new BuildException("IOError in stlist", ie); | |||
} | |||
} | |||
} | |||
// now do it again for the directories so they appear last. | |||
e = this.keys(); | |||
while (e.hasMoreElements()) { | |||
java.io.File local = (java.io.File) e.nextElement(); | |||
Item remoteItem = (Item) this.get(local); | |||
// once we find a folder that isn't in the repository, | |||
// we know we can add it. | |||
if (local.isDirectory()) { | |||
Folder folder = (Folder) remoteItem; | |||
if (isRecursive()) { | |||
log("Listing uncontrolled folder " | |||
+ folder.getFolderHierarchy() | |||
+ " from " + local.getAbsoluteFile()); | |||
UnmatchedFileMap submap = | |||
new UnmatchedListingMap().init(local, folder); | |||
submap.processUncontrolledItems(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -1,362 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.BuildNumber; | |||
import com.starbase.starteam.Server; | |||
import com.starbase.starteam.StarTeamFinder; | |||
import com.starbase.starteam.TypeNames; | |||
import com.starbase.starteam.User; | |||
import com.starbase.starteam.View; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.Task; | |||
/** | |||
* Common super class for all StarTeam tasks. | |||
* At this level of the hierarchy we are concerned only with obtaining a | |||
* connection to the StarTeam server. The subclass <code>TreeBasedTask</code>, | |||
* also abstract defines the tree-walking behavior common to many subtasks. | |||
* | |||
* @see TreeBasedTask | |||
* @version 1.1 | |||
*/ | |||
public abstract class StarTeamTask extends Task { | |||
// ATTRIBUTES | |||
/** | |||
* The username of the connection | |||
*/ | |||
private String userName; | |||
/** | |||
* The username of the connection | |||
*/ | |||
private String password; | |||
/** | |||
* name of Starteam server to connect to | |||
*/ | |||
private String servername; | |||
/** | |||
* port of Starteam server to connect to | |||
*/ | |||
private String serverport; | |||
/** | |||
* name of Starteam project to connect to | |||
*/ | |||
private String projectname; | |||
/** | |||
* name of Starteam view to connect to | |||
*/ | |||
private String viewname; | |||
/** | |||
*The starteam server through which all activities will be done. | |||
*/ | |||
private Server server = null; | |||
private void logStarteamVersion() { | |||
log("StarTeam version: " | |||
+ BuildNumber.getDisplayString(), Project.MSG_VERBOSE); | |||
} | |||
///////////////////////////////////////////////////////// | |||
// GET/SET methods. | |||
// Setters, of course are where ant user passes in values. | |||
///////////////////////////////////////////////////////// | |||
/** | |||
* Set the name of StarTeamServer; | |||
* required if <tt>URL</tt> is not set. | |||
* @param servername a <code>String</code> value | |||
* @see #setURL(String) | |||
*/ | |||
public final void setServername(String servername) { | |||
this.servername = servername; | |||
} | |||
/** | |||
* returns the name of the StarTeamServer | |||
* | |||
* @return the name of the StarTeam server | |||
* @see #getURL() | |||
*/ | |||
public final String getServername() { | |||
return this.servername; | |||
} | |||
/** | |||
* set the port number of the StarTeam connection; | |||
* required if <tt>URL</tt> is not set. | |||
* @param serverport port number to be set | |||
* @see #setURL(String) | |||
*/ | |||
public final void setServerport(String serverport) { | |||
this.serverport = serverport; | |||
} | |||
/** | |||
* returns the port number of the StarTeam connection | |||
* | |||
* @return the port number of the StarTeam connection | |||
* @see #getURL() | |||
*/ | |||
public final String getServerport() { | |||
return this.serverport; | |||
} | |||
/** | |||
* set the name of the StarTeam project to be acted on; | |||
* required if <tt>URL</tt> is not set. | |||
* | |||
* @param projectname the name of the StarTeam project to be acted on | |||
* @see #setURL(String) | |||
*/ | |||
public final void setProjectname(String projectname) { | |||
this.projectname = projectname; | |||
} | |||
/** | |||
* returns the name of the StarTeam project to be acted on | |||
* | |||
* @return the name of the StarTeam project to be acted on | |||
* @see #getURL() | |||
*/ | |||
public final String getProjectname() { | |||
return this.projectname; | |||
} | |||
/** | |||
* set the name of the StarTeam view to be acted on; | |||
* required if <tt>URL</tt> is not set. | |||
* | |||
* @param viewname the name of the StarTeam view to be acted on | |||
* @see #setURL(String) | |||
*/ | |||
public final void setViewname(String viewname) { | |||
this.viewname = viewname; | |||
} | |||
/** | |||
* returns the name of the StarTeam view to be acted on | |||
* | |||
* @return the name of the StarTeam view to be acted on | |||
* @see #getURL() | |||
*/ | |||
public final String getViewname() { | |||
return this.viewname; | |||
} | |||
/** | |||
* Set the server name, server port, | |||
* project name and project folder in one shot; | |||
* optional, but the server connection must be specified somehow. | |||
* | |||
* @param url a <code>String</code> of the form | |||
* "servername:portnum/project/view" | |||
* @see #setServername(String) | |||
* @see #setServerport(String) | |||
* @see #setProjectname(String) | |||
* @see #setViewname(String) | |||
*/ | |||
public final void setURL(String url) { | |||
StringTokenizer t = new StringTokenizer(url, "/"); | |||
if (t.hasMoreTokens()) { | |||
String unpw = t.nextToken(); | |||
int pos = unpw.indexOf(":"); | |||
if (pos > 0) { | |||
this.servername = unpw.substring(0, pos); | |||
this.serverport = unpw.substring(pos + 1); | |||
if (t.hasMoreTokens()) { | |||
this.projectname = t.nextToken(); | |||
if (t.hasMoreTokens()) { | |||
this.viewname = t.nextToken(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* convenience method returns whole URL at once | |||
* returns | |||
* as a single string | |||
*/ | |||
/** | |||
* a convenience method which returns the whole StarTeam | |||
* connection information as a single URL string of | |||
* | |||
* @return a <code>String</code> of the form | |||
* "servername:portnum/project/view" | |||
* @see #getServername() | |||
* @see #getServerport() | |||
* @see #getProjectname() | |||
* @see #getViewname() | |||
*/ | |||
public final String getURL() { | |||
return this.servername + ":" | |||
+ this.serverport + "/" | |||
+ this.projectname + "/" | |||
+ ((null == this.viewname) ? "" : this.viewname); | |||
} | |||
/** | |||
* returns an URL string useful for interacting with many StarTeamFinder | |||
* methods. | |||
* | |||
* @return the URL string for this task. | |||
*/ | |||
protected final String getViewURL() { | |||
return getUserName() + ":" + getPassword() + "@" + getURL(); | |||
} | |||
/** | |||
* set the name of the StarTeam user, needed for the connection | |||
* | |||
* @param userName name of the user to be logged in | |||
*/ | |||
public final void setUserName(String userName) { | |||
this.userName = userName; | |||
} | |||
/** | |||
* returns the name of the StarTeam user | |||
* | |||
* @return the name of the StarTeam user | |||
*/ | |||
public final String getUserName() { | |||
return this.userName; | |||
} | |||
/** | |||
* set the password to be used for login; required. | |||
* | |||
* @param password the password to be used for login | |||
*/ | |||
public final void setPassword(String password) { | |||
this.password = password; | |||
} | |||
/** | |||
* returns the password used for login | |||
* | |||
* @return the password used for login | |||
*/ | |||
public final String getPassword() { | |||
return this.password; | |||
} | |||
/** | |||
* returns a reference to the server which may be used for informational | |||
* purposes by subclasses. | |||
* | |||
* @return a reference to the server | |||
*/ | |||
protected final Server getServer() { | |||
return this.server; | |||
} | |||
/** | |||
* disconnects from the StarTeam server. Should be called from the | |||
* finally clause of every StarTeamTask-based execute method. | |||
*/ | |||
protected final void disconnectFromServer() { | |||
if (null != this.server) { | |||
this.server.disconnect(); | |||
log("successful disconnect from StarTeam Server " + servername, | |||
Project.MSG_VERBOSE); | |||
} | |||
} | |||
/** | |||
* returns a list of TypeNames known to the server. | |||
* | |||
* @return a reference to the server's TypeNames | |||
*/ | |||
protected final TypeNames getTypeNames() { | |||
return this.server.getTypeNames(); | |||
} | |||
/** | |||
* Derived classes must override <code>createSnapshotView</code> | |||
* defining the kind of configured view appropriate to its task. | |||
* | |||
* @param rawview the unconfigured <code>View</code> | |||
* @return the snapshot <code>View</code> appropriately configured. | |||
* @throws BuildException on error | |||
*/ | |||
protected abstract View createSnapshotView(View rawview) | |||
throws BuildException; | |||
/** | |||
* All subclasses will call on this method to open the view needed for | |||
* processing. This method also saves a reference to the | |||
* <code>Server</code> that may be accessed for information at various | |||
* points in the process. | |||
* | |||
* @return the <code>View</code> that will be used for processing. | |||
* @see #createSnapshotView(View) | |||
* @see #getServer() | |||
* @throws BuildException on error | |||
*/ | |||
protected View openView() throws BuildException { | |||
logStarteamVersion(); | |||
View view = null; | |||
try { | |||
view = StarTeamFinder.openView(getViewURL()); | |||
} catch (Exception e) { | |||
throw new BuildException( | |||
"Failed to connect to " + getURL(), e); | |||
} | |||
if (null == view) { | |||
throw new BuildException("Cannot find view" + getURL() | |||
+ " in repository()"); | |||
} | |||
View snapshot = createSnapshotView(view); | |||
log("Connected to StarTeam view " + getURL(), | |||
Project.MSG_VERBOSE); | |||
this.server = snapshot.getServer(); | |||
return snapshot; | |||
} | |||
/** | |||
* Returns the name of the user with the supplied ID or a blank string | |||
* if user not found. | |||
* | |||
* @param userID a user's ID | |||
* @return the name of the user with ID userID | |||
*/ | |||
protected final String getUserName(int userID) { | |||
User u = this.server.getUser(userID); | |||
if (null == u) { | |||
return ""; | |||
} | |||
return u.getName(); | |||
} | |||
} |
@@ -1,867 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional.starteam; | |||
import com.starbase.starteam.Folder; | |||
import com.starbase.starteam.Label; | |||
import com.starbase.starteam.PropertyNames; | |||
import com.starbase.starteam.StarTeamFinder; | |||
import com.starbase.starteam.View; | |||
import com.starbase.starteam.ViewConfiguration; | |||
import com.starbase.util.OLEDate; | |||
import java.text.ParseException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.Hashtable; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.util.DateUtils; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* TreeBasedTask.java | |||
* This abstract class is the base for any tasks that are tree-based, that | |||
* is, for tasks which iterate over a tree of folders in StarTeam which | |||
* is reflected in a tree of folder the local machine. | |||
* | |||
* This class provides the tree-iteration functionality. Derived classes | |||
* will implement their specific task functionality by the visitor pattern, | |||
* specifically by implementing the method | |||
* <code>visit(Folder rootStarteamFolder, java.io.File rootLocalFolder)</code> | |||
* | |||
* Created: Sat Dec 15 16:55:19 2001 | |||
* | |||
* @see <a href="http://www.borland.com/us/products/starteam/index.html" | |||
* >borland StarTeam Web Site</a> | |||
*/ | |||
public abstract class TreeBasedTask extends StarTeamTask { | |||
/////////////////////////////////////////////////////////////// | |||
// default values for attributes. | |||
/////////////////////////////////////////////////////////////// | |||
/** | |||
* This constant sets the filter to include all files. This default has | |||
* the same result as <code>setIncludes("*")</code>. | |||
* | |||
* @see #getIncludes() | |||
* @see #setIncludes(String includes) | |||
*/ | |||
public static final String DEFAULT_INCLUDESETTING = "*"; | |||
/** | |||
* This disables the exclude filter by default. In other words, no files | |||
* are excluded. This setting is equivalent to | |||
* <code>setExcludes(null)</code>. | |||
* | |||
* @see #getExcludes() | |||
* @see #setExcludes(String excludes) | |||
*/ | |||
public static final String DEFAULT_EXCLUDESETTING = null; | |||
//ATTRIBUTES settable from ant. | |||
/** | |||
* The root folder of the operation in StarTeam. | |||
*/ | |||
private String rootStarteamFolder = "/"; | |||
/** | |||
* The local folder corresponding to starteamFolder. If not specified | |||
* the Star Team default folder will be used. | |||
*/ | |||
private String rootLocalFolder = null; | |||
/** | |||
* All files that fit this pattern are checked out. | |||
*/ | |||
private String includes = DEFAULT_INCLUDESETTING; | |||
/** | |||
* All files fitting this pattern are ignored. | |||
*/ | |||
private String excludes = DEFAULT_EXCLUDESETTING; | |||
/** | |||
* StarTeam label on which to perform task. | |||
*/ | |||
private String label = null; | |||
/** | |||
* Set recursion to false to check out files in only the given folder | |||
* and not in its subfolders. | |||
*/ | |||
private boolean recursive = true; | |||
/** | |||
* Set preloadFileInformation to true to load all file information from the server | |||
* at once. Increases performance significantly for projects with many files and/or folders. | |||
*/ | |||
private boolean preloadFileInformation = true; | |||
/** | |||
* If forced set to true, files in the target directory will | |||
* be processed regardless of status in the repository. | |||
* Usually this should be true if rootlocalfolder is set | |||
* because status will be relative to the default folder, not | |||
* to the one being processed. | |||
*/ | |||
private boolean forced = false; | |||
private Label labelInUse = null; | |||
/** | |||
* holder for the asofdate attribute | |||
*/ | |||
private String asOfDate = null; | |||
/** | |||
* holder for the asofdateformat attribute | |||
*/ | |||
private String asOfDateFormat = null; | |||
/////////////////////////////////////////////////////////////// | |||
// GET/SET methods. | |||
// Setters, of course are where ant user passes in values. | |||
/////////////////////////////////////////////////////////////// | |||
/** | |||
* Set the root of the subtree in the StarTeam repository from which to | |||
* work; optional. Defaults to the root folder of the view ('/'). | |||
* @param rootStarteamFolder the root folder | |||
*/ | |||
public void setRootStarteamFolder(String rootStarteamFolder) { | |||
this.rootStarteamFolder = rootStarteamFolder; | |||
} | |||
/** | |||
* returns the root folder in the Starteam repository | |||
* used for this operation | |||
* @return the root folder in use | |||
*/ | |||
public String getRootStarteamFolder() { | |||
return this.rootStarteamFolder; | |||
} | |||
/** | |||
* Set the local folder that will be the root of the tree | |||
* to which files are checked out; optional. | |||
* If this is not supplied, then the StarTeam "default folder" | |||
* associated with <tt>rootstarteamfolder</tt> is used. | |||
* | |||
* @param rootLocalFolder | |||
* the local folder that will mirror | |||
* this.rootStarteamFolder | |||
*/ | |||
public void setRootLocalFolder(String rootLocalFolder) { | |||
this.rootLocalFolder = rootLocalFolder; | |||
} | |||
/** | |||
* Returns the local folder specified by the user, | |||
* corresponding to the starteam folder for this operation | |||
* or null if not specified. | |||
* | |||
* @return the local folder that mirrors this.rootStarteamFolder | |||
*/ | |||
public String getRootLocalFolder() { | |||
return this.rootLocalFolder; | |||
} | |||
/** | |||
* Declare files to include using standard <tt>includes</tt> patterns; optional. | |||
* @param includes A string of filter patterns to include. Separate the | |||
* patterns by spaces. | |||
* @see #getIncludes() | |||
* @see #setExcludes(String excludes) | |||
* @see #getExcludes() | |||
*/ | |||
public void setIncludes(String includes) { | |||
this.includes = includes; | |||
} | |||
/** | |||
* Gets the patterns from the include filter. Rather that duplicate the | |||
* details of AntStarTeamCheckOut's filtering here, refer to these | |||
* links: | |||
* | |||
* @return A string of filter patterns separated by spaces. | |||
* @see #setIncludes(String includes) | |||
* @see #setExcludes(String excludes) | |||
* @see #getExcludes() | |||
*/ | |||
public String getIncludes() { | |||
return includes; | |||
} | |||
/** | |||
* if excludes have been specified, emit the list to the log | |||
*/ | |||
protected void logIncludes() { | |||
if (DEFAULT_INCLUDESETTING != this.includes) { | |||
log(" Includes specified: " + this.includes); | |||
} | |||
} | |||
/** | |||
* Declare files to exclude using standard <tt>excludes</tt> patterns; optional. | |||
* When filtering files, AntStarTeamCheckOut | |||
* uses an unmodified version of <code>DirectoryScanner</code>'s | |||
* <code>match</code> method, so here are the patterns straight from the | |||
* Ant source code: | |||
* <br/> | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: | |||
* <br/>'*' which means zero or more characters, | |||
* <br/>'?' which means one and only one character. | |||
* <br/> | |||
* For example, if you want to check out all files except .XML and | |||
* .HTML files, you would put the following line in your program: | |||
* <code>setExcludes("*.XML,*.HTML");</code> | |||
* Finally, note that filters have no effect on the <b>directories</b> | |||
* that are scanned; you could not skip over all files in directories | |||
* whose names begin with "project," for instance. | |||
* <br/> | |||
* Treatment of overlapping inlcudes and excludes: To give a simplistic | |||
* example suppose that you set your include filter to "*.htm *.html" | |||
* and your exclude filter to "index.*". What happens to index.html? | |||
* AntStarTeamCheckOut will not check out index.html, as it matches an | |||
* exclude filter ("index.*"), even though it matches the include | |||
* filter, as well. | |||
* <br/> | |||
* Please also read the following sections before using filters: | |||
* | |||
* @param excludes A string of filter patterns to exclude. Separate the | |||
* patterns by spaces. | |||
* @see #setIncludes(String includes) | |||
* @see #getIncludes() | |||
* @see #getExcludes() | |||
*/ | |||
public void setExcludes(String excludes) { | |||
this.excludes = excludes; | |||
} | |||
/** | |||
* Gets the patterns from the exclude filter. Rather that duplicate the | |||
* details of AntStarTeanCheckOut's filtering here, refer to these | |||
* links: | |||
* | |||
* @return A string of filter patterns separated by spaces. | |||
* @see #setExcludes(String excludes) | |||
* @see #setIncludes(String includes) | |||
* @see #getIncludes() | |||
*/ | |||
public String getExcludes() { | |||
return excludes; | |||
} | |||
/** | |||
* if excludes have been specified, emit the list to the log | |||
*/ | |||
protected void logExcludes() { | |||
if (DEFAULT_EXCLUDESETTING != this.excludes) { | |||
log(" Excludes specified: " + this.excludes); | |||
} | |||
} | |||
// CheckStyle:MethodNameCheck OFF - bc | |||
/** | |||
* protected function to allow subclasses to set the label (or not). | |||
* sets the StarTeam label | |||
* | |||
* @param label name of the StarTeam label to be set | |||
*/ | |||
protected void _setLabel(String label) { | |||
if (null != label) { | |||
label = label.trim(); | |||
if (label.length() > 0) { | |||
this.label = label; | |||
} | |||
} | |||
} | |||
/** | |||
* non-public method callable only by derived classes that implement | |||
* setAsOfDate (so that derived tasks that do not accept this | |||
* parameter will fail if user attempts to use it. | |||
* | |||
* @param asOfDate asOfDate entered by user. | |||
* @since Ant 1.6 | |||
*/ | |||
protected void _setAsOfDate(String asOfDate) { | |||
if (asOfDate != null && asOfDate.length() > 0) { | |||
this.asOfDate = asOfDate; | |||
} | |||
} | |||
/** | |||
* non-public method callable only by derived classes that implement | |||
* setAsOfDateFormat (so that derived tasks that do not accept this | |||
* parameter will fail if user attempts to use it. | |||
* | |||
* @param asOfDateFormat asOfDate format entered by user. | |||
* @since Ant 1.6 | |||
*/ | |||
protected void _setAsOfDateFormat(String asOfDateFormat) { | |||
if (asOfDateFormat != null && asOfDateFormat.length() > 0) { | |||
this.asOfDateFormat = asOfDateFormat; | |||
} | |||
} | |||
// CheckStyle:VisibilityModifier ON | |||
/** | |||
* return the asOfDate entered by the user for internal use by derived | |||
* classes. | |||
* | |||
* @return the asOfDate entered by the user | |||
* @since Ant 1.6 | |||
*/ | |||
protected String getAsOfDate() { | |||
return this.asOfDate; | |||
} | |||
/** | |||
* If an asofDate parameter has been supplied by the user return a | |||
* StarTeam view based on the configuration of the StarTeam view | |||
* specified the user as of the date specified in the parameter. | |||
* If no asofDate has been specified, return null. | |||
* | |||
* This method is meant to be called from within implementations of the | |||
* <code>createSnapshotView</code> abstract method. | |||
* | |||
* @param raw the raw view to be configured as of the supplied date | |||
* | |||
* @return the view as configured. | |||
* @exception BuildException | |||
* thrown if the date is not parsable by the default or | |||
* supplied format patterns. | |||
* @since Ant 1.6 | |||
*/ | |||
protected View getViewConfiguredByDate(View raw) throws BuildException { | |||
if (this.asOfDate == null) { | |||
return null; | |||
} | |||
Date asOfDate = null; | |||
SimpleDateFormat fmt = null; | |||
if (this.asOfDateFormat != null) { | |||
fmt = new SimpleDateFormat(this.asOfDateFormat); | |||
try { | |||
asOfDate = fmt.parse(this.asOfDate); | |||
} catch (ParseException px) { | |||
throw new BuildException("AsOfDate " | |||
+ this.asOfDate | |||
+ " not parsable by supplied format " | |||
+ this.asOfDateFormat); | |||
} | |||
} else { | |||
try { | |||
asOfDate = DateUtils.parseIso8601DateTimeOrDate( | |||
this.asOfDate); | |||
} catch (ParseException px) { | |||
throw new BuildException("AsOfDate " | |||
+ this.asOfDate | |||
+ " not parsable by default" | |||
+ " ISO8601 formats"); | |||
} | |||
} | |||
return new View(raw, ViewConfiguration.createFromTime( | |||
new OLEDate(asOfDate))); | |||
} | |||
/** | |||
* return the label passed to the task by the user as a string | |||
* | |||
* @return the label passed to the task by the user as a string | |||
*/ | |||
protected String getLabel() { | |||
return this.label; | |||
} | |||
/** | |||
* Get the value of recursive. | |||
* @return value of recursive. | |||
*/ | |||
public boolean isRecursive() { | |||
return this.recursive; | |||
} | |||
/** | |||
* Flag to set to include files in subfolders in the operation; optional, | |||
* default true. | |||
* @param v Value to assign to recursive. | |||
*/ | |||
public void setRecursive(boolean v) { | |||
this.recursive = v; | |||
} | |||
/** | |||
* Get the value of preloadFileInformation. | |||
* @return value of preloadFileInformation. | |||
*/ | |||
public boolean isPreloadFileInformation() { | |||
return this.preloadFileInformation; | |||
} | |||
/** | |||
* Flag to set to preload file information from the server; optional, | |||
* default true. | |||
* Increases performance significantly for projects with many files | |||
* and/or folders. | |||
* @param v Value to assign to preloadFileInformation. | |||
*/ | |||
public void setPreloadFileInformation(boolean v) { | |||
this.preloadFileInformation = v; | |||
} | |||
/** | |||
* Get the value of forced. | |||
* @return value of forced. | |||
*/ | |||
public boolean isForced() { | |||
return this.forced; | |||
} | |||
/** | |||
* Flag to force actions regardless of the status | |||
* that StarTeam is maintaining for the file; optional, default false. | |||
* If <tt>rootlocalfolder</tt> is set then | |||
* this should be set "true" as otherwise the checkout will be based on statuses | |||
* which do not relate to the target folder. | |||
* @param v Value to assign to forced. | |||
*/ | |||
public void setForced(boolean v) { | |||
this.forced = v; | |||
} | |||
/** | |||
* returns true if a label has been specified and it is a view label. | |||
* | |||
* @return true if a label has been specified and it is a view label | |||
*/ | |||
protected boolean isUsingViewLabel() { | |||
return null != this.labelInUse && this.labelInUse.isViewLabel(); | |||
} | |||
/** | |||
* returns true if a label has been specified and it is a revision label. | |||
* | |||
* @return true if a label has been specified and it is a revision label | |||
*/ | |||
protected boolean isUsingRevisionLabel() { | |||
return null != this.labelInUse && this.labelInUse.isRevisionLabel(); | |||
} | |||
/** | |||
* returns the label being used | |||
* | |||
* @return the label being used | |||
*/ | |||
protected Label getLabelInUse() { | |||
return this.labelInUse; | |||
} | |||
/** | |||
* show the label in the log and its type. | |||
*/ | |||
protected void logLabel() { | |||
if (this.isUsingViewLabel()) { | |||
log(" Using view label " + getLabel()); | |||
} else if (this.isUsingRevisionLabel()) { | |||
log(" Using revision label " + getLabel()); | |||
} | |||
} | |||
/** | |||
* show the asofDate in the log | |||
* @since Ant 1.6 | |||
*/ | |||
protected void logAsOfDate() { | |||
if (null != this.asOfDate) { | |||
log(" Using view as of date " + getAsOfDate()); | |||
} | |||
} | |||
/////////////////////////////////////////////////////////////// | |||
// INCLUDE-EXCLUDE processing | |||
/////////////////////////////////////////////////////////////// | |||
/** | |||
* Look if the file should be processed by the task. | |||
* Don't process it if it fits no include filters or if | |||
* it fits an exclude filter. | |||
* | |||
* @param pName the item name to look for being included. | |||
* | |||
* @return whether the file should be processed or not. | |||
*/ | |||
protected boolean shouldProcess(String pName) { | |||
boolean includeIt = matchPatterns(getIncludes(), pName); | |||
boolean excludeIt = matchPatterns(getExcludes(), pName); | |||
return (includeIt && !excludeIt); | |||
} | |||
/** | |||
* Convenience method to see if a string match a one pattern | |||
* in given set of space-separated patterns. | |||
* @param patterns the space-separated list of patterns. | |||
* @param pName the name to look for matching. | |||
* @return whether the name match at least one pattern. | |||
*/ | |||
protected boolean matchPatterns(String patterns, String pName) { | |||
if (patterns == null) { | |||
return false; | |||
} | |||
StringTokenizer exStr = new StringTokenizer(patterns, ","); | |||
while (exStr.hasMoreTokens()) { | |||
if (DirectoryScanner.match(exStr.nextToken(), pName)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Finds and opens the root starteam folder of the operation specified | |||
* by this task. This will be one of the following cases: | |||
* | |||
* @return Starteam's root folder for the operation. | |||
* @exception BuildException | |||
* if the root folder cannot be found in the repository | |||
*/ | |||
private Folder configureRootStarteamFolder() | |||
throws BuildException { | |||
Folder starteamrootfolder = null; | |||
try { | |||
// no root local mapping has been specified. | |||
View snapshot = openView(); | |||
// find the starteam folder specified to be the root of the | |||
// operation. Throw if it can't be found. | |||
starteamrootfolder = | |||
StarTeamFinder.findFolder(snapshot.getRootFolder(), | |||
this.rootStarteamFolder); | |||
if (this.isPreloadFileInformation()) { | |||
PropertyNames pn = getServer().getPropertyNames(); | |||
String[] props = new String[] {pn.FILE_NAME, pn.FILE_PATH, | |||
pn.FILE_STATUS, pn.MODIFIED_TIME, | |||
pn.FILE_FILE_TIME_AT_CHECKIN, | |||
pn.MODIFIED_USER_ID, pn.FILE_SIZE, | |||
pn.FILE_ENCODING}; | |||
int depth = this.isRecursive() ? -1 : 0; | |||
starteamrootfolder.populateNow(getServer().getTypeNames().FILE, | |||
props, depth); | |||
} | |||
} catch (BuildException e) { | |||
throw e; | |||
} catch (Exception e) { | |||
StringBuffer msg = new StringBuffer("Unable to find root folder ") | |||
.append(this.rootStarteamFolder) | |||
.append(" in repository at ") | |||
.append(getURL()); | |||
if (this.label != null) { | |||
msg.append(" using specified label ").append(this.label); | |||
} | |||
if (this.asOfDate != null) { | |||
msg.append(" as of specified date ") | |||
.append(this.asOfDate); | |||
} | |||
throw new BuildException(msg.toString(), e); | |||
} | |||
if (null == starteamrootfolder) { | |||
throw new BuildException("Unable to find root folder " | |||
+ this.rootStarteamFolder + " in repository at " + getURL()); | |||
} | |||
return starteamrootfolder; | |||
} | |||
/** | |||
* Returns the local folder mapped to the given StarTeam root folder | |||
* of the operation. There are two cases here, depending on whether | |||
* <code>rootLocalFolder</code> is defined. | |||
* If <code>rootLocalFolder</code> is defined, it will be used to | |||
* establish a root mapping. Otherwise, the repository's default root | |||
* folder will be used. | |||
* | |||
* @param starteamrootfolder | |||
* root Starteam folder initialized for the operation | |||
* | |||
* @return the local folder corresponding to the root Starteam folder. | |||
* @see findRootStarteamFolder | |||
*/ | |||
private java.io.File getLocalRootMapping(Folder starteamrootfolder) { | |||
// set the local folder. | |||
String localrootfolder; | |||
if (null != this.rootLocalFolder) { | |||
localrootfolder = rootLocalFolder; | |||
} else { | |||
// either use default path or root local mapping, | |||
// which is now embedded in the root folder | |||
localrootfolder = starteamrootfolder.getPathFragment(); | |||
} | |||
return new java.io.File(localrootfolder); | |||
} | |||
/** | |||
* extenders should emit to the log an entry describing the parameters | |||
* that will be used by this operation. | |||
* | |||
* @param starteamrootFolder | |||
* root folder in StarTeam for the operation | |||
* @param targetrootFolder | |||
* root local folder for the operation (whether specified by the user or not. | |||
*/ | |||
protected abstract void logOperationDescription( | |||
Folder starteamrootFolder, java.io.File targetrootFolder); | |||
/** | |||
* This method does the work of opening the supplied Starteam view and | |||
* calling the <code>visit()</code> method to perform the task. | |||
* Derived classes can customize the called methods | |||
* <code>testPreconditions()</code> and <code>visit()</code>. | |||
* | |||
* @exception BuildException if any error occurs in the processing | |||
* @see <code>testPreconditions()</code> | |||
* @see <code>visit()</code> | |||
*/ | |||
public final void execute() throws BuildException { | |||
try { | |||
Folder starteamrootfolder = configureRootStarteamFolder(); | |||
// set the local folder. | |||
java.io.File localrootfolder = | |||
getLocalRootMapping(starteamrootfolder); | |||
testPreconditions(); | |||
// Tell user what he is doing | |||
logOperationDescription(starteamrootfolder, localrootfolder); | |||
// Inspect everything in the root folder and then recursively | |||
visit(starteamrootfolder, localrootfolder); | |||
} catch (Exception e) { | |||
throw new BuildException(e); | |||
} finally { | |||
disconnectFromServer(); | |||
} | |||
} | |||
private void findLabel(View v) throws BuildException { | |||
Label[] allLabels = v.getLabels(); | |||
for (int i = 0; i < allLabels.length; i++) { | |||
Label stLabel = allLabels[i]; | |||
log("checking label " + stLabel.getName(), Project.MSG_DEBUG); | |||
if (stLabel != null && !stLabel.isDeleted() && stLabel.getName().equals(this.label)) { | |||
if (!stLabel.isRevisionLabel() && !stLabel.isViewLabel()) { | |||
throw new BuildException("Unexpected label type."); | |||
} | |||
log("using label " + stLabel.getName(), Project.MSG_VERBOSE); | |||
this.labelInUse = stLabel; | |||
return; | |||
} | |||
} | |||
throw new BuildException("Error: label " | |||
+ this.label | |||
+ " does not exist in view " | |||
+ v.getFullName()); | |||
} | |||
/** | |||
* Helper method calls on the StarTeam API to retrieve an ID number | |||
* for the specified view, corresponding to this.label. | |||
* @param v the <code>View</code> in which to search for <code>this.label</code> | |||
* @return the ID number corresponding to <code>this.label</code> or -1 if | |||
* no label was provided. | |||
* @exception BuildException if <code>this.label</code> does not correspond | |||
* to any label in the supplied view | |||
*/ | |||
protected int getLabelID(View v) throws BuildException { | |||
if (null != this.label) { | |||
findLabel(v); | |||
return this.labelInUse.getID(); | |||
} | |||
return -1; | |||
} | |||
/** | |||
* Get the id of the label in use. | |||
* @return id of the label in use, if labelinuse is present, | |||
* otherwise return null | |||
*/ | |||
protected int getIDofLabelInUse() { | |||
if (null != this.labelInUse) { | |||
return this.labelInUse.getID(); | |||
} | |||
return -1; | |||
} | |||
/** | |||
* Derived classes must override this class to define actual processing | |||
* to be performed on each folder in the tree defined for the task | |||
* | |||
* @param rootStarteamFolder | |||
* the StarTeam folderto be visited | |||
* @param rootLocalFolder | |||
* the local mapping of rootStarteamFolder | |||
* | |||
* @throws BuildException on error | |||
*/ | |||
protected abstract void visit(Folder rootStarteamFolder, | |||
java.io.File rootLocalFolder) | |||
throws BuildException; | |||
/** | |||
* Derived classes must override this method to define tests for | |||
* any preconditons required by the task. This method is called at | |||
* the beginning of the execute() method. | |||
* | |||
* @exception BuildException throw if any fatal error exists in the | |||
* parameters supplied. If there is a non-fatal condition, just writing | |||
* to the log may be appropriate. | |||
* @see <code>execute()</code> | |||
*/ | |||
protected abstract void testPreconditions() throws BuildException; | |||
/** | |||
* Return the full repository path name of a file. Surprisingly there's | |||
* no method in com.starbase.starteam.File to provide this. | |||
* | |||
* @param remotefile the Star Team file whose path is to be returned | |||
* | |||
* @return the full repository path name of a file. | |||
*/ | |||
public static String getFullRepositoryPath( | |||
com.starbase.starteam.File remotefile) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(remotefile.getParentFolderHierarchy()) | |||
.append(remotefile.getName()); | |||
return sb.toString(); | |||
} | |||
/** | |||
* This class implements a map of existing local files to possibly | |||
* existing repository files. The map is created by a TreeBasedTask | |||
* upon recursing into a directory. Each local item is mapped to an | |||
* unattached StarTeam object of the proper type, File->File and | |||
* Directory->Folder. | |||
* | |||
* As the TreeBased does its work, it deletes from the map all items | |||
* it has processed. | |||
* | |||
* When the TreeBased task processes all the items from the repository, | |||
* whatever items left in the UnmatchedFileMap are uncontrolled items | |||
* and can be processed as appropriate to the task. In the case of | |||
* Checkouts, they can be optionally deleted from the local tree. In the | |||
* case of Checkins they can optionally be added to the repository. | |||
*/ | |||
protected abstract class UnmatchedFileMap extends Hashtable { | |||
/** | |||
* initializes the UnmatchedFileMap with entries from the local folder | |||
* These will be mapped to the corresponding StarTeam entry even though | |||
* it will not, in fact, exist in the repository. But through it, it | |||
* can be added, listed, etc. | |||
* | |||
* @param localFolder | |||
* the local folder from which the mappings will be made. | |||
* @param remoteFolder | |||
* the corresponding StarTeam folder which will be processed. | |||
*/ | |||
UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) { | |||
if (!localFolder.exists()) { | |||
return this; | |||
} | |||
String[] localFiles = localFolder.list(); | |||
for (int i = 0; i < localFiles.length; i++) { | |||
String fn = localFiles[i]; | |||
java.io.File localFile = | |||
new java.io.File(localFolder, localFiles[i]).getAbsoluteFile(); | |||
log("adding " + localFile + " to UnmatchedFileMap", | |||
Project.MSG_DEBUG); | |||
if (localFile.isDirectory()) { | |||
this.put(localFile, new Folder(remoteFolder, fn, fn)); | |||
} else { | |||
com.starbase.starteam.File remoteFile = | |||
new com.starbase.starteam.File(remoteFolder); | |||
remoteFile.setName(fn); | |||
this.put(localFile, remoteFile); | |||
} | |||
} | |||
return this; | |||
} | |||
/** | |||
* remove an item found to be controlled from the map. | |||
* | |||
* @param localFile the local item found to be controlled. | |||
*/ | |||
void removeControlledItem(java.io.File localFile) { | |||
if (isActive()) { | |||
log("removing processed " + localFile.getAbsoluteFile() | |||
+ " from UnmatchedFileMap", Project.MSG_DEBUG); | |||
this.remove(localFile.getAbsoluteFile()); | |||
} | |||
} | |||
/** | |||
* override will perform the action appropriate for its task to perform | |||
* on items which are on the local tree but not in StarTeam. It is | |||
* assumed that this method will not be called until all the items in | |||
* the corresponding folder have been processed, and that the internal | |||
* map * will contain only uncontrolled items. | |||
*/ | |||
abstract void processUncontrolledItems() throws BuildException; | |||
/** | |||
* overrides must define this to declare how this method knows if it | |||
* is active. This presents extra clock cycles when the functionality | |||
* is not called for. | |||
* | |||
* @return True if this object is to perform its functionality. | |||
*/ | |||
protected abstract boolean isActive(); | |||
} | |||
} |