/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.wc;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
/**
* The <b>SVNWCUtil</b> is a utility class providing some common methods used
* by Working Copy API classes for such purposes as creating default run-time
* configuration and authentication drivers and some others.
*
*
* @version 1.3
* @author TMate Software Ltd., Peter Skoog
* @since 1.2
* @see ISVNOptions
* @see <a target="_top" href="http://svnkit.com/kb/examples/">Examples</a>
*/
public class SVNWCUtil {
private static final String ECLIPSE_AUTH_MANAGER_CLASSNAME = "org.tmatesoft.svn.core.internal.wc.EclipseSVNAuthenticationManager";
private static Boolean ourIsEclipse;
/**
* Gets the location of the default SVN's run-time configuration area on the
* current machine. The result path depends on the platform on which SVNKit
* is running:
* <ul>
* <li>on <i>Windows</i> this path usually looks like <i>'Documents and
* Settings\UserName\Subversion'</i> or simply <i>'%APPDATA%\Subversion'</i>.
* <li>on a <i>Unix</i>-like platform - <i>'~/.subversion'</i>.
* </ul>
*
* @return a {@link java.io.File} representation of the default SVN's
* run-time configuration area location
*/
public static File getDefaultConfigurationDirectory() {
if (SVNFileUtil.isWindows && !SVNFileUtil.isOS2) {
return new File(SVNFileUtil.getApplicationDataPath(), "Subversion");
} else if (SVNFileUtil.isOpenVMS) {
return new File("/sys$login", ".subversion").getAbsoluteFile();
}
return new File(System.getProperty("user.home"), ".subversion");
}
/**
* Creates a default authentication manager that uses the default SVN's
* <i>servers</i> configuration and authentication storage. Whether the
* default auth storage is used or not depends on the 'store-auth-creds'</i>
* option that can be found in the SVN's <i>config</i> file under the
* <i>[auth]</i> section.
*
* @return a default implementation of the credentials and servers
* configuration driver interface
* @see #getDefaultConfigurationDirectory()
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager() {
return createDefaultAuthenticationManager(getDefaultConfigurationDirectory(), null, null);
}
/**
* Creates a default authentication manager that uses the <i>servers</i>
* configuration and authentication storage located in the provided
* directory. The authentication storage is enabled.
*
* @param configDir
* a new location of the run-time configuration area
* @return a default implementation of the credentials and servers
* configuration driver interface
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager(File configDir) {
return createDefaultAuthenticationManager(configDir, null, null, true);
}
/**
* Creates a default authentication manager that uses the default SVN's
* <i>servers</i> configuration and provided user's credentials. Whether
* the default auth storage is used or not depends on the 'store-auth-creds'</i>
* option that can be found in the SVN's <i>config</i> file under the
* <i>[auth]</i> section.
*
* @param userName
* a user's name
* @param password
* a user's password
* @return a default implementation of the credentials and servers
* configuration driver interface
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager(String userName, String password) {
return createDefaultAuthenticationManager(null, userName, password);
}
/**
* Creates a default authentication manager that uses the provided
* configuration directory and user's credentials. Whether the default auth
* storage is used or not depends on the 'store-auth-creds'</i> option that
* is looked up in the <i>config</i> file under the <i>[auth]</i> section.
* Files <i>config</i> and <i>servers</i> will be created (if they still
* don't exist) in the specified directory (they are the same as those ones
* you can find in the default SVN's run-time configuration area).
*
* @param configDir
* a new location of the run-time configuration area
* @param userName
* a user's name
* @param password
* a user's password
* @return a default implementation of the credentials and servers
* configuration driver interface
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager(File configDir, String userName, String password) {
DefaultSVNOptions options = createDefaultOptions(configDir, true);
boolean store = options.isAuthStorageEnabled();
return createDefaultAuthenticationManager(configDir, userName, password, store);
}
/**
* Creates a default authentication manager that uses the provided
* configuration directory and user's credentials. The
* <code>storeAuth</code> parameter affects on using the auth storage.
*
*
* @param configDir
* a new location of the run-time configuration area
* @param userName
* a user's name
* @param password
* a user's password
* @param storeAuth
* if <span class="javakeyword">true</span> then the auth
* storage is enabled, otherwise disabled
* @return a default implementation of the credentials and servers
* configuration driver interface
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager(File configDir, String userName, String password, boolean storeAuth) {
return createDefaultAuthenticationManager(configDir, userName, password, null, null, storeAuth);
}
/**
* Creates a default authentication manager that uses the provided
* configuration directory and user's credentials. The
* <code>storeAuth</code> parameter affects on using the auth storage.
*
*
* @param configDir
* a new location of the run-time configuration area
* @param userName
* a user's name
* @param password
* a user's password
* @param privateKey
* a private key file for SSH session
* @param passphrase
* a passphrase that goes with the key file
* @param storeAuth
* if <span class="javakeyword">true</span> then the auth
* storage is enabled, otherwise disabled
* @return a default implementation of the credentials and servers
* configuration driver interface
*/
public static ISVNAuthenticationManager createDefaultAuthenticationManager(File configDir, String userName, String password, File privateKey, String passphrase, boolean storeAuth) {
// check whether we are running inside Eclipse.
if (isEclipseKeyringSupported()) {
// use reflection to allow compilation when there is no Eclipse.
try {
ClassLoader loader = SVNWCUtil.class.getClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
Class<?> managerClass = loader.loadClass(ECLIPSE_AUTH_MANAGER_CLASSNAME);
if (managerClass != null) {
Constructor<?> method = managerClass.getConstructor(new Class[] {
File.class, Boolean.TYPE, String.class, String.class, File.class, String.class
});
if (method != null) {
return (ISVNAuthenticationManager) method.newInstance(new Object[] {
configDir, storeAuth ? Boolean.TRUE : Boolean.FALSE, userName, password, privateKey, passphrase
});
}
}
} catch (Throwable e) {
}
}
return new DefaultSVNAuthenticationManager(configDir, storeAuth, userName, password, privateKey, passphrase);
}
/**
* Creates a default run-time configuration options driver that uses the
* provided configuration directory.
*
* <p>
* If <code>dir</code> is not <span class="javakeyword">null</span> then
* all necessary config files (in particular <i>config</i> and <i>servers</i>)
* will be created in this directory if they still don't exist. Those files
* are the same as those ones you can find in the default SVN's run-time
* configuration area.
*
* @param dir
* a new location of the run-time configuration area
* @param readonly
* if <span class="javakeyword">true</span> then run-time
* configuration options are available only for reading, if <span
* class="javakeyword">false</span> then those options are
* available for both reading and writing
* @return a default implementation of the run-time configuration options
* driver interface
*/
public static DefaultSVNOptions createDefaultOptions(File dir, boolean readonly) {
return new DefaultSVNOptions(dir, readonly);
}
/**
* Creates a default run-time configuration options driver that uses the
* default SVN's run-time configuration area.
*
* @param readonly
* if <span class="javakeyword">true</span> then run-time
* configuration options are available only for reading, if <span
* class="javakeyword">false</span> then those options are
* available for both reading and writing
* @return a default implementation of the run-time configuration options
* driver interface
* @see #getDefaultConfigurationDirectory()
*/
public static DefaultSVNOptions createDefaultOptions(boolean readonly) {
return new DefaultSVNOptions(null, readonly);
}
/**
* Determines if a directory is under version control.
*
* @param dir
* a directory to check
* @return <span class="javakeyword">true</span> if versioned, otherwise
* <span class="javakeyword">false</span>
*/
public static boolean isVersionedDirectory(File dir) {
return SvnOperationFactory.isVersionedDirectory(dir);
}
/**
* Determines if a directory is the root of the Working Copy.
*
* @param versionedDir
* a versioned directory to check
* @return <span class="javakeyword">true</span> if
* <code>versionedDir</code> is versioned and the WC root (or the
* root of externals if <code>considerExternalAsRoot</code> is
* <span class="javakeyword">true</span>), otherwise <span
* class="javakeyword">false</span>
* @throws SVNException
* @since 1.1
*/
public static boolean isWorkingCopyRoot(final File versionedDir) throws SVNException {
return SvnOperationFactory.isWorkingCopyRoot(versionedDir);
}
/**
* @param versionedDir
* a versioned directory to check
* @param externalIsRoot
* @return <span class="javakeyword">true</span> if
* <code>versionedDir</code> is versioned and the WC root (or the
* root of externals if <code>considerExternalAsRoot</code> is
* <span class="javakeyword">true</span>), otherwise <span
* class="javakeyword">false</span>
* @throws SVNException
* @deprecated use {@link #isWorkingCopyRoot(File)}} instead
*/
public static boolean isWorkingCopyRoot(final File versionedDir, boolean externalIsRoot) throws SVNException {
if (isWorkingCopyRoot(versionedDir)) {
if (!externalIsRoot) {
return true;
}
File root = SvnOperationFactory.getWorkingCopyRoot(versionedDir, false);
return root.equals(versionedDir);
}
return false;
}
/**
* Returns the Working Copy root directory given a versioned directory that
* belongs to the Working Copy.
*
* <p>
* If both <span>versionedDir</span> and its parent directory are not
* versioned this method returns <span class="javakeyword">null</span>.
*
* @param versionedDir
* a directory belonging to the WC which root is to be searched
* for
* @param stopOnExternals
* if <span class="javakeyword">true</span> then this method
* will stop at the directory on which any externals definitions
* are set
* @return the WC root directory (if it is found) or <span
* class="javakeyword">null</span>.
* @throws SVNException
*/
public static File getWorkingCopyRoot(File versionedDir, boolean stopOnExternals) throws SVNException {
return SvnOperationFactory.getWorkingCopyRoot(versionedDir, stopOnExternals);
}
public static synchronized boolean isEclipseKeyringSupported() {
if (ourIsEclipse == null) {
ourIsEclipse = Boolean.FALSE;
try {
ClassLoader loader = SVNWCUtil.class.getClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
final Class<?> platform = loader.loadClass("org.eclipse.core.runtime.Platform");
final Method isRunning = platform.getMethod("isRunning", new Class[0]);
final Object result = isRunning.invoke(null, new Object[0]);
if (result != null && Boolean.TRUE.equals(result)) {
final EclipseVersion authBundleVersion = getBundle("org.eclipse.core.runtime.compatibility.auth");
boolean supportsKeyring = false;
if (authBundleVersion != null && authBundleVersion.major >= 3) {
supportsKeyring = true;
} else {
final EclipseVersion runtimeBundleVersion = getBundle("org.eclipse.core.runtime");
supportsKeyring = runtimeBundleVersion.major < 3 || (runtimeBundleVersion.major == 3 && runtimeBundleVersion.minor <= 2);
}
ourIsEclipse = supportsKeyring ? Boolean.TRUE : Boolean.FALSE;
}
} catch (Throwable th) {
}
}
return ourIsEclipse.booleanValue();
}
private static EclipseVersion getBundle(String bundleName) throws Throwable {
ClassLoader loader = SVNWCUtil.class.getClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
final Class<?> platform = loader.loadClass("org.eclipse.core.runtime.Platform");
if (platform == null) {
return null;
}
final Method getBundle = platform.getMethod("getBundle", new Class[] {String.class});
final Object bundle = getBundle.invoke(null, new Object[] {bundleName});
if (bundle == null) {
return null;
}
final Class<?> bundleClazz = loader.loadClass("org.osgi.framework.Bundle");
final Method getVersion = bundleClazz.getMethod("getVersion", new Class[0]);
final Object version = getVersion.invoke(bundle, new Object[0]);
if (version == null) {
return null;
}
final Class<?> versionClazz = loader.loadClass("org.osgi.framework.Version");
final Method getMajor = versionClazz.getMethod("getMajor", new Class[0]);
final Method getMinor = versionClazz.getMethod("getMinor", new Class[0]);
final Object major = getMajor.invoke(version, new Object[0]);
final Object minor = getMinor.invoke(version, new Object[0]);
final EclipseVersion result = new EclipseVersion();
result.major = (Integer) major;
result.minor = (Integer) minor;
return result;
}
private static class EclipseVersion {
int major;
int minor;
}
}