You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2003/02/13 14:59:53 UTC

cvs commit: ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam StarTeamCheckin.java StarTeamCheckout.java StarTeamLabel.java StarTeamList.java StarTeamTask.java TreeBasedTask.java

conor       2003/02/13 05:59:53

  Modified:    src/main/org/apache/tools/ant/taskdefs/optional/starteam
                        Tag: ANT_15_BRANCH StarTeamCheckin.java
                        StarTeamCheckout.java StarTeamLabel.java
                        StarTeamList.java StarTeamTask.java
                        TreeBasedTask.java
  Log:
  Merge of StarTeam fixes
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.5.2.3   +190 -113  ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckin.java
  
  Index: StarTeamCheckin.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckin.java,v
  retrieving revision 1.5.2.2
  retrieving revision 1.5.2.3
  diff -u -w -u -r1.5.2.2 -r1.5.2.3
  --- StarTeamCheckin.java	10 Feb 2003 14:25:20 -0000	1.5.2.2
  +++ StarTeamCheckin.java	13 Feb 2003 13:59:53 -0000	1.5.2.3
  @@ -53,18 +53,17 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  -import java.io.FileInputStream;
  -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.TypeNames;
   import com.starbase.starteam.View;
   import com.starbase.starteam.ViewConfiguration;
  -
  +import java.io.FileInputStream;
  +import java.io.IOException;
  +import java.util.Enumeration;
  +import java.util.Hashtable;
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.Project;
   
  @@ -72,8 +71,6 @@
    * 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
    *
    * @author <a href="mailto:scohen@localhost.localdomain">Steve Cohen</a>
  @@ -181,15 +178,50 @@
   
       /**
        * Implements base-class abstract function to define tests for
  -     * any preconditons required by the task
  +     * any preconditons required by the task.
        *
  -     * @exception BuildException not thrown in this implementation
  +     * @exception BuildException thrown if both rootLocalFolder 
  +     * and viewRootLocalFolder are defined
        */
       protected void testPreconditions() throws BuildException {
  -        if (null != getRootLocalFolder() && !isForced()) {
  -            log("Warning: rootLocalFolder specified, but forcing off.",
  -                    Project.MSG_WARN);
           }
  +    /**
  +     * 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." );
  +        }
  +
  +
       }
   
       /**
  @@ -202,129 +234,174 @@
        * @exception BuildException if any error occurs
        */
       protected void visit(Folder starteamFolder, java.io.File targetFolder)
  -            throws BuildException {
  +            throws BuildException 
  +    {
           try {
  -            Hashtable localFiles = listLocalFiles(targetFolder);
  +            if (null != getRootLocalFolder()) {
  +                starteamFolder.setAlternatePathFragment(
  +                    targetFolder.getAbsolutePath());
  +            }
   
  -            // If we have been told to create the working folders
  -            // 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);
  +            Folder[] foldersList = starteamFolder.getSubFolders();
  +            Item[] stFiles = starteamFolder.getItems(getTypeNames().FILE);
   
  -                delistLocalFile(localFiles, localFile);
  +            // 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.
   
  -                // If the file doesn't pass the include/exclude tests, skip it.
  -                if (!shouldProcess(filename)) {
  -                    log("Skipping " + eachFile.toString(), Project.MSG_INFO);
  -                    continue;
  -                }
  +            UnmatchedFileMap ufm = 
  +                new CheckinMap().init(
  +                    targetFolder.getAbsoluteFile(), starteamFolder);
   
   
  -                // 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.
  +            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());
   
  -                if (!isForced()) {
  -                    int fileStatus = (eachFile.getStatus());
  +                ufm.removeControlledItem(subfolder);
   
  -                    // 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;
  +                if (isRecursive()) {
  +                    visit(stFolder, subfolder);
                       }
                   }
   
  -                // Check in anything else.
   
  -                log("Checking In: " + (localFile.toString()), Project.MSG_INFO);
  -                eachFile.checkinFrom(localFile, this.comment,
  -                        this.lockStatus,
  -                        true, true, true);
  -            }
  +            for (int i = 0, size = stFiles.length; i < size; i++) {
  +                com.starbase.starteam.File stFile = 
  +                    (com.starbase.starteam.File) stFiles[i];
  +                processFile(stFile);
   
  -            // 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);
  -                }
  +                ufm.removeControlledItem(
  +                    new java.io.File(targetFolder, stFile.getName()));
               }
  +
               if (this.addUncontrolled) {
  -                addUncontrolledItems(localFiles, starteamFolder);
  +                ufm.processUncontrolledItems();
               }
   
  -
           } catch (IOException e) {
               throw new BuildException(e);
           }
  +
       }
   
       /**
  -     * Adds to the StarTeam repository everything on the local machine that
  -     * is not currently in the repository.
  -     * @param folder - StarTeam folder to which these items are to be added.
  +     * 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 addUncontrolledItems(Hashtable localFiles, Folder folder)
  +    private void processFile(com.starbase.starteam.File eachFile)
               throws IOException {
  -        try {
  -            Enumeration e = localFiles.keys();
  -            while (e.hasMoreElements()) {
  -                java.io.File file =
  -                        new java.io.File(e.nextElement().toString());
  -                add(folder, file);
  +        String filename = eachFile.getName();
  +
  +        // If the file doesn't pass the include/exclude tests, skip it.
  +        if (!shouldProcess(filename)) {
  +            log("Excluding " + getFullRepositoryPath(eachFile));
  +                return;
               }
  -        } catch (SecurityException e) {
  -            log("Error adding file: " + e, Project.MSG_ERR);
  +
  +        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);
           }
       }
   
       /**
  -     * Deletes the file from the local drive.
  -     * @param file the file or directory to delete.
  -     * @return true if the file was successfully deleted otherwise false.
  +     * handles the deletion of uncontrolled items
        */
  -    private void add(Folder parentFolder, java.io.File file)
  -            throws IOException {
  -        // If the current file is a Directory, we need to process all
  -        // of its children as well.
  -        if (file.isDirectory()) {
  -            log("Adding new folder to repository: " + file.getAbsolutePath(),
  -                    Project.MSG_INFO);
  -            Folder newFolder = new Folder(parentFolder);
  -            newFolder.setName(file.getName());
  -            newFolder.update();
  +    private class CheckinMap extends UnmatchedFileMap {
  +        protected boolean isActive() {
  +            return StarTeamCheckin.this.addUncontrolled;
  +        }
   
  -            // now visit this new folder to take care of adding any files
  -            // or subfolders within it.
  +    
  +        /**
  +         * 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()) {
  -                visit(newFolder, file);
  +                            UnmatchedFileMap submap = 
  +                                new CheckinMap().init(local, folder);
  +                            submap.processUncontrolledItems();
               }
           } else {
  -            log("Adding new file to repository: " + file.getAbsolutePath(),
  -                    Project.MSG_INFO);
  -            File newFile = new File(parentFolder);
  -            newFile.addFromStream(new FileInputStream(file),
  -                    file.getName(),
  -                    null, this.comment, 3, true);
  +                        com.starbase.starteam.File remoteFile =
  +                            (com.starbase.starteam.File) remoteItem;
  +                        log("Added uncontrolled file " 
  +                            + TreeBasedTask.getFullRepositoryPath(remoteFile)
  +                            + " from " + local.getAbsoluteFile());
  +    
  +                    }
  +                }
           }
       }
   }
  +
  +}
  +
  +
  
  
  
  1.9.2.4   +379 -127  ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java
  
  Index: StarTeamCheckout.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java,v
  retrieving revision 1.9.2.3
  retrieving revision 1.9.2.4
  diff -u -w -u -r1.9.2.3 -r1.9.2.4
  --- StarTeamCheckout.java	10 Feb 2003 14:25:20 -0000	1.9.2.3
  +++ StarTeamCheckout.java	13 Feb 2003 13:59:53 -0000	1.9.2.4
  @@ -1,7 +1,7 @@
   /*
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -53,17 +53,16 @@
    */
   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.TypeNames;
   import com.starbase.starteam.View;
   import com.starbase.starteam.ViewConfiguration;
  -
  +import java.io.IOException;
  +import java.util.Enumeration;
  +import java.util.Hashtable;
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.Project;
   
  @@ -112,8 +111,8 @@
       }
   
       /**
  -     * Should all all local files <i>not<i> in StarTeam be deleted?
  -     * Optional, defaults to "true".     
  +     * 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) {
  @@ -174,40 +173,132 @@
       }
   
       /**
  +     * should checked out files get the timestamp from the repository
  +     * or the time they are checked out.  True means use the repository 
  +     * timestamp.
  +     */
  +    private boolean useRepositoryTimeStamp = false;
  +
  +    /**
  +     * sets the useRepositoryTimestmp member.
  +     * 
  +     * @param useRepositoryTimeStamp
  +     *               true means checked out files will get the repository timestamp.
  +     *               false means the checked out files will be timestamped at the time
  +     *               of checkout.
  +     */
  +    public void setUseRepositoryTimeStamp(boolean useRepositoryTimeStamp)
  +    {
  +        this.useRepositoryTimeStamp = useRepositoryTimeStamp;
  +    }
  +
  +    /**
  +     * returns the value of the useRepositoryTimestamp member
  +     * 
  +     * @return the value of the useRepositoryTimestamp member
  +     */
  +    public boolean getUseRepositoryTimeStamp() {
  +        return this.useRepositoryTimeStamp;
  +    }
  +    /**
        * Override of base-class abstract function creates an
        * appropriately configured view for checkouts - either
  -     * the current view or a view from this.label.
  +     * 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
        */
  -    protected View createSnapshotView(View raw) {
  +    protected View createSnapshotView(View raw) 
  +    throws BuildException
  +    {
   
           int labelID = getLabelID(raw);
   
  -        // if a label has been supplied, use it to configure the view
  -        // otherwise use current view
  -        if (labelID >= 0) {
  +        // if a label has been supplied and it is a view label, use it 
  +        // to configure the view
  +        if (this.isUsingViewLabel()) {
               return new View(raw, ViewConfiguration.createFromLabel(labelID));
  -        } else {
  +        } 
  +        // if a label has been supplied and it is a revision label, use the raw 
  +        // the view as the snapshot
  +        else if (this.isUsingRevisionLabel()) {
  +            return raw;
  +        }
  +        // otherwise, use this view configured as the tip.
  +        else {
               return new View(raw, ViewConfiguration.createTip());
           }
       }
   
       /**
        * Implements base-class abstract function to define tests for
  -     * any preconditons required by the task
  +     * any preconditons required by the task.
        *
  -     * @exception BuildException not thrown in this implementation
  +     * @exception BuildException thrown if both rootLocalFolder 
  +     * and viewRootLocalFolder are defined
        */
       protected void testPreconditions() throws BuildException {
  -        if (null != getRootLocalFolder() && !isForced()) {
  -            log("Warning: rootLocalFolder specified, but forcing off.",
  +        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;
           }
       }
   
       /**
  +     * extenders should emit to the log an entry describing the parameters
  +     * that will be used by this operation.
  +     * 
  +     * @param starteamrootFolder
  +     *               root folder in StarTeam for the operation
  +     * @param targetrootFolder
  +     *               root local folder for the operation (whether specified 
  +     * by the user or not.
  +     */
  +
  +    protected void logOperationDescription(
  +        Folder starteamrootFolder, java.io.File targetrootFolder)
  +    {
  +        log((this.isRecursive() ? "Recursive" : "Non-recursive") + 
  +            " Checkout from: " + starteamrootFolder.getFolderHierarchy());
  +
  +        log("  Checking out to" 
  +            + (null == getRootLocalFolder() ? "(default): " : ": ") 
  +            + targetrootFolder.getAbsolutePath());
  +
  +
  +        logLabel();
  +        logIncludes();
  +        logExcludes();
  +
  +        if (this.lockStatus == Item.LockType.EXCLUSIVE) {
  +            log("  Items will be checked out with Exclusive locks.");
  +        }
  +        else if (this.lockStatus == Item.LockType.UNLOCKED) {
  +            log("  Items will be checked out unlocked (even if presently locked).");
  +        } 
  +        else {
  +            log("  Items will be checked out with no change in lock status.");
  +        }
  +        log("  Items will be checked out with " + 
  +            (this.useRepositoryTimeStamp ? "repository timestamps."  
  +                                        : "the current timestamp."));
  +        log("  Items will be checked out " +
  +            (this.isForced() ? "regardless of" : "in accordance with") +
  +            " repository status.");
  +        if (this.deleteUncontrolled) {
  +            log("  Local items not found in the repository will be deleted.");
  +        }
  +        log("  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.
        *
  @@ -217,59 +308,166 @@
        * @exception BuildException if any error occurs
        */
       protected void visit(Folder starteamFolder, java.io.File targetFolder)
  -            throws BuildException {
  +            throws BuildException 
  +    {  
           try {
  -            Hashtable localFiles = listLocalFiles(targetFolder);
   
  -            // If we have been told to create the working folders
  -            if (createDirs) {
  -                // Create if it doesn't exist
  +
  +            if (null != getRootLocalFolder()) {
  +                starteamFolder.setAlternatePathFragment(
  +                    targetFolder.getAbsolutePath());
  +            }
  +            
                   if (!targetFolder.exists()) {
  -                    targetFolder.mkdir();
  +                if (!this.isUsingRevisionLabel()) {
  +                    if (this.createDirs) {
  +                        if (targetFolder.mkdirs()) {
  +                            log("Creating folder: " + targetFolder);
  +                        } else {
  +                            throw new BuildException(
  +                                "Failed to create local folder " + targetFolder);
  +                        }
  +                    }
                   }
               }
  -            // 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);
  +            Folder[] foldersList = starteamFolder.getSubFolders();
  +            Item[] filesList = starteamFolder.getItems(getTypeNames().FILE);
   
  -                // If the file doesn't pass the include/exclude tests, skip it.
  -                if (!shouldProcess(filename)) {
  -                    log("Skipping " + eachFile.toString(), Project.MSG_INFO);
  -                    continue;
  +            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;
                   }
   
   
  -                // 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.
  +            // 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.
   
  -                if (!isForced()) {
  -                    int fileStatus = (eachFile.getStatus());
  +            UnmatchedFileMap ufm = 
  +                new CheckoutMap().
  +                    init(targetFolder.getAbsoluteFile(), starteamFolder);
   
  -                    // 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());
  +
  +
  +            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);
                       }
  -                    if (fileStatus == Status.CURRENT) {
  -                        log("Not processing " + eachFile.toString()
  -                                + " as it is current.",
  -                                Project.MSG_INFO);
  -                        continue;
  +                 }
  +
  +            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);
                       }
                   }
   
   
  -                // Check out anything else.
  +    /**
  +     * 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, 
  +                             java.io.File targetFolder )
  +    throws IOException 
  +    {
  +        String filename = eachFile.getName();
  +
  +        java.io.File localFile = new java.io.File(targetFolder, filename);
  +
  +        // If the file doesn't pass the include/exclude tests, skip it.
  +        if (!shouldProcess(filename)) {
  +            log("Excluding " + getFullRepositoryPath(eachFile), 
  +                Project.MSG_INFO);
  +                return;
  +        }
  +
  +        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
  @@ -281,79 +479,133 @@
                   // 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);
  +            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());
               }
   
  -            // 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);
  +            log(eachFile.toString() + " has status of " + 
  +                Status.name(fileStatus), Project.MSG_DEBUG);
  +
  +
  +            switch (fileStatus) {
  +            case Status.OUTOFDATE:
  +            case Status.MISSING:
  +                log("Checking out: " + describeCheckout(eachFile));
  +                break;
  +            default:
  +                if (isForced()) {
  +                    log("Forced checkout of " 
  +                        + describeCheckout(eachFile) 
  +                        + " over status " + Status.name(fileStatus));
  +                } else {
  +                    log("Skipping: " + getFullRepositoryPath(eachFile) + 
  +                        " - status: " + Status.name(fileStatus));
  +                    checkout = false;
                   }
               }
   
  -            if (this.deleteUncontrolled) {
  -                deleteUncontrolledItems(localFiles);
  +            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, true, true);
  +            }
  +        }
  +    }
  +    /**
  +     * handles the deletion of uncontrolled items
  +     */
  +    private class CheckoutMap extends UnmatchedFileMap {
  +        protected boolean isActive() {
  +            return StarTeamCheckout.this.deleteUncontrolled;
               }
   
  -        } catch (IOException e) {
  -            throw new BuildException(e);
  +        /**
  +         * override of the base class init.  It can be much simpler, since
  +         * the action to be taken is simply to delete the local files.  No
  +         * further interaction with the repository is necessary.
  +         * 
  +         * @param localFolder
  +         *        the local folder from which the mappings will be made.
  +         * @param remoteFolder
  +         *        not used in this implementation
  +         */
  +        UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) {
  +            if (!localFolder.exists()) {
  +                return this;
  +            }
  +
  +            String[] localFiles = localFolder.list();
  +    
  +            for (int i=0; i < localFiles.length; i++) {
  +                java.io.File localFile = 
  +                    new java.io.File(localFolder, localFiles[i]).getAbsoluteFile();
  +                
  +                log("adding " + localFile + " to UnmatchedFileMap",
  +                    Project.MSG_DEBUG);
  +    
  +                if (localFile.isDirectory()) {
  +                    this.put(localFile, "");
  +                } 
  +                else {
  +                    this.put(localFile, "");
           }
       }
  +            return this;
  +        }
  +
   
   
       /**
  -     * Deletes everything on the local machine that is not in the repository.
  -     *
  -     * @param localFiles the list of filenames whose elements are to be deleted
  +         * 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.
        */
  -    private void deleteUncontrolledItems(Hashtable localFiles) {
  -        try {
  -            Enumeration e = localFiles.keys();
  +        void processUncontrolledItems() throws BuildException {
  +            if (this.isActive()) {
  +                Enumeration e = this.keys();
               while (e.hasMoreElements()) {
  -                java.io.File file =
  -                        new java.io.File(e.nextElement().toString());
  -                delete(file);
  +                    java.io.File local = (java.io.File) e.nextElement();
  +                    delete(local);
               }
  -        } 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.
  +         * 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.
        */
  -    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]);
  +        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);
               }
           }
  -
  -        log("Deleting: " + file.getAbsolutePath(), Project.MSG_INFO);
  -        return file.delete();
  +            local.delete();
  +            log("Deleted uncontrolled item " + local.getAbsolutePath());
       }
  -
  -
   }
   
   
  -
  -
  -
  -
  -
  -
  -
  -
  +}
  
  
  
  1.9.2.4   +72 -8     ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java
  
  Index: StarTeamLabel.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java,v
  retrieving revision 1.9.2.3
  retrieving revision 1.9.2.4
  diff -u -w -u -r1.9.2.3 -r1.9.2.4
  --- StarTeamLabel.java	10 Feb 2003 14:25:20 -0000	1.9.2.3
  +++ StarTeamLabel.java	13 Feb 2003 13:59:53 -0000	1.9.2.4
  @@ -53,15 +53,13 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  -import java.text.ParseException;
  -import java.text.SimpleDateFormat;
  -import java.util.Date;
  -
   import com.starbase.starteam.Label;
   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 org.apache.tools.ant.BuildException;
   
   /**
  @@ -96,6 +94,19 @@
       private String description;
   
       /**
  +     * If true, this will be a build label.  If false, it will be a build
  +     * label.  The default is false.  Has no effect if revision label is
  +     * true.
  +     */
  +    private boolean buildlabel = false;
  +    
  +    /**
  +     * If true, this will be a revision label.  If false, it will be a build
  +     * label.  The default is false.
  +     */
  +    private boolean revisionlabel = false;
  +
  +    /**
        * The time of the last successful. The new label will be a snapshot of the
        * repository at this time. String should be formatted as "yyyyMMddHHmmss"
        */
  @@ -120,6 +131,30 @@
       }
   
       /**
  +     * set the type of label based on the supplied value - if true, this 
  +     * label will be a revision label, if false, a build label.
  +     * 
  +     * @param revision If true this will be a revision label; if false, 
  +     * a build label
  +     */
  +    public void setBuildLabel( boolean buildlabel ) {
  +        this.buildlabel = buildlabel;
  +    }
  +    
  +    /**
  +     * set the type of label based on the supplied value - if true, this 
  +     * label will be a revision label, if false, a build label.
  +     * 
  +     * @param revision If true this will be a revision label; if false, 
  +     * a build label
  +     */
  +    public void setRevisionLabel( boolean revisionlabel ) {
  +        this.revisionlabel = revisionlabel;
  +    }
  +
  +
  +
  +    /**
        * The timestamp of the build that will be stored with the label; required.  
        * Must be formatted <code>yyyyMMddHHmmss</code>
        */
  @@ -128,7 +163,8 @@
               Date lastBuildTime = DATE_FORMAT.parse(lastbuild);
               this.lastBuild = new OLEDate(lastBuildTime);
           } catch (ParseException e) {
  -            throw new BuildException("Unable to parse the date '" + lastbuild + "'", e);
  +            throw new BuildException("Unable to parse the date '" + 
  +                                     lastbuild + "'", e);
           }
       }
   
  @@ -139,11 +175,33 @@
        */
       public void execute() throws BuildException {
   
  +        if (this.revisionlabel && this.buildlabel) {
  +            throw new BuildException(
  +                "'revisionlabel' and 'buildlabel' both specified.  " +
  +                "A revision label cannot be a build label.");
  +        }
  +
           View snapshot = openView();
   
           // Create the new label and update the repository
  -        new Label(snapshot, labelName, description, this.lastBuild, true).update();
  -        log("Created Label " + labelName);
  +
  +        if (this.revisionlabel) {
  +            new Label(snapshot, this.labelName, this.description).update();
  +            log("Created Revision Label " + this.labelName);
  +        } 
  +        else if (null != lastBuild){
  +            new Label(snapshot, this.labelName, this.description,this.lastBuild,
  +                      this.buildlabel).update();
  +            log("Created View Label (" 
  +                +(this.buildlabel ? "" : "non-") + "build) " + this.labelName
  +                +" as of " + this.lastBuild.toString());
  +        }
  +        else {
  +            new Label(snapshot, this.labelName, this.description,
  +                      this.buildlabel).update();
  +            log("Created View Label (" 
  +                +(this.buildlabel ? "" : "non-") + "build) " + this.labelName);
  +        }
       }
   
       /**
  @@ -155,7 +213,13 @@
        * @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.6.2.4   +125 -21   ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java
  
  Index: StarTeamList.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java,v
  retrieving revision 1.6.2.3
  retrieving revision 1.6.2.4
  diff -u -w -u -r1.6.2.3 -r1.6.2.4
  --- StarTeamList.java	10 Feb 2003 14:25:20 -0000	1.6.2.3
  +++ StarTeamList.java	13 Feb 2003 13:59:53 -0000	1.6.2.4
  @@ -53,17 +53,18 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  -import java.io.IOException;
  -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 java.io.IOException;
  +import java.text.SimpleDateFormat;
  +import java.util.Enumeration;
  +import java.util.Hashtable;
   import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.Project;
   
   /**
    * Produces a listing of the contents of the StarTeam repository
  @@ -78,6 +79,7 @@
    */
   
   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.  
  @@ -120,6 +122,29 @@
       }
   
       /**
  +     * extenders should emit to the log an entry describing the parameters
  +     * that will be used by this operation.
  +     *
  +     * @param starteamrootFolder
  +     *               root folder in StarTeam for the operation
  +     * @param targetrootFolder
  +     *               root local folder for the operation (whether specified by the user or not.
  +     */
  +    protected void logOperationDescription(Folder starteamrootFolder, java.io.File targetrootFolder) {
  +        log((this.isRecursive() ? "Recursive" : "Non-recursive") + 
  +            " Listing of: " + starteamrootFolder.getFolderHierarchy());
  +
  +        log("Listing against local folder" 
  +            + (null == getRootLocalFolder() ? " (default): " : ": ") 
  +            + targetrootFolder.getAbsolutePath(),
  +                    Project.MSG_INFO);
  +        logLabel();
  +        logIncludes();
  +        logExcludes();
  +
  +
  +    }
  +    /**
        * Implements base-class abstract function to perform the checkout
        * operation on the files in each folder of the tree.
        *
  @@ -130,26 +155,35 @@
       protected void visit(Folder starteamFolder, java.io.File targetFolder)
               throws BuildException {
           try {
  -            if (null == getRootLocalFolder()) {
  -                log("Folder: " + starteamFolder.getName() + " (Default folder: " + targetFolder + ")");
  -            } else {
  -                log("Folder: " + starteamFolder.getName() + " (Local folder: " + targetFolder + ")");
  +            if (null != getRootLocalFolder()) {
  +                starteamFolder.setAlternatePathFragment(
  +                    targetFolder.getAbsolutePath());
  +
               }
  -            Hashtable localFiles = listLocalFiles(targetFolder);
  +            Folder[] subFolders = starteamFolder.getSubFolders();
  +            Item[] files = starteamFolder.getItems(getTypeNames().FILE);
  +            
  +            UnmatchedFileMap ufm = 
  +                new UnmatchedListingMap().init(
  +                    targetFolder.getAbsoluteFile(), starteamFolder);
  +
  +            log("");
  +            log("Listing StarTeam folder " + 
  +                starteamFolder.getFolderHierarchy()); 
  +            log(" against local folder " + 
  +                targetFolder.getAbsolutePath());
  +
   
               // For all Files in this folder, we need to check
               // if there have been modifications.
   
  -            Item[] files = starteamFolder.getItems("File");
               for (int i = 0; i < files.length; i++) {
                   File eachFile = (File) files[i];
                   String filename = eachFile.getName();
                   java.io.File localFile =
                           new java.io.File(targetFolder, filename);
   
  -                delistLocalFile(localFiles, localFile);
  -
  -
  +                ufm.removeControlledItem(localFile);
   
                   // If the file doesn't pass the include/exclude tests, skip it.
                   if (!shouldProcess(filename)) {
  @@ -162,32 +196,40 @@
   
               // Now we recursively call this method on all sub folders in this
               // folder unless recursive attribute is off.
  -            Folder[] subFolders = starteamFolder.getSubFolders();
               for (int i = 0; i < subFolders.length; i++) {
                   java.io.File targetSubfolder =
                           new java.io.File(targetFolder, subFolders[i].getName());
  -                delistLocalFile(localFiles, targetSubfolder);
  +                ufm.removeControlledItem(targetSubfolder);
                   if (isRecursive()) {
                       visit(subFolders[i], targetSubfolder);
                   }
               }
  +            if (this.listUncontrolled) {
  +                ufm.processUncontrolledItems();
  +            }
   
           } catch (IOException e) {
               throw new BuildException(e);
           }
       }
   
  +    private static final SimpleDateFormat SDF = 
  +        new SimpleDateFormat("yyyy-MM-dd hh:mm:ss zzz");
  +
       protected void list(File reposFile, java.io.File localFile)
               throws IOException {
           StringBuffer b = new StringBuffer();
  -        if (null == getRootLocalFolder()) {
  -            // status is irrelevant to us if we have specified a
  -            // root local folder.
  -            b.append(pad(Status.name(reposFile.getStatus()), 12)).append(' ');
  +        int status = reposFile.getStatus();
  +        java.util.Date displayDate = null;
  +        if (status==Status.NEW) {
  +            displayDate = new java.util.Date(localFile.lastModified());
  +        } else {
  +            displayDate = reposFile.getModifiedTime().createDate();
           }
  +        b.append(pad(Status.name(status), 12)).append(' ');
           b.append(pad(getUserName(reposFile.getLocker()), 20))
                   .append(' ')
  -                .append(reposFile.getModifiedTime().toString())
  +                .append(SDF.format(displayDate))
                   .append(rpad(String.valueOf(reposFile.getSize()), 9))
                   .append(' ')
                   .append(reposFile.getName());
  @@ -212,6 +254,68 @@
       protected static String rpad(String s, int padlen) {
           s = blankstr + 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.6.2.3   +54 -24    ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java
  
  Index: StarTeamTask.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java,v
  retrieving revision 1.6.2.2
  retrieving revision 1.6.2.3
  diff -u -w -u -r1.6.2.2 -r1.6.2.3
  --- StarTeamTask.java	10 Feb 2003 14:25:20 -0000	1.6.2.2
  +++ StarTeamTask.java	13 Feb 2003 13:59:53 -0000	1.6.2.3
  @@ -53,14 +53,15 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  -import java.util.StringTokenizer;
  -
  +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;
   
   /**
  @@ -114,6 +115,12 @@
        */
       private Server server = null;
   
  +    private void logStarteamVersion() {
  +        log("StarTeam version: "+ 
  +            BuildNumber.getDisplayString(), Project.MSG_DEBUG);
  +    }
  +
  +
       /////////////////////////////////////////////////////////
       // GET/SET methods.
       // Setters, of course are where ant user passes in values.
  @@ -125,7 +132,7 @@
        * @param servername a <code>String</code> value
        * @see #setURL(String)
        */
  -    public void setServername(String servername) {
  +    public final void setServername(String servername) {
           this.servername = servername;
       }
   
  @@ -135,7 +142,7 @@
        * @return the name of the StarTeam server
        * @see #getURL()
        */
  -    public String getServername() {
  +    public final String getServername() {
           return this.servername;
       }
   
  @@ -145,7 +152,7 @@
        * @param serverport port number to be set
        * @see #setURL(String)
        */
  -    public void setServerport(String serverport) {
  +    public final void setServerport(String serverport) {
           this.serverport = serverport;
       }
   
  @@ -155,7 +162,7 @@
        * @return the port number of the StarTeam connection
        * @see #getURL()
        */
  -    public String getServerport() {
  +    public final String getServerport() {
           return this.serverport;
       }
   
  @@ -166,7 +173,7 @@
        * @param projectname the name of the StarTeam project to be acted on
        * @see #setURL(String)
        */
  -    public void setProjectname(String projectname) {
  +    public final void setProjectname(String projectname) {
           this.projectname = projectname;
       }
   
  @@ -176,7 +183,7 @@
        * @return the name of the StarTeam project to be acted on
        * @see #getURL()
        */
  -    public String getProjectname() {
  +    public final String getProjectname() {
           return this.projectname;
       }
   
  @@ -187,7 +194,7 @@
        * @param projectname the name of the StarTeam view to be acted on
        * @see #setURL(String)
        */
  -    public void setViewname(String viewname) {
  +    public final void setViewname(String viewname) {
           this.viewname = viewname;
       }
   
  @@ -197,7 +204,7 @@
        * @return the name of the StarTeam view to be acted on
        * @see #getURL()
        */
  -    public String getViewname() {
  +    public final String getViewname() {
           return this.viewname;
       }
   
  @@ -214,7 +221,7 @@
        * @see #setProjectname(String)
        * @see #setViewname(String)
        */
  -    public void setURL(String url) {
  +    public final void setURL(String url) {
           StringTokenizer t = new StringTokenizer(url, "/");
           if (t.hasMoreTokens()) {
               String unpw = t.nextToken();
  @@ -248,7 +255,7 @@
        * @see #getProjectname()
        * @see #getViewname()
        */
  -    public String getURL() {
  +    public final String getURL() {
           return
                   this.servername + ":" +
                   this.serverport + "/" +
  @@ -257,11 +264,20 @@
       }
   
       /**
  +     * returns an URL string useful for interacting with many StarTeamFinder
  +     * methods.
  +     * 
  +     * @return the URL string for this task.
  +     */
  +    protected final String getViewURL() {
  +        return getUserName() + ":" + getPassword() + "@" + getURL();
  +    }
  +    /**
        * set the name of the StarTeam user, needed for the connection
        *
        * @param userName name of the user to be logged in
        */
  -    public void setUserName(String userName) {
  +    public final void setUserName(String userName) {
           this.userName = userName;
       }
   
  @@ -270,7 +286,7 @@
        *
        * @return the name of the StarTeam user
        */
  -    public String getUserName() {
  +    public final String getUserName() {
           return this.userName;
       }
   
  @@ -279,7 +295,7 @@
        *
        * @param password the password to be used for login
        */
  -    public void setPassword(String password) {
  +    public final void setPassword(String password) {
           this.password = password;
       }
   
  @@ -288,7 +304,7 @@
        *
        * @return the password used for login
        */
  -    public String getPassword() {
  +    public final String getPassword() {
           return this.password;
       }
   
  @@ -298,18 +314,27 @@
        *
        * @return a reference to the server
        */
  -    protected Server getServer() {
  +    protected final Server getServer() {
           return this.server;
       }
   
       /**
  +     * returns a list of TypeNames known to the server.
  +     *
  +     * @return a reference to the server's TypeNames
  +     */
  +    protected final TypeNames getTypeNames() {
  +        return this.server.getTypeNames();
  +    }
  +    /**
        * Derived classes must override <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.
        */
  -    protected abstract View createSnapshotView(View rawview);
  +    protected abstract View createSnapshotView(View rawview) 
  +    throws BuildException;
   
       /**
        * All subclasses will call on this method to open the view needed for
  @@ -322,10 +347,15 @@
        * @see #getServer()
        */
       protected View openView() throws BuildException {
  -        View view =
  -                StarTeamFinder.openView(getUserName() + ":"
  -                + getPassword()
  -                + "@" + getURL());
  +
  +        logStarteamVersion();
  +        View view = null;
  +        try {
  +            view = StarTeamFinder.openView(getViewURL());
  +        } catch (Exception e) {
  +            throw new BuildException(
  +                "Failed to connect to " + getURL(), e);
  +        }
   
           if (null == view) {
               throw new BuildException("Cannot find view" + getURL() +
  @@ -344,7 +374,7 @@
        * @param userID a user's ID
        * @return the name of the user with ID userID
        */
  -    protected String getUserName(int userID) {
  +    protected final String getUserName(int userID) {
           User u = this.server.getUser(userID);
           if (null == u) {
               return "";
  
  
  
  1.8.2.3   +330 -82   ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java
  
  Index: TreeBasedTask.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java,v
  retrieving revision 1.8.2.2
  retrieving revision 1.8.2.3
  diff -u -w -u -r1.8.2.2 -r1.8.2.3
  --- TreeBasedTask.java	10 Feb 2003 14:25:20 -0000	1.8.2.2
  +++ TreeBasedTask.java	13 Feb 2003 13:59:53 -0000	1.8.2.3
  @@ -1,7 +1,7 @@
   /*
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -53,16 +53,18 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  -import java.util.Hashtable;
  -import java.util.StringTokenizer;
  -
   import com.starbase.starteam.Folder;
  +import com.starbase.starteam.Item;
   import com.starbase.starteam.Label;
   import com.starbase.starteam.StarTeamFinder;
   import com.starbase.starteam.View;
  -
  +import java.util.Enumeration;
  +import java.util.Hashtable;
  +import java.util.StringTokenizer;
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.DirectoryScanner;
  +import org.apache.tools.ant.Project;
  +import org.apache.tools.ant.ProjectComponent;
   
   /**
    * FileBasedTask.java
  @@ -116,7 +118,7 @@
   
       /**
        * The local folder corresponding to starteamFolder.  If not specified
  -     * the Star Team defalt folder will be used.
  +     * the Star Team default folder will be used.
        */
       private String rootLocalFolder = null;
   
  @@ -150,6 +152,7 @@
        */
       private boolean forced = false;
   
  +    private Label labelInUse = null;
   
       ///////////////////////////////////////////////////////////////
       // GET/SET methods.
  @@ -179,23 +182,32 @@
        * 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
  +     * 
  +     * @param rootLocalFolder
  +     *               the local folder that will mirror
        *                        this.rootStarteamFolder
  +     * 
  +     * @see rootLocalFolder
        */
       public void setRootLocalFolder(String rootLocalFolder) {
           this.rootLocalFolder = rootLocalFolder;
       }
   
  +
  +
       /**
        * Returns the local folder specified by the user,
  -     * corresponding to the starteam folder for this operation.
  -     * or null if not specified
  +     * corresponding to the starteam folder for this operation
  +     * or null if not specified.
  +     * 
        * @return the local folder that mirrors this.rootStarteamFolder
  +     * @see rootLocalFolder
        */
       public String getRootLocalFolder() {
           return this.rootLocalFolder;
       }
   
  +
       /**
        * Declare files to include using standard <tt>includes</tt> patterns; optional. 
        * @param includes A string of filter patterns to include. Separate the
  @@ -223,6 +235,15 @@
       }
   
       /**
  +     * if excludes have been specified, emit the list to the log
  +     */
  +    protected void logIncludes() {
  +        if (this.DEFAULT_INCLUDESETTING != this.includes) {
  +            log("  Includes specified: "+ this.includes);
  +        }
  +    }
  +
  +    /**
        * Declare files to exclude using standard <tt>excludes</tt> patterns; optional. 
        * When filtering files, AntStarTeamCheckOut
        * uses an unmodified version of <CODE>DirectoryScanner</CODE>'s
  @@ -275,6 +296,16 @@
       }
   
       /**
  +     * if excludes have been specified, emit the list to the log
  +     */
  +    protected void logExcludes() {
  +        if (this.DEFAULT_EXCLUDESETTING != this.excludes) {
  +            log("  Excludes specified: "+ this.excludes);
  +        }
  +    }
  +
  +
  +    /**
        * protected function to allow subclasses to set the label (or not).
        * sets the StarTeam label
        *
  @@ -289,6 +320,10 @@
           }
       }
   
  +    protected String getLabel() {
  +        return this.label;
  +    }
  +
       /**
        * Get the value of recursive.
        * @return value of recursive.
  @@ -326,6 +361,49 @@
           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 
  +     */
  +    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());
  +        }
  +    }
  +
  +
  +
  +
       ///////////////////////////////////////////////////////////////
       // INCLUDE-EXCLUDE processing
       ///////////////////////////////////////////////////////////////
  @@ -334,8 +412,10 @@
        * Look if the file should be processed by the task.
        * Don't process it if it fits no include filters or if
        * it fits an exclude filter.
  +     * 
        * @param pName the item name to look for being included.
  -     * @return whether the file should be checked out or not.
  +     * 
  +     * @return whether the file should be processed or not.
        */
       protected boolean shouldProcess(String pName) {
           boolean includeIt = matchPatterns(getIncludes(), pName);
  @@ -364,49 +444,144 @@
       }
   
       /**
  -     * This method does the work of opening the supplied  Starteam view and
  -     * calling the <code>visit()</code> method to perform the task.
  +     * Finds and opens the root starteam folder of the operation specified
  +     * by this task.  This will be one of the following cases:
        *
  -     * @exception BuildException if any error occurs in the processing
  -     * @see <code>visit()</code>
  -     */
  -
  -    public void execute() throws BuildException {
  +     * @return Starteam's root folder for the operation.
  +     * @exception BuildException
  +     *                   if the root folder cannot be found in the repository
  +     */
  +    private final Folder configureRootStarteamFolder() 
  +        throws BuildException 
  +    {
  +        Folder starteamrootfolder = null;
           try {
  -            testPreconditions();
  -
  +            // no root local mapping has been specified.
               View snapshot = openView();
   
               // find the starteam folder specified to be the root of the
               // operation.  Throw if it can't be found.
  -            Folder starteamrootfolder =
  +
  +            starteamrootfolder =
                       StarTeamFinder.findFolder(snapshot.getRootFolder(),
                               this.rootStarteamFolder);
   
  +        } 
  +        catch (BuildException e) {
  +            throw e;
  +        }
  +        catch (Exception e) {
  +            throw new BuildException(
  +                "Unable to find root folder " + this.rootStarteamFolder + 
  +                " in repository at " + getURL(), e);
  +
  +        }
  +
               if (null == starteamrootfolder) {
                   throw new BuildException(
  -                        "Unable to find root folder in repository.");
  +                "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 final java.io.File getLocalRootMapping(Folder starteamrootfolder) {
               // set the local folder.
  -            java.io.File localrootfolder;
  -            if (null == this.rootLocalFolder) {
  -                // use Star Team's default
  -                localrootfolder =
  -                        new java.io.File(starteamrootfolder.getPath());
  -            } else {
  -                // force StarTeam to use our folder
  -                localrootfolder = new java.io.File(getRootLocalFolder());
  -                log("overriding local folder to " + localrootfolder);
  +        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);
           }
       }
   
  +    private void findLabel(View v) throws BuildException {
  +        Label[] allLabels = v.getLabels();
  +        for (int i = 0; i < allLabels.length; i++) {
  +            Label stLabel = allLabels[i];
  +            log("checking label " + stLabel.getName(), Project.MSG_DEBUG);
  +            if (stLabel.getName().equals(this.label)) {
  +                if (!stLabel.isRevisionLabel() && !stLabel.isViewLabel()) {
  +                    throw new BuildException("Unexpected label type.");
  +                }
  +                log("using label " + stLabel.getName(), Project.MSG_DEBUG);
  +                this.labelInUse = stLabel;
  +                return;
  +            }
  +        }
  +        throw new BuildException("Error: label "
  +                + this.label
  +                + " does not exist in view "
  +                + v.getFullName());
  +
  +    }
  +
       /**
        * Helper method calls on the StarTeam API to retrieve an ID number
        * for the specified view, corresponding to this.label.
  @@ -418,32 +593,37 @@
        */
       protected int getLabelID(View v) throws BuildException {
           if (null != this.label) {
  -            Label[] allLabels = v.getLabels();
  -            for (int i = 0; i < allLabels.length; i++) {
  -                if (allLabels[i].getName().equals(this.label)) {
  -                    return allLabels[i].getID();
  +            findLabel(v);
  +            return this.labelInUse.getID();
                   }
  +        return -1;
               }
  -            throw new BuildException("Error: label "
  -                    + this.label
  -                    + " does not exist in view");
  +
  +    protected int getIDofLabelInUse() {
  +        if (null != this.labelInUse) {
  +            return this.labelInUse.getID();
           }
           return -1;
       }
   
  -
       /**
        * Derived classes must override this class to define actual processing
        * to be performed on each folder in the tree defined for the task
        *
  -     * @param rootStarteamFolder the StarTeam folderto be visited
  -     * @param rootLocalFolder the local mapping of rootStarteamFolder
  +     * @param rootStarteamFolder
  +     *               the StarTeam folderto be visited
  +     * @param rootLocalFolder
  +     *               the local mapping of rootStarteamFolder
  +     * 
  +     * @exception BuildException
        */
       protected abstract void visit(Folder rootStarteamFolder,
                                     java.io.File rootLocalFolder)
               throws BuildException;
   
   
  +
  +
       /**
        * Derived classes must override this method to define tests for
        * any preconditons required by the task.  This method is called at
  @@ -456,46 +636,114 @@
        */
       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();
  +    }
  +
       /**
  -     * Gets the collection of the local file names in the supplied directory.
  -     * We need to check this collection against what we find in Starteam to
  -     * understand what we need to do in order to synch with the repository.
  -     *
  -     * @param localFolder - the local folder to scan
  -     * @return an "identity" hashtable whose keys each represent a file or
  -     * directory in localFolder.
  -     */
  -    protected static Hashtable listLocalFiles(java.io.File localFolder) {
  -
  -        Hashtable localFileList = new Hashtable();
  -        // we can't use java 2 collections so we will use an identity
  -        // Hashtable to  hold the file names.  We only care about the keys,
  -        // not the values (which will all be "").
  +     * This class implements a map of existing local files to possibly
  +     * existing repository files.  The map is created by a TreeBasedTask
  +     * upon recursing into a directory.  Each local item is mapped to an
  +     * unattached StarTeam object of the proper type, File->File and
  +     * Directory->Folder.
  +     * 
  +     * As the TreeBased does its work, it deletes from the map all items
  +     * it has processed.  
  +     * 
  +     * When the TreeBased task processes all the items from the repository,
  +     * whatever items left in the UnmatchedFileMap are uncontrolled items
  +     * and can be processed as appropriate to the task.  In the case of
  +     * Checkouts, they can be optionally deleted from the local tree.  In the 
  +     * case of Checkins they can optionally be added to the resository.
  +     */
  +    protected abstract class UnmatchedFileMap extends Hashtable {
  +    
  +        /**
  +         * initializes the UnmatchedFileMap with entries from the local folder
  +         * These will be mapped to the corresponding StarTeam entry even though
  +         * it will not, in fact, exist in the repository.  But through it, it 
  +         * can be added, listed, etc.
  +         * 
  +         * @param localFolder
  +         *        the local folder from which the mappings will be made.
  +         * @param remoteFolder
  +         *        the corresponding StarTeam folder which will be processed.
  +         */
  +        UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) {
  +            if (!localFolder.exists()) {
  +                return this;
  +            }
   
  -        if (localFolder.exists()) {
               String[] localFiles = localFolder.list();
  +    
               for (int i = 0; i < localFiles.length; i++) {
  -                localFileList.put(localFolder.toString() +
  -                        java.io.File.separatorChar + localFiles[i], "");
  +                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 localFileList;
  +            }
  +            return this;
       }
   
       /**
  -     * Removes from the collection of the local file names
  -     * the supplied name of a processed file.  When we are done, only
  -     * files not in StarTeam will remain in localFiles.
  -     * @param localFiles a <code>Hashtable</code> value
  -     * @param thisfile file to remove from list.
  -     * @return true if file was removed, false if it wasn't found.
  +         * remove an item found to be controlled from the map.
  +         * 
  +         * @param localFile the local item found to be controlled.
        */
  -    protected boolean delistLocalFile(Hashtable localFiles, java.io.File thisfile) {
  -        return null != localFiles.remove(thisfile.toString());
  +        void removeControlledItem(java.io.File localFile) {
  +            if (isActive()) {
  +                log("removing processed " + localFile.getAbsoluteFile() + 
  +                    " from UnmatchedFileMap", Project.MSG_DEBUG);
  +                this.remove(localFile.getAbsoluteFile());
       }
   }
  +        /**
  +         * override will perform the action appropriate for its task to perform
  +         * on items which are on the local tree but not in StarTeam.  It is 
  +         * assumed that this method will not be called until all the items in
  +         * the corresponding folder have been processed, and that the internal 
  +         * map * will contain only uncontrolled items.
  +         */
  +        abstract void processUncontrolledItems() throws BuildException;
  +    
  +        /**
  +         * overrides must define this to declare how this method knows if it 
  +         * is active.  This presents extra clock cycles when the functionality
  +         * is not called for.
  +         * 
  +         * @return True if this object is to perform its functionality.
  +         */
  +        abstract protected boolean isActive();
   
  +    }
   
  +}