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(); | |||
| } | |||
| } | |||