2016-01-07 08:17:16 -05:00
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "CollectionManagerPrivatePCH.h"
# include "ISourceControlModule.h"
2015-07-09 14:24:02 -04:00
# include "TextFilterExpressionEvaluator.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "CollectionManager"
2015-05-21 07:43:16 -04:00
struct FCollectionUtils
{
2015-06-19 07:33:02 -04:00
static void AppendCollectionToArray ( const TSet < FName > & InObjectSet , TArray < FName > & OutObjectArray )
2015-05-21 07:43:16 -04:00
{
2015-06-19 07:33:02 -04:00
OutObjectArray . Reserve ( OutObjectArray . Num ( ) + InObjectSet . Num ( ) ) ;
for ( const FName & ObjectName : InObjectSet )
2015-05-21 07:43:16 -04:00
{
2015-06-19 07:33:02 -04:00
OutObjectArray . Add ( ObjectName ) ;
2015-05-21 07:43:16 -04:00
}
}
} ;
2015-07-09 09:59:51 -04:00
FCollection : : FCollection ( const FString & InFilename , bool InUseSCC , ECollectionStorageMode : : Type InStorageMode )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ensure ( InFilename . Len ( ) > 0 ) ;
2014-03-14 14:13:41 -04:00
bUseSCC = InUseSCC ;
SourceFilename = InFilename ;
CollectionName = FName ( * FPaths : : GetBaseFilename ( InFilename ) ) ;
2015-06-19 07:33:02 -04:00
2015-07-09 09:59:51 -04:00
StorageMode = InStorageMode ;
2015-06-19 07:33:02 -04:00
CollectionGuid = FGuid : : NewGuid ( ) ;
// Initialize the file version to the most recent
FileVersion = ECollectionVersion : : CurrentVersion ;
}
TSharedRef < FCollection > FCollection : : Clone ( const FString & InFilename , bool InUseSCC , ECollectionCloneMode InCloneMode ) const
{
TSharedRef < FCollection > NewCollection = MakeShareable ( new FCollection ( * this ) ) ;
// Set the new collection name and path
NewCollection - > bUseSCC = InUseSCC ;
NewCollection - > SourceFilename = InFilename ;
NewCollection - > CollectionName = FName ( * FPaths : : GetBaseFilename ( InFilename ) ) ;
2015-07-09 09:59:51 -04:00
NewCollection - > StorageMode = StorageMode ;
2015-06-19 07:33:02 -04:00
// Create a new GUID?
if ( InCloneMode = = ECollectionCloneMode : : Unique )
{
NewCollection - > CollectionGuid = FGuid : : NewGuid ( ) ;
}
return NewCollection ;
}
bool FCollection : : Load ( FText & OutError )
{
2015-07-09 14:24:02 -04:00
Empty ( ) ;
2015-06-19 07:33:02 -04:00
FString FullFileContentsString ;
if ( ! FFileHelper : : LoadFileToString ( FullFileContentsString , * SourceFilename ) )
{
OutError = FText : : Format ( LOCTEXT ( " LoadError_FailedToLoadFile " , " Failed to load the collection '{0}' from disk. " ) , FText : : FromString ( SourceFilename ) ) ;
return false ;
}
2014-03-14 14:13:41 -04:00
// Normalize line endings and parse into array
TArray < FString > FileContents ;
FullFileContentsString . ReplaceInline ( TEXT ( " \r " ) , TEXT ( " " ) ) ;
2015-03-02 15:51:37 -05:00
FullFileContentsString . ParseIntoArray ( FileContents , TEXT ( " \n " ) , /*bCullEmpty=*/ false ) ;
2014-03-14 14:13:41 -04:00
if ( FileContents . Num ( ) = = 0 )
{
// Empty file, assume static collection with no items
return true ;
}
// Load the header from the contents array
TMap < FString , FString > HeaderPairs ;
while ( FileContents . Num ( ) )
{
// Pop the 0th element from the contents array and read it
const FString Line = FileContents [ 0 ] . Trim ( ) . TrimTrailing ( ) ;
FileContents . RemoveAt ( 0 ) ;
if ( Line . Len ( ) = = 0 )
{
// Empty line. Done reading headers.
break ;
}
FString Key ;
FString Value ;
if ( Line . Split ( TEXT ( " : " ) , & Key , & Value ) )
{
HeaderPairs . Add ( Key , Value ) ;
}
}
// Now process the header pairs to prepare and validate this collection
if ( ! LoadHeaderPairs ( HeaderPairs ) )
{
// Bad header
2015-06-19 07:33:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " LoadError_BadHeader " , " The collection file '{0}' contains a bad header and could not be loaded. " ) , FText : : FromString ( SourceFilename ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Now load the content if the header load was successful
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
// Static collection, a flat list of asset paths
2015-05-21 07:43:16 -04:00
for ( FString Line : FileContents )
2014-03-14 14:13:41 -04:00
{
2015-05-21 07:43:16 -04:00
Line . Trim ( ) ;
Line . TrimTrailing ( ) ;
2014-03-14 14:13:41 -04:00
if ( Line . Len ( ) )
{
2015-06-26 13:13:02 -04:00
AddObjectToCollection ( FName ( * Line ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2015-07-09 09:59:51 -04:00
else
{
// Dynamic collection, a single query line
DynamicQueryText = ( FileContents . Num ( ) > 0 ) ? FileContents [ 0 ] : FString ( ) ;
DynamicQueryText . Trim ( ) ;
DynamicQueryText . TrimTrailing ( ) ;
}
2014-03-14 14:13:41 -04:00
2015-06-19 07:33:02 -04:00
DiskSnapshot . TakeSnapshot ( * this ) ;
2014-03-14 14:13:41 -04:00
return true ;
}
bool FCollection : : Save ( FText & OutError )
{
if ( ! ensure ( SourceFilename . Len ( ) ) )
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
return false ;
}
// Store the start time for profiling reasons
double SaveStartTime = FPlatformTime : : Seconds ( ) ;
// Keep track of save progress to update the slow task dialog
const int32 SaveProgressDenominator = 3 ;
int32 SaveProgressNumerator = 0 ;
GWarn - > BeginSlowTask ( FText : : Format ( LOCTEXT ( " SavingCollection " , " Saving Collection {0} " ) , FText : : FromName ( CollectionName ) ) , true ) ;
GWarn - > UpdateProgress ( SaveProgressNumerator + + , SaveProgressDenominator ) ;
if ( bUseSCC )
{
// Checkout the file
if ( ! CheckoutCollection ( OutError ) )
{
UE_LOG ( LogCollectionManager , Error , TEXT ( " Failed to check out a collection file: %s " ) , * CollectionName . ToString ( ) ) ;
GWarn - > EndSlowTask ( ) ;
return false ;
}
}
GWarn - > UpdateProgress ( SaveProgressNumerator + + , SaveProgressDenominator ) ;
// Generate a string with the file contents
FString FileOutput ;
// Start with the header
TMap < FString , FString > HeaderPairs ;
2015-06-19 07:33:02 -04:00
SaveHeaderPairs ( HeaderPairs ) ;
2015-05-21 07:43:16 -04:00
for ( const auto & HeaderPair : HeaderPairs )
2014-03-14 14:13:41 -04:00
{
2015-05-21 07:43:16 -04:00
FileOutput + = HeaderPair . Key + TEXT ( " : " ) + HeaderPair . Value + LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
FileOutput + = LINE_TERMINATOR ;
// Now for the content
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
2015-05-21 07:43:16 -04:00
// Write out the set as a sorted array to keep things in a known order for diffing
2015-06-19 07:33:02 -04:00
TArray < FName > ObjectList = ObjectSet . Array ( ) ;
ObjectList . Sort ( ) ;
2015-05-21 07:43:16 -04:00
2015-06-19 07:33:02 -04:00
// Static collection. Save a flat list of all objects in the collection.
for ( const FName & ObjectName : ObjectList )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
FileOutput + = ObjectName . ToString ( ) + LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
}
2015-07-09 09:59:51 -04:00
else
{
// Dynamic collection, a single query line
FileOutput + = DynamicQueryText + LINE_TERMINATOR ;
}
2014-03-14 14:13:41 -04:00
// Attempt to save the file
bool bSaveSuccessful = false ;
if ( ensure ( FileOutput . Len ( ) ) )
{
// We have some output, write it to file
if ( FFileHelper : : SaveStringToFile ( FileOutput , * SourceFilename ) )
{
bSaveSuccessful = true ;
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_WriteFailed " , " Failed to write to collection file: {0} " ) , FText : : FromString ( SourceFilename ) ) ;
UE_LOG ( LogCollectionManager , Error , TEXT ( " %s " ) , * OutError . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
}
GWarn - > UpdateProgress ( SaveProgressNumerator + + , SaveProgressDenominator ) ;
if ( bSaveSuccessful )
{
if ( bUseSCC )
{
// Check in the file if the save was successful
if ( bSaveSuccessful )
{
if ( ! CheckinCollection ( OutError ) )
{
UE_LOG ( LogCollectionManager , Error , TEXT ( " Failed to check in a collection successfully saving: %s " ) , * CollectionName . ToString ( ) ) ;
bSaveSuccessful = false ;
}
}
// If the save was not successful or the checkin failed, revert
if ( ! bSaveSuccessful )
{
FText Unused ;
if ( ! RevertCollection ( Unused ) )
{
// The revert failed... file will be left on disk as it was saved.
// DiskAssetList will still hold the version of the file when this collection was last loaded or saved successfully so nothing will be out of sync.
// If the user closes the editor before successfully saving, this file may not be exactly what was seen at the time the editor closed.
UE_LOG ( LogCollectionManager , Warning , TEXT ( " Failed to revert a checked out collection after failing to save or checkin: %s " ) , * CollectionName . ToString ( ) ) ;
}
}
}
}
GWarn - > UpdateProgress ( SaveProgressNumerator + + , SaveProgressDenominator ) ;
if ( bSaveSuccessful )
{
2015-06-19 07:33:02 -04:00
// Files are always saved at the latest version as loading should take care of data upgrades
FileVersion = ECollectionVersion : : CurrentVersion ;
DiskSnapshot . TakeSnapshot ( * this ) ;
2014-03-14 14:13:41 -04:00
}
GWarn - > EndSlowTask ( ) ;
UE_LOG ( LogCollectionManager , Verbose , TEXT ( " Saved collection %s in %0.6f seconds " ) , * CollectionName . ToString ( ) , FPlatformTime : : Seconds ( ) - SaveStartTime ) ;
return bSaveSuccessful ;
}
2015-07-03 13:54:34 -04:00
bool FCollection : : Update ( FText & OutError )
{
if ( ! ensure ( SourceFilename . Len ( ) ) )
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
return false ;
}
if ( ! bUseSCC )
{
// Not under SCC control, so already up-to-date
return true ;
}
FScopedSlowTask SlowTask ( 1.0f , FText : : Format ( LOCTEXT ( " UpdatingCollection " , " Updating Collection {0} " ) , FText : : FromName ( CollectionName ) ) ) ;
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( ! ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
OutError = LOCTEXT ( " Error_SCCDisabled " , " Source control is not enabled. Enable source control in the preferences menu. " ) ;
return false ;
}
if ( ! SourceControlProvider . IsAvailable ( ) )
{
OutError = LOCTEXT ( " Error_SCCNotAvailable " , " Source control is currently not available. Check your connection and try again. " ) ;
return false ;
}
const FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
// If not at the head revision, sync up
if ( SourceControlState . IsValid ( ) & & ! SourceControlState - > IsCurrent ( ) )
{
if ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FSync > ( ) , AbsoluteFilename ) = = ECommandResult : : Failed )
{
// Could not sync up with the head revision
OutError = FText : : Format ( LOCTEXT ( " Error_SCCSync " , " Failed to sync collection '{0}' to the head revision. " ) , FText : : FromName ( CollectionName ) ) ;
return false ;
}
// Check to see if the file exists at the head revision
if ( IFileManager : : Get ( ) . FileExists ( * SourceFilename ) )
{
// File found! Load it and merge with our local changes
FText LoadErrorText ;
2015-07-09 09:59:51 -04:00
FCollection NewCollection ( SourceFilename , false , ECollectionStorageMode : : Static ) ;
2015-07-03 13:54:34 -04:00
if ( ! NewCollection . Load ( LoadErrorText ) )
{
// Failed to load the head revision file so it isn't safe to delete it
OutError = FText : : Format ( LOCTEXT ( " Error_SCCBadHead " , " Failed to load the collection '{0}' at the head revision. {1} " ) , FText : : FromName ( CollectionName ) , LoadErrorText ) ;
return false ;
}
// Loaded the head revision, now merge up so the files are in a consistent state
MergeWithCollection ( NewCollection ) ;
}
// Make sure we get a fresh state from the server
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
// Got an updated version?
if ( SourceControlState . IsValid ( ) & & ! SourceControlState - > IsCurrent ( ) )
{
OutError = FText : : Format ( LOCTEXT ( " Error_SCCNotCurrent " , " Collection '{0}' is not at head revision after sync. " ) , FText : : FromName ( CollectionName ) ) ;
return false ;
}
}
return true ;
}
2015-07-07 10:31:39 -04:00
bool FCollection : : Merge ( const FCollection & NewCollection )
{
return MergeWithCollection ( NewCollection ) ;
}
2014-03-14 14:13:41 -04:00
bool FCollection : : DeleteSourceFile ( FText & OutError )
{
bool bSuccessfullyDeleted = false ;
if ( SourceFilename . Len ( ) )
{
if ( bUseSCC )
{
bSuccessfullyDeleted = DeleteFromSourceControl ( OutError ) ;
}
else
{
bSuccessfullyDeleted = IFileManager : : Get ( ) . Delete ( * SourceFilename ) ;
if ( ! bSuccessfullyDeleted )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_DiskDeleteFailed " , " Failed to delete the collection file: {0} " ) , FText : : FromString ( SourceFilename ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
else
{
// No source file. Since it doesn't exist we will say it is deleted.
bSuccessfullyDeleted = true ;
}
if ( bSuccessfullyDeleted )
{
2015-06-19 07:33:02 -04:00
DiskSnapshot = FCollectionSnapshot ( ) ;
2014-03-14 14:13:41 -04:00
}
return bSuccessfullyDeleted ;
}
2015-07-09 14:24:02 -04:00
void FCollection : : Empty ( )
{
ObjectSet . Reset ( ) ;
DynamicQueryText . Reset ( ) ;
DynamicQueryExpressionEvaluatorPtr . Reset ( ) ;
DiskSnapshot . TakeSnapshot ( * this ) ;
}
2015-06-26 13:13:02 -04:00
bool FCollection : : AddObjectToCollection ( FName ObjectPath )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static & & ! ObjectSet . Contains ( ObjectPath ) )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ObjectSet . Add ( ObjectPath ) ;
2014-03-14 14:13:41 -04:00
return true ;
}
return false ;
}
2015-06-26 13:13:02 -04:00
bool FCollection : : RemoveObjectFromCollection ( FName ObjectPath )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
return ObjectSet . Remove ( ObjectPath ) > 0 ;
}
return false ;
2014-03-14 14:13:41 -04:00
}
void FCollection : : GetAssetsInCollection ( TArray < FName > & Assets ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
for ( const FName & ObjectName : ObjectSet )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( ! ObjectName . ToString ( ) . StartsWith ( TEXT ( " /Script/ " ) ) )
{
Assets . Add ( ObjectName ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
void FCollection : : GetClassesInCollection ( TArray < FName > & Classes ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
for ( const FName & ObjectName : ObjectSet )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( ObjectName . ToString ( ) . StartsWith ( TEXT ( " /Script/ " ) ) )
{
Classes . Add ( ObjectName ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
void FCollection : : GetObjectsInCollection ( TArray < FName > & Objects ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
FCollectionUtils : : AppendCollectionToArray ( ObjectSet , Objects ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-05-21 07:43:16 -04:00
bool FCollection : : IsObjectInCollection ( FName ObjectPath ) const
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
return ObjectSet . Contains ( ObjectPath ) ;
}
return false ;
2014-03-14 14:13:41 -04:00
}
2015-06-26 13:13:02 -04:00
bool FCollection : : IsRedirectorInCollection ( FName ObjectPath ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
// Redirectors are fixed up in-memory once the asset registry has finished loading,
// so we need to test our on-disk set of objects rather than our in-memory set of objects
return DiskSnapshot . ObjectSet . Contains ( ObjectPath ) ;
}
return false ;
}
bool FCollection : : SetDynamicQueryText ( const FString & InQueryText )
{
if ( StorageMode = = ECollectionStorageMode : : Dynamic )
{
DynamicQueryText = InQueryText ;
return true ;
}
return false ;
}
FString FCollection : : GetDynamicQueryText ( ) const
{
return ( StorageMode = = ECollectionStorageMode : : Dynamic ) ? DynamicQueryText : FString ( ) ;
2015-06-26 13:13:02 -04:00
}
2015-07-09 14:24:02 -04:00
bool FCollection : : TestDynamicQuery ( const ITextFilterExpressionContext & InContext ) const
{
if ( StorageMode = = ECollectionStorageMode : : Dynamic )
{
if ( ! DynamicQueryExpressionEvaluatorPtr . IsValid ( ) )
{
DynamicQueryExpressionEvaluatorPtr = MakeShareable ( new FTextFilterExpressionEvaluator ( ETextFilterExpressionEvaluatorMode : : Complex ) ) ;
}
if ( ! DynamicQueryExpressionEvaluatorPtr - > GetFilterText ( ) . ToString ( ) . Equals ( DynamicQueryText , ESearchCase : : CaseSensitive ) )
{
DynamicQueryExpressionEvaluatorPtr - > SetFilterText ( FText : : FromString ( DynamicQueryText ) ) ;
}
return DynamicQueryExpressionEvaluatorPtr - > TestTextFilter ( InContext ) ;
}
return false ;
}
2015-07-03 13:54:34 -04:00
FCollectionStatusInfo FCollection : : GetStatusInfo ( ) const
{
FCollectionStatusInfo StatusInfo ;
StatusInfo . bIsDirty = IsDirty ( ) ;
2015-07-09 09:59:51 -04:00
StatusInfo . bIsEmpty = IsEmpty ( ) ;
2015-07-03 13:54:34 -04:00
StatusInfo . bUseSCC = bUseSCC ;
StatusInfo . NumObjects = ObjectSet . Num ( ) ;
if ( bUseSCC & & ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( SourceControlProvider . IsAvailable ( ) )
{
const FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
StatusInfo . SCCState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : Use ) ;
}
}
return StatusInfo ;
}
bool FCollection : : IsDirty ( ) const
{
if ( ParentCollectionGuid ! = DiskSnapshot . ParentCollectionGuid )
{
return true ;
}
2015-07-09 09:59:51 -04:00
bool bHasChanges = false ;
2015-07-03 13:54:34 -04:00
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
TArray < FName > ObjectsAdded ;
TArray < FName > ObjectsRemoved ;
GetObjectDifferencesFromDisk ( ObjectsAdded , ObjectsRemoved ) ;
2015-07-03 13:54:34 -04:00
2015-07-09 09:59:51 -04:00
bHasChanges = ObjectsAdded . Num ( ) ! = 0 | | ObjectsRemoved . Num ( ) ! = 0 ;
}
else
{
bHasChanges = DynamicQueryText ! = DiskSnapshot . DynamicQueryText ;
}
return bHasChanges ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
2014-03-14 14:13:41 -04:00
bool FCollection : : IsEmpty ( ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
return ObjectSet . Num ( ) = = 0 ;
}
else
{
return DynamicQueryText . IsEmpty ( ) ;
}
2014-03-14 14:13:41 -04:00
}
void FCollection : : PrintCollection ( ) const
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCollectionManager , Log , TEXT ( " Printing static elements of collection %s " ) , * CollectionName . ToString ( ) ) ;
UE_LOG ( LogCollectionManager , Log , TEXT ( " ============================= " ) ) ;
2015-05-21 07:43:16 -04:00
// Print the set as a sorted array to keep things in a sane order
2015-06-19 07:33:02 -04:00
TArray < FName > ObjectList = ObjectSet . Array ( ) ;
ObjectList . Sort ( ) ;
2015-05-21 07:43:16 -04:00
2015-06-19 07:33:02 -04:00
for ( const FName & ObjectName : ObjectList )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
UE_LOG ( LogCollectionManager , Log , TEXT ( " %s " ) , * ObjectName . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-07-09 09:59:51 -04:00
else
{
UE_LOG ( LogCollectionManager , Log , TEXT ( " Printing dynamic query of collection %s " ) , * CollectionName . ToString ( ) ) ;
UE_LOG ( LogCollectionManager , Log , TEXT ( " ============================= " ) ) ;
UE_LOG ( LogCollectionManager , Log , TEXT ( " %s " ) , * DynamicQueryText ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
void FCollection : : SaveHeaderPairs ( TMap < FString , FString > & OutHeaderPairs ) const
2014-03-14 14:13:41 -04:00
{
// These pairs will appear at the top of the file followed by a newline
2015-06-19 07:33:02 -04:00
OutHeaderPairs . Add ( TEXT ( " FileVersion " ) , FString : : FromInt ( ECollectionVersion : : CurrentVersion ) ) ; // Files are always saved at the latest version as loading should take care of data upgrades
2015-07-09 09:59:51 -04:00
OutHeaderPairs . Add ( TEXT ( " Type " ) , ECollectionStorageMode : : ToString ( StorageMode ) ) ;
2015-06-19 07:33:02 -04:00
OutHeaderPairs . Add ( TEXT ( " Guid " ) , CollectionGuid . ToString ( EGuidFormats : : DigitsWithHyphens ) ) ;
OutHeaderPairs . Add ( TEXT ( " ParentGuid " ) , ParentCollectionGuid . ToString ( EGuidFormats : : DigitsWithHyphens ) ) ;
2014-03-14 14:13:41 -04:00
}
bool FCollection : : LoadHeaderPairs ( const TMap < FString , FString > & InHeaderPairs )
{
// These pairs will appeared at the top of the file being loaded
// First find all the known pairs
const FString * Version = InHeaderPairs . Find ( TEXT ( " FileVersion " ) ) ;
if ( ! Version )
{
// FileVersion is required
return false ;
}
const FString * Type = InHeaderPairs . Find ( TEXT ( " Type " ) ) ;
if ( ! Type )
{
// Type is required
return false ;
}
2015-07-09 09:59:51 -04:00
StorageMode = ECollectionStorageMode : : FromString ( * * Type ) ;
2015-06-19 07:33:02 -04:00
FileVersion = ( ECollectionVersion : : Type ) FCString : : Atoi ( * * Version ) ;
if ( FileVersion > = ECollectionVersion : : AddedCollectionGuid )
{
const FString * GuidStr = InHeaderPairs . Find ( TEXT ( " Guid " ) ) ;
if ( ! GuidStr | | ! FGuid : : Parse ( * GuidStr , CollectionGuid ) )
{
// Guid is required
return false ;
}
const FString * ParentGuidStr = InHeaderPairs . Find ( TEXT ( " ParentGuid " ) ) ;
if ( ! ParentGuidStr | | ! FGuid : : Parse ( * ParentGuidStr , ParentCollectionGuid ) )
{
ParentCollectionGuid = FGuid ( ) ;
}
}
2014-03-14 14:13:41 -04:00
2015-06-19 07:33:02 -04:00
return FileVersion > 0 & & FileVersion < = ECollectionVersion : : CurrentVersion ;
2014-03-14 14:13:41 -04:00
}
2015-07-07 10:31:39 -04:00
bool FCollection : : MergeWithCollection ( const FCollection & Other )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
bool bHasChanges = ParentCollectionGuid ! = Other . ParentCollectionGuid ;
2015-07-07 10:31:39 -04:00
2015-07-09 09:59:51 -04:00
ParentCollectionGuid = Other . ParentCollectionGuid ;
if ( StorageMode ! = Other . StorageMode )
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
bHasChanges = true ;
StorageMode = Other . StorageMode ;
2015-07-09 14:24:02 -04:00
// Storage mode has changed! Empty the collection so we just copy over the new data verbatim
Empty ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
2015-07-07 10:31:39 -04:00
// Work out whether we have any changes compared to the other collection
2015-06-19 07:33:02 -04:00
TArray < FName > ObjectsAdded ;
TArray < FName > ObjectsRemoved ;
2015-07-07 10:31:39 -04:00
GetObjectDifferences ( ObjectSet , Other . ObjectSet , ObjectsAdded , ObjectsRemoved ) ;
2014-03-14 14:13:41 -04:00
2015-07-09 09:59:51 -04:00
bHasChanges = bHasChanges | | ObjectsAdded . Num ( ) > 0 | | ObjectsRemoved . Num ( ) > 0 ;
2014-03-14 14:13:41 -04:00
2015-07-07 10:31:39 -04:00
if ( bHasChanges )
2014-03-14 14:13:41 -04:00
{
2015-07-07 10:31:39 -04:00
// Gather the differences from the file on disk
ObjectsAdded . Reset ( ) ;
ObjectsRemoved . Reset ( ) ;
GetObjectDifferencesFromDisk ( ObjectsAdded , ObjectsRemoved ) ;
// Copy asset list from other collection
2015-07-09 09:59:51 -04:00
ObjectSet = Other . ObjectSet ;
2015-07-07 10:31:39 -04:00
// Add the objects that were added before the merge
for ( const FName & AddedObjectName : ObjectsAdded )
{
ObjectSet . Add ( AddedObjectName ) ;
}
// Remove the objects that were removed before the merge
for ( const FName & RemovedObjectName : ObjectsRemoved )
{
ObjectSet . Remove ( RemovedObjectName ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-07-07 10:31:39 -04:00
}
2015-07-09 09:59:51 -04:00
else
{
bHasChanges = bHasChanges | | DynamicQueryText ! = Other . DynamicQueryText ;
DynamicQueryText = Other . DynamicQueryText ;
}
DiskSnapshot = Other . DiskSnapshot ;
2015-07-07 10:31:39 -04:00
return bHasChanges ;
}
void FCollection : : GetObjectDifferences ( const TSet < FName > & BaseSet , const TSet < FName > & NewSet , TArray < FName > & ObjectsAdded , TArray < FName > & ObjectsRemoved )
{
// Find the objects that were removed compared to the base set
for ( const FName & BaseObjectName : BaseSet )
{
if ( ! NewSet . Contains ( BaseObjectName ) )
{
ObjectsRemoved . Add ( BaseObjectName ) ;
}
}
// Find the objects that were added compare to the base set
for ( const FName & NewObjectName : NewSet )
{
if ( ! BaseSet . Contains ( NewObjectName ) )
{
ObjectsAdded . Add ( NewObjectName ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2015-07-03 13:54:34 -04:00
void FCollection : : GetObjectDifferencesFromDisk ( TArray < FName > & ObjectsAdded , TArray < FName > & ObjectsRemoved ) const
2014-03-14 14:13:41 -04:00
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
{
GetObjectDifferences ( DiskSnapshot . ObjectSet , ObjectSet , ObjectsAdded , ObjectsRemoved ) ;
}
2014-03-14 14:13:41 -04:00
}
bool FCollection : : CheckoutCollection ( FText & OutError )
{
if ( ! ensure ( SourceFilename . Len ( ) ) )
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
return false ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( ! ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
OutError = LOCTEXT ( " Error_SCCDisabled " , " Source control is not enabled. Enable source control in the preferences menu. " ) ;
return false ;
}
if ( ! SourceControlProvider . IsAvailable ( ) )
{
OutError = LOCTEXT ( " Error_SCCNotAvailable " , " Source control is currently not available. Check your connection and try again. " ) ;
return false ;
}
2015-06-16 09:25:36 -04:00
const FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
2014-03-14 14:13:41 -04:00
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
bool bSuccessfullyCheckedOut = false ;
if ( SourceControlState . IsValid ( ) & & SourceControlState - > IsDeleted ( ) )
{
// Revert our delete
if ( ! RevertCollection ( OutError ) )
{
return false ;
}
// Make sure we get a fresh state from the server
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
}
// If not at the head revision, sync up
if ( SourceControlState . IsValid ( ) & & ! SourceControlState - > IsCurrent ( ) )
{
2015-06-16 09:25:36 -04:00
if ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FSync > ( ) , AbsoluteFilename ) = = ECommandResult : : Failed )
2014-03-14 14:13:41 -04:00
{
// Could not sync up with the head revision
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCSync " , " Failed to sync collection '{0}' to the head revision. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Check to see if the file exists at the head revision
2015-06-19 07:33:02 -04:00
if ( IFileManager : : Get ( ) . FileExists ( * SourceFilename ) )
2014-03-14 14:13:41 -04:00
{
// File found! Load it and merge with our local changes
2015-06-19 07:33:02 -04:00
FText LoadErrorText ;
2015-07-09 09:59:51 -04:00
FCollection NewCollection ( SourceFilename , false , ECollectionStorageMode : : Static ) ;
2015-06-19 07:33:02 -04:00
if ( ! NewCollection . Load ( LoadErrorText ) )
2014-03-14 14:13:41 -04:00
{
// Failed to load the head revision file so it isn't safe to delete it
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCBadHead " , " Failed to load the collection '{0}' at the head revision. {1} " ) , FText : : FromName ( CollectionName ) , LoadErrorText ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Loaded the head revision, now merge up so the files are in a consistent state
MergeWithCollection ( NewCollection ) ;
}
// Make sure we get a fresh state from the server
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
}
if ( SourceControlState . IsValid ( ) )
{
2015-06-16 09:25:36 -04:00
if ( ! SourceControlState - > IsSourceControlled ( ) )
{
// Not yet in the depot. We'll add it when we call CheckinCollection
bSuccessfullyCheckedOut = true ;
}
else if ( SourceControlState - > IsAdded ( ) | | SourceControlState - > IsCheckedOut ( ) )
2014-03-14 14:13:41 -04:00
{
// Already checked out or opened for add
bSuccessfullyCheckedOut = true ;
}
else if ( SourceControlState - > CanCheckout ( ) )
{
// In depot and needs to be checked out
2015-06-16 09:25:36 -04:00
bSuccessfullyCheckedOut = ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FCheckOut > ( ) , AbsoluteFilename ) = = ECommandResult : : Succeeded ) ;
2014-03-14 14:13:41 -04:00
if ( ! bSuccessfullyCheckedOut )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCCheckout " , " Failed to check out collection '{0}' " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else if ( ! SourceControlState - > IsCurrent ( ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCNotCurrent " , " Collection '{0}' is not at head revision after sync. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
else if ( SourceControlState - > IsCheckedOutOther ( ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCCheckedOutOther " , " Collection '{0}' is checked out by another user. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCUnknown " , " Could not determine source control state for collection '{0}' " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
OutError = LOCTEXT ( " Error_SCCInvalid " , " Source control state is invalid. " ) ;
}
return bSuccessfullyCheckedOut ;
}
bool FCollection : : CheckinCollection ( FText & OutError )
{
if ( ! ensure ( SourceFilename . Len ( ) ) )
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
return false ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( ! ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
OutError = LOCTEXT ( " Error_SCCDisabled " , " Source control is not enabled. Enable source control in the preferences menu. " ) ;
return false ;
}
if ( ! SourceControlProvider . IsAvailable ( ) )
{
OutError = LOCTEXT ( " Error_SCCNotAvailable " , " Source control is currently not available. Check your connection and try again. " ) ;
return false ;
}
2015-06-16 09:25:36 -04:00
const FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
2014-03-14 14:13:41 -04:00
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
2015-06-16 09:25:36 -04:00
if ( SourceControlState . IsValid ( ) & & ! SourceControlState - > IsSourceControlled ( ) )
{
// Not yet in the depot. Add it.
const bool bWasAdded = ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FMarkForAdd > ( ) , AbsoluteFilename ) = = ECommandResult : : Succeeded ) ;
if ( ! bWasAdded )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCAdd " , " Failed to add collection '{0}' to source control. " ) , FText : : FromName ( CollectionName ) ) ;
2015-06-16 09:25:36 -04:00
return false ;
}
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
}
2014-03-14 14:13:41 -04:00
if ( SourceControlState . IsValid ( ) & & ! ( SourceControlState - > IsCheckedOut ( ) | | SourceControlState - > IsAdded ( ) ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCNotCheckedOut " , " Collection '{0}' not checked out or open for add. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Form an appropriate summary for the changelist
const FText CollectionNameText = FText : : FromName ( CollectionName ) ;
2015-06-19 07:33:02 -04:00
FTextBuilder ChangelistDescBuilder ;
if ( SourceControlState . IsValid ( ) & & SourceControlState - > IsAdded ( ) )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionAddedNewDesc " , " Added collection '{0}' " ) , CollectionNameText ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-07-09 09:59:51 -04:00
if ( StorageMode = = ECollectionStorageMode : : Static )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
// Gather differences from disk
TArray < FName > ObjectsAdded ;
TArray < FName > ObjectsRemoved ;
GetObjectDifferencesFromDisk ( ObjectsAdded , ObjectsRemoved ) ;
2014-03-14 14:13:41 -04:00
2015-06-19 07:33:02 -04:00
ObjectsAdded . Sort ( ) ;
ObjectsRemoved . Sort ( ) ;
// Report added files
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " FirstObjectAdded " ) , ObjectsAdded . Num ( ) > 0 ? FText : : FromName ( ObjectsAdded [ 0 ] ) : NSLOCTEXT ( " Core " , " None " , " None " ) ) ;
Args . Add ( TEXT ( " NumberAdded " ) , FText : : AsNumber ( ObjectsAdded . Num ( ) ) ) ;
Args . Add ( TEXT ( " FirstObjectRemoved " ) , ObjectsRemoved . Num ( ) > 0 ? FText : : FromName ( ObjectsRemoved [ 0 ] ) : NSLOCTEXT ( " Core " , " None " , " None " ) ) ;
Args . Add ( TEXT ( " NumberRemoved " ) , FText : : AsNumber ( ObjectsRemoved . Num ( ) ) ) ;
Args . Add ( TEXT ( " CollectionName " ) , CollectionNameText ) ;
if ( ObjectsAdded . Num ( ) = = 1 )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionAddedSingleDesc " , " Added '{FirstObjectAdded}' to collection '{CollectionName}' " ) , Args ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
else if ( ObjectsAdded . Num ( ) > 1 )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionAddedMultipleDesc " , " Added {NumberAdded} objects to collection '{CollectionName}': " ) , Args ) ;
ChangelistDescBuilder . Indent ( ) ;
for ( const FName & AddedObjectName : ObjectsAdded )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . AppendLine ( FText : : FromName ( AddedObjectName ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . Unindent ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
if ( ObjectsRemoved . Num ( ) = = 1 )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionRemovedSingleDesc " , " Removed '{FirstObjectRemoved}' from collection '{CollectionName}' " ) , Args ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 07:33:02 -04:00
else if ( ObjectsRemoved . Num ( ) > 1 )
{
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionRemovedMultipleDesc " , " Removed {NumberRemoved} objects from collection '{CollectionName}' " ) , Args ) ;
ChangelistDescBuilder . Indent ( ) ;
for ( const FName & RemovedObjectName : ObjectsRemoved )
{
ChangelistDescBuilder . AppendLine ( FText : : FromName ( RemovedObjectName ) ) ;
}
ChangelistDescBuilder . Unindent ( ) ;
}
}
2015-07-09 09:59:51 -04:00
else
{
if ( DiskSnapshot . DynamicQueryText ! = DynamicQueryText )
{
2015-12-10 16:56:55 -05:00
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionChangedDynamicQueryDesc " , " Changed the dynamic query of collection '{0}' to '{1}' " ) , CollectionNameText , FText : : FromString ( DynamicQueryText ) ) ;
2015-07-09 09:59:51 -04:00
}
}
2015-06-19 07:33:02 -04:00
// Parent change?
if ( DiskSnapshot . ParentCollectionGuid ! = ParentCollectionGuid )
{
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionChangedParentDesc " , " Changed the parent of collection '{0}' " ) , CollectionNameText ) ;
}
// Version bump?
if ( FileVersion < ECollectionVersion : : CurrentVersion )
{
ChangelistDescBuilder . AppendLineFormat ( LOCTEXT ( " CollectionUpgradedDesc " , " Upgraded collection '{0}' (was version {1}, now version {2}) " ) , CollectionNameText , FText : : AsNumber ( FileVersion ) , FText : : AsNumber ( ECollectionVersion : : CurrentVersion ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-06-19 07:33:02 -04:00
FText ChangelistDesc = ChangelistDescBuilder . ToText ( ) ;
if ( ChangelistDesc . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
2015-06-19 07:33:02 -04:00
// No changes could be detected
ChangelistDesc = FText : : Format ( LOCTEXT ( " CollectionNotModifiedDesc " , " Collection '{0}' not modified " ) , CollectionNameText ) ;
2014-03-14 14:13:41 -04:00
}
// Finally check in the file
TSharedRef < FCheckIn , ESPMode : : ThreadSafe > CheckInOperation = ISourceControlOperation : : Create < FCheckIn > ( ) ;
CheckInOperation - > SetDescription ( ChangelistDesc ) ;
if ( SourceControlProvider . Execute ( CheckInOperation , AbsoluteFilename ) )
{
return true ;
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCCheckIn " , " Failed to check in collection '{0}'. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
}
bool FCollection : : RevertCollection ( FText & OutError )
{
if ( ! ensure ( SourceFilename . Len ( ) ) )
{
OutError = LOCTEXT ( " Error_Internal " , " There was an internal error. " ) ;
return false ;
}
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( ! ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
OutError = LOCTEXT ( " Error_SCCDisabled " , " Source control is not enabled. Enable source control in the preferences menu. " ) ;
return false ;
}
if ( ! SourceControlProvider . IsAvailable ( ) )
{
OutError = LOCTEXT ( " Error_SCCNotAvailable " , " Source control is currently not available. Check your connection and try again. " ) ;
return false ;
}
FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
if ( SourceControlState . IsValid ( ) & & ! ( SourceControlState - > IsCheckedOut ( ) | | SourceControlState - > IsAdded ( ) ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCNotCheckedOut " , " Collection '{0}' not checked out or open for add. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
2014-04-23 19:31:56 -04:00
if ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FRevert > ( ) , AbsoluteFilename ) = = ECommandResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
return true ;
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCRevert " , " Could not revert collection '{0}' " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
}
bool FCollection : : DeleteFromSourceControl ( FText & OutError )
{
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( ! ISourceControlModule : : Get ( ) . IsEnabled ( ) )
{
OutError = LOCTEXT ( " Error_SCCDisabled " , " Source control is not enabled. Enable source control in the preferences menu. " ) ;
return false ;
}
if ( ! SourceControlProvider . IsAvailable ( ) )
{
OutError = LOCTEXT ( " Error_SCCNotAvailable " , " Source control is currently not available. Check your connection and try again. " ) ;
return false ;
}
bool bDeletedSuccessfully = false ;
const int32 DeleteProgressDenominator = 2 ;
int32 DeleteProgressNumerator = 0 ;
const FText CollectionNameText = FText : : FromName ( CollectionName ) ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " CollectionName " ) , CollectionNameText ) ;
const FText StatusUpdate = FText : : Format ( LOCTEXT ( " DeletingCollection " , " Deleting Collection {CollectionName} " ) , Args ) ;
GWarn - > BeginSlowTask ( StatusUpdate , true ) ;
GWarn - > UpdateProgress ( DeleteProgressNumerator + + , DeleteProgressDenominator ) ;
FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( SourceFilename ) ;
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
GWarn - > UpdateProgress ( DeleteProgressNumerator + + , DeleteProgressDenominator ) ;
// If checked out locally for some reason, revert
if ( SourceControlState . IsValid ( ) & & ( SourceControlState - > IsAdded ( ) | | SourceControlState - > IsCheckedOut ( ) | | SourceControlState - > IsDeleted ( ) ) )
{
if ( ! RevertCollection ( OutError ) )
{
// Failed to revert, just bail out
GWarn - > EndSlowTask ( ) ;
return false ;
}
// Make sure we get a fresh state from the server
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
}
// If not at the head revision, sync up
if ( SourceControlState . IsValid ( ) & & ! SourceControlState - > IsCurrent ( ) )
{
2014-04-23 19:31:56 -04:00
if ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FSync > ( ) , AbsoluteFilename ) = = ECommandResult : : Failed )
2014-03-14 14:13:41 -04:00
{
// Could not sync up with the head revision
GWarn - > EndSlowTask ( ) ;
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCSync " , " Failed to sync collection '{0}' to the head revision. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Check to see if the file exists at the head revision
2015-06-19 07:33:02 -04:00
if ( ! IFileManager : : Get ( ) . FileExists ( * SourceFilename ) )
2014-03-14 14:13:41 -04:00
{
// File was already deleted, consider this a success
GWarn - > EndSlowTask ( ) ;
return true ;
}
2015-07-09 09:59:51 -04:00
FCollection NewCollection ( SourceFilename , false , ECollectionStorageMode : : Static ) ;
2015-06-19 07:33:02 -04:00
FText LoadErrorText ;
if ( ! NewCollection . Load ( LoadErrorText ) )
2014-03-14 14:13:41 -04:00
{
// Failed to load the head revision file so it isn't safe to delete it
GWarn - > EndSlowTask ( ) ;
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCBadHead " , " Failed to load the collection '{0}' at the head revision. {1} " ) , FText : : FromName ( CollectionName ) , LoadErrorText ) ;
2014-03-14 14:13:41 -04:00
return false ;
}
// Loaded the head revision, now merge up so the files are in a consistent state
MergeWithCollection ( NewCollection ) ;
// Make sure we get a fresh state from the server
SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
}
GWarn - > UpdateProgress ( DeleteProgressNumerator + + , DeleteProgressDenominator ) ;
if ( SourceControlState . IsValid ( ) )
{
if ( SourceControlState - > IsAdded ( ) | | SourceControlState - > IsCheckedOut ( ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCDeleteWhileCheckedOut " , " Failed to delete collection '{0}' in source control because it is checked out or open for add. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
else if ( SourceControlState - > CanCheckout ( ) )
{
2014-04-23 19:31:56 -04:00
if ( SourceControlProvider . Execute ( ISourceControlOperation : : Create < FDelete > ( ) , AbsoluteFilename ) = = ECommandResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
// Now check in the delete
const FText ChangelistDesc = FText : : Format ( LOCTEXT ( " CollectionDeletedDesc " , " Deleted collection: {CollectionName} " ) , CollectionNameText ) ;
TSharedRef < FCheckIn , ESPMode : : ThreadSafe > CheckInOperation = ISourceControlOperation : : Create < FCheckIn > ( ) ;
CheckInOperation - > SetDescription ( ChangelistDesc ) ;
if ( SourceControlProvider . Execute ( CheckInOperation , AbsoluteFilename ) )
{
// Deleted successfully!
bDeletedSuccessfully = true ;
}
else
{
FText Unused ;
if ( ! RevertCollection ( Unused ) )
{
UE_LOG ( LogCollectionManager , Warning , TEXT ( " Failed to revert collection '%s' after failing to check in the file that was marked for delete. " ) , * CollectionName . ToString ( ) ) ;
}
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCCheckIn " , " Failed to check in collection '{0}'. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCDeleteFailed " , " Failed to delete collection '{0}' in source control. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else if ( ! SourceControlState - > IsSourceControlled ( ) )
{
// Not yet in the depot or deleted. We can just delete it from disk.
bDeletedSuccessfully = IFileManager : : Get ( ) . Delete ( * AbsoluteFilename ) ;
if ( ! bDeletedSuccessfully )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_DiskDeleteFailed " , " Failed to delete the collection file: {0} " ) , FText : : FromString ( AbsoluteFilename ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else if ( ! SourceControlState - > IsCurrent ( ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCNotCurrent " , " Collection '{0}' is not at head revision after sync. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
else if ( SourceControlState - > IsCheckedOutOther ( ) )
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCCheckedOutOther " , " Collection '{0}' is checked out by another user. " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-06-26 13:13:02 -04:00
OutError = FText : : Format ( LOCTEXT ( " Error_SCCUnknown " , " Could not determine source control state for collection '{0}' " ) , FText : : FromName ( CollectionName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
OutError = LOCTEXT ( " Error_SCCInvalid " , " Source control state is invalid. " ) ;
}
GWarn - > UpdateProgress ( DeleteProgressNumerator + + , DeleteProgressDenominator ) ;
GWarn - > EndSlowTask ( ) ;
return bDeletedSuccessfully ;
}
# undef LOCTEXT_NAMESPACE