// Called by P4API on "change -i" command. OutBuffer is filled with changelist specification text void InputData(StrBuf* OutBuffer, Error* OutError) { #if USE_P4_API FString OutputDesc; OutputDesc += TEXT("Change:\tnew\n\n"); OutputDesc += TEXT("Client:\t"); OutputDesc += TO_TCHAR(P4Client.GetClient().Text(), bIsUnicodeServer); OutputDesc += TEXT("\n\n"); OutputDesc += TEXT("User:\t"); OutputDesc += TO_TCHAR(P4Client.GetUser().Text(), bIsUnicodeServer); OutputDesc += TEXT("\n\n"); OutputDesc += TEXT("Status:\tnew\n\n"); OutputDesc += TEXT("Description:\n"); { TArray<FString> DescLines; Description.ToString().ParseIntoArray(DescLines, TEXT("\n"), false); for (const FString& DescLine : DescLines) { OutputDesc += TEXT("\t"); OutputDesc += DescLine; OutputDesc += TEXT("\n"); } } OutputDesc += TEXT("\n"); OutputDesc += TEXT("Files:\n\n"); OutBuffer->Append(FROM_TCHAR(*OutputDesc, bIsUnicodeServer)); #endif }
// Called by P4API on "change -i" command. OutBuffer is filled with changelist specification text void InputData(StrBuf* OutBuffer, Error* OutError) { FString OutputDesc; OutputDesc += TEXT("Change:\tnew\n\n"); OutputDesc += TEXT("Client:\t"); OutputDesc += TO_TCHAR(P4Client.GetClient().Text(), bIsUnicodeServer); OutputDesc += TEXT("\n\n"); OutputDesc += TEXT("User:\t"); OutputDesc += TO_TCHAR(P4Client.GetUser().Text(), bIsUnicodeServer); OutputDesc += "\n\n"; OutputDesc += "Status:\tnew\n\n"; OutputDesc += "Description:\n\t"; OutputDesc += Description; OutputDesc += TEXT("\n\n"); OutputDesc += TEXT("Files:\n\n"); OutBuffer->Append(FROM_TCHAR(*OutputDesc, bIsUnicodeServer)); }
void FPerforceConnection::EstablishConnection(const FPerforceConnectionInfo& InConnectionInfo) { #if USE_P4_API // Verify Input. ServerName and UserName are required if ( InConnectionInfo.Port.IsEmpty() || InConnectionInfo.UserName.IsEmpty() ) { return; } //Connection assumed successful bEstablishedConnection = true; UE_LOG(LogSourceControl, Verbose, TEXT("Attempting P4 connection: %s/%s"), *InConnectionInfo.Port, *InConnectionInfo.UserName); P4Client.SetProtocol("tag", ""); P4Client.SetProtocol("enableStreams", ""); //Set configuration based params P4Client.SetPort(TCHAR_TO_ANSI(*InConnectionInfo.Port)); Error P4Error; if(InConnectionInfo.Password.Len() > 0) { UE_LOG(LogSourceControl, Verbose, TEXT(" ... applying password" )); P4Client.DefinePassword(TCHAR_TO_ANSI(*InConnectionInfo.Password), &P4Error); if(P4Error.Test()) { StrBuf ErrorMessage; P4Error.Fmt(&ErrorMessage); UE_LOG(LogSourceControl, Error, TEXT("P4ERROR: Could not set password.")); UE_LOG(LogSourceControl, Error, TEXT("%s"), ANSI_TO_TCHAR(ErrorMessage.Text())); } } if(InConnectionInfo.HostOverride.Len() > 0) { UE_LOG(LogSourceControl, Verbose, TEXT(" ... overriding host" )); P4Client.SetHost(TCHAR_TO_ANSI(*InConnectionInfo.HostOverride)); } UE_LOG(LogSourceControl, Verbose, TEXT(" ... connecting" )); //execute the connection to perforce using the above settings P4Client.Init(&P4Error); //ensure the connection is valid UE_LOG(LogSourceControl, Verbose, TEXT(" ... validating connection" )); if (P4Error.Test()) { bEstablishedConnection = false; StrBuf ErrorMessage; P4Error.Fmt(&ErrorMessage); UE_LOG(LogSourceControl, Error, TEXT("P4ERROR: Invalid connection to server.")); UE_LOG(LogSourceControl, Error, TEXT("%s"), ANSI_TO_TCHAR(ErrorMessage.Text())); } else { TArray<FString> Params; TArray<FText> ErrorMessages; FP4RecordSet Records; bool bConnectionDropped = false; const bool bStandardDebugOutput = false; const bool bAllowRetry = true; UE_LOG(LogSourceControl, Verbose, TEXT(" ... checking unicode status" )); if (RunCommand(TEXT("info"), Params, Records, ErrorMessages, FOnIsCancelled(), bConnectionDropped, bStandardDebugOutput, bAllowRetry)) { // Get character encoding bIsUnicode = Records[0].Find(TEXT("unicode")) != NULL; if(bIsUnicode) { P4Client.SetTrans(CharSetApi::UTF_8); UE_LOG(LogSourceControl, Verbose, TEXT(" server is unicode" )); } // Now we know our unicode status we can gather the client root P4Client.SetUser(FROM_TCHAR(*InConnectionInfo.UserName, bIsUnicode)); if(InConnectionInfo.Password.Len() > 0) { Login(InConnectionInfo); } if (InConnectionInfo.Ticket.Len()) { P4Client.SetPassword(FROM_TCHAR(*InConnectionInfo.Ticket, bIsUnicode)); } if (InConnectionInfo.Workspace.Len()) { P4Client.SetClient(FROM_TCHAR(*InConnectionInfo.Workspace, bIsUnicode)); } P4Client.SetCwd(FROM_TCHAR(*FPaths::RootDir(), bIsUnicode)); // Gather the client root UE_LOG(LogSourceControl, Verbose, TEXT(" ... getting info" )); bConnectionDropped = false; if (RunCommand(TEXT("info"), Params, Records, ErrorMessages, FOnIsCancelled(), bConnectionDropped, bStandardDebugOutput, bAllowRetry)) { UE_LOG(LogSourceControl, Verbose, TEXT(" ... getting clientroot" )); ClientRoot = Records[0](TEXT("clientRoot")); //make sure all slashes point the same way ClientRoot = ClientRoot.Replace(TEXT("\\"), TEXT("/")); } } } #endif }
bool FPerforceConnection::RunCommand(const FString& InCommand, const TArray<FString>& InParameters, FP4RecordSet& OutRecordSet, TArray<FText>& OutErrorMessage, FOnIsCancelled InIsCancelled, bool& OutConnectionDropped, const bool bInStandardDebugOutput, const bool bInAllowRetry) { #if USE_P4_API if (!bEstablishedConnection) { return false; } FString FullCommand = InCommand; // Prepare arguments int32 ArgC = InParameters.Num(); UTF8CHAR** ArgV = new UTF8CHAR*[ArgC]; for (int32 Index = 0; Index < ArgC; Index++) { if(bIsUnicode) { FTCHARToUTF8 UTF8String(*InParameters[Index]); ArgV[Index] = new UTF8CHAR[UTF8String.Length() + 1]; FMemory::Memcpy(ArgV[Index], UTF8String.Get(), UTF8String.Length() + 1); } else { ArgV[Index] = new UTF8CHAR[InParameters[Index].Len() + 1]; FMemory::Memcpy(ArgV[Index], TCHAR_TO_ANSI(*InParameters[Index]), InParameters[Index].Len() + 1); } if (bInStandardDebugOutput) { FullCommand += TEXT(" "); FullCommand += InParameters[Index]; } } if (bInStandardDebugOutput) { UE_LOG( LogSourceControl, Log, TEXT("Attempting 'p4 %s'"), *FullCommand ); } double SCCStartTime = FPlatformTime::Seconds(); P4Client.SetArgv(ArgC, (char**)ArgV); FP4KeepAlive KeepAlive(InIsCancelled); P4Client.SetBreak(&KeepAlive); OutRecordSet.Reset(); FP4ClientUser User(OutRecordSet, bIsUnicode, OutErrorMessage); P4Client.Run(FROM_TCHAR(*InCommand, bIsUnicode), &User); if ( P4Client.Dropped() ) { OutConnectionDropped = true; } P4Client.SetBreak(NULL); // Free arguments for (int32 Index = 0; Index < ArgC; Index++) { delete [] ArgV[Index]; } delete [] ArgV; if (bInStandardDebugOutput) { UE_LOG( LogSourceControl, VeryVerbose, TEXT("P4 execution time: %0.4f seconds. Command: %s"), FPlatformTime::Seconds() - SCCStartTime, *FullCommand ); } #endif return OutRecordSet.Num() > 0; }
bool FPerforceConnection::EnsureValidConnection(FString& InOutServerName, FString& InOutUserName, FString& InOutWorkspaceName, const FPerforceConnectionInfo& InConnectionInfo) { bool bIsUnicodeServer = false; bool bConnectionOK = false; #if USE_P4_API FMessageLog SourceControlLog("SourceControl"); FString NewServerName = InOutServerName; FString NewUserName = InOutUserName; FString NewClientSpecName = InOutWorkspaceName; ClientApi TestP4; TestP4.SetProtocol("tag", ""); TestP4.SetProtocol("enableStreams", ""); if (NewServerName.Len() && NewUserName.Len() && NewClientSpecName.Len()) { //attempt connection with given settings TestP4.SetPort(TCHAR_TO_ANSI(*NewServerName)); if(InConnectionInfo.Password.Len() > 0) { TestP4.SetPassword(TCHAR_TO_ANSI(*InConnectionInfo.Password)); } if(InConnectionInfo.HostOverride.Len() > 0) { TestP4.SetHost(TCHAR_TO_ANSI(*InConnectionInfo.HostOverride)); } } Error P4Error; TestP4.Init(&P4Error); bConnectionOK = !P4Error.Test(); if (!bConnectionOK) { //Connection FAILED StrBuf ErrorMessage; P4Error.Fmt(&ErrorMessage); SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Failed to connect to source control provider.")); SourceControlLog.Error(FText::FromString(ANSI_TO_TCHAR(ErrorMessage.Text()))); FFormatNamedArguments Arguments; Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) ); Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) ); Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) ); Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) ); SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments)); } // run an info command to determine unicode status if(bConnectionOK) { TArray<FText> ErrorMessages; bConnectionOK = CheckUnicodeStatus(TestP4, bIsUnicodeServer, ErrorMessages); if(!bConnectionOK) { SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Could not determine server unicode status.")); SourceControlLog.Error(ErrorMessages.Num() > 0 ? ErrorMessages[0] : LOCTEXT("P4ErrorConnection_Unknown error", "Unknown error")); FFormatNamedArguments Arguments; Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) ); Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) ); Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) ); Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) ); SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments)); } else { if(bIsUnicodeServer) { // set translation mode. From here onwards we need to use UTF8 when using text args TestP4.SetTrans(CharSetApi::UTF_8); } // now we have determined unicode status, we can set the values that can be specified in non-ansi characters TestP4.SetCwd(FROM_TCHAR(*FPaths::RootDir(), bIsUnicodeServer)); TestP4.SetUser(FROM_TCHAR(*NewUserName, bIsUnicodeServer)); TestP4.SetClient(FROM_TCHAR(*NewClientSpecName, bIsUnicodeServer)); if(InConnectionInfo.Ticket.Len()) { TestP4.SetPassword(FROM_TCHAR(*InConnectionInfo.Ticket, bIsUnicodeServer)); } } } if (bConnectionOK) { // If a client spec was not specified, attempt to auto-detect it here. If the detection is not successful, neither is this connection since we need a client spec. if ( NewClientSpecName.IsEmpty() ) { FPerforceConnectionInfo AutoCredentials = InConnectionInfo; AutoCredentials.Port = TO_TCHAR(TestP4.GetPort().Text(), bIsUnicodeServer); AutoCredentials.UserName = TO_TCHAR(TestP4.GetUser().Text(), bIsUnicodeServer); bConnectionOK = FPerforceConnection::AutoDetectWorkspace(AutoCredentials, NewClientSpecName); if ( bConnectionOK ) { TestP4.SetClient(FROM_TCHAR(*NewClientSpecName, bIsUnicodeServer)); } } } if (bConnectionOK) { TArray<FText> ErrorMessages; bConnectionOK = TestConnection(TestP4, NewClientSpecName, bIsUnicodeServer, ErrorMessages); if (!bConnectionOK) { //Login FAILED SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Failed to connect to source control provider.")); SourceControlLog.Error(ErrorMessages.Num() > 0 ? ErrorMessages[0] : LOCTEXT("P4ErrorConnection_InvalidWorkspace", "Invalid workspace")); FFormatNamedArguments Arguments; Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) ); Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) ); Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) ); Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) ); SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments)); } } //whether successful or not, disconnect to clean up TestP4.Final(&P4Error); if (bConnectionOK && P4Error.Test()) { //Disconnect FAILED bConnectionOK = false; StrBuf ErrorMessage; P4Error.Fmt(&ErrorMessage); SourceControlLog.Error(LOCTEXT("P4ErrorFailedDisconnect", "P4ERROR: Failed to disconnect from Server.")); SourceControlLog.Error(FText::FromString(TO_TCHAR(ErrorMessage.Text(), bIsUnicodeServer))); } //if never specified, take the default connection values if (NewServerName.Len() == 0) { NewServerName = TO_TCHAR(TestP4.GetPort().Text(), bIsUnicodeServer); } if (NewUserName.Len() == 0) { NewUserName = TO_TCHAR(TestP4.GetUser().Text(), bIsUnicodeServer); } if (NewClientSpecName.Len() == 0) { NewClientSpecName = TO_TCHAR(TestP4.GetClient().Text(), bIsUnicodeServer); if (NewClientSpecName == TO_TCHAR(TestP4.GetHost().Text(), bIsUnicodeServer)) { // If the client spec name is the same as host name, assume P4 couldn't get the actual // spec name for this host and let GetPerforceLogin() try to find a proper one. bConnectionOK = false; } } if (bConnectionOK) { InOutServerName = NewServerName; InOutUserName = NewUserName; InOutWorkspaceName = NewClientSpecName; } #endif return bConnectionOK; }
void Prompt( const StrPtr& InMessage, StrBuf& OutPrompt, int NoEcho, Error* InError ) { #if USE_P4_API OutPrompt.Set(FROM_TCHAR(*Password, bIsUnicodeServer)); #endif }