// Copyright (c) 2014-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com) // // Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt // or copy at http://opensource.org/licenses/MIT) #pragma once #include "CoreMinimal.h" #include "ISourceControlOperation.h" #include "ISourceControlState.h" #include "ISourceControlProvider.h" #include "IGitSourceControlWorker.h" #include "GitSourceControlState.h" #include "GitSourceControlMenu.h" class FGitSourceControlCommand; DECLARE_DELEGATE_RetVal(FGitSourceControlWorkerRef, FGetGitSourceControlWorker) /// Git version and capabilites extracted from the string "git version 2.11.0.windows.3" struct FGitVersion { // Git version extracted from the string "git version 2.11.0.windows.3" (Windows) or "git version 2.11.0" (Linux/Mac/Cygwin/WSL) int Major; // 2 Major version number int Minor; // 11 Minor version number int Patch; // 0 Patch/bugfix number int Windows; // 3 Windows specific revision number (under Windows only) uint32 bHasCatFileWithFilters : 1; uint32 bHasGitLfs : 1; uint32 bHasGitLfsLocking : 1; FGitVersion() : Major(0) , Minor(0) , Patch(0) , Windows(0) , bHasCatFileWithFilters(false) , bHasGitLfs(false) , bHasGitLfsLocking(false) { } inline bool IsGreaterOrEqualThan(int InMajor, int InMinor) const { return (Major > InMajor) || (Major == InMajor && (Minor >= InMinor)); } }; class FGitSourceControlProvider : public ISourceControlProvider { public: /** Constructor */ FGitSourceControlProvider() : bGitAvailable(false) , bGitRepositoryFound(false) { } /* ISourceControlProvider implementation */ virtual void Init(bool bForceConnection = true) override; virtual void Close() override; virtual FText GetStatusText() const override; virtual bool IsEnabled() const override; virtual bool IsAvailable() const override; virtual const FName& GetName(void) const override; virtual bool QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest) /* override UE4.20 */ { return false; } virtual void RegisterStateBranches(const TArray& BranchNames, const FString& ContentRoot) /* override UE4.20 */ {} virtual int32 GetStateBranchIndex(const FString& InBranchName) const /* override UE4.20 */ { return INDEX_NONE; } virtual ECommandResult::Type GetState( const TArray& InFiles, TArray< TSharedRef >& OutState, EStateCacheUsage::Type InStateCacheUsage ) override; virtual TArray GetCachedStateByPredicate(TFunctionRef Predicate) const override; virtual FDelegateHandle RegisterSourceControlStateChanged_Handle(const FSourceControlStateChanged::FDelegate& SourceControlStateChanged) override; virtual void UnregisterSourceControlStateChanged_Handle(FDelegateHandle Handle) override; virtual ECommandResult::Type Execute(const TSharedRef& InOperation, const TArray& InFiles, EConcurrency::Type InConcurrency = EConcurrency::Synchronous, const FSourceControlOperationComplete& InOperationCompleteDelegate = FSourceControlOperationComplete()) override; virtual bool CanCancelOperation( const TSharedRef& InOperation ) const override; virtual void CancelOperation( const TSharedRef& InOperation ) override; virtual bool UsesLocalReadOnlyState() const override; virtual bool UsesChangelists() const override; virtual bool UsesCheckout() const override; virtual void Tick() override; virtual TArray< TSharedRef > GetLabels( const FString& InMatchingSpec ) const override; #if SOURCE_CONTROL_WITH_SLATE virtual TSharedRef MakeSettingsWidget() const override; #endif /** * Check configuration, else standard paths, and run a Git "version" command to check the availability of the binary. */ void CheckGitAvailability(); /** * Find the .git/ repository and check it's status. */ void CheckRepositoryStatus(const FString& InPathToGitBinary); /** Is git binary found and working. */ inline bool IsGitAvailable() const { return bGitAvailable; } /** Git version for feature checking */ inline const FGitVersion& GetGitVersion() const { return GitVersion; } /** Get the path to the root of the Git repository: can be the ProjectDir itself, or any parent directory */ inline const FString& GetPathToRepositoryRoot() const { return PathToRepositoryRoot; } /** Git config user.name */ inline const FString& GetUserName() const { return UserName; } /** Git config user.email */ inline const FString& GetUserEmail() const { return UserEmail; } /** Git remote origin url */ inline const FString& GetRemoteUrl() const { return RemoteUrl; } /** Helper function used to update state cache */ TSharedRef GetStateInternal(const FString& Filename); /** * Register a worker with the provider. * This is used internally so the provider can maintain a map of all available operations. */ void RegisterWorker( const FName& InName, const FGetGitSourceControlWorker& InDelegate ); /** Remove a named file from the state cache */ bool RemoveFileFromCache(const FString& Filename); /** Get files in cache */ TArray GetFilesInCache(); private: /** Is git binary found and working. */ bool bGitAvailable; /** Is git repository found. */ bool bGitRepositoryFound; /** Is LFS File Locking enabled? */ bool bUsingGitLfsLocking = false; /** Helper function for Execute() */ TSharedPtr CreateWorker(const FName& InOperationName) const; /** Helper function for running command synchronously. */ ECommandResult::Type ExecuteSynchronousCommand(class FGitSourceControlCommand& InCommand, const FText& Task); /** Issue a command asynchronously if possible. */ ECommandResult::Type IssueCommand(class FGitSourceControlCommand& InCommand); /** Output any messages this command holds */ void OutputCommandMessages(const class FGitSourceControlCommand& InCommand) const; /** Update repository status on Connect and UpdateStatus operations */ void UpdateRepositoryStatus(const class FGitSourceControlCommand& InCommand); /** Path to the root of the Git repository: can be the ProjectDir itself, or any parent directory (found by the "Connect" operation) */ FString PathToRepositoryRoot; /** Git config user.name (from local repository, else globally) */ FString UserName; /** Git config user.email (from local repository, else globally) */ FString UserEmail; /** Name of the current branch */ FString BranchName; /** URL of the "origin" defaut remote server */ FString RemoteUrl; /** Current Commit full SHA1 */ FString CommitId; /** Current Commit description's Summary */ FString CommitSummary; /** State cache */ TMap > StateCache; /** The currently registered source control operations */ TMap WorkersMap; /** Queue for commands given by the main thread */ TArray < FGitSourceControlCommand* > CommandQueue; /** For notifying when the source control states in the cache have changed */ FSourceControlStateChanged OnSourceControlStateChanged; /** Git version for feature checking */ FGitVersion GitVersion; /** Source Control Menu Extension */ FGitSourceControlMenu GitSourceControlMenu; };