1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.starteam;
  18. import com.starbase.starteam.File;
  19. import com.starbase.starteam.Folder;
  20. import com.starbase.starteam.Item;
  21. import com.starbase.starteam.Status;
  22. import com.starbase.starteam.View;
  23. import com.starbase.starteam.ViewConfiguration;
  24. import java.io.IOException;
  25. import java.text.SimpleDateFormat;
  26. import java.util.Enumeration;
  27. import org.apache.tools.ant.BuildException;
  28. import org.apache.tools.ant.Project;
  29. /**
  30. * Produces a listing of the contents of the StarTeam repository
  31. * at the specified view and StarTeamFolder.
  32. *
  33. * Created: Tue Dec 25 06:51:14 2001
  34. *
  35. * @version 1.0
  36. *
  37. * @ant.task name="stlist" category="scm"
  38. */
  39. public class StarTeamList extends TreeBasedTask {
  40. private boolean listUncontrolled = true;
  41. /**
  42. * List files, dates, and statuses as of this label; optional.
  43. * The label must exist in starteam or an exception will be thrown.
  44. * If not specified, the most recent version of each file will be listed.
  45. *
  46. * @param label the label to be listed
  47. */
  48. public void setLabel(String label) {
  49. _setLabel(label);
  50. }
  51. /**
  52. * List files, dates, and statuses as of this date; optional.
  53. * If not specified, the most recent version of each file will be listed.
  54. *
  55. * @param asOfDateParam the date as of which the listing to be made
  56. * @since Ant 1.6
  57. */
  58. public void setAsOfDate(String asOfDateParam) {
  59. _setAsOfDate(asOfDateParam);
  60. }
  61. /**
  62. * Date Format with which asOfDate parameter to be parsed; optional.
  63. * Must be a SimpleDateFormat compatible string.
  64. * If not specified, and asOfDateParam is specified, parse will use ISO8601
  65. * datetime and date formats.
  66. *
  67. * @param asOfDateFormat the SimpleDateFormat-compatible format string
  68. * @since Ant 1.6
  69. */
  70. public void setAsOfDateFormat(String asOfDateFormat) {
  71. _setAsOfDateFormat(asOfDateFormat);
  72. }
  73. /**
  74. * Override of base-class abstract function creates an
  75. * appropriately configured view for checkoutlists - either
  76. * the current view or a view from this.label.
  77. *
  78. * @param raw the unconfigured <code>View</code>
  79. * @return the snapshot <code>View</code> appropriately configured.
  80. */
  81. protected View createSnapshotView(View raw) {
  82. int labelID = getLabelID(raw);
  83. // if a label has been supplied, use it to configure the view
  84. // otherwise use current view
  85. if (labelID >= 0) {
  86. return new View(raw, ViewConfiguration.createFromLabel(labelID));
  87. }
  88. // if a date has been supplied use a view configured to the date.
  89. View view = getViewConfiguredByDate(raw);
  90. if (view != null) {
  91. return view;
  92. }
  93. // otherwise, use this view configured as the tip.
  94. else {
  95. return new View(raw, ViewConfiguration.createTip());
  96. }
  97. }
  98. /**
  99. * Required base-class abstract function implementation checks for
  100. * incompatible parameters.
  101. *
  102. * @exception BuildException thrown on incompatible params specified
  103. */
  104. protected void testPreconditions() throws BuildException {
  105. if (null != getLabel() && null != getAsOfDate()) {
  106. throw new BuildException(
  107. "Both label and asOfDate specified. "
  108. + "Unable to process request.");
  109. }
  110. }
  111. /**
  112. * extenders should emit to the log an entry describing the parameters
  113. * that will be used by this operation.
  114. *
  115. * @param starteamrootFolder
  116. * root folder in StarTeam for the operation
  117. * @param targetrootFolder
  118. * root local folder for the operation (whether specified by the user or not.
  119. */
  120. protected void logOperationDescription(Folder starteamrootFolder,
  121. java.io.File targetrootFolder) {
  122. log((this.isRecursive() ? "Recursive" : "Non-recursive")
  123. + " Listing of: " + starteamrootFolder.getFolderHierarchy());
  124. log("Listing against local folder"
  125. + (null == getRootLocalFolder() ? " (default): " : ": ")
  126. + targetrootFolder.getAbsolutePath(),
  127. Project.MSG_INFO);
  128. logLabel();
  129. logAsOfDate();
  130. logIncludes();
  131. logExcludes();
  132. }
  133. /**
  134. * Implements base-class abstract function to perform the checkout
  135. * operation on the files in each folder of the tree.
  136. *
  137. * @param starteamFolder the StarTeam folder from which files to be
  138. * checked out
  139. * @param targetFolder the local mapping of rootStarteamFolder
  140. */
  141. protected void visit(Folder starteamFolder, java.io.File targetFolder)
  142. throws BuildException {
  143. try {
  144. if (null != getRootLocalFolder()) {
  145. starteamFolder.setAlternatePathFragment(
  146. targetFolder.getAbsolutePath());
  147. }
  148. Folder[] subFolders = starteamFolder.getSubFolders();
  149. Item[] files = starteamFolder.getItems(getTypeNames().FILE);
  150. UnmatchedFileMap ufm =
  151. new UnmatchedListingMap().init(
  152. targetFolder.getAbsoluteFile(), starteamFolder);
  153. log("");
  154. log("Listing StarTeam folder "
  155. + starteamFolder.getFolderHierarchy());
  156. log(" against local folder " + targetFolder.getAbsolutePath());
  157. // For all Files in this folder, we need to check
  158. // if there have been modifications.
  159. for (int i = 0; i < files.length; i++) {
  160. File eachFile = (File) files[i];
  161. String filename = eachFile.getName();
  162. java.io.File localFile =
  163. new java.io.File(targetFolder, filename);
  164. ufm.removeControlledItem(localFile);
  165. // If the file doesn't pass the include/exclude tests, skip it.
  166. if (!shouldProcess(filename)) {
  167. continue;
  168. }
  169. list(eachFile, localFile);
  170. }
  171. // Now we recursively call this method on all sub folders in this
  172. // folder unless recursive attribute is off.
  173. for (int i = 0; i < subFolders.length; i++) {
  174. java.io.File targetSubfolder =
  175. new java.io.File(targetFolder, subFolders[i].getName());
  176. ufm.removeControlledItem(targetSubfolder);
  177. if (isRecursive()) {
  178. visit(subFolders[i], targetSubfolder);
  179. }
  180. }
  181. if (this.listUncontrolled) {
  182. ufm.processUncontrolledItems();
  183. }
  184. } catch (IOException e) {
  185. throw new BuildException(e);
  186. }
  187. }
  188. private static final SimpleDateFormat SDF =
  189. new SimpleDateFormat("yyyy-MM-dd hh:mm:ss zzz");
  190. protected void list(File reposFile, java.io.File localFile)
  191. throws IOException {
  192. StringBuffer b = new StringBuffer();
  193. int status = reposFile.getStatus();
  194. java.util.Date displayDate = null;
  195. if (status == Status.NEW) {
  196. displayDate = new java.util.Date(localFile.lastModified());
  197. } else {
  198. displayDate = reposFile.getModifiedTime().createDate();
  199. }
  200. b.append(pad(Status.name(status), 12)).append(' ');
  201. b.append(pad(getUserName(reposFile.getLocker()), 20))
  202. .append(' ')
  203. .append(SDF.format(displayDate))
  204. .append(rpad(String.valueOf(reposFile.getSize()), 9))
  205. .append(' ')
  206. .append(reposFile.getName());
  207. log(b.toString());
  208. }
  209. private static final String blankstr = blanks(30);
  210. private static String blanks(int len) {
  211. StringBuffer b = new StringBuffer();
  212. for (int i = 0; i < len; i++) {
  213. b.append(' ');
  214. }
  215. return b.toString();
  216. }
  217. protected static String pad(String s, int padlen) {
  218. return (s + blankstr).substring(0, padlen);
  219. }
  220. protected static String rpad(String s, int padlen) {
  221. s = blankstr + s;
  222. return s.substring(s.length() - padlen);
  223. }
  224. /**
  225. * handles the list of uncontrolled items
  226. */
  227. private class UnmatchedListingMap extends UnmatchedFileMap {
  228. protected boolean isActive() {
  229. return StarTeamList.this.listUncontrolled;
  230. }
  231. /**
  232. * lists uncontrolled items from the local tree. It is assumed
  233. * that this method will not be called until all the items in the
  234. * corresponding folder have been processed, and that the internal map
  235. * will contain only uncontrolled items.
  236. */
  237. void processUncontrolledItems() throws BuildException {
  238. if (this.isActive()) {
  239. Enumeration e = this.keys();
  240. // handle the files so they appear first
  241. while (e.hasMoreElements()) {
  242. java.io.File local = (java.io.File) e.nextElement();
  243. Item remoteItem = (Item) this.get(local);
  244. // once we find a folder that isn't in the repository,
  245. // we know we can add it.
  246. if (local.isFile()) {
  247. com.starbase.starteam.File remoteFile =
  248. (com.starbase.starteam.File) remoteItem;
  249. try {
  250. list(remoteFile, local);
  251. } catch (IOException ie) {
  252. throw new BuildException("IOError in stlist", ie);
  253. }
  254. }
  255. }
  256. // now do it again for the directories so they appear last.
  257. e = this.keys();
  258. while (e.hasMoreElements()) {
  259. java.io.File local = (java.io.File) e.nextElement();
  260. Item remoteItem = (Item) this.get(local);
  261. // once we find a folder that isn't in the repository,
  262. // we know we can add it.
  263. if (local.isDirectory()) {
  264. Folder folder = (Folder) remoteItem;
  265. if (isRecursive()) {
  266. log("Listing uncontrolled folder "
  267. + folder.getFolderHierarchy()
  268. + " from " + local.getAbsoluteFile());
  269. UnmatchedFileMap submap =
  270. new UnmatchedListingMap().init(local, folder);
  271. submap.processUncontrolledItems();
  272. }
  273. }
  274. }
  275. }
  276. }
  277. }
  278. }