001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs.optional.starteam;
019:
020: import com.starbase.starteam.Folder;
021: import com.starbase.starteam.Item;
022: import com.starbase.starteam.Status;
023: import com.starbase.starteam.View;
024: import com.starbase.starteam.ViewConfiguration;
025: import java.io.IOException;
026: import java.util.Enumeration;
027: import org.apache.tools.ant.BuildException;
028:
029: /**
030: * Checks files into a StarTeam project.
031: * Optionally adds files and in the local tree that
032: * are not managed by the repository to its control.
033: * Created: Sat Dec 15 20:26:07 2001
034: *
035: * @version 1.0
036: *
037: * @ant.task name="stcheckin" category="scm" product="Starteam"
038: */
039: public class StarTeamCheckin extends TreeBasedTask {
040:
041: /**
042: * Constructor for StarTeamCheckin.
043: */
044: public StarTeamCheckin() {
045: // we want this to have a false default, unlike for Checkin.
046: setRecursive(false);
047: }
048:
049: private boolean createFolders = true;
050:
051: /**
052: * The comment which will be stored with the checkin.
053: */
054: private String comment = null;
055:
056: /**
057: * holder for the add Uncontrolled attribute. If true, all
058: * local files not in StarTeam will be added to the repository.
059: */
060: private boolean addUncontrolled = false;
061:
062: /**
063: * Sets the value of createFolders
064: *
065: * @param argCreateFolders Value to assign to this.createFolders
066: */
067: public void setCreateFolders(boolean argCreateFolders) {
068: this .createFolders = argCreateFolders;
069: }
070:
071: /**
072: * Get the comment attribute for this operation
073: * @return value of comment.
074: */
075: public String getComment() {
076: return this .comment;
077: }
078:
079: /**
080: * Optional checkin comment to be saved with the file.
081: * @param comment Value to assign to comment.
082: */
083: public void setComment(String comment) {
084: this .comment = comment;
085: }
086:
087: /**
088: * Get the value of addUncontrolled.
089: * @return value of addUncontrolled.
090: */
091: public boolean isAddUncontrolled() {
092: return this .addUncontrolled;
093: }
094:
095: /**
096: * if true, any files or folders NOT in StarTeam will be
097: * added to the repository. Defaults to "false".
098: * @param addUncontrolled Value to assign to addUncontrolled.
099: */
100: public void setAddUncontrolled(boolean addUncontrolled) {
101: this .addUncontrolled = addUncontrolled;
102: }
103:
104: /**
105: * This attribute tells whether unlocked files on checkin (so that
106: * other users may access them) checkout or to leave the checkout status
107: * alone (default).
108: * @see #setUnlocked(boolean)
109: */
110: private int lockStatus = Item.LockType.UNCHANGED;
111:
112: /**
113: * Set to do an unlocked checkout; optional, default is false;
114: * If true, file will be unlocked so that other users may
115: * change it. If false, lock status will not change.
116: * @param v true means do an unlocked checkout
117: * false means leave status alone.
118: */
119: public void setUnlocked(boolean v) {
120: if (v) {
121: this .lockStatus = Item.LockType.UNLOCKED;
122: } else {
123: this .lockStatus = Item.LockType.UNCHANGED;
124: }
125: }
126:
127: /**
128: * Override of base-class abstract function creates an
129: * appropriately configured view. For checkins this is
130: * always the current or "tip" view.
131: *
132: * @param raw the unconfigured <code>View</code>
133: * @return the snapshot <code>View</code> appropriately configured.
134: */
135: protected View createSnapshotView(View raw) {
136: return new View(raw, ViewConfiguration.createTip());
137: }
138:
139: /**
140: * Implements base-class abstract function to define tests for
141: * any preconditons required by the task.
142: *
143: * @exception BuildException thrown if both rootLocalFolder
144: * and viewRootLocalFolder are defined
145: */
146: protected void testPreconditions() throws BuildException {
147: }
148:
149: /**
150: * Implements base-class abstract function to emit to the log an
151: * entry describing the parameters that will be used by this operation.
152: *
153: * @param starteamrootFolder
154: * root folder in StarTeam for the operation
155: * @param targetrootFolder
156: * root local folder for the operation
157: * (whether specified by the user or not).
158: */
159: protected void logOperationDescription(Folder starteamrootFolder,
160: java.io.File targetrootFolder) {
161: log((this .isRecursive() ? "Recursive" : "Non-recursive")
162: + " Checkin from"
163: + (null == getRootLocalFolder() ? " (default): " : ": ")
164: + targetrootFolder.getAbsolutePath());
165:
166: log("Checking in to: "
167: + starteamrootFolder.getFolderHierarchy());
168: logIncludes();
169: logExcludes();
170:
171: if (this .lockStatus == Item.LockType.UNLOCKED) {
172: log(" Items will be checked in unlocked.");
173: } else {
174: log(" Items will be checked in with no change in lock status.");
175: }
176:
177: if (this .isForced()) {
178: log(" Items will be checked in in accordance with repository "
179: + "status and regardless of lock status.");
180: } else {
181: log(" Items will be checked in regardless of repository status "
182: + "only if locked.");
183: }
184:
185: }
186:
187: /**
188: * Implements base-class abstract function to perform the checkout
189: * operation on the files in each folder of the tree.
190: *
191: * @param starteamFolder the StarTeam folder to which files
192: * will be checked in
193: * @param targetFolder local folder from which files will be checked in
194: * @exception BuildException if any error occurs
195: */
196: protected void visit(Folder starteamFolder,
197: java.io.File targetFolder) throws BuildException {
198: try {
199: if (null != getRootLocalFolder()) {
200: starteamFolder.setAlternatePathFragment(targetFolder
201: .getAbsolutePath());
202: }
203:
204: Folder[] foldersList = starteamFolder.getSubFolders();
205: Item[] stFiles = starteamFolder
206: .getItems(getTypeNames().FILE);
207:
208: // note, it's important to scan the items BEFORE we make the
209: // UnmatchedFileMap because that creates a bunch of NEW
210: // folders and files (unattached to repository) and we
211: // don't want to include those in our traversal.
212:
213: UnmatchedFileMap ufm = new CheckinMap().init(targetFolder
214: .getAbsoluteFile(), starteamFolder);
215:
216: for (int i = 0, size = foldersList.length; i < size; i++) {
217: Folder stFolder = foldersList[i];
218: java.io.File subfolder = new java.io.File(targetFolder,
219: stFolder.getName());
220:
221: ufm.removeControlledItem(subfolder);
222:
223: if (isRecursive()) {
224: visit(stFolder, subfolder);
225: }
226: }
227:
228: for (int i = 0, size = stFiles.length; i < size; i++) {
229: com.starbase.starteam.File stFile = (com.starbase.starteam.File) stFiles[i];
230: processFile(stFile);
231:
232: ufm.removeControlledItem(new java.io.File(targetFolder,
233: stFile.getName()));
234: }
235:
236: if (this .addUncontrolled) {
237: ufm.processUncontrolledItems();
238: }
239:
240: } catch (IOException e) {
241: throw new BuildException(e);
242: }
243:
244: }
245:
246: /**
247: * provides a string showing from and to full paths for logging
248: *
249: * @param remotefile the Star Team file being processed.
250: *
251: * @return a string showing from and to full paths
252: */
253: private String describeCheckin(com.starbase.starteam.File remotefile) {
254: StringBuffer sb = new StringBuffer();
255: sb.append(remotefile.getFullName()).append(" --> ").append(
256: getFullRepositoryPath(remotefile));
257: return sb.toString();
258: }
259:
260: /**
261: * Processes (checks-out) <code>stFiles</code>files from StarTeam folder.
262: *
263: * @param eachFile repository file to process
264: * @param targetFolder a java.io.File (Folder) to work
265: * @throws IOException when StarTeam API fails to work with files
266: */
267: private void processFile(com.starbase.starteam.File eachFile)
268: throws IOException {
269: String filename = eachFile.getName();
270:
271: // If the file doesn't pass the include/exclude tests, skip it.
272: if (!shouldProcess(filename)) {
273: log("Excluding " + getFullRepositoryPath(eachFile));
274: return;
275: }
276:
277: boolean checkin = true;
278: int fileStatus = (eachFile.getStatus());
279:
280: // We try to update the status once to give StarTeam
281: // another chance.
282:
283: if (fileStatus == Status.MERGE || fileStatus == Status.UNKNOWN) {
284: eachFile.updateStatus(true, true);
285: fileStatus = (eachFile.getStatus());
286: }
287:
288: if (fileStatus == Status.MODIFIED) {
289: log("Checking in: " + describeCheckin(eachFile));
290: } else if (fileStatus == Status.MISSING) {
291: log("Local file missing: " + describeCheckin(eachFile));
292: checkin = false;
293: } else {
294: if (isForced()) {
295: log("Forced checkin of " + describeCheckin(eachFile)
296: + " over status " + Status.name(fileStatus));
297: } else {
298: log("Skipping: " + getFullRepositoryPath(eachFile)
299: + " - status: " + Status.name(fileStatus));
300: checkin = false;
301: }
302: }
303: if (checkin) {
304: eachFile.checkin(this .comment, this .lockStatus, this
305: .isForced(), true, true);
306: }
307: }
308:
309: /**
310: * handles the deletion of uncontrolled items
311: */
312: private class CheckinMap extends UnmatchedFileMap {
313: protected boolean isActive() {
314: return StarTeamCheckin.this .addUncontrolled;
315: }
316:
317: /**
318: * This override adds all its members to the repository. It is assumed
319: * that this method will not be called until all the items in the
320: * corresponding folder have been processed, and that the internal map
321: * will contain only uncontrolled items.
322: */
323: void processUncontrolledItems() throws BuildException {
324: if (this .isActive()) {
325: Enumeration e = this .keys();
326: while (e.hasMoreElements()) {
327: java.io.File local = (java.io.File) e.nextElement();
328: Item remoteItem = (Item) this .get(local);
329: remoteItem.update();
330:
331: // once we find a folder that isn't in the repository,
332: // we know we can add it.
333: if (local.isDirectory()) {
334: Folder folder = (Folder) remoteItem;
335: log("Added uncontrolled folder "
336: + folder.getFolderHierarchy()
337: + " from " + local.getAbsoluteFile());
338: if (isRecursive()) {
339: UnmatchedFileMap submap = new CheckinMap()
340: .init(local, folder);
341: submap.processUncontrolledItems();
342: }
343: } else {
344: com.starbase.starteam.File remoteFile = (com.starbase.starteam.File) remoteItem;
345: log("Added uncontrolled file "
346: + TreeBasedTask
347: .getFullRepositoryPath(remoteFile)
348: + " from " + local.getAbsoluteFile());
349:
350: }
351: }
352: }
353: }
354: }
355:
356: }
|