#region CPL License
/*
Nuclex.NAnt.Tasks
Copyright (C) 2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Microsoft.Win32;
namespace Nuclex.NAnt.Tasks.Helpers {
/// Locates the subversion executable on the system
public static class SubversionLocator {
/// Tries to locate the Subversion executable on the current system
///
/// You do not need to call this normally. The 'Location' property will
/// automatically initiate a search the first time it is called. Only call
/// this method if you suspect the system might have changed and wish to
/// rescan for the Subversion executable.
///
public static void Locate() {
if(OsHelper.IsWindows) {
location = findUsingRegistry();
if(location == null) {
location = findOnWindows();
}
} else {
location = findOnUnix();
}
locationAttempted = true;
}
/// The location of the Subversion executable or null if not found
///
/// Will search for Subversion on the system the first time it is called, so it
/// may block for a moment before returning.
///
public static string Location {
get {
if(!locationAttempted) {
Locate();
}
return location;
}
}
/// Tries to locate subversion using a file search on windows
/// The directory the subversion executable can be found in or null
private static string findOnWindows() {
Debug.Assert(OsHelper.IsWindows);
if(EnvironmentHelper.RunningOn64BitOS) {
string location = searchWindowsProgramFilesFolder(KnownFolders.ProgramFiles64Path);
if(location != null) {
return location;
}
}
return searchWindowsProgramFilesFolder(KnownFolders.ProgramFiles32Path);
}
/// Searches the program files folder for a Subversion executable
/// The path to the Subversion executable or null if not found
private static string searchWindowsProgramFilesFolder(string programFilesFolder) {
string location = searchWindowsSubversionDistribution(
programFilesFolder, "CollabNet Subversion*"
);
if(location == null) {
location = searchWindowsSubversionDistribution(
programFilesFolder, "SlikSvn*"
);
}
return location;
}
/// Searches for an installed Subversion distribution on windows
/// Path of the program files folder
/// Mark of the directories that will be checked
/// The directory of the subversion executable, if found
private static string searchWindowsSubversionDistribution(
string programFilesFolder, string folderMask
) {
string[] subversionFolders = Directory.GetDirectories(
programFilesFolder, folderMask
);
for(int index = 0; index < subversionFolders.Length; ++index) {
string potentialLocation = Path.Combine(subversionFolders[index], "svn.exe");
if(File.Exists(potentialLocation)) {
return potentialLocation;
}
potentialLocation = Path.Combine(subversionFolders[index], @"bin\svn.exe");
if(File.Exists(potentialLocation)) {
return potentialLocation;
}
}
return null;
}
/// Tries to locate a subversion executable using the registry
/// The path to the subversion installation folder or null
private static string findUsingRegistry() {
string location = tryCollabNetSvnFromRegistry();
if(location == null) {
location = trySlikSvnFromRegistry();
}
return location;
}
/// Tries to locate SlikSvn using its registry path
/// The path to the SlikSvn installation folder or null if not found
private static string trySlikSvnFromRegistry() {
using(
RegistryKey slikSvnKey = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\SlikSvn\Install"
)
) {
if(slikSvnKey == null) {
return null;
}
string folder = (string)slikSvnKey.GetValue("Location");
if(Directory.Exists(folder)) {
string potentialLocation = Path.Combine(folder, "svn.exe");
if(File.Exists(potentialLocation)) {
return potentialLocation;
}
}
}
return null;
}
/// Tries to locate CollabNet Subversion using the registry
/// The installation folder of CollabNet Subversion or null
private static string tryCollabNetSvnFromRegistry() {
using(
RegistryKey collabNetKey = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\CollabNet\Subversion"
)
) {
if(collabNetKey == null) {
return null;
}
string[] versionKeyNames = collabNetKey.GetSubKeyNames();
for(int index = versionKeyNames.Length - 1; index >= 0; --index) {
using(
RegistryKey versionKey = collabNetKey.OpenSubKey(versionKeyNames[index])
) {
string location = tryCollabNetSvnPath(versionKey, "Client");
if(location == null) {
location = tryCollabNetSvnPath(versionKey, "Server");
}
if(location != null) {
return location;
}
}
} // for each version key
}
return null;
}
/// Checks one of the specific CollabNet release type keys
/// Version key under the CollabNet main key
///
/// Which type of release to check (either "Client" or "Server")
///
/// The path to the subversion installation folder or null
private static string tryCollabNetSvnPath(RegistryKey versionKey, string type) {
using(RegistryKey serverKey = versionKey.OpenSubKey(type)) {
if(serverKey == null) {
return null;
}
string folder = (string)serverKey.GetValue("Install Location");
if(Directory.Exists(folder)) {
string potentialLocation = Path.Combine(folder, "svn.exe");
if(File.Exists(potentialLocation)) {
return potentialLocation;
}
}
}
return null;
}
/// Tries to locate 7-Zip in its default path on a unix system
/// The path to the 7-Zip executable or null if not found
private static string findOnUnix() {
Debug.Assert(OsHelper.IsUnix);
string subversionPath = "/usr/local/bin/svn";
if(File.Exists(subversionPath)) {
return subversionPath;
}
subversionPath = "/usr/bin/svn";
if(File.Exists(subversionPath)) {
return subversionPath;
}
subversionPath = "/bin/svn";
if(File.Exists(subversionPath)) {
return subversionPath;
}
return null;
}
/// whether we attempted to locate Subversion already
private static volatile bool locationAttempted;
/// The location of the Subversion executable or null
private static string location;
}
} // namespace Nuclex.NAnt.Tasks.Helpers