Skip to content

Commit

Permalink
Merge pull request #110 from PlasticSCM/1004874-smartlocks-workingbra…
Browse files Browse the repository at this point in the history
…nch-filter

Make use of the new --workingbranch to filter multiple destination branches
  • Loading branch information
juliomaqueda authored Mar 5, 2024
2 parents 0e8b294 + b519266 commit 7829ac7
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 122 deletions.
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,20 +522,32 @@ Binary assets should be locked for exclusive access to avoid merge conflicts.

To lock all assets on the whole `Content` directory, you need to put a `lock.conf` in your server directory (for instance `C:\Program Files\PlasticSCM5\server`) with this content:

rep:<repname> [lockserver:[<server>:<port>]]
rep:<repname> [br:[<destination_branch>]] [excluded_branches:<exclusion_pattern>…]
/Content

For instance the more generic one would be:
For instance a specific ruleset to one repository:

rep:*
rep:UE5PlasticPluginDev
/Content

or to be more specific to one repository:
or with multiple destination branches for Locks:

rep:UE5PlasticPluginDev lockserver:localhost:8087
rep:UE5PlasticPluginDev br:/main /main/release excluded_branches:/main/experiments
/Content

or using file extensions instead of a path:

rep:UE5PlasticPluginDev
*.uasset
*.umap

The more generic config applying to all respository on the server would be:

rep: *
/Content

But beware, as this default global rule will not be used (merged) with any other rules specific repository, but completely replaced ("overridden") by them.

On Unity Version Control Cloud, you can just set-up lock rules like that:

/Content
Expand Down
60 changes: 25 additions & 35 deletions Source/PlasticSourceControl/Private/PlasticSourceControlMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "PlasticSourceControlMenu.h"

#include "PlasticSourceControlLock.h"
#include "PlasticSourceControlModule.h"
#include "PlasticSourceControlOperations.h"
#include "PlasticSourceControlProvider.h"
Expand Down Expand Up @@ -188,6 +189,10 @@ void FPlasticSourceControlMenu::ExtendAssetContextMenu()

void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& MenuBuilder, TArray<FAssetData> InAssetObjectPaths)
{
const FPlasticSourceControlProvider& Provider = FPlasticSourceControlModule::Get().GetProvider();
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);
const TArray<FPlasticSourceControlLockRef> SelectedLocks = PlasticSourceControlUtils::GetLocksForWorkingBranch(Provider, Files);

MenuBuilder.BeginSection("AssetPlasticActions", LOCTEXT("UnityVersionControlAssetContextLocksMenuHeading", "Unity Version Control Locks"));

{
Expand All @@ -200,8 +205,8 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me
FSlateIcon(FEditorStyle::GetStyleSetName(), "PropertyWindow.Unlocked"),
#endif
FUIAction(
FExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::ExecuteReleaseLocks, InAssetObjectPaths),
FCanExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::CanReleaseLocks, InAssetObjectPaths)
FExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::ExecuteReleaseLocks, SelectedLocks),
FCanExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::CanReleaseLocks, SelectedLocks)
)
);
}
Expand All @@ -216,8 +221,8 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me
FSlateIcon(FEditorStyle::GetStyleSetName(), "PropertyWindow.Unlocked"),
#endif
FUIAction(
FExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::ExecuteRemoveLocks, InAssetObjectPaths),
FCanExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::CanRemoveLocks, InAssetObjectPaths)
FExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::ExecuteRemoveLocks, SelectedLocks),
FCanExecuteAction::CreateRaw(this, &FPlasticSourceControlMenu::CanRemoveLocks, SelectedLocks)
)
);
}
Expand All @@ -243,16 +248,12 @@ void FPlasticSourceControlMenu::GeneratePlasticAssetContextMenu(FMenuBuilder& Me
MenuBuilder.EndSection();
}

bool FPlasticSourceControlMenu::CanReleaseLocks(TArray<FAssetData> InAssetObjectPaths) const
bool FPlasticSourceControlMenu::CanReleaseLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks) const
{
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

for (const FString& File : Files)
for (const FPlasticSourceControlLockRef& Lock : InSelectedLocks)
{
const FString AbsoluteFilename = FPaths::ConvertRelativePathToFull(File);
const auto State = FPlasticSourceControlModule::Get().GetProvider().GetStateInternal(AbsoluteFilename);
// If exclusively Checked Out (Locked) the lock can be released coming back to it's potential underlying "Retained" status if changes where already checked in the branch
if (!State->LockedBy.IsEmpty() && State->LockedId != ISourceControlState::INVALID_REVISION)
// If "Locked" (currently exclusively Checked Out) the lock can be Released, coming back to it's potential underlying "Retained" status if changes where already checked in the branch
if (Lock->bIsLocked)
{
return true;
}
Expand All @@ -261,45 +262,34 @@ bool FPlasticSourceControlMenu::CanReleaseLocks(TArray<FAssetData> InAssetObject
return false;
}

bool FPlasticSourceControlMenu::CanRemoveLocks(TArray<FAssetData> InAssetObjectPaths) const
bool FPlasticSourceControlMenu::CanRemoveLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks) const
{
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

for (const FString& File : Files)
{
const FString AbsoluteFilename = FPaths::ConvertRelativePathToFull(File);
const auto State = FPlasticSourceControlModule::Get().GetProvider().GetStateInternal(AbsoluteFilename);
// If Locked or Retained, the lock can be removed, that is completely deleted in order to simply ignore the changes from the branch
if (State->LockedId != ISourceControlState::INVALID_REVISION)
{
return true;
}
}

return false;
// All "Locked" or "Retained" locks can be Removed
return (InSelectedLocks.Num() > 0);
}

void FPlasticSourceControlMenu::ExecuteReleaseLocks(TArray<FAssetData> InAssetObjectPaths)
void FPlasticSourceControlMenu::ExecuteReleaseLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks)
{
ExecuteUnlock(InAssetObjectPaths, false);
ExecuteUnlock(MoveTemp(InSelectedLocks), false);
}

