You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown nick.penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2806454 on 2015/12/16 by Bob.Tellez #UE4 Getting crash reporting working again on linux servers. Since -Unattended is now being passed BEFORE the target folder, the cmd line parsing code was failing so now it parses tokens and switches in a more general way. Also, diagnostics.txt had the incorrect case, since the d is supposed to be capitolized and the crash report processor is case sensitive. #rb Ben.Zeigler #codereview Dmitry.Rekman Change 2805502 on 2015/12/16 by Ben.Zeigler #UE4 Move ValidateEnumProperties into ValidateGeneratedClass, it was happening too early in the generation process so was being called at an invalid time. As a result of this ValidateEnumProperties will not be called correctly for compile on load blueprints, that issue is covered in UE-24569 #codereview mike.beach, bob.tellez Change 2805288 on 2015/12/16 by David.Nikdel #HTTP #HttpRetry - Add new Failed_ConnectionError code to EHttpRequestStatus to distinguish between connection errors and protocol errors. - Changed HTTP retry logic a little bit * If a response was received, retry on service-specific explicit HTTP codes (defaults to empty) * If a response was not received and we did not send a full request, automatically retry * If a response was not received and a request may have been sent, retry if the verb is GET or HEAD (should be idempotent) - Adjusted Curl/IOS/Mac/PS4/WinInet to try and distinguish Failed_ConnectionError where possible * Other systems will default to Failed which is ok (ConnectionError is an opportunistic categorization) * Opened a PS4 ticket to try to improve detection, but unfortunately there's no way (currently) to distinguish between send timeout, connection timeout, and receive timeout, the latter being the problematic case. - Removed the concept of global/default HTTP retry status codes. No system has enough knowledge to set those globally. * Individual requests still specify explicit "retryable" codes and McpServiceBase sets that on each request on a per-service basis #RB: Sam.Zamani #CodeReview: Sam.Zamani, Josh.Markiewicz, Alex.Fennell, Dmitry.Rekman, Sam.Spiro #Fixes: FORT-17804 Change 2803864 on 2015/12/15 by Bob.Tellez #UE4 Changed usage of !UE_SERVER to !IsRunningDedicatedServer in cases where we are preventing load attempts on UFonts. This is so running an editor build with -server works the same as running a cooked server. #rb Dmitry.Rekman #codereview Nick.Darnell Change 2803677 on 2015/12/15 by Billy.Bramer - Expose equality and inequality operators for gameplay attributes #rb Todd.Eckert Change 2802881 on 2015/12/14 by Bob.Tellez #UE4 InheritableComponentHandler no longer keeps records for components that we are no longer inheriting. #rb Phillip.Kavan, Maciej.Mroz #codereview Phillip.Kavan, Maciej.Mroz Change 2801636 on 2015/12/14 by Bob.Tellez #UE4 Returning package insert order for non-imports back to being after those of matching priorities unconditionally since this is what you want even when you are not using the asset registry to preload packages. #codereview Graeme.Thornton Change 2800400 on 2015/12/11 by Jonathan.Lindquist Submitting a new Pivot Painter Edition - now renders to textures - improved workflow - greater capabilities Change 2799579 on 2015/12/11 by John.Abercrombie [AUTOMERGE] Fixed EQS BP query wrappers getting GCed before wrapped query finishes #UE4 Fixes FORT-18649 - Patrols don't spawn consistently - The patrol blueprint was waiting (endlessly) for an EQS query to finish but because the wrapper could be GC-ed while the EQS query was running the delegate would never fire #rb me (this code was written by MieszkoZ) (removed code review for integration of Mieszko.Zielinski, Phil.Cole, Dominic.Barile) -------- Integrated using branch UE4-Fortnite-To-UE4-FortniteReleases/0.10 (reversed) of change#2799575 by John.Abercrombie on 2015/12/11 09:55:11. Change 2799018 on 2015/12/10 by Bob.Tellez #UE4 The asset registry tags stripped from cooked builds is now a blacklist by default that includes only the FiB tag. You can opt-in to using the whitelist by flipping the bUseAssetRegistryTagsWhitelistInsteadOfBlacklist flag. #rb Fred.Kimberley #codereview Peter.Knepley Change 2798926 on 2015/12/10 by Bob.Tellez #UE4 Removed some showflags from the list of "Fixed" showflags since they were actually in use at runtime in Fortnite in a scene capture. #jira FORT-18514 #codereview Martin.Mittring Change 2797758 on 2015/12/10 by Mark.Satterthwaite Defer calls to AUGraphUpdate into FCoreAudioDevice::UpdateHardware - this call will synchronise the calling thread with the CoreAudio thread/run-loop so that the CoreAudio graph is safe to modify and this may incur a significant stall. This means it is far more efficient to amortise the cost of all changes to the graph with a single call. To ensure correctness the audio format conversion components are cached and disposed of after the call to AUGraphUpdate so that any existing operations on the CoreAudio thread are completed prior to disposal. Change 2781204 on 2015/11/25 by Dmitry.Rekman Linux: use jemalloc by default if available. - Alleviates one of the reasons for player disconnect (FORT-18048), which was machines running OOM. #rb Bob.Tellez #codereview Bob.Tellez, Ben.Zeigler Change 2779398 on 2015/11/24 by Mark.Satterthwaite Switch the default graphics API on Mac back to OpenGL, but allow Metal to run with -metal (or -metalsm5 for experimental SM5 support).
451 lines
15 KiB
C++
451 lines
15 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SourceControlPrivatePCH.h"
|
|
#include "SourceControlHelpers.h"
|
|
#include "ISourceControlProvider.h"
|
|
#include "ISourceControlState.h"
|
|
#include "ISourceControlModule.h"
|
|
#include "ISourceControlLabel.h"
|
|
#include "ISourceControlRevision.h"
|
|
#include "CoreUObject.h"
|
|
#include "MessageLog.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "SourceControlHelpers"
|
|
|
|
namespace SourceControlHelpers
|
|
{
|
|
|
|
const FString& GetSettingsIni()
|
|
{
|
|
if(ISourceControlModule::Get().GetUseGlobalSettings())
|
|
{
|
|
return GetGlobalSettingsIni();
|
|
}
|
|
else
|
|
{
|
|
static FString SourceControlSettingsIni;
|
|
if(SourceControlSettingsIni.Len() == 0)
|
|
{
|
|
const FString SourceControlSettingsDir = FPaths::GeneratedConfigDir();
|
|
FConfigCacheIni::LoadGlobalIniFile(SourceControlSettingsIni, TEXT("SourceControlSettings"), NULL, false, false, true, *SourceControlSettingsDir);
|
|
}
|
|
return SourceControlSettingsIni;
|
|
}
|
|
}
|
|
|
|
const FString& GetGlobalSettingsIni()
|
|
{
|
|
static FString SourceControlGlobalSettingsIni;
|
|
if(SourceControlGlobalSettingsIni.Len() == 0)
|
|
{
|
|
const FString SourceControlSettingsDir = FPaths::EngineSavedDir() + TEXT("Config/");
|
|
FConfigCacheIni::LoadGlobalIniFile(SourceControlGlobalSettingsIni, TEXT("SourceControlSettings"), NULL, false, false, true, *SourceControlSettingsDir);
|
|
}
|
|
return SourceControlGlobalSettingsIni;
|
|
}
|
|
|
|
static FString PackageFilename_Internal( const FString& InPackageName )
|
|
{
|
|
FString Filename = InPackageName;
|
|
|
|
// Get the filename by finding it on disk first
|
|
if ( !FPackageName::DoesPackageExist(InPackageName, NULL, &Filename) )
|
|
{
|
|
// The package does not exist on disk, see if we can find it in memory and predict the file extension
|
|
// Only do this if the supplied package name is valid
|
|
const bool bIncludeReadOnlyRoots = false;
|
|
if ( FPackageName::IsValidLongPackageName(InPackageName, bIncludeReadOnlyRoots) )
|
|
{
|
|
UPackage* Package = FindPackage(NULL, *InPackageName);
|
|
if ( Package )
|
|
{
|
|
// This is a package in memory that has not yet been saved. Determine the extension and convert to a filename
|
|
const FString PackageExtension = Package->ContainsMap() ? FPackageName::GetMapPackageExtension() : FPackageName::GetAssetPackageExtension();
|
|
Filename = FPackageName::LongPackageNameToFilename(InPackageName, PackageExtension);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Filename;
|
|
}
|
|
|
|
FString PackageFilename( const FString& InPackageName )
|
|
{
|
|
return FPaths::ConvertRelativePathToFull(PackageFilename_Internal(InPackageName));
|
|
}
|
|
|
|
FString PackageFilename( const UPackage* InPackage )
|
|
{
|
|
FString Filename;
|
|
if(InPackage != NULL)
|
|
{
|
|
Filename = FPaths::ConvertRelativePathToFull(PackageFilename_Internal(InPackage->GetName()));
|
|
}
|
|
return Filename;
|
|
}
|
|
|
|
TArray<FString> PackageFilenames( const TArray<UPackage*>& InPackages )
|
|
{
|
|
TArray<FString> OutNames;
|
|
for (int32 PackageIndex = 0; PackageIndex < InPackages.Num(); PackageIndex++)
|
|
{
|
|
OutNames.Add(FPaths::ConvertRelativePathToFull(PackageFilename(InPackages[PackageIndex])));
|
|
}
|
|
|
|
return OutNames;
|
|
}
|
|
|
|
TArray<FString> PackageFilenames( const TArray<FString>& InPackageNames )
|
|
{
|
|
TArray<FString> OutNames;
|
|
for (int32 PackageIndex = 0; PackageIndex < InPackageNames.Num(); PackageIndex++)
|
|
{
|
|
OutNames.Add(FPaths::ConvertRelativePathToFull(PackageFilename_Internal(InPackageNames[PackageIndex])));
|
|
}
|
|
|
|
return OutNames;
|
|
}
|
|
|
|
TArray<FString> AbsoluteFilenames( const TArray<FString>& InFileNames )
|
|
{
|
|
TArray<FString> AbsoluteFiles;
|
|
for(const auto& FileName : InFileNames)
|
|
{
|
|
if(!FPaths::IsRelative(FileName))
|
|
{
|
|
AbsoluteFiles.Add(FileName);
|
|
}
|
|
else
|
|
{
|
|
AbsoluteFiles.Add(FPaths::ConvertRelativePathToFull(FileName));
|
|
}
|
|
}
|
|
|
|
return AbsoluteFiles;
|
|
}
|
|
|
|
void RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray<FString>& InFiles )
|
|
{
|
|
// Make sure we update the modified state of the files
|
|
TSharedRef<FUpdateStatus, ESPMode::ThreadSafe> UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>();
|
|
UpdateStatusOperation->SetUpdateModifiedState(true);
|
|
InProvider.Execute(UpdateStatusOperation, InFiles);
|
|
|
|
TArray<FString> UnchangedFiles;
|
|
TArray< TSharedRef<ISourceControlState, ESPMode::ThreadSafe> > OutStates;
|
|
InProvider.GetState(InFiles, OutStates, EStateCacheUsage::Use);
|
|
|
|
for(TArray< TSharedRef<ISourceControlState, ESPMode::ThreadSafe> >::TConstIterator It(OutStates); It; It++)
|
|
{
|
|
TSharedRef<ISourceControlState, ESPMode::ThreadSafe> SourceControlState = *It;
|
|
if(SourceControlState->IsCheckedOut() && !SourceControlState->IsModified())
|
|
{
|
|
UnchangedFiles.Add(SourceControlState->GetFilename());
|
|
}
|
|
}
|
|
|
|
if(UnchangedFiles.Num())
|
|
{
|
|
InProvider.Execute( ISourceControlOperation::Create<FRevert>(), UnchangedFiles );
|
|
}
|
|
}
|
|
|
|
bool AnnotateFile( ISourceControlProvider& InProvider, const FString& InLabel, const FString& InFile, TArray<FAnnotationLine>& OutLines )
|
|
{
|
|
TArray< TSharedRef<ISourceControlLabel> > Labels = InProvider.GetLabels( InLabel );
|
|
if(Labels.Num() > 0)
|
|
{
|
|
TSharedRef<ISourceControlLabel> Label = Labels[0];
|
|
TArray< TSharedRef<ISourceControlRevision, ESPMode::ThreadSafe> > Revisions;
|
|
Label->GetFileRevisions(InFile, Revisions);
|
|
if(Revisions.Num() > 0)
|
|
{
|
|
TSharedRef<ISourceControlRevision, ESPMode::ThreadSafe> Revision = Revisions[0];
|
|
if(Revision->GetAnnotated(OutLines))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier, const FString& InFile, TArray<FAnnotationLine>& OutLines )
|
|
{
|
|
TSharedRef<FUpdateStatus, ESPMode::ThreadSafe> UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>();
|
|
UpdateStatusOperation->SetUpdateHistory(true);
|
|
if(InProvider.Execute(UpdateStatusOperation, InFile) == ECommandResult::Succeeded)
|
|
{
|
|
FSourceControlStatePtr State = InProvider.GetState(InFile, EStateCacheUsage::Use);
|
|
if(State.IsValid())
|
|
{
|
|
for(int32 HistoryIndex = State->GetHistorySize() - 1; HistoryIndex >= 0; HistoryIndex--)
|
|
{
|
|
// check that the changelist corresponds to this revision - we assume history is in latest-first order
|
|
TSharedPtr<ISourceControlRevision, ESPMode::ThreadSafe> Revision = State->GetHistoryItem(HistoryIndex);
|
|
if(Revision.IsValid() && Revision->GetCheckInIdentifier() >= InCheckInIdentifier)
|
|
{
|
|
if(Revision->GetAnnotated(OutLines))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MarkFileForAdd( const FString& InFilePath )
|
|
{
|
|
if (InFilePath.IsEmpty())
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("UnspecifiedCheckoutFile", "Check out file not specified"));
|
|
return false;
|
|
}
|
|
|
|
if (!ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("SourceControlDisabled", "Source control is not enabled."));
|
|
return false;
|
|
}
|
|
|
|
if (!ISourceControlModule::Get().GetProvider().IsAvailable())
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("SourceControlServerUnavailable", "Source control server is currently not available."));
|
|
return false;
|
|
}
|
|
|
|
// mark for add now if needed
|
|
ISourceControlProvider& Provider = ISourceControlModule::Get().GetProvider();
|
|
FSourceControlStatePtr SourceControlState = Provider.GetState(InFilePath, EStateCacheUsage::Use);
|
|
if (!SourceControlState.IsValid())
|
|
{
|
|
// Improper or invalid SCC state
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add(TEXT("InFilePath"), FText::FromString(InFilePath));
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("CouldNotDetermineState", "Could not determine source control state of file '{InFilePath}'."), Arguments));
|
|
return false;
|
|
}
|
|
|
|
// add it if necessary
|
|
if (!SourceControlState->IsSourceControlled() || SourceControlState->IsUnknown())
|
|
{
|
|
ECommandResult::Type Result = Provider.Execute(ISourceControlOperation::Create<FMarkForAdd>(), InFilePath);
|
|
if (Result != ECommandResult::Succeeded)
|
|
{
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add(TEXT("InFilePath"), FText::FromString(InFilePath));
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("MarkForAddFailed", "Failed to add file '{InFilePath}'."), Arguments));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CheckOutFile( const FString& InFilePath )
|
|
{
|
|
if ( InFilePath.IsEmpty() )
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("UnspecifiedCheckoutFile", "Check out file not specified"));
|
|
return false;
|
|
}
|
|
|
|
if( !ISourceControlModule::Get().IsEnabled() )
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("SourceControlDisabled", "Source control is not enabled."));
|
|
return false;
|
|
}
|
|
|
|
if( !ISourceControlModule::Get().GetProvider().IsAvailable() )
|
|
{
|
|
FMessageLog("SourceControl").Error(LOCTEXT("SourceControlServerUnavailable", "Source control server is currently not available."));
|
|
return false;
|
|
}
|
|
|
|
bool bSuccessfullyCheckedOut = false;
|
|
TArray<FString> FilesToBeCheckedOut;
|
|
FilesToBeCheckedOut.Add( InFilePath );
|
|
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState( InFilePath, EStateCacheUsage::ForceUpdate );
|
|
if(SourceControlState.IsValid())
|
|
{
|
|
FString SimultaneousCheckoutUser;
|
|
if( SourceControlState->IsAdded() ||
|
|
SourceControlState->IsCheckedOut())
|
|
{
|
|
// Already checked out or opened for add
|
|
bSuccessfullyCheckedOut = true;
|
|
}
|
|
else
|
|
{
|
|
if(SourceControlState->CanCheckout())
|
|
{
|
|
bSuccessfullyCheckedOut = (SourceControlProvider.Execute( ISourceControlOperation::Create<FCheckOut>(), FilesToBeCheckedOut ) == ECommandResult::Succeeded);
|
|
if (!bSuccessfullyCheckedOut)
|
|
{
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("CheckoutFailed", "Failed to check out file '{InFilePath}'."), Arguments));
|
|
}
|
|
}
|
|
else if(!SourceControlState->IsSourceControlled())
|
|
{
|
|
bSuccessfullyCheckedOut = (SourceControlProvider.Execute( ISourceControlOperation::Create<FMarkForAdd>(), FilesToBeCheckedOut ) == ECommandResult::Succeeded);
|
|
if (!bSuccessfullyCheckedOut)
|
|
{
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("AddFailed", "Failed to add file '{InFilePath}' to source control."), Arguments));
|
|
}
|
|
}
|
|
else if(!SourceControlState->IsCurrent())
|
|
{
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("NotAtHeadRevision", "File '{InFilePath}' is not at head revision."), Arguments));
|
|
}
|
|
else if(SourceControlState->IsCheckedOutOther(&(SimultaneousCheckoutUser)))
|
|
{
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
Arguments.Add( TEXT("SimultaneousCheckoutUser"), FText::FromString(SimultaneousCheckoutUser) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("SimultaneousCheckout", "File '{InFilePath}' is checked out by another ('{SimultaneousCheckoutUser}')."), Arguments));
|
|
}
|
|
else
|
|
{
|
|
// Improper or invalid SCC state
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("CouldNotDetermineState", "Could not determine source control state of file '{InFilePath}'."), Arguments));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Improper or invalid SCC state
|
|
FFormatNamedArguments Arguments;
|
|
Arguments.Add( TEXT("InFilePath"), FText::FromString(InFilePath) );
|
|
FMessageLog("SourceControl").Error(FText::Format(LOCTEXT("CouldNotDetermineState", "Could not determine source control state of file '{InFilePath}'."), Arguments));
|
|
}
|
|
|
|
return bSuccessfullyCheckedOut;
|
|
}
|
|
|
|
bool CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescription, const FOnPostCheckOut& OnPostCheckOut, FText& OutFailReason )
|
|
{
|
|
bool bSucceeded = true;
|
|
|
|
ISourceControlProvider& Provider = ISourceControlModule::Get().GetProvider();
|
|
|
|
// first check for source control check out
|
|
if (ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
FSourceControlStatePtr SourceControlState = Provider.GetState(InDestFile, EStateCacheUsage::ForceUpdate);
|
|
if (SourceControlState.IsValid())
|
|
{
|
|
if (SourceControlState->IsSourceControlled() && SourceControlState->CanCheckout())
|
|
{
|
|
ECommandResult::Type Result = Provider.Execute(ISourceControlOperation::Create<FCheckOut>(), InDestFile);
|
|
bSucceeded = (Result == ECommandResult::Succeeded);
|
|
if (!bSucceeded)
|
|
{
|
|
OutFailReason = FText::Format(LOCTEXT("SourceControlCheckoutError", "Could not check out {0} file."), InFileDescription);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bSucceeded)
|
|
{
|
|
if(OnPostCheckOut.IsBound())
|
|
{
|
|
bSucceeded = OnPostCheckOut.Execute(InDestFile, InFileDescription, OutFailReason);
|
|
}
|
|
}
|
|
|
|
// mark for add now if needed
|
|
if (bSucceeded && ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
FSourceControlStatePtr SourceControlState = Provider.GetState(InDestFile, EStateCacheUsage::Use);
|
|
if (SourceControlState.IsValid())
|
|
{
|
|
if (!SourceControlState->IsSourceControlled())
|
|
{
|
|
ECommandResult::Type Result = Provider.Execute(ISourceControlOperation::Create<FMarkForAdd>(), InDestFile);
|
|
bSucceeded = (Result == ECommandResult::Succeeded);
|
|
if (!bSucceeded)
|
|
{
|
|
OutFailReason = FText::Format(LOCTEXT("SourceControlMarkForAddError", "Could not mark {0} file for add."), InFileDescription);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bSucceeded;
|
|
}
|
|
|
|
bool CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSourceFile, const FText& InFileDescription, FText& OutFailReason)
|
|
{
|
|
struct Local
|
|
{
|
|
static bool CopyFile(const FString& InDestinationFile, const FText& InFileDesc, FText& OutFailureReason, FString InFileToCopy)
|
|
{
|
|
const bool bReplace = true;
|
|
const bool bEvenIfReadOnly = true;
|
|
bool bSucceeded = (IFileManager::Get().Copy(*InDestinationFile, *InFileToCopy, bReplace, bEvenIfReadOnly) == COPY_OK);
|
|
if (!bSucceeded)
|
|
{
|
|
OutFailureReason = FText::Format(LOCTEXT("ExternalImageCopyError", "Could not overwrite {0} file."), InFileDesc);
|
|
}
|
|
|
|
return bSucceeded;
|
|
}
|
|
};
|
|
|
|
return CheckoutOrMarkForAdd(InDestFile, InFileDescription, FOnPostCheckOut::CreateStatic(&Local::CopyFile, InSourceFile), OutFailReason);
|
|
}
|
|
|
|
bool BranchPackage( UPackage* DestPackage, UPackage* SourcePackage )
|
|
{
|
|
if(ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
|
|
const FString SourceFilename = PackageFilename(SourcePackage);
|
|
const FString DestFilename = PackageFilename(DestPackage);
|
|
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceFilename, EStateCacheUsage::ForceUpdate);
|
|
if(SourceControlState.IsValid() && SourceControlState->IsSourceControlled())
|
|
{
|
|
TSharedRef<FCopy, ESPMode::ThreadSafe> CopyOperation = ISourceControlOperation::Create<FCopy>();
|
|
CopyOperation->SetDestination(DestFilename);
|
|
|
|
return (SourceControlProvider.Execute(CopyOperation, SourceFilename) == ECommandResult::Succeeded);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
FScopedSourceControl::FScopedSourceControl()
|
|
{
|
|
ISourceControlModule::Get().GetProvider().Init();
|
|
}
|
|
|
|
FScopedSourceControl::~FScopedSourceControl()
|
|
{
|
|
ISourceControlModule::Get().GetProvider().Close();
|
|
}
|
|
|
|
ISourceControlProvider& FScopedSourceControl::GetProvider()
|
|
{
|
|
return ISourceControlModule::Get().GetProvider();
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |