Files
UnrealEngineUWP/Engine/Source/Developer/SourceControl/Public/SourceControlOperations.h
paul chipchase b587f92b64 Add support for downloading a file from source control directly without actually checking it out (ie p4 print) and add additional support so that the command can be called from a background thread.
- Only implemented for perforce source control at the moment.
- The source control operation FDownload file can be used just like any other command via ::Execute BUT it will also work with the new method ::TryToDownloadFileFromBackgroundThread which unlike ::Execute can be called from a background thread.

#rb Sebastien.Lussier
#rnx

* PerforceConnection
- Extend ::RunCommand to take an optional FSharedBuffer reference which can be used to return text/binary data downloaded as part of a perforce command
-- Ideally we would replace all of the out parameters with a single struct but that level of refactor would be better suited to its own submit.
- Removed the bool parameter for FP4ClientUser and replaced it with a set of flags instead
- Added a flag to allow FP4ClientUser to store data, either in binary or text format from a perforce command. Although in general this will be the result of a p4 print command.

* PerforceSourceControlCommand
- No longer assert if the command is not on the game thread if the operation indicates that it is safe to run on a background thread.

* PerforceSourceControlModule
- Register the 'DownloadFile' worker

* PerforceSourceControlOperations
- Add FPerforceDownloadFileWorker

* PerforceSourceControlProvider
- Adding implementation for ::TryToDownloadFileFromBackgroundThread.
-- This method is thread safe compared to the normal ::Execute call due to:
-- 1) This method does not accept any callbacks as the most common use of callbacks with ::Execute is to update the UI.
-- 2) This method does not add the command to any of the internal queues nor rely on Tick to process the command.
-- 3) The worker is invoked directly from the calling thread rather than as a background task.
--4) This method does not allow commands that modify the cached states as this would be very difficult to manage without rewriting how all commands are processed to make sure that they are only run one at a time and the results processed in order. NOTE that async commands can be issued from the game thread and can in theory be run in any order on the p4 server depending on how the background task processing works out with no certainty as to the order the results will be processed in. It is unlikely that we will process results out of order but not impossible, but this is a pre-exisiting issue with the current API, extending it to be fully multithreaded will just make it worse.
-- Note that we do not explicity check if the command supports being called from a background thread, as creating the command will check that anyway.
- Calling ::OutputCommandMessages is now thread safe. When called from the game thread it will issue it's output via FMessageLog as before but when called from a background thread we will use the UE_LOG macros instead. Marshalling all output in the same way is something we will need to solve when/if we make the entire API thread safe.

* PerforceControlSettings
- Improve thread safety when calling ::GetConnectionInfo
- If the password is stored in the UI then this is not thread safe but that feature is hidden at the moment due to being unsecure. I am unsure if we want to move the password to be stored in a member variable that can be accessed from any thread and only updated via the UI or not.

* SourceControlOperations
- Add new FDownloadFile operation.
- This can either download the file(s) to FSharedBuffers which can be accessed by calling ::GetFileData OR directly to a directory on disk if the target directory is supplied as part of the constructor.

* ISourceControlOperation
- Add a new base method CanBeCalledFromBackgroundThreads (false by default) which can be overriden by derived classes and return true to indicate that the operation can be run from a background thread. This is intended for use by FDownloadFile with the perforce source control provider in lieu and making the API fully thread safe.
#preflight 60a2290322cce000014243ae

#ROBOMERGE-SOURCE: CL 16346666 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v804-16311228)

[CL 16346668 by paul chipchase in ue5-release-engine-test branch]
2021-05-17 05:07:23 -04:00

