001: /*
002: * ====================================================================
003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012: package org.tmatesoft.svn.examples.wc;
013:
014: import org.tmatesoft.svn.core.SVNCancelException;
015: import org.tmatesoft.svn.core.SVNLock;
016: import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
017: import org.tmatesoft.svn.core.wc.SVNStatus;
018: import org.tmatesoft.svn.core.wc.SVNStatusType;
019: import org.tmatesoft.svn.core.wc.SVNEvent;
020: import org.tmatesoft.svn.core.wc.ISVNEventHandler;
021: import org.tmatesoft.svn.core.wc.SVNEventAction;
022:
023: /*
024: * This is an implementation of ISVNStatusHandler & ISVNEventHandler that is
025: * used in WorkingCopy.java to display status information. This implementation
026: * is passed to
027: *
028: * SVNStatusClient.doStatus(File path, boolean recursive, boolean remote,
029: * boolean reportAll, boolean includeIgnored, boolean collectParentExternals,
030: * ISVNStatusHandler handler)
031: *
032: * For each item to be processed doStatus(..) collects status information and
033: * creates an SVNStatus object which holds that information. Then doStatus(..)
034: * calls an implementor's handler.handleStatus(SVNStatus) passing it the status
035: * info collected.
036: *
037: * StatusHandler will be also provided to an SVNStatusClient object as a
038: * handler of events generated by a doStatus(..) method. For example, if the
039: * status is invoked with the flag remote=true (like 'svn status -u' command),
040: * so then the status operation will be finished with dispatching an SVNEvent
041: * to ISVNEventHandler that will 'say' that the status is performed against the
042: * youngest revision (the event holds that revision number).
043: */
044: public class StatusHandler implements ISVNStatusHandler,
045: ISVNEventHandler {
046: private boolean myIsRemote;
047:
048: public StatusHandler(boolean isRemote) {
049: myIsRemote = isRemote;
050: }
051:
052: /*
053: * This is an implementation of ISVNStatusHandler.handleStatus(SVNStatus
054: * status)
055: */
056: public void handleStatus(SVNStatus status) {
057: /*
058: * Gets the status of file/directory/symbolic link text contents.
059: * It is SVNStatusType who contains information on the state of an
060: * item.
061: */
062: SVNStatusType contentsStatus = status.getContentsStatus();
063:
064: String pathChangeType = " ";
065:
066: boolean isAddedWithHistory = status.isCopied();
067: if (contentsStatus == SVNStatusType.STATUS_MODIFIED) {
068: /*
069: * The contents of the file have been Modified.
070: */
071: pathChangeType = "M";
072: } else if (contentsStatus == SVNStatusType.STATUS_CONFLICTED) {
073: /*
074: * The file item is in a state of Conflict. That is, changes
075: * received from the server during an update overlap with local
076: * changes the user has in his working copy.
077: */
078: pathChangeType = "C";
079: } else if (contentsStatus == SVNStatusType.STATUS_DELETED) {
080: /*
081: * The file, directory or symbolic link item has been scheduled for
082: * Deletion from the repository.
083: */
084: pathChangeType = "D";
085: } else if (contentsStatus == SVNStatusType.STATUS_ADDED) {
086: /*
087: * The file, directory or symbolic link item has been scheduled for
088: * Addition to the repository.
089: */
090: pathChangeType = "A";
091: } else if (contentsStatus == SVNStatusType.STATUS_UNVERSIONED) {
092: /*
093: * The file, directory or symbolic link item is not under version
094: * control.
095: */
096: pathChangeType = "?";
097: } else if (contentsStatus == SVNStatusType.STATUS_EXTERNAL) {
098: /*
099: * The item is unversioned, but is used by an eXternals definition.
100: */
101: pathChangeType = "X";
102: } else if (contentsStatus == SVNStatusType.STATUS_IGNORED) {
103: /*
104: * The file, directory or symbolic link item is not under version
105: * control, and is configured to be Ignored during 'add', 'import'
106: * and 'status' operations.
107: */
108: pathChangeType = "I";
109: } else if (contentsStatus == SVNStatusType.STATUS_MISSING
110: || contentsStatus == SVNStatusType.STATUS_INCOMPLETE) {
111: /*
112: * The file, directory or symbolic link item is under version
113: * control but is missing or somehow incomplete. The item can be
114: * missing if it is removed using a command incompatible with the
115: * native Subversion command line client (for example, just removed
116: * from the filesystem). In the case the item is a directory, it
117: * can be incomplete if the user happened to interrupt a checkout
118: * or update.
119: */
120: pathChangeType = "!";
121: } else if (contentsStatus == SVNStatusType.STATUS_OBSTRUCTED) {
122: /*
123: * The file, directory or symbolic link item is in the repository
124: * as one kind of object, but what's actually in the user's working
125: * copy is some other kind. For example, Subversion might have a
126: * file in the repository, but the user removed the file and
127: * created a directory in its place, without using the 'svn delete'
128: * or 'svn add' command (or SVNKit analogues for them).
129: */
130: pathChangeType = "~";
131: } else if (contentsStatus == SVNStatusType.STATUS_REPLACED) {
132: /*
133: * The file, directory or symbolic link item was Replaced in the
134: * user's working copy; that is, the item was deleted, and a new
135: * item with the same name was added (within a single revision).
136: * While they may have the same name, the repository considers them
137: * to be distinct objects with distinct histories.
138: */
139: pathChangeType = "R";
140: } else if (contentsStatus == SVNStatusType.STATUS_NONE
141: || contentsStatus == SVNStatusType.STATUS_NORMAL) {
142: /*
143: * The item was not modified (normal).
144: */
145: pathChangeType = " ";
146: }
147:
148: /*
149: * If SVNStatusClient.doStatus(..) was invoked with remote = true the
150: * following code finds out whether the current item had been changed
151: * in the repository
152: */
153: String remoteChangeType = " ";
154:
155: if (status.getRemotePropertiesStatus() != SVNStatusType.STATUS_NONE
156: || status.getRemoteContentsStatus() != SVNStatusType.STATUS_NONE) {
157: /*
158: * the local item is out of date
159: */
160: remoteChangeType = "*";
161: }
162: /*
163: * Now getting the status of properties of an item. SVNStatusType also
164: * contains information on the properties state.
165: */
166: SVNStatusType propertiesStatus = status.getPropertiesStatus();
167: /*
168: * Default - properties are normal (unmodified).
169: */
170: String propertiesChangeType = " ";
171: if (propertiesStatus == SVNStatusType.STATUS_MODIFIED) {
172: /*
173: * Properties were modified.
174: */
175: propertiesChangeType = "M";
176: } else if (propertiesStatus == SVNStatusType.STATUS_CONFLICTED) {
177: /*
178: * Properties are in conflict with the repository.
179: */
180: propertiesChangeType = "C";
181: }
182:
183: /*
184: * Whether the item was locked in the .svn working area (for example,
185: * during a commit or maybe the previous operation was interrupted, in
186: * this case the lock needs to be cleaned up).
187: */
188: boolean isLocked = status.isLocked();
189: /*
190: * Whether the item is switched to a different URL (branch).
191: */
192: boolean isSwitched = status.isSwitched();
193: /*
194: * If the item is a file it may be locked.
195: */
196: SVNLock localLock = status.getLocalLock();
197: /*
198: * If doStatus() was run with remote=true and the item is a file,
199: * checks whether a remote lock presents.
200: */
201: SVNLock remoteLock = status.getRemoteLock();
202: String lockLabel = " ";
203:
204: if (localLock != null) {
205: /*
206: * at first suppose the file is locKed
207: */
208: lockLabel = "K";
209: if (remoteLock != null) {
210: /*
211: * if the lock-token of the local lock differs from the lock-
212: * token of the remote lock - the lock was sTolen!
213: */
214: if (!remoteLock.getID().equals(localLock.getID())) {
215: lockLabel = "T";
216: }
217: } else {
218: if (myIsRemote) {
219: /*
220: * the local lock presents but there's no lock in the
221: * repository - the lock was Broken. This is true only if
222: * doStatus() was invoked with remote=true.
223: */
224: lockLabel = "B";
225: }
226: }
227: } else if (remoteLock != null) {
228: /*
229: * the file is not locally locked but locked in the repository -
230: * the lock token is in some Other working copy.
231: */
232: lockLabel = "O";
233: }
234:
235: /*
236: * Obtains the working revision number of the item.
237: */
238: long workingRevision = status.getRevision().getNumber();
239: /*
240: * Obtains the number of the revision when the item was last changed.
241: */
242: long lastChangedRevision = status.getCommittedRevision()
243: .getNumber();
244: String offset = " ";
245: String[] offsets = new String[3];
246: offsets[0] = offset.substring(0, 6 - String.valueOf(
247: workingRevision).length());
248: offsets[1] = offset.substring(0, 6 - String.valueOf(
249: lastChangedRevision).length());
250: //status
251: offsets[2] = offset.substring(0, offset.length()
252: - (status.getAuthor() != null ? status.getAuthor()
253: .length() : 1));
254: /*
255: * status is shown in the manner of the native Subversion command line
256: * client's command "svn status"
257: */
258: System.out.println(pathChangeType
259: + propertiesChangeType
260: + (isLocked ? "L" : " ")
261: + (isAddedWithHistory ? "+" : " ")
262: + (isSwitched ? "S" : " ")
263: + lockLabel
264: + " "
265: + remoteChangeType
266: + " "
267: + workingRevision
268: + offsets[0]
269: + (lastChangedRevision >= 0 ? String
270: .valueOf(lastChangedRevision) : "?")
271: + offsets[1]
272: + (status.getAuthor() != null ? status.getAuthor()
273: : "?") + offsets[2]
274: + status.getFile().getPath());
275: }
276:
277: /*
278: * This is an implementation for
279: * ISVNEventHandler.handleEvent(SVNEvent event, double progress)
280: */
281: public void handleEvent(SVNEvent event, double progress) {
282: /*
283: * Gets the current action. An action is represented by SVNEventAction.
284: * In case of a status operation a current action can be determined via
285: * SVNEvent.getAction() and SVNEventAction.STATUS_-like constants.
286: */
287: SVNEventAction action = event.getAction();
288: /*
289: * Print out the revision against which the status was performed. This
290: * event is dispatched when the SVNStatusClient.doStatus() was invoked
291: * with the flag remote set to true - that is for a local status it
292: * won't be dispatched.
293: */
294: if (action == SVNEventAction.STATUS_COMPLETED) {
295: System.out.println("Status against revision: "
296: + event.getRevision());
297: }
298:
299: }
300:
301: /*
302: * Should be implemented to check if the current operation is cancelled. If
303: * it is, this method should throw an SVNCancelException.
304: */
305: public void checkCancelled() throws SVNCancelException {
306:
307: }
308:
309: }
|