Files
UnrealEngineUWP/Engine/Source/Developer/SourceControl/Private/ISourceControlProvider.cpp
paul chipchase 4fa806cf66 Add a new initialization path to ISourceControlProvider allowing the caller to customize the initialization logic and retrieve more info about the initialization itself.
#rb Per.Larsson

### ISourceControlProvider
- Add a new ISourceControlProvider::Init overload that returns a struct (FInitResult) and takes a bitfield of flags (EInitFlags) so that we can more easily extend the initialization in future and return things to the caller.
- If a provider does not implement the new overload we fall-back to the original. This will be removed once all providers support the new path.

### PerforceSourceControlProvider
- Support the new init options via FPerforceConnection::EnsureValidConnection and update places that call it.

### FPerforceConnection
- Update ::AutoDetectWorkspace to return errors to the caller rather than handle its own logging.
- ::TestLoginConnection and ::TestClientConnection no longer calls FPerforceSourceControlProvider::SetLastErrors, this will be done at a higher level.
- ::AutoDetectWorkspace still does its own logging which will be fixed in a future update, it does however return its errors to the caller.
- Split the implementation of ::EnsureValidConnection to a stand alone internal function, the original function now handles and consolidates error handling.
-- Changed the logic to early out of failure rather than constantly checking a boolean all the way down.
-- Tried to remove the need for FPerforceSourceControlProvider to be passed in but a few places still require it.
-- Fixed our handling of the P4PORT value so that we can at least report problems if the address uses unicode characters. I have not yet tested if we can actually connect to such an address. We no longer use the servers unicode setting to decide the port strings encoding as it is not affected by the server settings.
-- Each error encountered should now record a localized error that we expect the user to be able to react to, then an array of errors from the API itself.
-- Once the internal code has run we will do a pass on all errors (if any) and strip any whitespace at the end (p4 tends to end error messages with newline characters) and then add a final entry to the additional errors detailing the settings at the point of failure. This was mostly being done before but is now enforced for every error.
-- No longer log the ticket, although the workflow to allow the user to supply one is not common we still probably don't want to save that to log files.

[CL 26952104 by paul chipchase in ue5-main branch]
2023-08-09 07:27:34 -04:00

148 lines
6.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ISourceControlProvider.h"
#include "SourceControlHelpers.h"
#include "SourceControlOperations.h"
#define LOCTEXT_NAMESPACE "ISourceControlProvider"
ISourceControlProvider::FInitResult ISourceControlProvider::Init(EInitFlags Flags)
{
// TODO: This implementation is for compatibility. Once all providers have their own
// implementation it should be removed.
const bool bForceConnection = EnumHasAnyFlags(Flags, EInitFlags::AttemptConnection);
Init(bForceConnection);
FInitResult Result;
Result.bIsAvailable = IsAvailable();
return Result;
}
ECommandResult::Type ISourceControlProvider::Login(const FString& InPassword, EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
TSharedRef<FConnect, ESPMode::ThreadSafe> ConnectOperation = ISourceControlOperation::Create<FConnect>();
ConnectOperation->SetPassword(InPassword);
return Execute(ConnectOperation, InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::GetState(const TArray<UPackage*>& InPackages, TArray<FSourceControlStateRef>& OutState, EStateCacheUsage::Type InStateCacheUsage)
{
TArray<FString> Files = SourceControlHelpers::PackageFilenames(InPackages);
return GetState(Files, OutState, InStateCacheUsage);
}
FSourceControlStatePtr ISourceControlProvider::GetState(const UPackage* InPackage, EStateCacheUsage::Type InStateCacheUsage)
{
return GetState(SourceControlHelpers::PackageFilename(InPackage), InStateCacheUsage);
}
FSourceControlStatePtr ISourceControlProvider::GetState(const FString& InFile, EStateCacheUsage::Type InStateCacheUsage)
{
TArray< FSourceControlStateRef > States;
if (GetState( { InFile }, States, InStateCacheUsage) == ECommandResult::Succeeded)
{
if (!States.IsEmpty())
{
FSourceControlStateRef State = States[0];
return State;
}
}
return nullptr;
}
FSourceControlChangelistStatePtr ISourceControlProvider::GetState(const FSourceControlChangelistRef& InChangelist, EStateCacheUsage::Type InStateCacheUsage)
{
TArray< FSourceControlChangelistStateRef > States;
if (GetState( { InChangelist }, States, InStateCacheUsage) == ECommandResult::Succeeded)
{
if (!States.IsEmpty())
{
FSourceControlChangelistStatePtr State = States[0];
return State;
}
}
return nullptr;
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, const TArray<FString>& InFiles, EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
return Execute(InOperation, nullptr, InFiles, InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, const EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
return Execute(InOperation, nullptr, TArray<FString>(), InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, const UPackage* InPackage, const EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
return Execute(InOperation, SourceControlHelpers::PackageFilename(InPackage), InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, const FString& InFile, const EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
TArray<FString> FileArray;
if (!InFile.IsEmpty())
{
FileArray.Add(InFile);
}
return Execute(InOperation, FileArray, InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, const TArray<UPackage*>& InPackages, const EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
TArray<FString> FileArray = SourceControlHelpers::PackageFilenames(InPackages);
return Execute(InOperation, nullptr, FileArray, InConcurrency, InOperationCompleteDelegate);
}
ECommandResult::Type ISourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, FSourceControlChangelistPtr InChangelist, const EConcurrency::Type InConcurrency, const FSourceControlOperationComplete& InOperationCompleteDelegate)
{
return Execute(InOperation, InChangelist, TArray<FString>(), InConcurrency, InOperationCompleteDelegate);
}
TSharedPtr<class ISourceControlLabel> ISourceControlProvider::GetLabel(const FString& InLabelName) const
{
TArray< TSharedRef<class ISourceControlLabel> > Labels = GetLabels(InLabelName);
if (Labels.Num() > 0)
{
return Labels[0];
}
return nullptr;
}
bool ISourceControlProvider::TryToDownloadFileFromBackgroundThread(const TSharedRef<class FDownloadFile>& InOperation, const FString& InFile)
{
TArray<FString> FileArray;
FileArray.Add(InFile);
return TryToDownloadFileFromBackgroundThread(InOperation, FileArray);
}
bool ISourceControlProvider::TryToDownloadFileFromBackgroundThread(const TSharedRef<class FDownloadFile>& InOperation, const TArray<FString>& InFiles)
{
// TryToDownloadFileFromBackgroundThread is unsupported by this source control provider
FFormatNamedArguments Arguments;
Arguments.Add(TEXT("ProviderName"), FText::FromName(GetName()));
FText Message = FText::Format(LOCTEXT("UnsupportedOperationTryToDownloadFileFromBackgroundThread", "TryToDownloadFileFromBackgroundThread is not supported by revision control provider '{ProviderName}'"), Arguments);
InOperation->AddErrorMessge(Message);
return false;
}
ECommandResult::Type ISourceControlProvider::SwitchWorkspace(FStringView NewWorkspaceName, FSourceControlResultInfo& OutResultInfo, FString* OutOldWorkspaceName)
{
FFormatNamedArguments Arguments;
Arguments.Add(TEXT("ProviderName"), FText::FromName(GetName()));
FText Message = FText::Format(LOCTEXT("UnsupportedOperationSwitchWorkspace", "SwitchWorkspace is not supported by revision control provider '{ProviderName}'"), Arguments);
OutResultInfo.ErrorMessages.Add(Message);
return ECommandResult::Failed;
}
#undef LOCTEXT_NAMESPACE