697 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Containers/StringFwd.h"
#include "Memory/SharedBuffer.h"
#include "ISourceControlChangelist.h"
#include "SourceControlOperationBase.h"
#define LOCTEXT_NAMESPACE "SourceControl"
/**
* Operation used to connect (or test a connection) to source control
*/
class FConnect : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Connect";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Connecting", "Connecting to source control...");
}
const FString& GetPassword() const
{
return Password;
}
void SetPassword(const FString& InPassword)
{
Password = InPassword;
}
const FText& GetErrorText() const
{
return OutErrorText;
}
void SetErrorText(const FText& InErrorText)
{
OutErrorText = InErrorText;
}
protected:
/** Password we use for this operation */
FString Password;
/** Error text for easy diagnosis */
FText OutErrorText;
};
/**
* Operation used to check files into source control
*/
class FCheckIn : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "CheckIn";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_CheckIn", "Checking file(s) into Source Control...");
}
void SetDescription( const FText& InDescription )
{
Description = InDescription;
}
const FText& GetDescription() const
{
return Description;
}
void SetSuccessMessage( const FText& InSuccessMessage )
{
SuccessMessage = InSuccessMessage;
}
const FText& GetSuccessMessage() const
{
return SuccessMessage;
}
protected:
/** Description of the checkin */
FText Description;
/** A short message listing changelist/revision we submitted, if successful */
FText SuccessMessage;
};
/**
* Operation used to check files out of source control
*/
class FCheckOut : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "CheckOut";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_CheckOut", "Checking file(s) out of Source Control...");
}
};
/**
* Operation used to mark files for add in source control
*/
class FMarkForAdd : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "MarkForAdd";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Add", "Adding file(s) to Source Control...");
}
};
/**
* Operation used to mark files for delete in source control
*/
class FDelete : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Delete";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Delete", "Deleting file(s) from Source Control...");
}
};
/**
* Operation used to revert changes made back to the state they are in source control
*/
class FRevert : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Revert";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Revert", "Reverting file(s) in Source Control...");
}
void SetSoftRevert(const bool bInSoftRevert)
{
bIsSoftRevert = bInSoftRevert;
}
bool IsSoftRevert() const
{
return bIsSoftRevert;
}
protected:
bool bIsSoftRevert = false;
};
/**
* Operation used to sync files to the state they are in source control
*/
class FSync : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Sync";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Sync", "Syncing file(s) from source control...");
}
UE_DEPRECATED(4.26, "FSync::SetRevisionNumber(int32) has been deprecated. Please update to Fsync::SetRevision(const FString&).")
void SetRevisionNumber(int32 InRevisionNumber)
{
SetRevision(FString::Printf(TEXT("%d"), InRevisionNumber));
}
void SetRevision( const FString& InRevision )
{
Revision = InRevision;
}
const FString& GetRevision() const
{
return Revision;
}
protected:
/** Revision to sync to */
FString Revision;
};
/**
* Operation used to update the source control status of files
*/
class FUpdateStatus : public FSourceControlOperationBase
{
public:
FUpdateStatus()
: bUpdateHistory(false)
, bGetOpenedOnly(false)
, bUpdateModifiedState(false)
, bCheckingAllFiles(false)
, bForceQuiet(false)
{
}
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "UpdateStatus";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Update", "Updating file(s) source control status...");
}
void SetUpdateHistory( bool bInUpdateHistory )
{
bUpdateHistory = bInUpdateHistory;
}
void SetGetOpenedOnly( bool bInGetOpenedOnly )
{
bGetOpenedOnly = bInGetOpenedOnly;
}
void SetUpdateModifiedState( bool bInUpdateModifiedState )
{
bUpdateModifiedState = bInUpdateModifiedState;
}
void SetCheckingAllFiles( bool bInCheckingAllFiles )
{
bCheckingAllFiles = bInCheckingAllFiles;
}
void SetQuiet(bool bInQuiet)
{
bForceQuiet = bInQuiet;
}
bool ShouldUpdateHistory() const
{
return bUpdateHistory;
}
bool ShouldGetOpenedOnly() const
{
return bGetOpenedOnly;
}
bool ShouldUpdateModifiedState() const
{
return bUpdateModifiedState;
}
bool ShouldCheckAllFiles() const
{
return bCheckingAllFiles;
}
bool ShouldBeQuiet() const
{
return bForceQuiet;
}
protected:
/** Whether to update history */
bool bUpdateHistory;
/** Whether to just get files that are opened/edited */
bool bGetOpenedOnly;
/** Whether to update the modified state - expensive */
bool bUpdateModifiedState;
/** Hint that we are intending on checking all files in the project - some providers can optimize for this */
bool bCheckingAllFiles;
/** Controls whether the operation will trigger an update or not */
bool bForceQuiet;
};
/**
* Operation used to copy a file or directory from one location to another
*/
class FCopy : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Copy";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Copy", "Copying file(s) in Source Control...");
}
void SetDestination(const FString& InDestination)
{
Destination = InDestination;
}
const FString& GetDestination() const
{
return Destination;
}
protected:
/** Destination path of the copy operation */
FString Destination;
};
/**
* Operation used to resolve a file that is in a conflicted state.
*/
class FResolve : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Resolve";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_Resolve", "Resolving file(s) in Source Control...");
}
};
/**
* Operation used to retrieve pending changelist(s).
*/
class FGetPendingChangelists : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "GetPendingChangelists";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_GetPendingChangelists", "Retrieving pending changelist(s) from Source Control...");
}
};
/**
* Operation used to update the source control status of changelist(s)
*/
class FUpdatePendingChangelistsStatus : public FSourceControlOperationBase
{
public:
void SetUpdateFilesStates(bool bInUpdateFilesStates)
{
bUpdateFilesStates = bInUpdateFilesStates;
}
bool ShouldUpdateFilesStates() const
{
return bUpdateFilesStates;
}
void SetUpdateShelvedFilesStates(bool bInUpdateShelvedFilesStates)
{
bUpdateShelvedFilesStates = bInUpdateShelvedFilesStates;
}
bool ShouldUpdateShelvedFilesStates() const
{
return bUpdateShelvedFilesStates;
}
void SetUpdateAllChangelists(bool bInUpdateAllChangelists)
{
bUpdateAllChangelists = bInUpdateAllChangelists;
ChangelistsToUpdate.Empty();
}
bool ShouldUpdateAllChangelists() const
{
return bUpdateAllChangelists;
}
void SetChangelistsToUpdate(const TArray<FSourceControlChangelistRef>& InChangelistsToUpdate)
{
ChangelistsToUpdate = InChangelistsToUpdate;
bUpdateAllChangelists = false;
}
const TArray<FSourceControlChangelistRef>& GetChangelistsToUpdate() const
{
return ChangelistsToUpdate;
}
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "UpdateChangelistsStatus";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_UpdateChangelistsStatus", "Updating changelist(s) status from Source Control...");
}
private:
bool bUpdateFilesStates = false;
bool bUpdateShelvedFilesStates = false;
bool bUpdateAllChangelists = false;
TArray<FSourceControlChangelistRef> ChangelistsToUpdate;
};
/**
* Operation used to create a new changelist
*/
class FNewChangelist : public FSourceControlOperationBase
{
public:
virtual FName GetName() const override
{
return "NewChangelist";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_NewChangelist", "Creating new changelist from Source Control...");
}
void SetDescription(const FText& InDescription)
{
Description = InDescription;
}
const FText& GetDescription() const
{
return Description;
}
protected:
/** Description of the changelist */
FText Description;
};
/**
* Operation used to delete an empty changelist
*/
class FDeleteChangelist : public FSourceControlOperationBase
{
public:
virtual FName GetName() const override
{
return "DeleteChangelist";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_DeleteChangelist", "Deleting a changelist from Source Control...");
}
};
/**
* Operation to change the description of a changelist
*/
class FEditChangelist : public FSourceControlOperationBase
{
public:
virtual FName GetName() const override
{
return "EditChangelist";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_EditChangelist", "Editing a changelist from Source Control...");
}
void SetDescription(const FText& InDescription)
{
Description = InDescription;
}
const FText& GetDescription() const
{
return Description;
}
protected:
/** Description of the changelist */
FText Description;
};
/**
* Operation to revert unchanged file(s) or all unchanged files in a changelist
*/
class FRevertUnchanged : public FSourceControlOperationBase
{
public:
virtual FName GetName() const override
{
return "RevertUnchanged";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_RevertUnchanged", "Reverting unchanged files from Source Control...");
}
};
/**
* Operation used to move files between changelists
*/
class FMoveToChangelist : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "MoveToChangelist";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_MoveToChangelist", "Moving files to target changelist...");
}
};
/**
* Operation used to shelve files in a changelist
*/
class FShelve : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Shelve";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_ShelveOperation", "Shelving files in changelist...");
}
void SetDescription(const FText& InDescription)
{
Description = InDescription;
}
const FText& GetDescription() const
{
return Description;
}
private:
/** Description of the changelist, will be used only to create a new changelist when needed */
FText Description;
};
/**
* Operation used to unshelve files from a changelist
*/
class FUnshelve : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "Unshelve";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_UnshelveOperation", "Unshelving files from changelist...");
}
};
/**
* Operation used to delete shelved files from a changelist
*/
class FDeleteShelved : public FSourceControlOperationBase
{
public:
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "DeleteShelved";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_DeleteShelvedOperation", "Deleting shelved files from changelist...");
}
};
/**
* Operation used to download a file from the source control server
*/
class FDownloadFile : public FSourceControlOperationBase
{
public:
/**
* This constructor will download the files and keep them in memory,
* which can then be accessed by calling XXX.
*/
FDownloadFile() = default;
/** This constructor will download the files to the given directory */
SOURCECONTROL_API FDownloadFile(FStringView InTargetDirectory);
// ISourceControlOperation interface
virtual FName GetName() const override
{
return "DownloadFile";
}
virtual FText GetInProgressString() const override
{
return LOCTEXT("SourceControl_PrintOperation", "Downloading file from server...");
}
virtual bool CanBeCalledFromBackgroundThreads() const
{
return true;
}
FString GetTargetDirectory() const
{
return TargetDirectory;
}
void AddFileData(const FString& Filename, FSharedBuffer FileData)
{
FileDataMap.Add(Filename, FileData);
}
FSharedBuffer GetFileData(const FStringView& Filename)
{
const uint32 Hash = GetTypeHash(Filename);
FSharedBuffer* Buffer = FileDataMap.FindByHash(Hash, Filename);
if (Buffer != nullptr)
{
return *Buffer;
}
else
{
return FSharedBuffer();
}
}
private:
FString TargetDirectory;
TMap<FString, FSharedBuffer> FileDataMap;
};
#undef LOCTEXT_NAMESPACE