blob: 99b49688b9b6e553169359ff820c6e6abb08c56b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional.starteam;
import com.starbase.starteam.File;
import com.starbase.starteam.Folder;
import com.starbase.starteam.Item;
import com.starbase.starteam.Status;
import com.starbase.starteam.View;
import com.starbase.starteam.ViewConfiguration;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
/**
* Produces a listing of the contents of the StarTeam repository
* at the specified view and StarTeamFolder.
*
* Created: Tue Dec 25 06:51:14 2001
*
* @version 1.0
*
* @ant.task name="stlist" category="scm"
*/
public class StarTeamList extends TreeBasedTask {
private boolean listUncontrolled = true;
/**
* List files, dates, and statuses as of this label; optional.
* The label must exist in starteam or an exception will be thrown.
* If not specified, the most recent version of each file will be listed.
*
* @param label the label to be listed
*/
public void setLabel(String label) {
_setLabel(label);
}
/**
* List files, dates, and statuses as of this date; optional.
* If not specified, the most recent version of each file will be listed.
*
* @param asOfDateParam the date as of which the listing to be made
* @since Ant 1.6
*/
public void setAsOfDate(String asOfDateParam) {
_setAsOfDate(asOfDateParam);
}
/**
* Date Format with which asOfDate parameter to be parsed; optional.
* Must be a SimpleDateFormat compatible string.
* If not specified, and asOfDateParam is specified, parse will use ISO8601
* datetime and date formats.
*
* @param asOfDateFormat the SimpleDateFormat-compatible format string
* @since Ant 1.6
*/
public void setAsOfDateFormat(String asOfDateFormat) {
_setAsOfDateFormat(asOfDateFormat);
}
/**
* Override of base-class abstract function creates an
* appropriately configured view for checkoutlists - either
* the current view or a view from this.label.
*
* @param raw the unconfigured <code>View</code>
* @return the snapshot <code>View</code> appropriately configured.
*/
protected View createSnapshotView(View raw) {
int labelID = getLabelID(raw);
// if a label has been supplied, use it to configure the view
// otherwise use current view
if (labelID >= 0) {
return new View(raw, ViewConfiguration.createFromLabel(labelID));
}
// if a date has been supplied use a view configured to the date.
View view = getViewConfiguredByDate(raw);
if (view != null) {
return view;
// otherwise, use this view configured as the tip.
} else {
return new View(raw, ViewConfiguration.createTip());
}
}
/**
* Required base-class abstract function implementation checks for
* incompatible parameters.
*
* @exception BuildException thrown on incompatible params specified
*/
protected void testPreconditions() throws BuildException {
if (null != getLabel() && null != getAsOfDate()) {
throw new BuildException(
"Both label and asOfDate specified. "
+ "Unable to process request.");
}
}
/**
* extenders should emit to the log an entry describing the parameters
* that will be used by this operation.
*
* @param starteamrootFolder
* root folder in StarTeam for the operation
* @param targetrootFolder
* root local folder for the operation (whether specified by the user or not.
*/
protected void logOperationDescription(Folder starteamrootFolder,
java.io.File targetrootFolder) {
log((this.isRecursive() ? "Recursive" : "Non-recursive")
+ " Listing of: " + starteamrootFolder.getFolderHierarchy());
log("Listing against local folder"
+ (null == getRootLocalFolder() ? " (default): " : ": ")
+ targetrootFolder.getAbsolutePath(),
Project.MSG_INFO);
logLabel();
logAsOfDate();
logIncludes();
logExcludes();
}
/**
* Implements base-class abstract function to perform the checkout
* operation on the files in each folder of the tree.
*
* @param starteamFolder the StarTeam folder from which files to be
* checked out
* @param targetFolder the local mapping of rootStarteamFolder
* @throws BuildException on error
*/
protected void visit(Folder starteamFolder, java.io.File targetFolder)
throws BuildException {
try {
if (null != getRootLocalFolder()) {
starteamFolder.setAlternatePathFragment(
targetFolder.getAbsolutePath());
}
Folder[] subFolders = starteamFolder.getSubFolders();
Item[] files = starteamFolder.getItems(getTypeNames().FILE);
UnmatchedFileMap ufm =
new UnmatchedListingMap().init(
targetFolder.getAbsoluteFile(), starteamFolder);
log("");
log("Listing StarTeam folder "
+ starteamFolder.getFolderHierarchy());
log(" against local folder " + targetFolder.getAbsolutePath());
// For all Files in this folder, we need to check
// if there have been modifications.
for (int i = 0; i < files.length; i++) {
File eachFile = (File) files[i];
String filename = eachFile.getName();
java.io.File localFile =
new java.io.File(targetFolder, filename);
ufm.removeControlledItem(localFile);
// If the file doesn't pass the include/exclude tests, skip it.
if (!shouldProcess(filename)) {
continue;
}
list(eachFile, localFile);
}
// Now we recursively call this method on all sub folders in this
// folder unless recursive attribute is off.
for (int i = 0; i < subFolders.length; i++) {
java.io.File targetSubfolder =
new java.io.File(targetFolder, subFolders[i].getName());
ufm.removeControlledItem(targetSubfolder);
if (isRecursive()) {
visit(subFolders[i], targetSubfolder);
}
}
if (this.listUncontrolled) {
ufm.processUncontrolledItems();
}
} catch (IOException e) {
throw new BuildException(e);
}
}
private static final SimpleDateFormat SDF =
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss zzz");
/**
* Log a repositary file and it's corresponding local file.
* @param reposFile the repositary file to log
* @param localFile the corresponding local file
* @throws IOException on error getting information from files
*/
protected void list(File reposFile, java.io.File localFile)
throws IOException {
StringBuffer b = new StringBuffer();
int status = reposFile.getStatus();
java.util.Date displayDate = null;
if (status == Status.NEW) {
displayDate = new java.util.Date(localFile.lastModified());
} else {
displayDate = reposFile.getModifiedTime().createDate();
}
b.append(pad(Status.name(status), 12)).append(' ');
b.append(pad(getUserName(reposFile.getLocker()), 20))
.append(' ')
.append(SDF.format(displayDate))
.append(rpad(String.valueOf(reposFile.getSize()), 9))
.append(' ')
.append(reposFile.getName());
log(b.toString());
}
private static final String BLANK_STRING = blanks(30);
private static String blanks(int len) {
StringBuffer b = new StringBuffer();
for (int i = 0; i < len; i++) {
b.append(' ');
}
return b.toString();
}
/**
* Return a padded string.
* @param s the string to pad
* @param padlen the size of the padded string
* @return the padded string
*/
protected static String pad(String s, int padlen) {
return (s + BLANK_STRING).substring(0, padlen);
}
/**
* Return a right padded string.
* @param s the string to pad
* @param padlen the size of the padded string
* @return the padded string
*/
protected static String rpad(String s, int padlen) {
s = BLANK_STRING + s;
return s.substring(s.length() - padlen);
}
/**
* handles the list of uncontrolled items
*/
private class UnmatchedListingMap extends UnmatchedFileMap {
protected boolean isActive() {
return StarTeamList.this.listUncontrolled;
}
/**
* lists uncontrolled items from the local tree. It is assumed
* that this method will not be called until all the items in the
* corresponding folder have been processed, and that the internal map
* will contain only uncontrolled items.
*/
void processUncontrolledItems() throws BuildException {
if (this.isActive()) {
Enumeration e = this.keys();
// handle the files so they appear first
while (e.hasMoreElements()) {
java.io.File local = (java.io.File) e.nextElement();
Item remoteItem = (Item) this.get(local);
// once we find a folder that isn't in the repository,
// we know we can add it.
if (local.isFile()) {
com.starbase.starteam.File remoteFile =
(com.starbase.starteam.File) remoteItem;
try {
list(remoteFile, local);
} catch (IOException ie) {
throw new BuildException("IOError in stlist", ie);
}
}
}
// now do it again for the directories so they appear last.
e = this.keys();
while (e.hasMoreElements()) {
java.io.File local = (java.io.File) e.nextElement();
Item remoteItem = (Item) this.get(local);
// once we find a folder that isn't in the repository,
// we know we can add it.
if (local.isDirectory()) {
Folder folder = (Folder) remoteItem;
if (isRecursive()) {
log("Listing uncontrolled folder "
+ folder.getFolderHierarchy()
+ " from " + local.getAbsoluteFile());
UnmatchedFileMap submap =
new UnmatchedListingMap().init(local, folder);
submap.processUncontrolledItems();
}
}
}
}
}
}
}