| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001-2002 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| */ |
| package org.apache.tools.ant.taskdefs.optional.starteam; |
| |
| import java.io.IOException; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| |
| 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 org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| |
| /** |
| * This class logs into StarTeam checks out any changes that have occurred since |
| * the last successful build. 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> |
| * |
| * @author Christopher Charlier, ThoughtWorks, Inc. 2001 |
| * @author <a href="mailto:jcyip@thoughtworks.com">Jason Yip</a> |
| * @author Jason Pettiss |
| * @author <a href="mailto:stevec@ignitesports.com">Steve Cohen</a> |
| * @version 1.1 |
| * @see <A HREF="http://www.starbase.com/">StarBase 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; |
| |
| /** |
| * Set the attribute that tells ant if we want to create all directories |
| * that are in the Starteam repository regardless if they are empty. |
| * |
| * @param value the value to set the attribute to. |
| */ |
| public void setCreateWorkingDirs(boolean value) { |
| this.createDirs = value; |
| } |
| |
| /** |
| * Sets the attribute that tells ant whether or not to remove local files |
| * that are NOT found in the Starteam repository to the supplied value. |
| * |
| * @param value the value to set the attribute to. |
| */ |
| public void setDeleteUncontrolled(boolean value) { |
| this.deleteUncontrolled = value; |
| } |
| |
| /** |
| * Sets the label StarTeam is to use for checkout. |
| * |
| * @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. 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."); |
| } |
| } |
| } |
| |
| /** |
| * Override of base-class abstract function creates an |
| * appropriately configured view for checkouts - either |
| * the current view or a view from this.label. |
| * |
| * @param raw the unconfigured <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)); |
| } else { |
| return new View(raw, ViewConfiguration.createTip()); |
| } |
| } |
| |
| /** |
| * Implements base-class abstract function to define tests for |
| * any preconditons required by the task |
| * |
| * @exception BuildException not thrown in this implementation |
| */ |
| protected void testPreconditions() throws BuildException { |
| if (null != getRootLocalFolder() && !isForced()) { |
| log("Warning: rootLocalFolder specified, but forcing off.", |
| Project.MSG_WARN); |
| } |
| } |
| |
| /** |
| * 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 { |
| Hashtable localFiles = listLocalFiles(targetFolder); |
| |
| // If we have been told to create the working folders |
| if (createDirs) { |
| // Create if it doesn't exist |
| if (!targetFolder.exists()) { |
| targetFolder.mkdir(); |
| } |
| } |
| // For all Files in this folder, we need to check |
| // if there have been modifications. |
| |
| Item[] files = starteamFolder.getItems("File"); |
| for (int i = 0; i < files.length; i++) { |
| File eachFile = (File) files[i]; |
| String filename = eachFile.getName(); |
| java.io.File localFile = |
| new java.io.File(targetFolder, filename); |
| |
| delistLocalFile(localFiles, localFile); |
| |
| // If the file doesn't pass the include/exclude tests, skip it. |
| if (!shouldProcess(filename)) { |
| log("Skipping " + eachFile.toString(), Project.MSG_INFO); |
| continue; |
| } |
| |
| |
| // If forced is not set then we may save ourselves some work by |
| // looking at the status flag. |
| // Otherwise, we care nothing about these statuses. |
| |
| if (!isForced()) { |
| int fileStatus = (eachFile.getStatus()); |
| |
| // We try to update the status once to give StarTeam |
| // another chance. |
| if (fileStatus == Status.MERGE || fileStatus == Status.UNKNOWN) { |
| eachFile.updateStatus(true, true); |
| fileStatus = (eachFile.getStatus()); |
| } |
| if (fileStatus == Status.CURRENT) { |
| log("Not processing " + eachFile.toString() |
| + " as it is current.", |
| Project.MSG_INFO); |
| continue; |
| } |
| } |
| |
| |
| // Check out anything else. |
| // Just a note: StarTeam has a status for NEW which implies |
| // that there is an item on your local machine that is not |
| // in the repository. These are the items that show up as |
| // NOT IN VIEW in the Starteam GUI. |
| // One would think that we would want to perhaps checkin the |
| // NEW items (not in all cases! - Steve Cohen 15 Dec 2001) |
| // Unfortunately, the sdk doesn't really work, and we can't |
| // actually see anything with a status of NEW. That is why |
| // we can just check out everything here without worrying |
| // about losing anything. |
| |
| log("Checking Out: " + (localFile.toString()), Project.MSG_INFO); |
| eachFile.checkoutTo(localFile, this.lockStatus, |
| true, true, true); |
| } |
| |
| // Now we recursively call this method on all sub folders in this |
| // folder unless recursive attribute is off. |
| Folder[] subFolders = starteamFolder.getSubFolders(); |
| for (int i = 0; i < subFolders.length; i++) { |
| java.io.File targetSubfolder = |
| new java.io.File(targetFolder, subFolders[i].getName()); |
| delistLocalFile(localFiles, targetSubfolder); |
| if (isRecursive()) { |
| visit(subFolders[i], targetSubfolder); |
| } |
| } |
| |
| if (this.deleteUncontrolled) { |
| deleteUncontrolledItems(localFiles); |
| } |
| |
| } catch (IOException e) { |
| throw new BuildException(e); |
| } |
| } |
| |
| |
| /** |
| * Deletes everything on the local machine that is not in the repository. |
| * |
| * @param localFiles the list of filenames whose elements are to be deleted |
| */ |
| private void deleteUncontrolledItems(Hashtable localFiles) { |
| try { |
| Enumeration e = localFiles.keys(); |
| while (e.hasMoreElements()) { |
| java.io.File file = |
| new java.io.File(e.nextElement().toString()); |
| delete(file); |
| } |
| } catch (SecurityException e) { |
| log("Error deleting file: " + e, Project.MSG_ERR); |
| } |
| } |
| |
| /** |
| * Deletes the file from the local drive. |
| * @param file the file or directory to delete. |
| * @return true if the file was successfully deleted otherwise false. |
| */ |
| private boolean delete(java.io.File file) { |
| // If the current file is a Directory, we need to delete all |
| // of its children as well. |
| if (file.isDirectory()) { |
| java.io.File[] children = file.listFiles(); |
| for (int i = 0; i < children.length; i++) { |
| delete(children[i]); |
| } |
| } |
| |
| log("Deleting: " + file.getAbsolutePath(), Project.MSG_INFO); |
| return file.delete(); |
| } |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |