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.core.wc;
013:
014: import java.io.File;
015: import java.lang.reflect.Constructor;
016: import java.lang.reflect.Method;
017:
018: import org.tmatesoft.svn.core.SVNCancelException;
019: import org.tmatesoft.svn.core.SVNException;
020: import org.tmatesoft.svn.core.SVNProperty;
021: import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
022: import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
023: import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
024: import org.tmatesoft.svn.core.internal.wc.SVNExternalInfo;
025: import org.tmatesoft.svn.core.internal.wc.SVNFileType;
026: import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
027: import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea;
028: import org.tmatesoft.svn.core.internal.wc.admin.SVNVersionedProperties;
029: import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
030:
031: /**
032: * The <b>SVNWCUtil</b> is a utility class providing some common methods used
033: * by Working Copy API classes for such purposes as creating default run-time
034: * configuration and authentication drivers and some others.
035: *
036: *
037: * @version 1.1.1
038: * @author TMate Software Ltd., Peter Skoog
039: * @see ISVNOptions
040: * @see <a target="_top" href="http://svnkit.com/kb/examples/">Examples</a>
041: */
042: public class SVNWCUtil {
043:
044: private static final String ECLIPSE_AUTH_MANAGER_CLASSNAME = "org.tmatesoft.svn.core.internal.wc.EclipseSVNAuthenticationManager";
045: private static Boolean ourIsEclipse;
046:
047: /**
048: * Gets the location of the default SVN's run-time configuration area on the
049: * current machine. The result path depends on the platform on which SVNKit
050: * is running:
051: * <ul>
052: * <li>on <i>Windows</i> this path usually looks like <i>'Documents and
053: * Settings\UserName\Subversion'</i> or simply <i>'%APPDATA%\Subversion'</i>.
054: * <li>on a <i>Unix</i>-like platform - <i>'~/.subversion'</i>.
055: * </ul>
056: *
057: * @return a {@link java.io.File} representation of the default SVN's
058: * run-time configuration area location
059: */
060: public static File getDefaultConfigurationDirectory() {
061: if (SVNFileUtil.isWindows) {
062: return new File(SVNFileUtil.getApplicationDataPath(),
063: "Subversion");
064: } else if (SVNFileUtil.isOpenVMS) {
065: return new File("/sys$login", ".subversion")
066: .getAbsoluteFile();
067: }
068: return new File(System.getProperty("user.home"), ".subversion");
069: }
070:
071: /**
072: * Creates a default authentication manager that uses the default SVN's
073: * <i>servers</i> configuration and authentication storage. Whether the
074: * default auth storage is used or not depends on the 'store-auth-creds'</i>
075: * option that can be found in the SVN's <i>config</i> file under the
076: * <i>[auth]</i> section.
077: *
078: * @return a default implementation of the credentials and servers
079: * configuration driver interface
080: * @see #getDefaultConfigurationDirectory()
081: */
082: public static ISVNAuthenticationManager createDefaultAuthenticationManager() {
083: return createDefaultAuthenticationManager(
084: getDefaultConfigurationDirectory(), null, null);
085: }
086:
087: /**
088: * Creates a default authentication manager that uses the <i>servers</i>
089: * configuration and authentication storage located in the provided
090: * directory. The authentication storage is enabled.
091: *
092: * @param configDir
093: * a new location of the run-time configuration area
094: * @return a default implementation of the credentials and servers
095: * configuration driver interface
096: */
097: public static ISVNAuthenticationManager createDefaultAuthenticationManager(
098: File configDir) {
099: return createDefaultAuthenticationManager(configDir, null,
100: null, true);
101: }
102:
103: /**
104: * Creates a default authentication manager that uses the default SVN's
105: * <i>servers</i> configuration and provided user's credentials. Whether
106: * the default auth storage is used or not depends on the 'store-auth-creds'</i>
107: * option that can be found in the SVN's <i>config</i> file under the
108: * <i>[auth]</i> section.
109: *
110: * @param userName
111: * a user's name
112: * @param password
113: * a user's password
114: * @return a default implementation of the credentials and servers
115: * configuration driver interface
116: */
117: public static ISVNAuthenticationManager createDefaultAuthenticationManager(
118: String userName, String password) {
119: return createDefaultAuthenticationManager(null, userName,
120: password);
121: }
122:
123: /**
124: * Creates a default authentication manager that uses the provided
125: * configuration directory and user's credentials. Whether the default auth
126: * storage is used or not depends on the 'store-auth-creds'</i> option that
127: * is looked up in the <i>config</i> file under the <i>[auth]</i> section.
128: * Files <i>config</i> and <i>servers</i> will be created (if they still
129: * don't exist) in the specified directory (they are the same as those ones
130: * you can find in the default SVN's run-time configuration area).
131: *
132: * @param configDir
133: * a new location of the run-time configuration area
134: * @param userName
135: * a user's name
136: * @param password
137: * a user's password
138: * @return a default implementation of the credentials and servers
139: * configuration driver interface
140: */
141: public static ISVNAuthenticationManager createDefaultAuthenticationManager(
142: File configDir, String userName, String password) {
143: ISVNOptions options = createDefaultOptions(configDir, true);
144: boolean store = options.isAuthStorageEnabled();
145: return createDefaultAuthenticationManager(configDir, userName,
146: password, store);
147: }
148:
149: /**
150: * Creates a default authentication manager that uses the provided
151: * configuration directory and user's credentials. The
152: * <code>storeAuth</code> parameter affects on using the auth storage.
153: *
154: *
155: * @param configDir
156: * a new location of the run-time configuration area
157: * @param userName
158: * a user's name
159: * @param password
160: * a user's password
161: * @param storeAuth
162: * if <span class="javakeyword">true</span> then the auth
163: * storage is enabled, otherwise disabled
164: * @return a default implementation of the credentials and servers
165: * configuration driver interface
166: */
167: public static ISVNAuthenticationManager createDefaultAuthenticationManager(
168: File configDir, String userName, String password,
169: boolean storeAuth) {
170: return createDefaultAuthenticationManager(configDir, userName,
171: password, null, null, storeAuth);
172: }
173:
174: /**
175: * Creates a default authentication manager that uses the provided
176: * configuration directory and user's credentials. The
177: * <code>storeAuth</code> parameter affects on using the auth storage.
178: *
179: *
180: * @param configDir
181: * a new location of the run-time configuration area
182: * @param userName
183: * a user's name
184: * @param password
185: * a user's password
186: * @param privateKey
187: * a private key file for SSH session
188: * @param passphrase
189: * a passphrase that goes with the key file
190: * @param storeAuth
191: * if <span class="javakeyword">true</span> then the auth
192: * storage is enabled, otherwise disabled
193: * @return a default implementation of the credentials and servers
194: * configuration driver interface
195: */
196: public static ISVNAuthenticationManager createDefaultAuthenticationManager(
197: File configDir, String userName, String password,
198: File privateKey, String passphrase, boolean storeAuth) {
199: // check whether we are running inside Eclipse.
200: if (isEclipse()) {
201: // use reflection to allow compilation when there is no Eclipse.
202: try {
203: ClassLoader loader = SVNWCUtil.class.getClassLoader();
204: if (loader == null) {
205: loader = ClassLoader.getSystemClassLoader();
206: }
207: Class managerClass = loader
208: .loadClass(ECLIPSE_AUTH_MANAGER_CLASSNAME);
209: if (managerClass != null) {
210: Constructor method = managerClass
211: .getConstructor(new Class[] { File.class,
212: Boolean.TYPE, String.class,
213: String.class, File.class,
214: String.class });
215: if (method != null) {
216: return (ISVNAuthenticationManager) method
217: .newInstance(new Object[] {
218: configDir,
219: storeAuth ? Boolean.TRUE
220: : Boolean.FALSE,
221: userName, password, privateKey,
222: passphrase });
223: }
224: }
225: } catch (Throwable e) {
226: }
227: }
228: return new DefaultSVNAuthenticationManager(configDir,
229: storeAuth, userName, password, privateKey, passphrase);
230: }
231:
232: /**
233: * Creates a default run-time configuration options driver that uses the
234: * provided configuration directory.
235: *
236: * <p>
237: * If <code>dir</code> is not <span class="javakeyword">null</span> then
238: * all necessary config files (in particular <i>config</i> and <i>servers</i>)
239: * will be created in this directory if they still don't exist. Those files
240: * are the same as those ones you can find in the default SVN's run-time
241: * configuration area.
242: *
243: * @param dir
244: * a new location of the run-time configuration area
245: * @param readonly
246: * if <span class="javakeyword">true</span> then run-time
247: * configuration options are available only for reading, if <span
248: * class="javakeyword">false</span> then those options are
249: * available for both reading and writing
250: * @return a default implementation of the run-time configuration options
251: * driver interface
252: */
253: public static ISVNOptions createDefaultOptions(File dir,
254: boolean readonly) {
255: return new DefaultSVNOptions(dir, readonly);
256: }
257:
258: /**
259: * Creates a default run-time configuration options driver that uses the
260: * default SVN's run-time configuration area.
261: *
262: * @param readonly
263: * if <span class="javakeyword">true</span> then run-time
264: * configuration options are available only for reading, if <span
265: * class="javakeyword">false</span> then those options are
266: * available for both reading and writing
267: * @return a default implementation of the run-time configuration options
268: * driver interface
269: * @see #getDefaultConfigurationDirectory()
270: */
271: public static ISVNOptions createDefaultOptions(boolean readonly) {
272: return new DefaultSVNOptions(null, readonly);
273: }
274:
275: /**
276: * Determines if a directory is under version control.
277: *
278: * @param dir
279: * a directory to check
280: * @return <span class="javakeyword">true</span> if versioned, otherwise
281: * <span class="javakeyword">false</span>
282: */
283: public static boolean isVersionedDirectory(File dir) {
284: SVNFileType type = SVNFileType.getType(dir);
285: if (type != SVNFileType.DIRECTORY) {
286: return false;
287: }
288: SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
289: try {
290: wcAccess.open(dir, false, 0);
291: } catch (SVNException e) {
292: return false;
293: } finally {
294: try {
295: wcAccess.close();
296: } catch (SVNException e) {
297: //
298: }
299: }
300: return true;
301: }
302:
303: /**
304: * Determines if a directory is the root of the Working Copy.
305: *
306: * @param versionedDir
307: * a versioned directory to check
308: * @return <span class="javakeyword">true</span> if
309: * <code>versionedDir</code> is versioned and the WC root (or the
310: * root of externals if <code>considerExternalAsRoot</code> is
311: * <span class="javakeyword">true</span>), otherwise <span
312: * class="javakeyword">false</span>
313: * @throws SVNException
314: * @since 1.1
315: */
316: public static boolean isWorkingCopyRoot(final File versionedDir)
317: throws SVNException {
318: SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
319: try {
320: wcAccess.open(versionedDir, false, 0);
321: return wcAccess.isWCRoot(versionedDir);
322: } catch (SVNException e) {
323: return false;
324: } finally {
325: wcAccess.close();
326: }
327: }
328:
329: /**
330: * @param versionedDir
331: * a versioned directory to check
332: * @param externalIsRoot
333: * @return <span class="javakeyword">true</span> if
334: * <code>versionedDir</code> is versioned and the WC root (or the
335: * root of externals if <code>considerExternalAsRoot</code> is
336: * <span class="javakeyword">true</span>), otherwise <span
337: * class="javakeyword">false</span>
338: * @throws SVNException
339: * @deprecated use {@link #isWorkingCopyRoot(File)}} instead
340: */
341: public static boolean isWorkingCopyRoot(final File versionedDir,
342: boolean externalIsRoot) throws SVNException {
343: if (isWorkingCopyRoot(versionedDir)) {
344: if (!externalIsRoot) {
345: return true;
346:
347: }
348: File root = getWorkingCopyRoot(versionedDir, false);
349: return root.equals(versionedDir);
350: }
351: return false;
352: }
353:
354: /**
355: * Returns the Working Copy root directory given a versioned directory that
356: * belongs to the Working Copy.
357: *
358: * <p>
359: * If both <span>versionedDir</span> and its parent directory are not
360: * versioned this method returns <span class="javakeyword">null</span>.
361: *
362: * @param versionedDir
363: * a directory belonging to the WC which root is to be searched
364: * for
365: * @param stopOnExtenrals
366: * if <span class="javakeyword">true</span> then this method
367: * will stop at the directory on which any externals definitions
368: * are set
369: * @return the WC root directory (if it is found) or <span
370: * class="javakeyword">null</span>.
371: * @throws SVNException
372: */
373: public static File getWorkingCopyRoot(File versionedDir,
374: boolean stopOnExtenrals) throws SVNException {
375: versionedDir = versionedDir.getAbsoluteFile();
376: if (versionedDir == null
377: || (!isVersionedDirectory(versionedDir) && !isVersionedDirectory(versionedDir
378: .getParentFile()))) {
379: // both this dir and its parent are not versioned.
380: return null;
381: }
382:
383: File parent = versionedDir.getParentFile();
384: if (parent == null) {
385: return versionedDir;
386: }
387:
388: if (isWorkingCopyRoot(versionedDir)) {
389: // this is root.
390: if (stopOnExtenrals) {
391: return versionedDir;
392: }
393: File parentRoot = getWorkingCopyRoot(parent,
394: stopOnExtenrals);
395: if (parentRoot == null) {
396: // if parent is not versioned return this dir.
397: return versionedDir;
398: }
399: // parent is versioned. we have to check if it contains externals
400: // definition for this dir.
401:
402: while (parent != null) {
403: SVNWCAccess parentAccess = SVNWCAccess
404: .newInstance(null);
405: try {
406: SVNAdminArea dir = parentAccess.open(parent, false,
407: 0);
408: SVNVersionedProperties props = dir
409: .getProperties(dir.getThisDirName());
410: SVNExternalInfo[] externals = SVNWCAccess
411: .parseExternals(
412: "",
413: props
414: .getPropertyValue(SVNProperty.EXTERNALS));
415: // now externals could point to our dir.
416: for (int i = 0; i < externals.length; i++) {
417: SVNExternalInfo external = externals[i];
418: File externalFile = new File(parent, external
419: .getPath());
420: if (externalFile.equals(versionedDir)) {
421: return parentRoot;
422: }
423: }
424: } catch (SVNException e) {
425: if (e instanceof SVNCancelException) {
426: throw e;
427: }
428: } finally {
429: parentAccess.close();
430: }
431: if (parent.equals(parentRoot)) {
432: break;
433: }
434: parent = parent.getParentFile();
435: }
436: return versionedDir;
437: }
438:
439: return getWorkingCopyRoot(parent, stopOnExtenrals);
440: }
441:
442: private static boolean isEclipse() {
443: if (ourIsEclipse == null) {
444: try {
445: ClassLoader loader = SVNWCUtil.class.getClassLoader();
446: if (loader == null) {
447: loader = ClassLoader.getSystemClassLoader();
448: }
449: Class platform = loader
450: .loadClass("org.eclipse.core.runtime.Platform");
451: Method isRunning = platform.getMethod("isRunning",
452: new Class[0]);
453: Object result = isRunning.invoke(null, new Object[0]);
454: if (result != null && Boolean.TRUE.equals(result)) {
455: ourIsEclipse = Boolean.TRUE;
456: return true;
457: }
458: } catch (Throwable th) {
459: }
460: ourIsEclipse = Boolean.FALSE;
461: }
462: return ourIsEclipse.booleanValue();
463: }
464: }
|