void FPlasticSourceControlMenu::ExecuteRemoveLocks(TArray<FAssetData> InAssetObjectPaths)
void FPlasticSourceControlMenu::ExecuteRemoveLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks)
{
ExecuteUnlock(InAssetObjectPaths, true);
ExecuteUnlock(MoveTemp(InSelectedLocks), true);
}

void FPlasticSourceControlMenu::ExecuteUnlock(const TArray<FAssetData>& InAssetObjectPaths, const bool bInRemove)
void FPlasticSourceControlMenu::ExecuteUnlock(TArray<FPlasticSourceControlLockRef>&& InSelectedLocks, const bool bInRemove)
{
if (!Notification.IsInProgress())
{
const TArray<FString> Files = PackageUtils::AssetDataToFileNames(InAssetObjectPaths);

// Launch a custom "Release/Remove Lock" operation
FPlasticSourceControlProvider& Provider = FPlasticSourceControlModule::Get().GetProvider();
const FString& WorkspaceRoot = Provider.GetPathToWorkspaceRoot();
const TArray<FString> Files = PlasticSourceControlUtils::LocksToFileNames(WorkspaceRoot, InSelectedLocks);
TSharedRef<FPlasticUnlock, ESPMode::ThreadSafe> UnlockOperation = ISourceControlOperation::Create<FPlasticUnlock>();
const ECommandResult::Type Result = Provider.Execute(UnlockOperation, Files, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FPlasticSourceControlMenu::OnSourceControlOperationComplete));
UnlockOperation->bRemove = bInRemove;
UnlockOperation->Locks = MoveTemp(InSelectedLocks);
const ECommandResult::Type Result = Provider.Execute(UnlockOperation, Files, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FPlasticSourceControlMenu::OnSourceControlOperationComplete));
if (Result == ECommandResult::Succeeded)
{
// Display an ongoing notification during the whole operation (packages will be reloaded at the completion of the operation)
Expand Down
12 changes: 7 additions & 5 deletions Source/PlasticSourceControl/Private/PlasticSourceControlMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
class FMenuBuilder;
struct FToolMenuSection;

typedef TSharedRef<class FPlasticSourceControlLock, ESPMode::ThreadSafe> FPlasticSourceControlLockRef;

/** Unity Version Control extension of the Source Control toolbar menu */
class FPlasticSourceControlMenu
{
Expand Down Expand Up @@ -59,11 +61,11 @@ class FPlasticSourceControlMenu
/** Called to generate concert asset context menu. */
void GeneratePlasticAssetContextMenu(FMenuBuilder& MenuBuilder, TArray<FAssetData> InAssetObjectPaths);

bool CanRemoveLocks(TArray<FAssetData> InAssetObjectPaths) const;
bool CanReleaseLocks(TArray<FAssetData> InAssetObjectPaths) const;
void ExecuteRemoveLocks(TArray<FAssetData> InAssetObjectPaths);
void ExecuteReleaseLocks(TArray<FAssetData> InAssetObjectPaths);
void ExecuteUnlock(const TArray<FAssetData>& InAssetObjectPaths, const bool bInRemove);
bool CanRemoveLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks) const;
bool CanReleaseLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks) const;
void ExecuteRemoveLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks);
void ExecuteReleaseLocks(TArray<FPlasticSourceControlLockRef> InSelectedLocks);
void ExecuteUnlock(TArray<FPlasticSourceControlLockRef>&& InSelectedLocks, const bool bInRemove);

private:
/** Tracks if the menu extension has been registered with the editor or not */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,9 @@ bool FPlasticGetLocksWorker::Execute(FPlasticSourceControlCommand& InCommand)
TSharedRef<FPlasticGetLocks, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FPlasticGetLocks>(InCommand.Operation);

{
InCommand.bCommandSuccessful = PlasticSourceControlUtils::RunListLocks(GetProvider().GetRepositoryName(), Operation->Locks);
// In the View Locks window, always show locks for all destination branches
const bool bForAllDestBranches = true;
InCommand.bCommandSuccessful = PlasticSourceControlUtils::RunListLocks(GetProvider(), bForAllDestBranches, Operation->Locks);
}

