2019-12-26 23:01:54 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using UnrealBuildTool ;
2018-08-14 18:32:34 -04:00
using Tools.DotNETCommon ;
2014-03-14 14:13:41 -04:00
namespace AutomationTool
{
/// <summary>
2017-08-31 12:08:38 -04:00
/// Contains detected Perforce settings.
2014-03-14 14:13:41 -04:00
/// </summary>
public class P4Environment
{
2017-08-31 12:08:38 -04:00
/// <summary>
/// The Perforce host and port number (eg. perforce:1666)
/// </summary>
public string ServerAndPort
{
get ;
private set ;
2014-04-23 20:07:00 -04:00
}
2017-08-31 12:08:38 -04:00
/// <summary>
/// The Perforce username
/// </summary>
public string User
{
get ;
private set ;
}
/// <summary>
/// Name of the Perforce client containing UAT.
/// </summary>
public string Client
{
get ;
private set ;
}
/// <summary>
/// The current branch containing UAT. This may be a depot path (eg. //depot/UE4) or the name of a stream (eg. //UE4/Main).
/// </summary>
public string Branch
{
get ;
private set ;
}
/// <summary>
/// Path to the root of the branch as a client path (//MyClient/UE4).
/// </summary>
public string ClientRoot
{
get ;
private set ;
}
/// <summary>
/// The Perforce host and port number (eg. perforce:1666)
/// </summary>
[Obsolete("The P4Port property has been deprecated in 4.18. Use the ServerAndPort property instead.")]
public string P4Port
{
get { return ServerAndPort ; }
}
/// <summary>
/// Root directory of the current branch
/// </summary>
[Obsolete("The BuildRootP4 property has been deprecated in 4.18. Use the Branch property instead.")]
public string BuildRootP4
{
get { return Branch ; }
}
/// <summary>
/// Escaped branch name
/// </summary>
[Obsolete("The BuildRootEscaped property has been deprecated in 4.18. Use the CommandUtils.EscapePath(P4Env.Branch) instead.")]
public string BuildRootEscaped
{
get { return CommandUtils . EscapePath ( BuildRootP4 ) ; }
}
/// <summary>
/// The currently synced changelist.
/// </summary>
2014-04-23 20:07:00 -04:00
public int Changelist
{
get
{
if ( ChangelistInternal < = 0 )
{
2017-01-30 16:52:08 -05:00
throw new AutomationException ( "P4Environment.Changelist has not been initialized but is requested. Set uebp_CL env var or run UAT with -P4 to automatically detect changelist." ) ;
2014-04-23 20:07:00 -04:00
}
2014-04-23 20:10:20 -04:00
return ChangelistInternal ;
2014-04-23 20:07:00 -04:00
}
protected set
{
ChangelistInternal = value ;
}
}
2017-08-31 12:08:38 -04:00
/// <summary>
/// Deprecated accessor for the current changelist as a string.
/// </summary>
[Obsolete("The ChangelistString property has been deprecated in 4.18. Use the integer Changelist property instead.")]
public string ChangelistString
{
get { return Changelist . ToString ( ) ; }
}
/// <summary>
/// Backing value for the current changelist property
/// </summary>
private int ChangelistInternal = - 1 ;
/// <summary>
/// The currently synced code changelist.
/// </summary>
2016-07-29 17:10:25 -04:00
public int CodeChangelist
{
get
{
if ( CodeChangelistInternal < = 0 )
{
2017-01-30 16:52:08 -05:00
throw new AutomationException ( "P4Environment.CodeChangelist has not been initialized but is requested. Set uebp_CodeCL env var or run UAT with -P4 to automatically detect changelist." ) ;
2016-07-29 17:10:25 -04:00
}
return CodeChangelistInternal ;
}
protected set
{
CodeChangelistInternal = value ;
}
}
2017-08-31 12:08:38 -04:00
/// <summary>
/// Backing value for the current code changelist
/// </summary>
private int CodeChangelistInternal = - 1 ;
2014-03-14 14:13:41 -04:00
2017-08-31 12:08:38 -04:00
/// <summary>
/// Constructor. Derives the Perforce environment settings.
/// </summary>
internal P4Environment ( CommandEnvironment CmdEnv )
2014-03-14 14:13:41 -04:00
{
2017-08-31 12:08:38 -04:00
// Get the Perforce port setting
2019-10-11 15:33:31 -04:00
ServerAndPort = CommandUtils . ParseParamValue ( Environment . GetCommandLineArgs ( ) , "-p4port" , null ) ;
2017-08-31 12:08:38 -04:00
if ( String . IsNullOrEmpty ( ServerAndPort ) )
{
2019-10-11 15:33:31 -04:00
// check env var
ServerAndPort = CommandUtils . GetEnvVar ( EnvVarNames . P4Port ) ;
if ( String . IsNullOrEmpty ( ServerAndPort ) )
{
ServerAndPort = DetectP4Port ( ) ;
}
2017-08-31 12:08:38 -04:00
CommandUtils . SetEnvVar ( EnvVarNames . P4Port , ServerAndPort ) ;
}
2014-03-14 14:13:41 -04:00
2017-08-31 12:08:38 -04:00
// Get the Perforce user setting
2019-10-11 15:33:31 -04:00
User = CommandUtils . ParseParamValue ( Environment . GetCommandLineArgs ( ) , "-p4user" , null ) ;
if ( String . IsNullOrEmpty ( User ) )
2017-08-31 12:08:38 -04:00
{
2019-10-11 15:33:31 -04:00
User = CommandUtils . GetEnvVar ( EnvVarNames . User ) ;
if ( String . IsNullOrEmpty ( User ) )
{
P4Connection DefaultConnection = new P4Connection ( User : null , Client : null , ServerAndPort : ServerAndPort ) ;
User = DetectUserName ( DefaultConnection ) ;
}
2017-08-31 12:08:38 -04:00
CommandUtils . SetEnvVar ( EnvVarNames . User , User ) ;
}
// Get the Perforce client setting
2014-03-14 14:13:41 -04:00
Client = CommandUtils . GetEnvVar ( EnvVarNames . Client ) ;
2018-10-11 10:23:11 -04:00
Branch = CommandUtils . GetEnvVar ( EnvVarNames . BuildRootP4 ) ;
ClientRoot = CommandUtils . GetEnvVar ( EnvVarNames . ClientRoot ) ;
if ( String . IsNullOrEmpty ( Client ) | | String . IsNullOrEmpty ( Branch ) | | String . IsNullOrEmpty ( ClientRoot ) )
2014-03-14 14:13:41 -04:00
{
2018-10-11 10:23:11 -04:00
// Create a connection using the current setting
2017-08-31 12:08:38 -04:00
P4Connection DefaultConnection = new P4Connection ( User : User , Client : null , ServerAndPort : ServerAndPort ) ;
2018-10-11 10:23:11 -04:00
// Get the client info
P4ClientInfo ThisClient ;
if ( String . IsNullOrEmpty ( Client ) )
{
2019-01-18 21:56:18 -05:00
string HostName = System . Net . Dns . GetHostName ( ) ;
ThisClient = DetectClient ( DefaultConnection , User , HostName , CmdEnv . UATExe ) ;
2018-10-11 10:23:11 -04:00
Log . TraceInformation ( "Using user {0} clientspec {1} {2}" , User , ThisClient . Name , ThisClient . RootPath ) ;
Client = ThisClient . Name ;
CommandUtils . SetEnvVar ( EnvVarNames . Client , Client ) ;
}
else
{
ThisClient = DefaultConnection . GetClientInfo ( Client ) ;
}
2017-08-31 12:08:38 -04:00
2018-10-11 10:23:11 -04:00
// Detect the root paths
2017-08-31 12:08:38 -04:00
if ( String . IsNullOrEmpty ( Branch ) | | String . IsNullOrEmpty ( ClientRoot ) )
2014-03-14 14:13:41 -04:00
{
2018-10-11 10:23:11 -04:00
P4Connection ClientConnection = new P4Connection ( User : User , Client : ThisClient . Name , ServerAndPort : ServerAndPort ) ;
string BranchPath ;
string ClientRootPath ;
DetectRootPaths ( ClientConnection , CmdEnv . LocalRoot , ThisClient , out BranchPath , out ClientRootPath ) ;
if ( String . IsNullOrEmpty ( Branch ) )
{
Branch = BranchPath ;
CommandUtils . SetEnvVar ( EnvVarNames . BuildRootP4 , Branch ) ;
}
if ( String . IsNullOrEmpty ( ClientRoot ) )
{
ClientRoot = ClientRootPath ;
CommandUtils . SetEnvVar ( EnvVarNames . ClientRoot , ClientRootPath ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2017-08-31 12:08:38 -04:00
// We expect the build root to not end with a path separator
if ( Branch . EndsWith ( "/" ) )
{
Branch = Branch . TrimEnd ( '/' ) ;
CommandUtils . SetEnvVar ( EnvVarNames . BuildRootP4 , Branch ) ;
}
2014-03-14 14:13:41 -04:00
2017-08-31 12:08:38 -04:00
// Set the current changelist
string ChangelistString = CommandUtils . GetEnvVar ( EnvVarNames . Changelist , null ) ;
if ( String . IsNullOrEmpty ( ChangelistString ) & & CommandUtils . P4CLRequired )
{
P4Connection Connection = new P4Connection ( User , Client , ServerAndPort ) ;
ChangelistString = DetectCurrentCL ( Connection , ClientRoot ) ;
CommandUtils . SetEnvVar ( EnvVarNames . Changelist , ChangelistString ) ;
}
if ( ! String . IsNullOrEmpty ( ChangelistString ) )
{
Changelist = int . Parse ( ChangelistString ) ;
}
2017-03-14 15:48:33 -04:00
2017-08-31 12:08:38 -04:00
// Set the current code changelist
string CodeChangelistString = CommandUtils . GetEnvVar ( EnvVarNames . CodeChangelist ) ;
if ( String . IsNullOrEmpty ( CodeChangelistString ) & & CommandUtils . P4CLRequired )
{
P4Connection Connection = new P4Connection ( User , Client , ServerAndPort ) ;
CodeChangelistString = DetectCurrentCodeCL ( Connection , ClientRoot ) ;
CommandUtils . SetEnvVar ( EnvVarNames . CodeChangelist , CodeChangelistString ) ;
}
if ( ! String . IsNullOrEmpty ( CodeChangelistString ) )
{
CodeChangelist = int . Parse ( CodeChangelistString ) ;
}
// Set the standard environment variables based on the values we've found
CommandUtils . SetEnvVar ( "P4PORT" , ServerAndPort ) ;
CommandUtils . SetEnvVar ( "P4USER" , User ) ;
CommandUtils . SetEnvVar ( "P4CLIENT" , Client ) ;
// Write a summary of the settings to the output window
2017-07-21 12:42:36 -04:00
if ( ! CommandUtils . CmdEnv . IsChildInstance )
{
Log . TraceInformation ( "Detected Perforce Settings:" ) ;
2017-08-31 12:08:38 -04:00
Log . TraceInformation ( " Server: {0}" , ServerAndPort ) ;
Log . TraceInformation ( " User: {0}" , User ) ;
Log . TraceInformation ( " Client: {0}" , Client ) ;
Log . TraceInformation ( " Branch: {0}" , Branch ) ;
2017-09-01 18:13:21 -04:00
if ( ChangelistInternal ! = - 1 )
{
Log . TraceInformation ( " Last Change: {0}" , Changelist ) ;
}
if ( CodeChangelistInternal ! = - 1 )
{
Log . TraceInformation ( " Last Code Change: {0}" , CodeChangelist ) ;
}
2017-07-21 12:42:36 -04:00
}
2017-03-14 15:48:33 -04:00
2017-08-31 12:08:38 -04:00
// Write all the environment variables to the log
2017-03-14 15:48:33 -04:00
Log . TraceLog ( "Perforce Environment Variables:" ) ;
2017-08-31 12:08:38 -04:00
Log . TraceLog ( " {0}={1}" , EnvVarNames . P4Port , InternalUtils . GetEnvironmentVariable ( EnvVarNames . P4Port , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . User , InternalUtils . GetEnvironmentVariable ( EnvVarNames . User , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . Client , InternalUtils . GetEnvironmentVariable ( EnvVarNames . Client , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . BuildRootP4 , InternalUtils . GetEnvironmentVariable ( EnvVarNames . BuildRootP4 , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . BuildRootEscaped , InternalUtils . GetEnvironmentVariable ( EnvVarNames . BuildRootEscaped , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . ClientRoot , InternalUtils . GetEnvironmentVariable ( EnvVarNames . ClientRoot , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . Changelist , InternalUtils . GetEnvironmentVariable ( EnvVarNames . Changelist , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , EnvVarNames . CodeChangelist , InternalUtils . GetEnvironmentVariable ( EnvVarNames . CodeChangelist , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , "P4PORT" , InternalUtils . GetEnvironmentVariable ( "P4PORT" , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , "P4USER" , InternalUtils . GetEnvironmentVariable ( "P4USER" , "" , true ) ) ;
Log . TraceLog ( " {0}={1}" , "P4CLIENT" , InternalUtils . GetEnvironmentVariable ( "P4CLIENT" , "" , true ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 20:07:00 -04:00
2017-08-31 12:08:38 -04:00
/// <summary>
/// Attempts to detect source control server address from environment variables.
/// </summary>
/// <returns>Source control server address.</returns>
private static string DetectP4Port ( )
2014-04-23 20:07:00 -04:00
{
2019-10-11 15:33:31 -04:00
string P4Port = null ;
2017-08-31 12:08:38 -04:00
// If it's not set, spawn Perforce to get the current server port setting
IProcessResult Result = CommandUtils . Run ( HostPlatform . Current . P4Exe , "set P4PORT" , null , CommandUtils . ERunOptions . NoLoggingOfRunCommand ) ;
if ( Result . ExitCode = = 0 )
2014-04-23 20:07:00 -04:00
{
2017-08-31 12:08:38 -04:00
const string KeyName = "P4PORT=" ;
if ( Result . Output . StartsWith ( KeyName ) )
{
2017-12-12 18:32:45 -05:00
int LastIdx = Result . Output . IndexOfAny ( new char [ ] { ' ' , '\n' , '\r' } ) ;
2017-08-31 12:08:38 -04:00
if ( LastIdx = = - 1 )
{
LastIdx = Result . Output . Length ;
}
P4Port = Result . Output . Substring ( KeyName . Length , LastIdx - KeyName . Length ) ;
}
2014-04-23 20:07:00 -04:00
}
2017-08-31 12:08:38 -04:00
// Otherwise fallback to the uebp variables, or the default
if ( String . IsNullOrEmpty ( P4Port ) )
2014-04-23 20:07:00 -04:00
{
2017-08-31 12:08:38 -04:00
Log . TraceWarning ( "P4PORT is not set. Using perforce:1666" ) ;
P4Port = "perforce:1666" ;
2014-04-23 20:07:00 -04:00
}
2017-08-31 12:08:38 -04:00
return P4Port ;
}
2014-04-23 20:07:00 -04:00
2017-08-31 12:08:38 -04:00
/// <summary>
/// Detects current user name.
/// </summary>
/// <returns></returns>
private static string DetectUserName ( P4Connection Connection )
{
var UserName = String . Empty ;
var P4Result = Connection . P4 ( "info" , AllowSpew : false ) ;
if ( P4Result . ExitCode ! = 0 )
2014-04-23 20:07:00 -04:00
{
2017-08-31 12:08:38 -04:00
throw new AutomationException ( "Perforce command failed: {0}. Please make sure your P4PORT or {1} is set properly." , P4Result . Output , EnvVarNames . P4Port ) ;
2014-04-23 20:07:00 -04:00
}
2017-08-31 12:08:38 -04:00
// Retrieve the P4 user name
var Tags = Connection . ParseTaggedP4Output ( P4Result . Output ) ;
if ( ! Tags . TryGetValue ( "User name" , out UserName ) | | String . IsNullOrEmpty ( UserName ) )
{
if ( ! String . IsNullOrEmpty ( UserName ) )
{
Log . TraceWarning ( "Unable to retrieve perforce user name. Trying to fall back to {0} which is set to {1}." , EnvVarNames . User , UserName ) ;
}
else
{
throw new AutomationException ( "Failed to retrieve user name." ) ;
}
}
return UserName ;
}
/// <summary>
/// Detects a workspace given the current user name, host name and depot path.
/// </summary>
/// <param name="UserName">User name</param>
/// <param name="HostName">Host</param>
/// <param name="UATLocation">Path to UAT exe, this will be checked agains the root path.</param>
/// <returns>Client to use.</returns>
private static P4ClientInfo DetectClient ( P4Connection Connection , string UserName , string HostName , string UATLocation )
{
CommandUtils . LogVerbose ( "uebp_CLIENT not set, detecting current client..." ) ;
var MatchingClients = new List < P4ClientInfo > ( ) ;
P4ClientInfo [ ] P4Clients = Connection . GetClientsForUser ( UserName , UATLocation ) ;
foreach ( var Client in P4Clients )
{
if ( ! String . IsNullOrEmpty ( Client . Host ) & & String . Compare ( Client . Host , HostName , true ) ! = 0 )
{
Log . TraceInformation ( "Rejecting client because of different Host {0} \"{1}\" != \"{2}\"" , Client . Name , Client . Host , HostName ) ;
continue ;
}
MatchingClients . Add ( Client ) ;
}
P4ClientInfo ClientToUse = null ;
if ( MatchingClients . Count = = 0 )
{
throw new AutomationException ( "No matching clientspecs found!" ) ;
}
else if ( MatchingClients . Count = = 1 )
{
ClientToUse = MatchingClients [ 0 ] ;
}
else
{
// We may have empty host clients here, so pick the first non-empty one if possible
foreach ( var Client in MatchingClients )
{
if ( ! String . IsNullOrEmpty ( Client . Host ) & & String . Compare ( Client . Host , HostName , true ) = = 0 )
{
ClientToUse = Client ;
break ;
}
}
if ( ClientToUse = = null )
{
Log . TraceWarning ( "{0} clients found that match the current host and root path. The most recently accessed client will be used." , MatchingClients . Count ) ;
ClientToUse = GetMostRecentClient ( MatchingClients ) ;
}
}
return ClientToUse ;
}
/// <summary>
/// Given a list of clients with the same owner and root path, tries to find the most recently accessed one.
/// </summary>
/// <param name="Clients">List of clients with the same owner and path.</param>
/// <returns>The most recent client from the list.</returns>
private static P4ClientInfo GetMostRecentClient ( List < P4ClientInfo > Clients )
{
Log . TraceVerbose ( "Detecting the most recent client." ) ;
P4ClientInfo MostRecentClient = null ;
var MostRecentAccessTime = DateTime . MinValue ;
foreach ( var ClientInfo in Clients )
{
if ( ClientInfo . Access . Ticks > MostRecentAccessTime . Ticks )
{
MostRecentAccessTime = ClientInfo . Access ;
MostRecentClient = ClientInfo ;
}
}
if ( MostRecentClient = = null )
{
throw new AutomationException ( "Failed to determine the most recent client in {0}" , Clients [ 0 ] . RootPath ) ;
}
return MostRecentClient ;
}
/// <summary>
/// Detects the current changelist the workspace is synced to.
/// </summary>
/// <param name="ClientRootPath">Workspace path.</param>
/// <returns>Changelist number as a string.</returns>
private static string DetectCurrentCL ( P4Connection Connection , string ClientRootPath )
{
CommandUtils . LogVerbose ( "uebp_CL not set, detecting 'have' CL..." ) ;
// Retrieve the current changelist
2018-08-21 13:37:48 -04:00
IProcessResult P4Result = Connection . P4 ( "changes -m 1 " + CommandUtils . CombinePaths ( PathSeparator . Depot , ClientRootPath , "/...#have" ) , AllowSpew : false ) ;
string [ ] CLTokens = P4Result . Output . Split ( new char [ ] { ' ' } , StringSplitOptions . RemoveEmptyEntries ) ;
if ( CLTokens . Length = = 0 )
2017-08-31 12:08:38 -04:00
{
2018-08-21 13:37:48 -04:00
throw new AutomationException ( "Unable to find current changelist (no output from 'p4 changes' command)" ) ;
2017-08-31 12:08:38 -04:00
}
2018-08-21 13:37:48 -04:00
string CLString = CLTokens [ 1 ] ;
int CL ;
if ( ! Int32 . TryParse ( CLString , out CL ) | | CLString ! = CL . ToString ( ) )
{
throw new AutomationException ( "Unable to parse current changelist from Perforce output:\n{0}" , P4Result . Output ) ;
}
2017-08-31 12:08:38 -04:00
return CLString ;
}
/// <summary>
/// Detects the current code changelist the workspace is synced to.
/// </summary>
/// <param name="ClientRootPath">Workspace path.</param>
/// <returns>Changelist number as a string.</returns>
private static string DetectCurrentCodeCL ( P4Connection Connection , string ClientRootPath )
{
CommandUtils . LogVerbose ( "uebp_CodeCL not set, detecting last code CL..." ) ;
2018-06-27 17:03:13 -04:00
// Retrieve the current changelist
StringBuilder P4Cmd = new StringBuilder ( "changes -m 1" ) ;
string [ ] CodeExtensions = { ".cs" , ".h" , ".cpp" , ".inl" , ".usf" , ".ush" , ".uproject" , ".uplugin" } ;
foreach ( string CodeExtension in CodeExtensions )
{
P4Cmd . AppendFormat ( " \"{0}/...{1}#have\"" , CommandUtils . CombinePaths ( PathSeparator . Depot , ClientRootPath ) , CodeExtension ) ;
}
IProcessResult P4Result = Connection . P4 ( P4Cmd . ToString ( ) , AllowSpew : false ) ;
2017-08-31 12:08:38 -04:00
// Loop through all the lines of the output. Even though we requested one result, we'll get one for each search pattern.
int CL = 0 ;
foreach ( string Line in P4Result . Output . Split ( '\n' ) )
{
string [ ] Tokens = Line . Trim ( ) . Split ( new char [ ] { ' ' } , StringSplitOptions . RemoveEmptyEntries ) ;
if ( Tokens . Length > = 2 )
{
int LineCL = Int32 . Parse ( Tokens [ 1 ] ) ;
CL = Math . Max ( CL , LineCL ) ;
}
}
return CL . ToString ( ) ;
}
/// <summary>
/// Detects root paths for the specified client.
/// </summary>
/// <param name="UATLocation">AutomationTool.exe location</param>
/// <param name="ThisClient">Client to detect the root paths for</param>
/// <param name="BuildRootPath">Build root</param>
/// <param name="LocalRootPath">Local root</param>
/// <param name="ClientRootPath">Client root</param>
private static void DetectRootPaths ( P4Connection Connection , string LocalRootPath , P4ClientInfo ThisClient , out string BuildRootPath , out string ClientRootPath )
{
if ( ! String . IsNullOrEmpty ( ThisClient . Stream ) )
{
BuildRootPath = ThisClient . Stream ;
ClientRootPath = String . Format ( "//{0}" , ThisClient . Name ) ;
}
else
{
// Figure out the build root
string KnownFilePathFromRoot = CommandEnvironment . KnownFileRelativeToRoot ;
string KnownLocalPath = CommandUtils . MakePathSafeToUseWithCommandLine ( CommandUtils . CombinePaths ( PathSeparator . Slash , LocalRootPath , KnownFilePathFromRoot ) ) ;
IProcessResult P4Result = Connection . P4 ( String . Format ( "files -m 1 {0}" , KnownLocalPath ) , AllowSpew : false ) ;
string KnownFileDepotMapping = P4Result . Output ;
// Get the build root
Log . TraceVerbose ( "Looking for {0} in {1}" , KnownFilePathFromRoot , KnownFileDepotMapping ) ;
int EndIdx = KnownFileDepotMapping . IndexOf ( KnownFilePathFromRoot , StringComparison . CurrentCultureIgnoreCase ) ;
if ( EndIdx < 0 )
{
EndIdx = KnownFileDepotMapping . IndexOf ( CommandUtils . ConvertSeparators ( PathSeparator . Slash , KnownFilePathFromRoot ) , StringComparison . CurrentCultureIgnoreCase ) ;
}
// Get the root path without the trailing path separator
BuildRootPath = KnownFileDepotMapping . Substring ( 0 , EndIdx - 1 ) ;
// Get the client root
if ( LocalRootPath . StartsWith ( CommandUtils . CombinePaths ( PathSeparator . Slash , ThisClient . RootPath , "/" ) , StringComparison . InvariantCultureIgnoreCase ) | | LocalRootPath = = CommandUtils . CombinePaths ( PathSeparator . Slash , ThisClient . RootPath ) )
{
2017-10-24 10:14:07 -04:00
ClientRootPath = CommandUtils . CombinePaths ( PathSeparator . Depot , String . Format ( "//{0}" , ThisClient . Name ) , LocalRootPath . Substring ( ThisClient . RootPath . Length ) ) ;
2017-08-31 12:08:38 -04:00
}
else
{
throw new AutomationException ( "LocalRootPath ({0}) does not start with the client root path ({1})" , LocalRootPath , ThisClient . RootPath ) ;
}
}
2014-04-23 20:07:00 -04:00
}
2014-03-14 14:13:41 -04:00
}
}