2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 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 )
{
2014-04-23 19:49:11 -04:00
const FString SourceControlSettingsDir = FPaths : : GeneratedConfigDir ( ) ;
2014-03-14 14:13:41 -04:00
FConfigCacheIni : : LoadGlobalIniFile ( SourceControlSettingsIni , TEXT ( " SourceControlSettings " ) , NULL , 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 , 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 ;
}
2014-05-16 06:46:44 -04:00
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 ;
}
2014-03-14 14:13:41 -04:00
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 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 ) ) ;
}
}
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 ) ) ;
}
}
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 & InDestFile , const FText & InFileDescription , FText & OutFailReason , FString InSourceFile )
{
const bool bReplace = true ;
const bool bEvenIfReadOnly = true ;
bool bSucceeded = ( IFileManager : : Get ( ) . Copy ( * InDestFile , * InSourceFile , bReplace , bEvenIfReadOnly ) = = COPY_OK ) ;
if ( ! bSucceeded )
{
OutFailReason = FText : : Format ( LOCTEXT ( " ExternalImageCopyError " , " Could not overwrite {0} file. " ) , InFileDescription ) ;
}
return bSucceeded ;
}
} ;
return CheckoutOrMarkForAdd ( InDestFile , InFileDescription , FOnPostCheckOut : : CreateStatic ( & Local : : CopyFile , InSourceFile ) , OutFailReason ) ;
}
2014-07-09 06:31:13 -04:00
bool BranchPackage ( UPackage * DestPackage , UPackage * SourcePackage )
2014-06-05 12:10:47 -04:00
{
if ( ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
2014-07-09 06:31:13 -04:00
const FString SourceFilename = PackageFilename ( SourcePackage ) ;
const FString DestFilename = PackageFilename ( DestPackage ) ;
2014-06-05 12:10:47 -04:00
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( SourceFilename , EStateCacheUsage : : ForceUpdate ) ;
if ( SourceControlState . IsValid ( ) & & SourceControlState - > IsSourceControlled ( ) )
{
TSharedRef < FCopy , ESPMode : : ThreadSafe > CopyOperation = ISourceControlOperation : : Create < FCopy > ( ) ;
CopyOperation - > SetDestination ( DestFilename ) ;
2014-07-09 06:31:13 -04:00
return ( SourceControlProvider . Execute ( CopyOperation , SourceFilename ) = = ECommandResult : : Succeeded ) ;
2014-06-05 12:10:47 -04:00
}
}
2014-07-09 06:31:13 -04:00
return false ;
2014-06-05 12:10:47 -04:00
}
2014-03-14 14:13:41 -04:00
}
FScopedSourceControl : : FScopedSourceControl ( )
{
ISourceControlModule : : Get ( ) . GetProvider ( ) . Init ( ) ;
}
FScopedSourceControl : : ~ FScopedSourceControl ( )
{
ISourceControlModule : : Get ( ) . GetProvider ( ) . Close ( ) ;
}
ISourceControlProvider & FScopedSourceControl : : GetProvider ( )
{
return ISourceControlModule : : Get ( ) . GetProvider ( ) ;
}
# undef LOCTEXT_NAMESPACE