diff --git a/docs/manual/OptionalTasks/starteam.html b/docs/manual/OptionalTasks/starteam.html index 3a3ec6ce6..6c531d2bb 100644 --- a/docs/manual/OptionalTasks/starteam.html +++ b/docs/manual/OptionalTasks/starteam.html @@ -1,7 +1,7 @@
-yyyyMMddHHmmss
<tstamp> <format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/> @@ -527,6 +550,35 @@ This example shows the use of this tag. It will create a label named Version description="Thorough description" />+This example creates a non-build View label named Version 6.3 with +"Thorough description" as its description. +
+ <tstamp> + <format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/> + </tstamp> + <stlabel URL="STARTEAM:49201/Aproject/AView" + username="auser" + password="secret" + label="Version 6.3" + lastbuild="${nowstamp}" + description="Thorough description" + buildlabel="false" + /> ++This example will create a Revision label that is a build label named Version 6.2.00.001 with +"revision label" as its description. +
+ <tstamp> + <format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/> + </tstamp> + <stlabel URL="STARTEAM:49201/Aproject/AView" + username="auser" + password="secret" + label="Version 6.2.00.001" + description="revision label" + revisionlabel="true" + /> +
stFiles
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,
+ java.io.File targetFolder )
+ 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;
}
- } catch (SecurityException e) {
- log("Error adding file: " + e, Project.MSG_ERR);
+ }
+ if (checkin) {
+ eachFile.checkin(this.comment, this.lockStatus,
+ this.isForced(), true, true);
}
}
/**
- * Deletes the file from the local drive.
- * @param file the file or directory to delete.
- * @return true if the file was successfully deleted otherwise false.
+ * handles the deletion of uncontrolled items
*/
- private void add(Folder parentFolder, java.io.File file)
- throws IOException {
- // If the current file is a Directory, we need to process all
- // of its children as well.
- if (file.isDirectory()) {
- log("Adding new folder to repository: " + file.getAbsolutePath(),
- Project.MSG_INFO);
- Folder newFolder = new Folder(parentFolder);
- newFolder.setName(file.getName());
- newFolder.update();
-
- // now visit this new folder to take care of adding any files
- // or subfolders within it.
- if (isRecursive()) {
- visit(newFolder, file);
+ 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());
+
+ }
+ }
}
- } else {
- log("Adding new file to repository: " + file.getAbsolutePath(),
- Project.MSG_INFO);
- File newFile = new File(parentFolder);
- newFile.addFromStream(new FileInputStream(file),
- file.getName(),
- null, this.comment, 3, true);
}
}
+
}
+
+
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java
index 7335e3137..3d98daaeb 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java
@@ -57,6 +57,7 @@ import com.starbase.starteam.File;
import com.starbase.starteam.Folder;
import com.starbase.starteam.Item;
import com.starbase.starteam.Status;
+import com.starbase.starteam.TypeNames;
import com.starbase.starteam.View;
import com.starbase.starteam.ViewConfiguration;
import java.io.IOException;
@@ -171,40 +172,127 @@ public class StarTeamCheckout extends TreeBasedTask {
}
}
+ /**
+ * 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;
+ }
/**
* Override of base-class abstract function creates an
* appropriately configured view for checkouts - either
- * the current view or a view from this.label.
- *
- * @param raw the unconfigured View
+ * 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 View
+ *
* @return the snapshot View
appropriately configured.
+ * @exception BuildException
*/
- protected View createSnapshotView(View raw) {
+ protected View createSnapshotView(View raw)
+ throws BuildException
+ {
int labelID = getLabelID(raw);
- // if a label has been supplied, use it to configure the view
- // otherwise use current view
- if (labelID >= 0) {
+ // 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));
- } else {
+ }
+ // 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;
+ }
+ // 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
+ * any preconditons required by the task.
*
- * @exception BuildException not thrown in this implementation
+ * @exception BuildException thrown if both rootLocalFolder
+ * and viewRootLocalFolder are defined
*/
protected void testPreconditions() throws BuildException {
- if (null != getRootLocalFolder() && !isForced()) {
- log("Warning: rootLocalFolder specified, but forcing off.",
- Project.MSG_WARN);
- }
+ //intentionally do nothing
}
+ /**
+ * 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();
+ 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(" Working directories will "+
+ (this.createDirs ? "be created as needed."
+ : "not be created."));
+
+ }
/**
* Implements base-class abstract function to perform the checkout
* operation on the files in each folder of the tree.
@@ -215,91 +303,64 @@ public class StarTeamCheckout extends TreeBasedTask {
* @exception BuildException if any error occurs
*/
protected void visit(Folder starteamFolder, java.io.File targetFolder)
- throws BuildException {
+ throws BuildException
+ {
try {
- Hashtable localFiles = listLocalFiles(targetFolder);
-
- // If we have been told to create the working folders
- if (createDirs) {
- // Create if it doesn't exist
- if (!targetFolder.exists()) {
- targetFolder.mkdir();
- }
- }
- // For all Files in this folder, we need to check
- // if there have been modifications.
-
- Item[] files = starteamFolder.getItems("File");
- 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);
-
- delistLocalFile(localFiles, localFile);
-
- // If the file doesn't pass the include/exclude tests, skip it.
- if (!shouldProcess(filename)) {
- log("Skipping " + eachFile.toString(), Project.MSG_INFO);
- continue;
- }
-
-
- // If forced is not set then we may save ourselves some work by
- // looking at the status flag.
- // Otherwise, we care nothing about these statuses.
-
- if (!isForced()) {
- 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.CURRENT) {
- log("Not processing " + eachFile.toString()
- + " as it is current.",
- Project.MSG_INFO);
- continue;
- }
- }
- // Check out anything else.
- // 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.
-
- log("Checking Out: " + (localFile.toString()), Project.MSG_INFO);
- eachFile.checkoutTo(localFile, this.lockStatus,
- true, true, true);
+ if (null != getRootLocalFolder()) {
+ starteamFolder.setAlternatePathFragment(
+ targetFolder.getAbsolutePath());
}
-
- // Now we recursively call this method on all sub folders in this
- // folder unless recursive attribute is off.
- Folder[] subFolders = starteamFolder.getSubFolders();
- for (int i = 0; i < subFolders.length; i++) {
- java.io.File targetSubfolder =
- new java.io.File(targetFolder, subFolders[i].getName());
- delistLocalFile(localFiles, targetSubfolder);
- if (isRecursive()) {
- visit(subFolders[i], targetSubfolder);
- }
+
+
+ Folder[] foldersList = starteamFolder.getSubFolders();
+ Item[] filesList = starteamFolder.getItems(getTypeNames().FILE);
+
+
+ // 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()) {
+ if (!subfolder.exists()) {
+ if (this.createDirs) {
+ log("Creating folder: " + subfolder);
+ subfolder.mkdirs();
+ }
+ }
+ if (subfolder.exists()) {
+ 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) {
- deleteUncontrolledItems(localFiles);
+ ufm.processUncontrolledItems();
}
-
} catch (IOException e) {
throw new BuildException(e);
}
@@ -307,51 +368,195 @@ public class StarTeamCheckout extends TreeBasedTask {
/**
- * Deletes everything on the local machine that is not in the repository.
- *
- * @param localFiles the list of filenames whose elements are to be deleted
+ * 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 void deleteUncontrolledItems(Hashtable localFiles) {
- try {
- Enumeration e = localFiles.keys();
- while (e.hasMoreElements()) {
- java.io.File file =
- new java.io.File(e.nextElement().toString());
- delete(file);
- }
- } catch (SecurityException e) {
- log("Error deleting file: " + e, Project.MSG_ERR);
+ 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);
}
-
/**
- * Deletes the file from the local drive.
- * @param file the file or directory to delete.
- * @return true if the file was successfully deleted otherwise false.
+ * Processes (checks out) stFiles
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 boolean delete(java.io.File file) {
- // If the current file is a Directory, we need to delete all
- // of its children as well.
- if (file.isDirectory()) {
- java.io.File[] children = file.listFiles();
- for (int i = 0; i < children.length; i++) {
- delete(children[i]);
- }
+ private void processFile(com.starbase.starteam.File eachFile,
+ java.io.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;
}
- log("Deleting: " + file.getAbsolutePath(), Project.MSG_INFO);
- return file.delete();
- }
-
-
-}
-
-
+ if (this.isUsingRevisionLabel()) {
+ 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()) {
+ log("Forced checkout of "
+ + describeCheckout(eachFile)
+ + " over status " + Status.name(fileStatus));
+ } else {
+ log("Skipping: " + getFullRepositoryPath(eachFile) +
+ " - status: " + Status.name(fileStatus));
+ checkout = false;
+ }
+ }
+ if (checkout) {
+ eachFile.checkout(this.lockStatus,
+ !this.useRepositoryTimeStamp, true, true);
+ }
+ }
+ }
+ /**
+ * 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();
+
+ 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());
+ }
+ }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java
index f68ca013c..1e1ce4777 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java
@@ -93,6 +93,19 @@ public class StarTeamLabel extends StarTeamTask {
*/
private String description;
+ /**
+ * If true, this will be a build label. If false, it will be a 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"
@@ -117,6 +130,30 @@ public class StarTeamLabel extends StarTeamTask {
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 revision 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 revision 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 yyyyMMddHHmmss
@@ -126,7 +163,8 @@ public class StarTeamLabel extends StarTeamTask {
Date lastBuildTime = DATE_FORMAT.parse(lastbuild);
this.lastBuild = new OLEDate(lastBuildTime);
} catch (ParseException e) {
- throw new BuildException("Unable to parse the date '" + lastbuild + "'", e);
+ throw new BuildException("Unable to parse the date '" +
+ lastbuild + "'", e);
}
}
@@ -137,11 +175,33 @@ public class StarTeamLabel extends StarTeamTask {
*/
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.");
+ }
+
View snapshot = openView();
// Create the new label and update the repository
- new Label(snapshot, labelName, description, this.lastBuild, true).update();
- log("Created Label " + labelName);
+
+ 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);
+ }
}
/**
@@ -153,7 +213,13 @@ public class StarTeamLabel extends StarTeamTask {
* @return the snapshot View
appropriately configured.
*/
protected View createSnapshotView(View raw) {
+ /*
+ if (this.revisionlabel) {
+ return raw;
+ }
return new View(raw, ViewConfiguration.createFromTime(this.lastBuild));
+ */
+ return raw;
}
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java
index a91e64968..0a12b6d8b 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java
@@ -60,8 +60,11 @@ 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 java.util.Hashtable;
import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
/**
* Produces a listing of the contents of the StarTeam repository
@@ -76,6 +79,7 @@ import org.apache.tools.ant.BuildException;
*/
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.
@@ -90,7 +94,7 @@ public class StarTeamList extends TreeBasedTask {
/**
* Override of base-class abstract function creates an
* appropriately configured view for checkoutlists - either
- * the current view or a view from this.label.
+ * the current view or a view from this.label.
*
* @param raw the unconfigured View
* @return the snapshot View
appropriately configured.
@@ -117,6 +121,29 @@ public class StarTeamList extends TreeBasedTask {
//intentionally do nothing.
}
+ /**
+ * 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();
+ logIncludes();
+ logExcludes();
+
+
+ }
/**
* Implements base-class abstract function to perform the checkout
* operation on the files in each folder of the tree.
@@ -128,26 +155,35 @@ public class StarTeamList extends TreeBasedTask {
protected void visit(Folder starteamFolder, java.io.File targetFolder)
throws BuildException {
try {
- if (null == getRootLocalFolder()) {
- log("Folder: " + starteamFolder.getName() + " (Default folder: " + targetFolder + ")");
- } else {
- log("Folder: " + starteamFolder.getName() + " (Local folder: " + targetFolder + ")");
+ if (null != getRootLocalFolder()) {
+ starteamFolder.setAlternatePathFragment(
+ targetFolder.getAbsolutePath());
+
}
- Hashtable localFiles = listLocalFiles(targetFolder);
+ 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.
- Item[] files = starteamFolder.getItems("File");
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);
- delistLocalFile(localFiles, localFile);
-
-
+ ufm.removeControlledItem(localFile);
// If the file doesn't pass the include/exclude tests, skip it.
if (!shouldProcess(filename)) {
@@ -160,32 +196,40 @@ public class StarTeamList extends TreeBasedTask {
// Now we recursively call this method on all sub folders in this
// folder unless recursive attribute is off.
- Folder[] subFolders = starteamFolder.getSubFolders();
for (int i = 0; i < subFolders.length; i++) {
java.io.File targetSubfolder =
new java.io.File(targetFolder, subFolders[i].getName());
- delistLocalFile(localFiles, targetSubfolder);
+ 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");
+
protected void list(File reposFile, java.io.File localFile)
throws IOException {
StringBuffer b = new StringBuffer();
- if (null == getRootLocalFolder()) {
- // status is irrelevant to us if we have specified a
- // root local folder.
- b.append(pad(Status.name(reposFile.getStatus()), 12)).append(' ');
+ 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(reposFile.getModifiedTime().toString())
+ .append(SDF.format(displayDate))
.append(rpad(String.valueOf(reposFile.getSize()), 9))
.append(' ')
.append(reposFile.getName());
@@ -212,6 +256,68 @@ public class StarTeamList extends TreeBasedTask {
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();
+ }
+ }
+ }
+ }
+ }
+
+
+ }
+
}// StarTeamList
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java
index 669e8dd3e..0d16deeed 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java
@@ -53,12 +53,15 @@
*/
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;
/**
@@ -112,6 +115,12 @@ public abstract class StarTeamTask extends Task {
*/
private Server server = null;
+ private void logStarteamVersion() {
+ log("StarTeam version: "+
+ BuildNumber.getDisplayString(), Project.MSG_DEBUG);
+ }
+
+
/////////////////////////////////////////////////////////
// GET/SET methods.
// Setters, of course are where ant user passes in values.
@@ -123,7 +132,7 @@ public abstract class StarTeamTask extends Task {
* @param servername a String
value
* @see #setURL(String)
*/
- public void setServername(String servername) {
+ public final void setServername(String servername) {
this.servername = servername;
}
@@ -133,7 +142,7 @@ public abstract class StarTeamTask extends Task {
* @return the name of the StarTeam server
* @see #getURL()
*/
- public String getServername() {
+ public final String getServername() {
return this.servername;
}
@@ -143,7 +152,7 @@ public abstract class StarTeamTask extends Task {
* @param serverport port number to be set
* @see #setURL(String)
*/
- public void setServerport(String serverport) {
+ public final void setServerport(String serverport) {
this.serverport = serverport;
}
@@ -153,7 +162,7 @@ public abstract class StarTeamTask extends Task {
* @return the port number of the StarTeam connection
* @see #getURL()
*/
- public String getServerport() {
+ public final String getServerport() {
return this.serverport;
}
@@ -164,7 +173,7 @@ public abstract class StarTeamTask extends Task {
* @param projectname the name of the StarTeam project to be acted on
* @see #setURL(String)
*/
- public void setProjectname(String projectname) {
+ public final void setProjectname(String projectname) {
this.projectname = projectname;
}
@@ -174,7 +183,7 @@ public abstract class StarTeamTask extends Task {
* @return the name of the StarTeam project to be acted on
* @see #getURL()
*/
- public String getProjectname() {
+ public final String getProjectname() {
return this.projectname;
}
@@ -185,7 +194,7 @@ public abstract class StarTeamTask extends Task {
* @param projectname the name of the StarTeam view to be acted on
* @see #setURL(String)
*/
- public void setViewname(String viewname) {
+ public final void setViewname(String viewname) {
this.viewname = viewname;
}
@@ -195,7 +204,7 @@ public abstract class StarTeamTask extends Task {
* @return the name of the StarTeam view to be acted on
* @see #getURL()
*/
- public String getViewname() {
+ public final String getViewname() {
return this.viewname;
}
@@ -212,7 +221,7 @@ public abstract class StarTeamTask extends Task {
* @see #setProjectname(String)
* @see #setViewname(String)
*/
- public void setURL(String url) {
+ public final void setURL(String url) {
StringTokenizer t = new StringTokenizer(url, "/");
if (t.hasMoreTokens()) {
String unpw = t.nextToken();
@@ -246,7 +255,7 @@ public abstract class StarTeamTask extends Task {
* @see #getProjectname()
* @see #getViewname()
*/
- public String getURL() {
+ public final String getURL() {
return
this.servername + ":" +
this.serverport + "/" +
@@ -254,12 +263,21 @@ public abstract class StarTeamTask extends Task {
((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 void setUserName(String userName) {
+ public final void setUserName(String userName) {
this.userName = userName;
}
@@ -268,7 +286,7 @@ public abstract class StarTeamTask extends Task {
*
* @return the name of the StarTeam user
*/
- public String getUserName() {
+ public final String getUserName() {
return this.userName;
}
@@ -277,7 +295,7 @@ public abstract class StarTeamTask extends Task {
*
* @param password the password to be used for login
*/
- public void setPassword(String password) {
+ public final void setPassword(String password) {
this.password = password;
}
@@ -286,7 +304,7 @@ public abstract class StarTeamTask extends Task {
*
* @return the password used for login
*/
- public String getPassword() {
+ public final String getPassword() {
return this.password;
}
@@ -296,10 +314,18 @@ public abstract class StarTeamTask extends Task {
*
* @return a reference to the server
*/
- protected Server getServer() {
+ protected final Server getServer() {
return this.server;
}
+ /**
+ * 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 createSnapshotView
* defining the kind of configured view appropriate to its task.
@@ -307,7 +333,8 @@ public abstract class StarTeamTask extends Task {
* @param rawview the unconfigured View
* @return the snapshot View
appropriately configured.
*/
- protected abstract View createSnapshotView(View rawview);
+ protected abstract View createSnapshotView(View rawview)
+ throws BuildException;
/**
* All subclasses will call on this method to open the view needed for
@@ -320,10 +347,15 @@ public abstract class StarTeamTask extends Task {
* @see #getServer()
*/
protected View openView() throws BuildException {
- View view =
- StarTeamFinder.openView(getUserName() + ":"
- + getPassword()
- + "@" + getURL());
+
+ 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() +
@@ -342,7 +374,7 @@ public abstract class StarTeamTask extends Task {
* @param userID a user's ID
* @return the name of the user with ID userID
*/
- protected String getUserName(int userID) {
+ protected final String getUserName(int userID) {
User u = this.server.getUser(userID);
if (null == u) {
return "";
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java
index c3d3a8b5f..2ec2cae35 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java
@@ -54,13 +54,17 @@
package org.apache.tools.ant.taskdefs.optional.starteam;
import com.starbase.starteam.Folder;
+import com.starbase.starteam.Item;
import com.starbase.starteam.Label;
import com.starbase.starteam.StarTeamFinder;
import com.starbase.starteam.View;
+import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
/**
* FileBasedTask.java
@@ -114,7 +118,7 @@ public abstract class TreeBasedTask extends StarTeamTask {
/**
* The local folder corresponding to starteamFolder. If not specified
- * the Star Team defalt folder will be used.
+ * the Star Team default folder will be used.
*/
private String rootLocalFolder = null;
@@ -148,6 +152,14 @@ public abstract class TreeBasedTask extends StarTeamTask {
*/
private boolean forced = false;
+ private Label labelInUse = null;
+
+ /**
+ * holds a list of local files against which files in the repository
+ * will be compared for addition on checkins or deletion on checkouts if
+ * the proper options have been set.
+ */
+ private Hashtable localFileList = new Hashtable();
///////////////////////////////////////////////////////////////
// GET/SET methods.
@@ -173,27 +185,36 @@ public abstract class TreeBasedTask extends StarTeamTask {
}
/**
- * Set the local folder that will be the root of the tree
+ * 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"
+ * If this is not supplied, then the StarTeam "default folder"
* associated with rootstarteamfolder is used.
- * @param rootLocalFolder the local folder that will mirror
- * this.rootStarteamFolder
+ *
+ * @param rootLocalFolder
+ * the local folder that will mirror
+ * this.rootStarteamFolder
+ *
+ * @see rootLocalFolder
*/
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
+ * corresponding to the starteam folder for this operation
+ * or null if not specified.
+ *
* @return the local folder that mirrors this.rootStarteamFolder
+ * @see rootLocalFolder
*/
public String getRootLocalFolder() {
return this.rootLocalFolder;
}
+
/**
* Declare files to include using standard includes patterns; optional.
* @param includes A string of filter patterns to include. Separate the
@@ -220,6 +241,15 @@ public abstract class TreeBasedTask extends StarTeamTask {
return includes;
}
+ /**
+ * if excludes have been specified, emit the list to the log
+ */
+ protected void logIncludes() {
+ if (this.DEFAULT_INCLUDESETTING != this.includes) {
+ log(" Includes specified: "+ this.includes);
+ }
+ }
+
/**
* Declare files to exclude using standard excludes patterns; optional.
* When filtering files, AntStarTeamCheckOut
@@ -272,6 +302,16 @@ public abstract class TreeBasedTask extends StarTeamTask {
return excludes;
}
+ /**
+ * if excludes have been specified, emit the list to the log
+ */
+ protected void logExcludes() {
+ if (this.DEFAULT_EXCLUDESETTING != this.excludes) {
+ log(" Excludes specified: "+ this.excludes);
+ }
+ }
+
+
/**
* protected function to allow subclasses to set the label (or not).
* sets the StarTeam label
@@ -287,6 +327,10 @@ public abstract class TreeBasedTask extends StarTeamTask {
}
}
+ protected String getLabel() {
+ return this.label;
+ }
+
/**
* Get the value of recursive.
* @return value of recursive.
@@ -324,6 +368,40 @@ public abstract class TreeBasedTask extends StarTeamTask {
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();
+ }
+
+ /**
+ * 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());
+ }
+ }
+
+
+
+
///////////////////////////////////////////////////////////////
// INCLUDE-EXCLUDE processing
///////////////////////////////////////////////////////////////
@@ -332,8 +410,10 @@ public abstract class TreeBasedTask extends StarTeamTask {
* 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 checked out or not.
+ *
+ * @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);
@@ -362,49 +442,159 @@ public abstract class TreeBasedTask extends StarTeamTask {
}
/**
- * This method does the work of opening the supplied Starteam view and
- * calling the visit()
method to perform the task.
- *
- * @exception BuildException if any error occurs in the processing
- * @see visit()
+ * gets a url representing the root of the view.
+ *
+ * @return a url corresponding to the root of the starteam view tree, useful for
+ * starteam lookups
*/
+ private final String getRootStarteamURL() {
+ StringBuffer buf = new StringBuffer(getViewURL());
+ if (!this.rootStarteamFolder.startsWith("/")) {
+ buf.append("/");
+ }
+ buf.append(this.rootStarteamFolder);
+ return buf.toString();
- public void execute() throws BuildException {
- try {
- testPreconditions();
+ }
+ /**
+ * 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 final 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.
- Folder starteamrootfolder =
+
+ starteamrootfolder =
StarTeamFinder.findFolder(snapshot.getRootFolder(),
this.rootStarteamFolder);
- if (null == starteamrootfolder) {
- throw new BuildException(
- "Unable to find root folder in repository.");
- }
+ }
+ catch (BuildException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new BuildException(
+ "Unable to find root folder " + this.rootStarteamFolder +
+ " in repository at " + getURL(), 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
+ * rootLocalFolder
is defined.
+ * If rootLocalFolder
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 final 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 visit()
method to perform the task.
+ * Derived classes can customize the called methods
+ * testPreconditions()
and visit()
.
+ *
+ * @exception BuildException if any error occurs in the processing
+ * @see testPreconditions()
+ * @see visit()
+ */
+
+ public final void execute() throws BuildException {
+ try {
+ testPreconditions();
+
+ Folder starteamrootfolder = configureRootStarteamFolder();
// set the local folder.
- java.io.File localrootfolder;
- if (null == this.rootLocalFolder) {
- // use Star Team's default
- localrootfolder =
- new java.io.File(starteamrootfolder.getPath());
- } else {
- // force StarTeam to use our folder
- localrootfolder = new java.io.File(getRootLocalFolder());
- log("overriding local folder to " + localrootfolder);
- }
+ java.io.File localrootfolder =
+ getLocalRootMapping(starteamrootfolder);
+ // 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);
}
}
+ 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.getName().equals(this.label)) {
+ if (!stLabel.isRevisionLabel() && !stLabel.isViewLabel()) {
+ throw new BuildException("Unexpected label type.");
+ }
+ log("using label " + stLabel.getName(), Project.MSG_DEBUG);
+ 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.
@@ -416,32 +606,37 @@ public abstract class TreeBasedTask extends StarTeamTask {
*/
protected int getLabelID(View v) throws BuildException {
if (null != this.label) {
- Label[] allLabels = v.getLabels();
- for (int i = 0; i < allLabels.length; i++) {
- if (allLabels[i].getName().equals(this.label)) {
- return allLabels[i].getID();
- }
- }
- throw new BuildException("Error: label "
- + this.label
- + " does not exist in view");
+ findLabel(v);
+ return this.labelInUse.getID();
}
return -1;
}
+ 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
+ *
+ * @param rootStarteamFolder
+ * the StarTeam folderto be visited
+ * @param rootLocalFolder
+ * the local mapping of rootStarteamFolder
+ *
+ * @exception BuildException
*/
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
@@ -454,46 +649,114 @@ public abstract class TreeBasedTask extends StarTeamTask {
*/
protected abstract void testPreconditions() throws BuildException;
+
/**
- * Gets the collection of the local file names in the supplied directory.
- * We need to check this collection against what we find in Starteam to
- * understand what we need to do in order to synch with the repository.
- *
- * @param localFolder - the local folder to scan
- * @return an "identity" hashtable whose keys each represent a file or
- * directory in localFolder.
+ * 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.
*/
- protected static Hashtable listLocalFiles(java.io.File localFolder) {
+ public static String getFullRepositoryPath(
+ com.starbase.starteam.File remotefile)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(remotefile.getParentFolderHierarchy())
+ .append(remotefile.getName());
+ return sb.toString();
+ }
- Hashtable localFileList = new Hashtable();
- // we can't use java 2 collections so we will use an identity
- // Hashtable to hold the file names. We only care about the keys,
- // not the values (which will all be "").
+ /**
+ * 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 resository.
+ */
+ 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;
+ }
- if (localFolder.exists()) {
String[] localFiles = localFolder.list();
- for (int i = 0; i < localFiles.length; i++) {
- localFileList.put(localFolder.toString() +
- java.io.File.separatorChar + localFiles[i], "");
+
+ 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;
}
- return localFileList;
+
+ /**
+ * 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.
+ */
+ abstract protected boolean isActive();
+
}
- /**
- * Removes from the collection of the local file names
- * the supplied name of a processed file. When we are done, only
- * files not in StarTeam will remain in localFiles.
- * @param localFiles a Hashtable
value
- * @param thisfile file to remove from list.
- * @return true if file was removed, false if it wasn't found.
- */
- protected boolean delistLocalFile(Hashtable localFiles, java.io.File thisfile) {
- return null != localFiles.remove(thisfile.toString());
- }
}
-
-