{
Expand Down Expand Up @@ -1083,43 +1085,29 @@ bool FPlasticUnlockWorker::Execute(FPlasticSourceControlCommand& InCommand)
check(InCommand.Operation->GetName() == GetName());
TSharedRef<FPlasticUnlock, ESPMode::ThreadSafe> Operation = StaticCastSharedRef<FPlasticUnlock>(InCommand.Operation);

if (Operation->Locks.Num() > 0)
{
// The View Locks window works with object specs using ItemIds and Branch names
// The unlock operation works on a per-branch basis when multiple Lock destinations are involved
TArray<FString> Branches;
Branches.Reserve(Operation->Locks.Num());
for (const FPlasticSourceControlLockRef& Lock : Operation->Locks)
{
Branches.AddUnique(Lock->Branch);
}
for (const FString& Branch : Branches)
{
TArray<FString> Parameters;
Parameters.Add(TEXT("unlock"));
if (Operation->bRemove)
Parameters.Add(TEXT("--remove"));
InCommand.bCommandSuccessful = true;

Parameters.Add(FString::Printf(TEXT("--branch=%s"), *Branch));
for (const FPlasticSourceControlLockRef& Lock : Operation->Locks)
{
if (Lock->Branch == Branch)
{
Parameters.Add(FString::Printf(TEXT("itemid:%d "), Lock->ItemId));
}
}
InCommand.bCommandSuccessful = PlasticSourceControlUtils::RunCommand(TEXT("lock"), Parameters, TArray<FString>(), InCommand.InfoMessages, InCommand.ErrorMessages);
}
TArray<FString> Branches;
for (const FPlasticSourceControlLockRef& Lock : Operation->Locks)
{
Branches.AddUnique(Lock->Branch);
}
else
for (const FString& Branch : Branches)
{
TArray<FString> Parameters;
Parameters.Add(TEXT("unlock"));
if (Operation->bRemove)
Parameters.Add(TEXT("--remove"));

// But the context "Unlock" menu only deals with filenames (Asset Paths given by Content Browser)
InCommand.bCommandSuccessful = PlasticSourceControlUtils::RunCommand(TEXT("lock"), Parameters, InCommand.Files, InCommand.InfoMessages, InCommand.ErrorMessages);
Parameters.Add(FString::Printf(TEXT("--branch=%s"), *Branch));
for (const FPlasticSourceControlLockRef& Lock : Operation->Locks)
{
if (Lock->Branch == Branch)
{
Parameters.Add(FString::Printf(TEXT("itemid:%d "), Lock->ItemId));
}
}
InCommand.bCommandSuccessful &= PlasticSourceControlUtils::RunCommand(TEXT("lock"), Parameters, TArray<FString>(), InCommand.InfoMessages, InCommand.ErrorMessages);
}

// now update the status of our files
Expand All @@ -1131,7 +1119,10 @@ bool FPlasticUnlockWorker::Execute(FPlasticSourceControlCommand& InCommand)

bool FPlasticUnlockWorker::UpdateStates()
{
return PlasticSourceControlUtils::UpdateCachedStates(MoveTemp(States));
PlasticSourceControlUtils::UpdateCachedStates(MoveTemp(States));
// Note: Force the return to always trigger a refresh of the List of Locks
// It's needed since when removing the Lock of a Checked Out asset there is actually no change in local status as the asset remains Checked Out!
return true;
}

FName FPlasticGetBranchesWorker::GetName() const
Expand Down Expand Up @@ -1186,6 +1177,7 @@ bool FPlasticSwitchToBranchWorker::Execute(FPlasticSourceControlCommand& InComma
{
// the current branch is used to asses the status of Retained Locks
GetProvider().SetBranchName(Operation->BranchName);
PlasticSourceControlUtils::InvalidateLocksCache();
PlasticSourceControlUtils::RunUpdateStatus(Operation->UpdatedFiles, PlasticSourceControlUtils::EStatusSearchType::ControlledOnly, false, InCommand.ErrorMessages, States, InCommand.ChangesetNumber, InCommand.BranchName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,14 +534,14 @@ void ParseFileinfoResults(const TArray<FString>& InResults, TArray<FPlasticSourc
ensureMsgf(InResults.Num() == InOutStates.Num(), TEXT("The fileinfo command should gives the same number of infos as the status command"));

const FPlasticSourceControlProvider& Provider = FPlasticSourceControlModule::Get().GetProvider();

const FString& BranchName = Provider.GetBranchName();
const FString& Repository = Provider.GetRepositoryName();

TArray<FPlasticSourceControlLockRef> Locks;
if (Provider.GetPlasticScmVersion() >= PlasticSourceControlVersions::SmartLocks)
{
PlasticSourceControlUtils::RunListLocks(Repository, Locks);
// In the Content Browser, only show locks applying to the current working branch
const bool bForAllDestBranches = false;
PlasticSourceControlUtils::RunListLocks(Provider, bForAllDestBranches, Locks);
}

// Iterate on all files and all status of the result (assuming same number of line of results than number of file states)
Expand Down
Loading

0 comments on commit 7829ac7

Please sign in to comment.