ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam StarTeamCheckin.java StarTeamCheckout.java StarTeamLabel.java StarTeamList.java StarTeamTask.java TreeBasedTask.java
Date Wed, 06 Nov 2002 11:07:10 GMT
bodewig     2002/11/06 03:07:10

  Modified:    docs/manual/OptionalTasks starteam.html
               src/main/org/apache/tools/ant/taskdefs/optional/starteam
                        StarTeamCheckin.java StarTeamCheckout.java
                        StarTeamLabel.java StarTeamList.java
                        StarTeamTask.java TreeBasedTask.java
  Log:
  various starteam task enhancements.
  
  PR: 14006,14208,14210
  Submitted by:	Steve Cohen <SteveC at ignitesports.com>
  Reviewed by:	Art Blake <Art.Blake at Metavante.com>,
                  Jonny Boman <Jonny.Boman@vikingline.fi>
  
  Revision  Changes    Path
  1.16      +75 -15    jakarta-ant/docs/manual/OptionalTasks/starteam.html
  
  Index: starteam.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/OptionalTasks/starteam.html,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- starteam.html	4 Sep 2002 11:05:18 -0000	1.15
  +++ starteam.html	6 Nov 2002 11:07:09 -0000	1.16
  @@ -1,7 +1,7 @@
   <html>
   <head>
   <meta http-equiv="Content-Language" content="en-us">
  -<title>StartTeam Tasks</title>
  +<title>StarTeam Tasks</title>
   </head>
   <body>
   <h1>StarTeam Support</h1>
  @@ -98,7 +98,10 @@
     <tr>
       <td valign="top">rootstarteamfolder</td>
       <td valign="top">The root of the subtree in the StarTeam repository from which to 
  -    check out files.  Defaults to the root folder of the view ('/'). </td>
  +    check out files.  Defaults to the root folder of the view ('/'). 
  +      <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
  +      Relative paths have little meaning in this context and confuse StarTeam.</i></b>
  +      </td>
       <td align="center" valign="top">no</td>
     </tr>  
     <tr>
  @@ -141,9 +144,7 @@
     <tr>
       <td valign="top">forced</td>
       <td valign="top">If true, checkouts will occur regardless of the status 
  -that StarTeam is maintaining for the file.  If rootlocalfolder is set then 
  -this should be set "true" as otherwise the checkout will be based on statuses 
  -which do not relate to the target folder.  Defaults to "false".</td>
  +that StarTeam is maintaining for the file.   If false, status will be used to determine which files to check out. Defaults to "false".</td>
       <td align="center" valign="top">no</td>
     </tr> 
    <tr>
  @@ -156,8 +157,16 @@
       <td valign="top">unlocked</td>
       <td valign="top">If true, file will be unlocked so that other users may
   change it.  This is a way to reverse changes that have not yet been checked in.
  -If false (default) has no effect. 
  +If false (default) has no effect.</td> 
     </tr>
  +  <tr>
  +    <td valign="top">userepositorytimestamp</td>
  +    <td valign="top">true means checked out files will get the repository timestamp.
  +false(default) means the checked out files will be timestamped at the time
  +of checkout.</td>    <td align="center" valign="top">no</td>
  +
  +  </tr>
  +    
   </table>
   
   <h3>Examples</h3>
  @@ -290,7 +299,9 @@
     <tr>
       <td valign="top">rootstarteamfolder</td>
       <td valign="top">The root of the subtree in the StarTeam repository into which to 
  -    files will be checked.  Defaults to the root folder of the view ('/'). </td>
  +    files will be checked.  Defaults to the root folder of the view ('/').
  +       <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
  +      Relative paths have little meaning in this context and confuse StarTeam.</i></b></td>
       <td align="center" valign="top">no</td>
     </tr>  
     <tr>
  @@ -330,9 +341,7 @@
     <tr>
       <td valign="top">forced</td>
       <td valign="top">If true, checkins will occur regardless of the status 
  -that StarTeam is maintaining for the file.  If rootlocalfolder is set then 
  -this should be set "true" as otherwise the checkin will be based on statuses 
  -which do not relate to the target folder.  Defaults to "false".</td>
  +that StarTeam is maintaining for the file.  If false, checkins will use this status to decide which files to update.  Defaults to "false".</td>
       <td align="center" valign="top">no</td>
     </tr>
       <td valign="top">unlocked</td>
  @@ -499,10 +508,24 @@
       <td valign="top">The name to be given to the label</td>
       <td align="center" valign="top">yes</td>
     </tr> 
  +  <tr>
  +    <td valign="top">revisionlabel</td>
  +    <td valign="top">Yes means that the label attribute is to be saved as a &quot;revision label&quot;.  No (default) means that it will be saved as a &quot;view label&quot;</td>
  +    <td align="center" valign="top">no</td>
  +  </tr> 
  +  <tr>
  +    <td valign="top">buildlabel</td>
  +    <td valign="top">Yes (default) means that the label attribute is to be saved as a &quot;build label&quot;.  
  +      This means that Change Requests which have an &quot;AddressedIn&quot; field value of &quot;next build&quot;
  +       will have this label assigned to that field when the label is created.  
  +       No means that no CRs will have this label assigned to them.  This will have no effect if <b>revisionlabel</b> is also true.  </td>
  +    <td align="center" valign="top">no</td>
  +  </tr> 
  +
    <tr>
       <td valign="top">lastbuild</td>
       <td valign="top">The timestamp of the build that will be stored with the label.  Must be formatted <code>yyyyMMddHHmmss</code></td>
  -    <td align="center" valign="top">yes</td>
  +    <td align="center" valign="top">no</td>
     </tr>
     <tr>
       <td valign="top">description</td>
  @@ -513,8 +536,8 @@
   
   <h3>Examples</h3>
   
  -This example shows the use of this tag.  It will create a label named <i>Version 6.2</i> with
  -<i>"Thorough description"</i> as its description.
  +This example shows the use of this tag.  It will create a View label that is a build label named <i>Version 6.2</i> with
  +<i>&quot;Thorough description&quot;</i> as its description.
   <pre>
     &lt;tstamp&gt;
       &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
  @@ -527,6 +550,35 @@
              description="Thorough description"
     /&gt;
   </pre>
  +This example creates a non-build View label named <i>Version 6.3</i> with
  +<i>&quot;Thorough description&quot;</i> as its description.
  +<pre>
  +  &lt;tstamp&gt;
  +    &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
  +  &lt;/tstamp&gt;  
  +  &lt;stlabel URL="STARTEAM:49201/Aproject/AView"
  +           username="auser"
  +           password="secret"
  +           label="Version 6.3"
  +           lastbuild="${nowstamp}"
  +           description="Thorough description"
  +           buildlabel="false"
  +  /&gt;
  +</pre>
  +This example will create a Revision label that is a build label named <i>Version 6.2.00.001</i> with
  +<i>&quot;revision label&quot;</i> as its description.
  +<pre>
  +  &lt;tstamp&gt;
  +    &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
  +  &lt;/tstamp&gt;  
  +  &lt;stlabel URL="STARTEAM:49201/Aproject/AView"
  +           username="auser"
  +           password="secret"
  +           label="Version 6.2.00.001"
  +           description="revision label"
  +           revisionlabel="true"
  +  /&gt;
  +</pre>
   
   <hr></hr>
   <a name="stlist">
  @@ -534,7 +586,7 @@
   
   <h3>Description</h3>
   
  -Produces a listing of the contents of the StarTeam repository at the specified view and StarTeamFolder.  The listing will contain the name of the user, if any, who has the file locked, the size of the file, its lastModifiedDate in the repository, and the name of the file.  Unless the rootLocalFolder is specified, listing will also show the status of the local file in the default local directory relative to the repository. 
  +Produces a listing of the contents of the StarTeam repository at the specified view and StarTeamFolder.  The listing will contain the name of the user, if any, who has the file locked, the size of the file, its lastModifiedDate in the repository, the name of the file, and the status of the local file in the default local directory relative to the repository. 
   
   <h3>Parameters</h3>
   See also <A href="#common-params">the required common StarTeam parameters</A>.<br></br>
  @@ -547,7 +599,8 @@
   
     <tr>
       <td valign="top">rootstarteamfolder</td>
  -    <td valign="top">The root of the subtree in the StarTeam repository to be listed.  Defaults to the root folder of the view ('/'). </td>
  +    <td valign="top">The root of the subtree in the StarTeam repository to be listed.  Defaults to the root folder of the view ('/'). <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
  +      Relative paths have little meaning in this context and confuse StarTeam.</i></b></td>
       <td align="center" valign="top">no</td>
     </tr>  
     <tr>
  @@ -576,6 +629,13 @@
       <td valign="top">Indicates if subfolders should be searched for files to list.  Defaults to "true".</td>
       <td align="center" valign="top">no</td>
     </tr>
  +    <tr>
  +    <td valign="top">listuncontrolled</td>
  +    <td valign="top">if true, any files or folders NOT in StarTeam will be included in the listing.
  +    If false, they won't.  Defaults to "true".</td>
  +    <td align="center" valign="top">no</td>
  +    </tr>
  +
   </table>
   <h3>Examples</h3>
   
  
  
  
  1.8       +188 -107  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckin.java
  
  Index: StarTeamCheckin.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckin.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- StarTeamCheckin.java	25 Jul 2002 15:21:20 -0000	1.7
  +++ StarTeamCheckin.java	6 Nov 2002 11:07:09 -0000	1.8
  @@ -57,6 +57,7 @@
   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;
  @@ -70,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>
  @@ -179,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." );
           }
  +
  +
       }
   
       /**
  @@ -200,129 +234,176 @@
        * @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);
  -
  -                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;
  -                }
  +            Folder[] foldersList = starteamFolder.getSubFolders();
  +            Item[] stFiles = starteamFolder.getItems(getTypeNames().FILE);
  +            
  +            // note, it's important to scan the items BEFORE we make the
  +            // UnmatchedFileMap because that creates a bunch of NEW
  +            // folders and files (unattached to repository) and we
  +            // don't want to include those in our traversal.
  +
  +            UnmatchedFileMap ufm = 
  +                new CheckinMap().init(
  +                    targetFolder.getAbsoluteFile(), starteamFolder);
  +
  +
  +            for (int i = 0, size = foldersList.length; i < size; i++) {
  +                Folder stFolder = foldersList[i];
  +                java.io.File subfolder = 
  +                    new java.io.File(targetFolder, stFolder.getName());
   
  +                ufm.removeControlledItem(subfolder);
   
  -                // If 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;
  -                    }
  +                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);
               }
   
  -            // 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);
  -                }
  +           
  +            for (int i = 0, size = stFiles.length; i < size; i++) {
  +                com.starbase.starteam.File stFile = 
  +                    (com.starbase.starteam.File) stFiles[i];
  +                processFile( stFile, targetFolder);
  +                
  +                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.
  -     */
  -    private void addUncontrolledItems(Hashtable localFiles, Folder folder)
  -            throws IOException {
  -        try {
  -            Enumeration e = localFiles.keys();
  -            while (e.hasMoreElements()) {
  -                java.io.File file =
  -                        new java.io.File(e.nextElement().toString());
  -                add(folder, file);
  +     * provides a string showing from and to full paths for logging
  +     * 
  +     * @param remotefile the Star Team file being processed.
  +     * 
  +     * @return a string showing from and to full paths
  +     */
  +    private String describeCheckin(com.starbase.starteam.File remotefile)
  +    {
  +        StringBuffer sb = new StringBuffer();
  +        sb.append(remotefile.getFullName())
  +          .append(" --> ")
  +          .append(getFullRepositoryPath(remotefile));
  +        return sb.toString();
  +    }
  +
  +    /**
  +     * Processes (checks-out) <code>stFiles</code>files from StarTeam folder.
  +     *
  +     * @param eachFile repository file to process
  +     * @param targetFolder a java.io.File (Folder) to work
  +     * @throws IOException when StarTeam API fails to work with files
  +     */
  +    private void processFile(com.starbase.starteam.File eachFile, 
  +                             java.io.File targetFolder )
  +    throws IOException 
  +    {
  +        String filename = eachFile.getName();
  +
  +        // If the file doesn't pass the include/exclude tests, skip it.
  +        if (!shouldProcess(filename)) {
  +            log("Excluding " + getFullRepositoryPath(eachFile));
  +                return;
  +        }
  +
  +        boolean checkin = true;
  +        int fileStatus = (eachFile.getStatus());
  +
  +        // We try to update the status once to give StarTeam
  +        // another chance.
  +
  +        if (fileStatus == Status.MERGE || fileStatus == Status.UNKNOWN) {
  +            eachFile.updateStatus(true, true);
  +            fileStatus = (eachFile.getStatus());
  +        }
  +
  +        if (fileStatus == Status.MODIFIED) {
  +            log("Checking in: " + describeCheckin(eachFile));
  +        } 
  +        else if (fileStatus == Status.MISSING) {
  +            log("Local file missing: " + describeCheckin(eachFile));
  +            checkin = false;
  +        }
  +        else {
  +            if (isForced()) {
  +                log("Forced checkin of " + describeCheckin(eachFile) + 
  +                    " over status " + Status.name(fileStatus));
  +            } else {
  +                log("Skipping: " + getFullRepositoryPath(eachFile) + 
  +                    " - status: " + Status.name(fileStatus));
  +                checkin = false;
               }
  -        } catch (SecurityException e) {
  -            log("Error adding file: " + e, Project.MSG_ERR);
  +        }
  +        if (checkin) {
  +            eachFile.checkin(this.comment, this.lockStatus, 
  +                             this.isForced(), true, true);
           }
       }
   
       /**
  -     * Deletes the file from the local drive.
  -     * @param file the file or directory to delete.
  -     * @return true if the file was successfully deleted otherwise false.
  -     */
  -    private void add(Folder parentFolder, java.io.File file)
  -            throws IOException {
  -        // If the current file is a Directory, we need to process all
  -        // of its children as well.
  -        if (file.isDirectory()) {
  -            log("Adding new folder to repository: " + file.getAbsolutePath(),
  -                    Project.MSG_INFO);
  -            Folder newFolder = new Folder(parentFolder);
  -            newFolder.setName(file.getName());
  -            newFolder.update();
  -
  -            // now visit this new folder to take care of adding any files
  -            // or subfolders within it.
  -            if (isRecursive()) {
  -                visit(newFolder, file);
  +     * handles the deletion of uncontrolled items
  +     */
  +    private class CheckinMap extends UnmatchedFileMap {
  +        protected boolean isActive() {
  +            return StarTeamCheckin.this.addUncontrolled;
  +        }
  +
  +    
  +        /**
  +         * This override adds all its members to the repository.  It is assumed 
  +         * that this method will not be called until all the items in the 
  +         * corresponding folder have been processed, and that the internal map
  +         * will contain only uncontrolled items.
  +         */
  +        void processUncontrolledItems() throws BuildException {
  +            if (this.isActive()) {
  +                Enumeration e = this.keys();
  +                while (e.hasMoreElements()) {
  +                    java.io.File local = (java.io.File) e.nextElement();
  +                    Item remoteItem = (Item) this.get(local);
  +                    remoteItem.update();
  +    
  +                    // once we find a folder that isn't in the repository, 
  +                    // we know we can add it.
  +                    if (local.isDirectory()) {
  +                        Folder folder = (Folder) remoteItem;
  +                        log("Added uncontrolled folder " 
  +                            + folder.getFolderHierarchy()
  +                            + " from " + local.getAbsoluteFile());
  +                        if (isRecursive()) {
  +                            UnmatchedFileMap submap = 
  +                                new CheckinMap().init(local, folder);
  +                            submap.processUncontrolledItems();
  +                        }
  +                    } else {
  +                        com.starbase.starteam.File remoteFile =
  +                            (com.starbase.starteam.File) remoteItem;
  +                        log("Added uncontrolled file " 
  +                            + TreeBasedTask.getFullRepositoryPath(remoteFile)
  +                            + " from " + local.getAbsoluteFile());
  +    
  +                    }
  +                }
               }
  -        } 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);
           }
       }
  +
   }
  +
  +
  
  
  
  1.13      +326 -121  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java
  
  Index: StarTeamCheckout.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamCheckout.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- StarTeamCheckout.java	25 Jul 2002 15:21:20 -0000	1.12
  +++ StarTeamCheckout.java	6 Nov 2002 11:07:09 -0000	1.13
  @@ -57,6 +57,7 @@
   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;
  @@ -172,40 +173,127 @@
       }
   
       /**
  +     * should checked out files get the timestamp from the repository
  +     * or the time they are checked out.  True means use the repository 
  +     * timestamp.
  +     */
  +    private boolean useRepositoryTimeStamp = false;
  +
  +    /**
  +     * sets the useRepositoryTimestmp member.
  +     * 
  +     * @param useRepositoryTimeStamp
  +     *               true means checked out files will get the repository timestamp.
  +     *               false means the checked out files will be timestamped at the time
  +     *               of checkout.
  +     */
  +    public void setUseRepositoryTimeStamp(boolean useRepositoryTimeStamp)
  +    {
  +        this.useRepositoryTimeStamp = useRepositoryTimeStamp;
  +    }
  +
  +    /**
  +     * returns the value of the useRepositoryTimestamp member
  +     * 
  +     * @return the value of the useRepositoryTimestamp member
  +     */
  +    public boolean getUseRepositoryTimeStamp() {
  +        return this.useRepositoryTimeStamp;
  +    }
  +    /**
        * Override of base-class abstract function creates an
        * appropriately configured view for checkouts - either
  -     * the current view or a view from this.label.
  -     *
  -     * @param raw the unconfigured <code>View</code>
  +     * 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.",
  -                    Project.MSG_WARN);
  -        }
  +        //intentionally do nothing
       }
   
       /**
  +     * extenders should emit to the log an entry describing the parameters
  +     * that will be used by this operation.
  +     * 
  +     * @param starteamrootFolder
  +     *               root folder in StarTeam for the operation
  +     * @param targetrootFolder
  +     *               root local folder for the operation (whether specified 
  +     * by the user or not.
  +     */
  +
  +    protected void logOperationDescription(
  +        Folder starteamrootFolder, java.io.File targetrootFolder)
  +    {
  +        log((this.isRecursive() ? "Recursive" : "Non-recursive") + 
  +            " Checkout from: " + starteamrootFolder.getFolderHierarchy());
  +
  +        log("  Checking out to" 
  +            + (null == getRootLocalFolder() ? "(default): " : ": ") 
  +            + targetrootFolder.getAbsolutePath());
  +
  +
  +        logLabel();
  +        logIncludes();
  +        logExcludes();
  +
  +        if (this.lockStatus == Item.LockType.EXCLUSIVE) {
  +            log("  Items will be checked out with Exclusive locks.");
  +        }
  +        else if (this.lockStatus == Item.LockType.UNLOCKED) {
  +            log("  Items will be checked out unlocked (even if presently locked).");
  +        } 
  +        else {
  +            log("  Items will be checked out with no change in lock status.");
  +        }
  +        log("  Items will be checked out with " + 
  +            (this.useRepositoryTimeStamp ? "repository timestamps."  
  +                                        : "the current timestamp."));
  +        log("  Items will be checked out " +
  +            (this.isForced() ? "regardless of" : "in accordance with") +
  +            " repository status.");
  +        if (this.deleteUncontrolled) {
  +            log("  Local items not found in the repository will be deleted.");
  +        }
  +        log("  Working directories will "+
  +            (this.createDirs ? "be created as needed." 
  +                             : "not be created."));
  +        
  +    }
  +    /**
        * Implements base-class abstract function to perform the checkout
        * operation on the files in each folder of the tree.
        *
  @@ -215,91 +303,64 @@
        * @exception BuildException if any error occurs
        */
       protected void visit(Folder starteamFolder, java.io.File targetFolder)
  -            throws BuildException {
  +            throws BuildException 
  +    {  
           try {
  -            Hashtable localFiles = listLocalFiles(targetFolder);
   
  -            // If we have been told to create the working folders
  -            if (createDirs) {
  -                // Create if it doesn't exist
  -                if (!targetFolder.exists()) {
  -                    targetFolder.mkdir();
  -                }
  -            }
  -            // For all Files in this folder, we need to check
  -            // if there have been modifications.
  -
  -            Item[] files = starteamFolder.getItems("File");
  -            for (int i = 0; i < files.length; i++) {
  -                File eachFile = (File) files[i];
  -                String filename = eachFile.getName();
  -                java.io.File localFile =
  -                        new java.io.File(targetFolder, filename);
  -
  -                delistLocalFile(localFiles, localFile);
  -
  -                // If the file doesn't pass the include/exclude tests, skip it.
  -                if (!shouldProcess(filename)) {
  -                    log("Skipping " + eachFile.toString(), Project.MSG_INFO);
  -                    continue;
  -                }
   
  +            if (null != getRootLocalFolder()) {
  +                starteamFolder.setAlternatePathFragment(
  +                    targetFolder.getAbsolutePath());
  +            }
  +            
  +            
  +            Folder[] foldersList = starteamFolder.getSubFolders();
  +            Item[] filesList = starteamFolder.getItems(getTypeNames().FILE);
  +            
  +            
  +            // note, it's important to scan the items BEFORE we make the
  +            // Unmatched file map because that creates a bunch of NEW
  +            // folders and files (unattached to repository) and we
  +            // don't want to include those in our traversal.
  +
  +            UnmatchedFileMap ufm = 
  +                new CheckoutMap().
  +                    init(targetFolder.getAbsoluteFile(), starteamFolder);
   
  -                // 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);
  -                }
  +            for (int i = 0; i < foldersList.length; i++) {
  +                Folder stFolder = foldersList[i];
  +
  +                java.io.File subfolder = 
  +                     new java.io.File(targetFolder, stFolder.getName());
  +
  +                 ufm.removeControlledItem(subfolder);
  +
  +                 if (isRecursive()) {
  +                     if (!subfolder.exists()) {
  +                         if (this.createDirs) {
  +                             log("Creating folder: " + subfolder);
  +                             subfolder.mkdirs();
  +                         }
  +                     }
  +                     if (subfolder.exists()) {
  +                         visit(stFolder, subfolder);
  +                     }
  +                 }
               }
   
  +            for (int i = 0; i < filesList.length; i++) {
  +                com.starbase.starteam.File stFile = 
  +                    (com.starbase.starteam.File) filesList[i];
  +                processFile( stFile, targetFolder);
  +                
  +                ufm.removeControlledItem(
  +                    new java.io.File(targetFolder, stFile.getName()));
  +            }
               if (this.deleteUncontrolled) {
  -                deleteUncontrolledItems(localFiles);
  +                ufm.processUncontrolledItems();
               }
  -
           } catch (IOException e) {
               throw new BuildException(e);
           }
  @@ -307,51 +368,195 @@
   
   
       /**
  -     * 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);
  +     * 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);
       }
  -
       /**
  -     * 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]);
  -            }
  +     * 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;
           }
   
  -        log("Deleting: " + file.getAbsolutePath(), Project.MSG_INFO);
  -        return file.delete();
  -    }
  -
  +        if (this.isUsingRevisionLabel()) {
  +            boolean success = eachFile.checkoutByLabelID(
  +                localFile,
  +                getIDofLabelInUse(),
  +                this.lockStatus,
  +                !this.useRepositoryTimeStamp,
  +                true,
  +                false);
  +            if (success) {
  +                log("Checked out " + describeCheckout(eachFile, localFile));
  +            }
  +        }
  +        else {
  +            boolean checkout = true;
   
  -}
  +            // Just a note: StarTeam has a status for NEW which implies
  +            // that there is an item  on your local machine that is not
  +            // in the repository.  These are the items that show up as
  +            // NOT IN VIEW in the Starteam GUI.
  +            // One would think that we would want to perhaps checkin the
  +            // NEW items (not in all cases! - Steve Cohen 15 Dec 2001)
  +            // Unfortunately, the sdk doesn't really work, and we can't
  +            // actually see  anything with a status of NEW. That is why
  +            // we can just check out  everything here without worrying
  +            // about losing anything.
  +
  +            int fileStatus = (eachFile.getStatus());
  +
  +            // We try to update the status once to give StarTeam
  +            // another chance.
  +
  +            if (fileStatus == Status.MERGE || 
  +                fileStatus == Status.UNKNOWN) 
  +            {
  +                eachFile.updateStatus(true, true);
  +                fileStatus = (eachFile.getStatus());
  +            }
   
  +            log(eachFile.toString() + " has status of " + 
  +                Status.name(fileStatus), Project.MSG_DEBUG);
   
   
  +            switch (fileStatus) {
  +            case Status.OUTOFDATE:
  +            case Status.MISSING:
  +                log("Checking out: " + describeCheckout(eachFile));
  +                break;
  +            default:
  +                if (isForced()) {
  +                    log("Forced checkout of " 
  +                        + describeCheckout(eachFile) 
  +                        + " over status " + Status.name(fileStatus));
  +                } else {
  +                    log("Skipping: " + getFullRepositoryPath(eachFile) + 
  +                        " - status: " + Status.name(fileStatus));
  +                    checkout = false;
  +                }
  +            }
   
  +            if (checkout) {
  +                eachFile.checkout(this.lockStatus, 
  +                                 !this.useRepositoryTimeStamp, true, true);
  +            }
  +        }
  +    }
  +    /**
  +     * handles the deletion of uncontrolled items
  +     */
  +    private class CheckoutMap extends UnmatchedFileMap {
  +        protected boolean isActive() {
  +            return StarTeamCheckout.this.deleteUncontrolled;
  +        }
   
  +        /**
  +         * override of the base class init.  It can be much simpler, since
  +         * the action to be taken is simply to delete the local files.  No
  +         * further interaction with the repository is necessary.
  +         * 
  +         * @param localFolder
  +         *        the local folder from which the mappings will be made.
  +         * @param remoteFolder
  +         *        not used in this implementation
  +         */
  +        UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) {
  +            if (!localFolder.exists()) {
  +                return this;
  +            }
   
  +            String[] localFiles = localFolder.list();
  +    
  +            for (int i=0; i < localFiles.length; i++) {
  +                java.io.File localFile = 
  +                    new java.io.File(localFolder, localFiles[i]).getAbsoluteFile();
  +                
  +                log("adding " + localFile + " to UnmatchedFileMap",
  +                    Project.MSG_DEBUG);
  +    
  +                if (localFile.isDirectory()) {
  +                    this.put(localFile, "");
  +                } 
  +                else {
  +                    this.put(localFile, "");
  +                }
  +            }
  +            return this;
  +        }
   
   
  +    
  +        /**
  +         * deletes uncontrolled items from the local tree.  It is assumed
  +         * that this method will not be called until all the items in the
  +         * corresponding folder have been processed, and that the internal map
  +         * will contain only uncontrolled items.
  +         */
  +        void processUncontrolledItems() throws BuildException {
  +            if (this.isActive()) {
  +                Enumeration e = this.keys();
  +                while (e.hasMoreElements()) {
  +                    java.io.File local = (java.io.File) e.nextElement();
  +                    delete(local);
  +                }
  +            }
  +        }
  +    
  +        /**
  +         * deletes all files and if the file is a folder recursively deletes
  +         * everything in it.
  +         * 
  +         * @param local  The local file or folder to be deleted.
  +         */
  +        void delete(java.io.File local) {
  +            // once we find a folder that isn't in the repository, 
  +            // anything below it can be deleted.
  +            if (local.isDirectory() && isRecursive()) {
  +                String[] contents = local.list();
  +                for (int i=0; i< contents.length; i++) {
  +                    java.io.File file = new java.io.File(local, contents[i]);
  +                    delete(file);
  +                }
  +            } 
  +            local.delete();
  +            log("Deleted uncontrolled item " + local.getAbsolutePath());
  +        }
  +    }
   
   
  +}
  
  
  
  1.12      +69 -3     jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java
  
  Index: StarTeamLabel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamLabel.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- StarTeamLabel.java	25 Jul 2002 15:21:20 -0000	1.11
  +++ StarTeamLabel.java	6 Nov 2002 11:07:09 -0000	1.12
  @@ -94,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"
        */
  @@ -118,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>
        */
  @@ -126,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);
           }
       }
   
  @@ -137,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);
  +        }
       }
   
       /**
  @@ -153,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.9       +123 -17   jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java
  
  Index: StarTeamList.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamList.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- StarTeamList.java	25 Jul 2002 15:21:20 -0000	1.8
  +++ StarTeamList.java	6 Nov 2002 11:07:09 -0000	1.9
  @@ -60,8 +60,11 @@
   import com.starbase.starteam.View;
   import com.starbase.starteam.ViewConfiguration;
   import java.io.IOException;
  +import java.text.SimpleDateFormat;
  +import java.util.Enumeration;
   import java.util.Hashtable;
   import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.Project;
   
   /**
    * Produces a listing of the contents of the StarTeam repository
  @@ -76,6 +79,7 @@
    */
   
   public class StarTeamList extends TreeBasedTask {
  +    private boolean listUncontrolled = true;
       /**
        * List files, dates, and statuses as of this label; optional.
        * The label must exist in starteam or an exception will be thrown.  
  @@ -90,7 +94,7 @@
       /**
        * Override of base-class abstract function creates an
        * appropriately configured view for checkoutlists - either
  -     * the current view or a view from this.label.
  +     * the current view or a view from this.label.   
        *
        * @param raw the unconfigured <code>View</code>
        * @return the snapshot <code>View</code> appropriately configured.
  @@ -118,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.
        *
  @@ -128,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)) {
  @@ -160,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());
  @@ -210,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.9       +53 -21    jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java
  
  Index: StarTeamTask.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/StarTeamTask.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- StarTeamTask.java	25 Jul 2002 15:21:20 -0000	1.8
  +++ StarTeamTask.java	6 Nov 2002 11:07:09 -0000	1.9
  @@ -53,12 +53,15 @@
    */
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
  +import com.starbase.starteam.BuildNumber;
   import com.starbase.starteam.Server;
   import com.starbase.starteam.StarTeamFinder;
  +import com.starbase.starteam.TypeNames;
   import com.starbase.starteam.User;
   import com.starbase.starteam.View;
   import java.util.StringTokenizer;
   import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.Project;
   import org.apache.tools.ant.Task;
   
   /**
  @@ -112,6 +115,12 @@
        */
       private Server server = null;
   
  +    private void logStarteamVersion() {
  +        log("StarTeam version: "+ 
  +            BuildNumber.getDisplayString(), Project.MSG_DEBUG);
  +    }
  +
  +
       /////////////////////////////////////////////////////////
       // GET/SET methods.
       // Setters, of course are where ant user passes in values.
  @@ -123,7 +132,7 @@
        * @param servername a <code>String</code> value
        * @see #setURL(String)
        */
  -    public void setServername(String servername) {
  +    public final void setServername(String servername) {
           this.servername = servername;
       }
   
  @@ -133,7 +142,7 @@
        * @return the name of the StarTeam server
        * @see #getURL()
        */
  -    public String getServername() {
  +    public final String getServername() {
           return this.servername;
       }
   
  @@ -143,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;
       }
   
  @@ -153,7 +162,7 @@
        * @return the port number of the StarTeam connection
        * @see #getURL()
        */
  -    public String getServerport() {
  +    public final String getServerport() {
           return this.serverport;
       }
   
  @@ -164,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;
       }
   
  @@ -174,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;
       }
   
  @@ -185,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;
       }
   
  @@ -195,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;
       }
   
  @@ -212,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();
  @@ -246,7 +255,7 @@
        * @see #getProjectname()
        * @see #getViewname()
        */
  -    public String getURL() {
  +    public final String getURL() {
           return
                   this.servername + ":" +
                   this.serverport + "/" +
  @@ -255,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;
       }
   
  @@ -268,7 +286,7 @@
        *
        * @return the name of the StarTeam user
        */
  -    public String getUserName() {
  +    public final String getUserName() {
           return this.userName;
       }
   
  @@ -277,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;
       }
   
  @@ -286,7 +304,7 @@
        *
        * @return the password used for login
        */
  -    public String getPassword() {
  +    public final String getPassword() {
           return this.password;
       }
   
  @@ -296,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
  @@ -320,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() +
  @@ -342,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.11      +339 -76   jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java
  
  Index: TreeBasedTask.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/starteam/TreeBasedTask.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TreeBasedTask.java	25 Jul 2002 15:21:20 -0000	1.10
  +++ TreeBasedTask.java	6 Nov 2002 11:07:09 -0000	1.11
  @@ -54,13 +54,17 @@
   package org.apache.tools.ant.taskdefs.optional.starteam;
   
   import com.starbase.starteam.Folder;
  +import com.starbase.starteam.Item;
   import com.starbase.starteam.Label;
   import com.starbase.starteam.StarTeamFinder;
   import com.starbase.starteam.View;
  +import java.util.Enumeration;
   import java.util.Hashtable;
   import java.util.StringTokenizer;
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.DirectoryScanner;
  +import org.apache.tools.ant.Project;
  +import org.apache.tools.ant.ProjectComponent;
   
   /**
    * FileBasedTask.java
  @@ -114,7 +118,7 @@
   
       /**
        * The local folder corresponding to starteamFolder.  If not specified
  -     * the Star Team defalt folder will be used.
  +     * the Star Team default folder will be used.
        */
       private String rootLocalFolder = null;
   
  @@ -148,6 +152,14 @@
        */
       private boolean forced = false;
   
  +    private Label labelInUse = null;
  +
  +    /**
  +     * holds a list of local files against which files in the repository
  +     * will be compared for addition on checkins or deletion on checkouts if 
  +     * the proper options have been set.
  +     */
  +    private Hashtable localFileList = new Hashtable();
   
       ///////////////////////////////////////////////////////////////
       // GET/SET methods.
  @@ -173,27 +185,36 @@
       }
   
       /**
  -     * Set the local folder that will be the root of the tree 
  +     * Set the local folder that will be the root of the tree
        * to which files are checked out; optional.
  -     * If this is not supplied, then the StarTeam "default folder" 
  +     * If this is not supplied, then the StarTeam "default folder"
        * associated with <tt>rootstarteamfolder</tt> is used.
  -     * @param rootLocalFolder the local folder that will mirror
  -     *                        this.rootStarteamFolder
  +     * 
  +     * @param rootLocalFolder
  +     *               the local folder that will mirror
  +     *               this.rootStarteamFolder
  +     * 
  +     * @see rootLocalFolder
        */
       public void setRootLocalFolder(String rootLocalFolder) {
           this.rootLocalFolder = rootLocalFolder;
       }
   
  +
  +
       /**
        * Returns the local folder specified by the user,
  -     * corresponding to the starteam folder for this operation.
  -     * or null if not specified
  +     * corresponding to the starteam folder for this operation
  +     * or null if not specified.
  +     * 
        * @return the local folder that mirrors this.rootStarteamFolder
  +     * @see rootLocalFolder
        */
       public String getRootLocalFolder() {
           return this.rootLocalFolder;
       }
   
  +
       /**
        * Declare files to include using standard <tt>includes</tt> patterns; optional. 
        * @param includes A string of filter patterns to include. Separate the
  @@ -221,6 +242,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
  @@ -273,6 +303,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
        *
  @@ -287,6 +327,10 @@
           }
       }
   
  +    protected String getLabel() {
  +        return this.label;
  +    }
  +
       /**
        * Get the value of recursive.
        * @return value of recursive.
  @@ -324,6 +368,40 @@
           this.forced = v;
       }
   
  +    /**
  +     *  returns true if a label has been specified and it is a view label.
  +     * 
  +     * @return  true if a label has been specified and it is a view label
  +     */
  +    protected boolean isUsingViewLabel() {
  +        return null != this.labelInUse && 
  +            this.labelInUse.isViewLabel();
  +    }
  +    /**
  +     *  returns true if a label has been specified and it is a revision label.
  +     * 
  +     * @return  true if a label has been specified and it is a revision label
  +     */
  +    protected boolean isUsingRevisionLabel() {
  +        return null != this.labelInUse && 
  +            this.labelInUse.isRevisionLabel();
  +    }
  +
  +    /**
  +     * show the label in the log and its type.
  +     */
  +    protected void logLabel() {
  +        if (this.isUsingViewLabel()) {
  +            log("  Using view label " + getLabel());
  +        }
  +        else if (this.isUsingRevisionLabel()) {
  +            log("  Using revision label " + getLabel());
  +        }
  +    }
  +
  +
  +
  +
       ///////////////////////////////////////////////////////////////
       // INCLUDE-EXCLUDE processing
       ///////////////////////////////////////////////////////////////
  @@ -332,8 +410,10 @@
        * Look if the file should be processed by the task.
        * Don't process it if it fits no include filters or if
        * it fits an exclude filter.
  -     * @param pName the item name to look for being included.
  -     * @return whether the file should be checked out or not.
  +     * 
  +     * @param pName  the item name to look for being included.
  +     * 
  +     * @return whether the file should be processed or not.
        */
       protected boolean shouldProcess(String pName) {
           boolean includeIt = matchPatterns(getIncludes(), pName);
  @@ -362,49 +442,159 @@
       }
   
       /**
  +     * gets a url representing the root of the view.
  +     * 
  +     * @return a url corresponding to the root of the starteam view tree, useful for
  +     *         starteam lookups
  +     */
  +    private final String getRootStarteamURL()  {
  +        StringBuffer buf = new StringBuffer(getViewURL());
  +        if (!this.rootStarteamFolder.startsWith("/")) {
  +            buf.append("/");
  +        }
  +        buf.append(this.rootStarteamFolder);
  +        return buf.toString();
  +
  +    }
  +
  +    /**
  +     * Finds and opens the root starteam folder of the operation specified
  +     * by this task.  This will be one of the following cases:
  +     * 
  +     * @return Starteam's root folder for the operation.
  +     * @exception BuildException
  +     *                   if the root folder cannot be found in the repository
  +     */
  +    private final Folder configureRootStarteamFolder() 
  +        throws BuildException 
  +    {
  +        Folder starteamrootfolder = null;
  +        try {
  +            // no root local mapping has been specified.
  +            View snapshot = openView();
  +
  +            // find the starteam folder specified to be the root of the
  +            // operation.  Throw if it can't be found.
  +
  +            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 " + 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.
  +        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 void execute() throws BuildException {
  +    public final void execute() throws BuildException {
           try {
               testPreconditions();
   
  -            View snapshot = openView();
  -
  -            // find the starteam folder specified to be the root of the
  -            // operation.  Throw if it can't be found.
  -            Folder starteamrootfolder =
  -                    StarTeamFinder.findFolder(snapshot.getRootFolder(),
  -                            this.rootStarteamFolder);
  -
  -            if (null == starteamrootfolder) {
  -                throw new BuildException(
  -                        "Unable to find root folder in repository.");
  -            }
  +            Folder starteamrootfolder = configureRootStarteamFolder();
   
               // set the local folder.
  -            java.io.File localrootfolder;
  -            if (null == this.rootLocalFolder) {
  -                // use Star Team's default
  -                localrootfolder =
  -                        new java.io.File(starteamrootfolder.getPath());
  -            } else {
  -                // force StarTeam to use our folder
  -                localrootfolder = new java.io.File(getRootLocalFolder());
  -                log("overriding local folder to " + localrootfolder);
  -            }
  +            java.io.File localrootfolder = 
  +                getLocalRootMapping(starteamrootfolder);
   
  +            // Tell user what he is doing
  +            logOperationDescription(starteamrootfolder, localrootfolder);
  +            
               // Inspect everything in the root folder and then recursively
               visit(starteamrootfolder, localrootfolder);
  +
           } catch (Exception e) {
               throw new BuildException(e);
           }
       }
   
  +    private void findLabel(View v) throws BuildException {
  +        Label[] allLabels = v.getLabels();
  +        for (int i = 0; i < allLabels.length; i++) {
  +            Label stLabel = allLabels[i];
  +            log("checking label " + stLabel.getName(), Project.MSG_DEBUG);
  +            if (stLabel.getName().equals(this.label)) {
  +                if (!stLabel.isRevisionLabel() && !stLabel.isViewLabel()) {
  +                    throw new BuildException("Unexpected label type.");
  +                }
  +                log("using label " + stLabel.getName(), Project.MSG_DEBUG);
  +                this.labelInUse = stLabel;
  +                return;
  +            }
  +        }
  +        throw new BuildException("Error: label "
  +                + this.label
  +                + " does not exist in view "
  +                + v.getFullName());
  +
  +    }
  +
       /**
        * Helper method calls on the StarTeam API to retrieve an ID number
        * for the specified view, corresponding to this.label.
  @@ -416,32 +606,37 @@
        */
       protected int getLabelID(View v) throws BuildException {
           if (null != this.label) {
  -            Label[] allLabels = v.getLabels();
  -            for (int i = 0; i < allLabels.length; i++) {
  -                if (allLabels[i].getName().equals(this.label)) {
  -                    return allLabels[i].getID();
  -                }
  -            }
  -            throw new BuildException("Error: label "
  -                    + this.label
  -                    + " does not exist in view");
  +            findLabel(v);
  +            return this.labelInUse.getID();
           }
           return -1;
       }
   
  +    protected int getIDofLabelInUse() {
  +        if (null != this.labelInUse) {
  +            return this.labelInUse.getID();
  +        }
  +        return -1;
  +    }
   
       /**
        * Derived classes must override this class to define actual processing
        * to be performed on each folder in the tree defined for the task
  -     *
  -     * @param rootStarteamFolder the StarTeam folderto be visited
  -     * @param rootLocalFolder the local mapping of rootStarteamFolder
  +     * 
  +     * @param rootStarteamFolder
  +     *               the StarTeam folderto be visited
  +     * @param rootLocalFolder
  +     *               the local mapping of rootStarteamFolder
  +     * 
  +     * @exception BuildException
        */
       protected abstract void visit(Folder rootStarteamFolder,
                                     java.io.File rootLocalFolder)
               throws BuildException;
   
   
  +
  +
       /**
        * Derived classes must override this method to define tests for
        * any preconditons required by the task.  This method is called at
  @@ -454,46 +649,114 @@
        */
       protected abstract void testPreconditions() throws BuildException;
   
  +
       /**
  -     * Gets the collection of the local file names in the supplied directory.
  -     * We need to check this collection against what we find in Starteam to
  -     * understand what we need to do in order to synch with the repository.
  -     *
  -     * @param localFolder - the local folder to scan
  -     * @return an "identity" hashtable whose keys each represent a file or
  -     * directory in localFolder.
  -     */
  -    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 "").
  +     * Return the full repository path name of a file.  Surprisingly there's
  +     * no method in com.starbase.starteam.File to provide this.
  +     * 
  +     * @param remotefile the Star Team file whose path is to be returned
  +     * 
  +     * @return the full repository path name of a file.
  +     */
  +    public static String getFullRepositoryPath(
  +        com.starbase.starteam.File remotefile)
  +    {
  +        StringBuffer sb = new StringBuffer();
  +        sb.append(remotefile.getParentFolderHierarchy())
  +          .append(remotefile.getName());
  +        return sb.toString();
  +    }
  +
  +    /**
  +     * This class implements a map of existing local files to possibly
  +     * existing repository files.  The map is created by a TreeBasedTask
  +     * upon recursing into a directory.  Each local item is mapped to an
  +     * unattached StarTeam object of the proper type, File->File and
  +     * Directory->Folder.
  +     * 
  +     * As the TreeBased does its work, it deletes from the map all items
  +     * it has processed.  
  +     * 
  +     * When the TreeBased task processes all the items from the repository,
  +     * whatever items left in the UnmatchedFileMap are uncontrolled items
  +     * and can be processed as appropriate to the task.  In the case of
  +     * Checkouts, they can be optionally deleted from the local tree.  In the 
  +     * case of Checkins they can optionally be added to the resository.
  +     */
  +    protected abstract class UnmatchedFileMap extends Hashtable {
  +    
  +        /**
  +         * initializes the UnmatchedFileMap with entries from the local folder
  +         * These will be mapped to the corresponding StarTeam entry even though
  +         * it will not, in fact, exist in the repository.  But through it, it 
  +         * can be added, listed, etc.
  +         * 
  +         * @param localFolder
  +         *        the local folder from which the mappings will be made.
  +         * @param remoteFolder
  +         *        the corresponding StarTeam folder which will be processed.
  +         */
  +        UnmatchedFileMap init(java.io.File localFolder, Folder remoteFolder) {
  +            if (!localFolder.exists()) {
  +                return this;
  +            }
   
  -        if (localFolder.exists()) {
               String[] localFiles = localFolder.list();
  -            for (int i = 0; i < localFiles.length; i++) {
  -                localFileList.put(localFolder.toString() +
  -                        java.io.File.separatorChar + localFiles[i], "");
  +    
  +            for (int i=0; i < localFiles.length; i++) {
  +                String fn = localFiles[i];
  +                java.io.File localFile = 
  +                    new java.io.File(localFolder, localFiles[i]).getAbsoluteFile();
  +                
  +                log("adding " + localFile + " to UnmatchedFileMap",
  +                    Project.MSG_DEBUG);
  +    
  +                if (localFile.isDirectory()) {
  +                    this.put(localFile, new Folder( remoteFolder, fn, fn));
  +                } 
  +                else {
  +                    com.starbase.starteam.File remoteFile = 
  +                        new com.starbase.starteam.File(remoteFolder);
  +                    remoteFile.setName(fn);
  +                    this.put(localFile, remoteFile);
  +                }
  +            }
  +            return this;
  +        }
  +    
  +        /**
  +         * remove an item found to be controlled from the map.
  +         * 
  +         * @param localFile the local item found to be controlled.
  +         */
  +        void removeControlledItem(java.io.File localFile) {
  +            if (isActive()) {
  +                log("removing processed " + localFile.getAbsoluteFile() + 
  +                    " from UnmatchedFileMap", Project.MSG_DEBUG);
  +                this.remove(localFile.getAbsoluteFile());
               }
           }
  -        return localFileList;
  +        /**
  +         * override will perform the action appropriate for its task to perform
  +         * on items which are on the local tree but not in StarTeam.  It is 
  +         * assumed that this method will not be called until all the items in
  +         * the corresponding folder have been processed, and that the internal 
  +         * map * will contain only uncontrolled items.
  +         */
  +        abstract void processUncontrolledItems() throws BuildException;
  +    
  +        /**
  +         * overrides must define this to declare how this method knows if it 
  +         * is active.  This presents extra clock cycles when the functionality
  +         * is not called for.
  +         * 
  +         * @return True if this object is to perform its functionality.
  +         */
  +        abstract protected boolean isActive();
  +    
       }
   
  -    /**
  -     * Removes from the collection of the local file names
  -     * the supplied name of a processed file.  When we are done, only
  -     * files not in StarTeam will remain in localFiles.
  -     * @param localFiles a <code>Hashtable</code> value
  -     * @param thisfile file to remove from list.
  -     * @return true if file was removed, false if it wasn't found.
  -     */
  -    protected boolean delistLocalFile(Hashtable localFiles, java.io.File thisfile) {
  -        return null != localFiles.remove(thisfile.toString());
  -    }
   }
  -
  -
   
   
   
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message