560 lines
18 KiB
C#
560 lines
18 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Threading;
|
|
|
|
using Codice.Client.BaseCommands;
|
|
using Codice.Client.BaseCommands.Config;
|
|
using Codice.Client.Commands;
|
|
using Codice.Client.Commands.WkTree;
|
|
using Codice.LogWrapper;
|
|
using GluonGui;
|
|
using PlasticGui;
|
|
using PlasticGui.WorkspaceWindow;
|
|
using Unity.PlasticSCM.Editor.AssetUtils;
|
|
using Unity.PlasticSCM.Editor.UI;
|
|
using Unity.PlasticSCM.Editor.Views.IncomingChanges;
|
|
using Unity.PlasticSCM.Editor.Views.PendingChanges;
|
|
|
|
namespace Unity.PlasticSCM.Editor
|
|
{
|
|
internal class WorkspaceOperationsMonitor
|
|
{
|
|
public interface IDisableAssetsProcessor
|
|
{
|
|
void Disable();
|
|
}
|
|
|
|
internal WorkspaceOperationsMonitor(
|
|
IPlasticAPI plasticApi,
|
|
IDisableAssetsProcessor disableAssetsProcessor,
|
|
bool isGluonMode)
|
|
{
|
|
mPlasticAPI = plasticApi;
|
|
mDisableAssetsProcessor = disableAssetsProcessor;
|
|
mIsGluonMode = isGluonMode;
|
|
}
|
|
|
|
internal void RegisterWindow(
|
|
WorkspaceWindow workspaceWindow,
|
|
ViewHost viewHost,
|
|
NewIncomingChangesUpdater incomingChangesUpdater)
|
|
{
|
|
mWorkspaceWindow = workspaceWindow;
|
|
mViewHost = viewHost;
|
|
mNewIncomingChangesUpdater = incomingChangesUpdater;
|
|
}
|
|
|
|
internal void UnRegisterWindow()
|
|
{
|
|
mWorkspaceWindow = null;
|
|
mViewHost = null;
|
|
mNewIncomingChangesUpdater = null;
|
|
}
|
|
|
|
internal void RegisterPendingChangesView(
|
|
PendingChangesTab pendingChangesTab)
|
|
{
|
|
mPendingChangesTab = pendingChangesTab;
|
|
}
|
|
|
|
internal void RegisterIncomingChangesView(
|
|
IIncomingChangesTab incomingChangesTab)
|
|
{
|
|
mIncomingChangesTab = incomingChangesTab;
|
|
}
|
|
|
|
internal void UnRegisterViews()
|
|
{
|
|
mPendingChangesTab = null;
|
|
mIncomingChangesTab = null;
|
|
}
|
|
|
|
internal void Start()
|
|
{
|
|
mIsRunning = true;
|
|
|
|
Thread thread = new Thread(TaskLoopThread);
|
|
thread.IsBackground = true;
|
|
thread.Start();
|
|
}
|
|
|
|
internal void Stop()
|
|
{
|
|
SetAsFinished();
|
|
}
|
|
|
|
internal void AddAssetsProcessorPathToAdd(
|
|
List<string> paths)
|
|
{
|
|
AddPathsToProcess(
|
|
mAssetsProcessorPathsToAdd, paths,
|
|
mLock, mResetEvent);
|
|
}
|
|
|
|
internal void AddAssetsProcessorPathToDelete(
|
|
string path)
|
|
{
|
|
AddPathsToProcess(
|
|
mAssetsProcessorPathsToDelete,
|
|
new List<string> { path },
|
|
mLock, mResetEvent);
|
|
}
|
|
|
|
internal void AddAssetsProcessorPathToCheckout(
|
|
List<string> paths)
|
|
{
|
|
AddPathsToProcess(
|
|
mAssetsProcessorPathsToCheckout, paths,
|
|
mLock, mResetEvent);
|
|
}
|
|
|
|
internal void AddAssetsProcessorPathToMove(
|
|
string srcPath,
|
|
string dstPath)
|
|
{
|
|
AddPathToMoveToProcess(
|
|
mAssetsProcessorPathsToMove,
|
|
new PathToMove(srcPath, dstPath),
|
|
mLock, mResetEvent);
|
|
}
|
|
|
|
internal void AddPathsToCheckout(
|
|
List<string> paths)
|
|
{
|
|
AddPathsToProcess(
|
|
mPathsToCheckout, paths,
|
|
mLock, mResetEvent);
|
|
}
|
|
|
|
void TaskLoopThread()
|
|
{
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
if (!mIsRunning)
|
|
break;
|
|
|
|
ProcessAssetProcessorOperations(
|
|
mPlasticAPI,
|
|
mAssetsProcessorPathsToAdd,
|
|
mAssetsProcessorPathsToDelete,
|
|
mAssetsProcessorPathsToCheckout,
|
|
mAssetsProcessorPathsToMove,
|
|
mLock,
|
|
mDisableAssetsProcessor);
|
|
|
|
ProcessCheckoutOperation(
|
|
mPlasticAPI,
|
|
mPathsToCheckout,
|
|
mLock);
|
|
|
|
bool hasAssetProcessorOperations = false;
|
|
bool hasCheckoutOperations = false;
|
|
HasPendingOperationsToProcess(
|
|
mAssetsProcessorPathsToAdd,
|
|
mAssetsProcessorPathsToDelete,
|
|
mAssetsProcessorPathsToCheckout,
|
|
mAssetsProcessorPathsToMove,
|
|
mPathsToCheckout,
|
|
mLock,
|
|
out hasAssetProcessorOperations,
|
|
out hasCheckoutOperations);
|
|
|
|
if (hasAssetProcessorOperations ||
|
|
hasCheckoutOperations)
|
|
continue;
|
|
|
|
if (!hasAssetProcessorOperations)
|
|
EditorDispatcher.Dispatch(AfterAssetProcessorOperation);
|
|
|
|
if (!hasCheckoutOperations)
|
|
EditorDispatcher.Dispatch(AfterCheckoutOperation);
|
|
|
|
SleepUntilNextWorkload();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
mLog.ErrorFormat(
|
|
"Error running the tasks loop : {0}", e.Message);
|
|
mLog.DebugFormat(
|
|
"Stacktrace: {0}", e.StackTrace);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AfterAssetProcessorOperation()
|
|
{
|
|
AutoRefresh.PendingChangesView(
|
|
mPendingChangesTab);
|
|
|
|
AutoRefresh.IncomingChangesView(
|
|
mIncomingChangesTab);
|
|
}
|
|
|
|
void AfterCheckoutOperation()
|
|
{
|
|
RefreshAsset.VersionControlCache();
|
|
|
|
if (mIsGluonMode)
|
|
{
|
|
RefreshViewsAfterCheckoutForGluon(mViewHost);
|
|
return;
|
|
}
|
|
|
|
if (mNewIncomingChangesUpdater != null)
|
|
mNewIncomingChangesUpdater.Update();
|
|
|
|
RefreshViewsAfterCheckoutForDeveloper(mWorkspaceWindow);
|
|
}
|
|
|
|
void SetAsFinished()
|
|
{
|
|
if (!mIsRunning)
|
|
return;
|
|
|
|
mIsRunning = false;
|
|
mResetEvent.Set();
|
|
}
|
|
|
|
void SleepUntilNextWorkload()
|
|
{
|
|
mResetEvent.Reset();
|
|
mResetEvent.WaitOne();
|
|
}
|
|
|
|
static void ProcessAssetProcessorOperations(
|
|
IPlasticAPI plasticApi,
|
|
List<string> assetsProcessorPathsToAdd,
|
|
List<string> assetsProcessorPathsToDelete,
|
|
List<string> assetsProcessorPathsToCheckout,
|
|
List<PathToMove> assetsProcessorPathsToMove,
|
|
object lockObj,
|
|
IDisableAssetsProcessor disableAssetsProcessor)
|
|
{
|
|
try
|
|
{
|
|
AssetsProcessorOperations.AddIfNotControlled(
|
|
plasticApi, ExtractPathsToProcess(
|
|
assetsProcessorPathsToAdd, lockObj));
|
|
|
|
AssetsProcessorOperations.DeleteIfControlled(
|
|
plasticApi, ExtractPathsToProcess(
|
|
assetsProcessorPathsToDelete, lockObj));
|
|
|
|
AssetsProcessorOperations.CheckoutIfControlledAndChanged(
|
|
plasticApi, ExtractPathsToProcess(
|
|
assetsProcessorPathsToCheckout, lockObj));
|
|
|
|
AssetsProcessorOperations.MoveIfControlled(
|
|
plasticApi, ExtractPathsToMoveToProcess(
|
|
assetsProcessorPathsToMove, lockObj));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogException(ex);
|
|
|
|
disableAssetsProcessor.Disable();
|
|
}
|
|
}
|
|
|
|
static void ProcessCheckoutOperation(
|
|
IPlasticAPI plasticApi,
|
|
List<string> pathsToProcess,
|
|
object lockObj)
|
|
{
|
|
List<string> paths = ExtractPathsToProcess(
|
|
pathsToProcess, lockObj);
|
|
|
|
if (paths.Count == 0)
|
|
return;
|
|
|
|
plasticApi.Checkout(
|
|
paths.ToArray(),
|
|
CheckoutModifiers.ProcessSymlinks);
|
|
}
|
|
|
|
static void AddPathsToProcess(
|
|
List<string> pathsToProcess,
|
|
List<string> paths,
|
|
object lockObj,
|
|
ManualResetEvent resetEvent)
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
pathsToProcess.AddRange(paths);
|
|
}
|
|
|
|
resetEvent.Set();
|
|
}
|
|
|
|
static void AddPathToMoveToProcess(
|
|
List<PathToMove> pathsToProcess,
|
|
PathToMove path,
|
|
object lockObj,
|
|
ManualResetEvent resetEvent)
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
pathsToProcess.Add(path);
|
|
}
|
|
|
|
resetEvent.Set();
|
|
}
|
|
|
|
static List<string> ExtractPathsToProcess(
|
|
List<string> pathsToProcess,
|
|
object lockObj)
|
|
{
|
|
List<string> result;
|
|
|
|
lock (lockObj)
|
|
{
|
|
result = new List<string>(pathsToProcess);
|
|
pathsToProcess.Clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static List<PathToMove> ExtractPathsToMoveToProcess(
|
|
List<PathToMove> pathsToProcess,
|
|
object lockObj)
|
|
{
|
|
List<PathToMove> result;
|
|
|
|
lock (lockObj)
|
|
{
|
|
result = new List<PathToMove>(pathsToProcess);
|
|
pathsToProcess.Clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void HasPendingOperationsToProcess(
|
|
List<string> assetsProcessorPathsToAdd,
|
|
List<string> assetsProcessorPathsToDelete,
|
|
List<string> assetsProcessorPathsToCheckout,
|
|
List<PathToMove> assetsProcessorPathsToMove,
|
|
List<string> pathsToCheckout,
|
|
object lockObj,
|
|
out bool hasAssetProcessorOperations,
|
|
out bool hasCheckoutOperations)
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
hasAssetProcessorOperations =
|
|
assetsProcessorPathsToAdd.Count > 0 ||
|
|
assetsProcessorPathsToDelete.Count > 0 ||
|
|
assetsProcessorPathsToCheckout.Count > 0 ||
|
|
assetsProcessorPathsToMove.Count > 0;
|
|
|
|
hasCheckoutOperations =
|
|
pathsToCheckout.Count > 0;
|
|
}
|
|
}
|
|
|
|
static void RefreshViewsAfterCheckoutForDeveloper(
|
|
IWorkspaceWindow workspaceWindow)
|
|
{
|
|
if (workspaceWindow == null)
|
|
return;
|
|
|
|
workspaceWindow.RefreshView(ViewType.BranchExplorerView);
|
|
workspaceWindow.RefreshView(ViewType.PendingChangesView);
|
|
workspaceWindow.RefreshView(ViewType.HistoryView);
|
|
}
|
|
|
|
static void RefreshViewsAfterCheckoutForGluon(
|
|
ViewHost viewHost)
|
|
{
|
|
if (viewHost == null)
|
|
return;
|
|
|
|
viewHost.RefreshView(ViewType.WorkspaceExplorerView);
|
|
viewHost.RefreshView(ViewType.CheckinView);
|
|
viewHost.RefreshView(ViewType.IncomingChangesView);
|
|
viewHost.RefreshView(ViewType.SearchView);
|
|
}
|
|
|
|
static void LogException(Exception ex)
|
|
{
|
|
mLog.WarnFormat("Message: {0}", ex.Message);
|
|
|
|
mLog.DebugFormat(
|
|
"StackTrace:{0}{1}",
|
|
Environment.NewLine, ex.StackTrace);
|
|
}
|
|
|
|
static class AssetsProcessorOperations
|
|
{
|
|
internal static void AddIfNotControlled(
|
|
IPlasticAPI plasticApi,
|
|
List<string> paths)
|
|
{
|
|
List<string> fullPaths = new List<string>();
|
|
|
|
IgnoredFilesFilter ignoredFilter = new IgnoredFilesFilter(
|
|
GlobalConfig.Instance);
|
|
|
|
foreach (string path in paths)
|
|
{
|
|
string fullPath = Path.GetFullPath(path);
|
|
string fullPathMeta = MetaPath.GetMetaPath(fullPath);
|
|
|
|
if (plasticApi.GetWorkspaceFromPath(fullPath) == null)
|
|
return;
|
|
|
|
if (plasticApi.GetWorkspaceTreeNode(fullPath) == null &&
|
|
!ignoredFilter.IsIgnored(fullPath))
|
|
fullPaths.Add(fullPath);
|
|
|
|
if (File.Exists(fullPathMeta) &&
|
|
plasticApi.GetWorkspaceTreeNode(fullPathMeta) == null &&
|
|
!ignoredFilter.IsIgnored(fullPath))
|
|
fullPaths.Add(fullPathMeta);
|
|
}
|
|
|
|
if (fullPaths.Count == 0)
|
|
return;
|
|
|
|
IList checkouts;
|
|
plasticApi.Add(
|
|
fullPaths.ToArray(),
|
|
GetDefaultAddOptions(),
|
|
out checkouts);
|
|
}
|
|
|
|
internal static void DeleteIfControlled(
|
|
IPlasticAPI plasticApi,
|
|
List<string> paths)
|
|
{
|
|
foreach (string path in paths)
|
|
{
|
|
string fullPath = Path.GetFullPath(path);
|
|
string fullPathMeta = MetaPath.GetMetaPath(fullPath);
|
|
|
|
if (plasticApi.GetWorkspaceTreeNode(fullPath) != null)
|
|
{
|
|
plasticApi.DeleteControlled(
|
|
fullPath, DeleteModifiers.None);
|
|
}
|
|
|
|
if (plasticApi.GetWorkspaceTreeNode(fullPathMeta) != null)
|
|
{
|
|
plasticApi.DeleteControlled(
|
|
fullPathMeta, DeleteModifiers.None);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void MoveIfControlled(
|
|
IPlasticAPI plasticApi,
|
|
List<PathToMove> paths)
|
|
{
|
|
foreach (PathToMove pathToMove in paths)
|
|
{
|
|
string fullSrcPath = Path.GetFullPath(pathToMove.SrcPath);
|
|
string fullSrcPathMeta = MetaPath.GetMetaPath(fullSrcPath);
|
|
|
|
string fullDstPath = Path.GetFullPath(pathToMove.DstPath);
|
|
string fullDstPathMeta = MetaPath.GetMetaPath(fullDstPath);
|
|
|
|
if (plasticApi.GetWorkspaceTreeNode(fullSrcPath) != null)
|
|
{
|
|
plasticApi.Move(
|
|
fullSrcPath, fullDstPath,
|
|
MoveModifiers.None);
|
|
}
|
|
|
|
if (plasticApi.GetWorkspaceTreeNode(fullSrcPathMeta) != null)
|
|
{
|
|
plasticApi.Move(
|
|
fullSrcPathMeta, fullDstPathMeta,
|
|
MoveModifiers.None);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void CheckoutIfControlledAndChanged(
|
|
IPlasticAPI plasticApi,
|
|
List<string> paths)
|
|
{
|
|
List<string> fullPaths = new List<string>();
|
|
|
|
foreach (string path in paths)
|
|
{
|
|
string fullPath = Path.GetFullPath(path);
|
|
string fullPathMeta = MetaPath.GetMetaPath(fullPath);
|
|
|
|
WorkspaceTreeNode node =
|
|
plasticApi.GetWorkspaceTreeNode(fullPath);
|
|
WorkspaceTreeNode nodeMeta =
|
|
plasticApi.GetWorkspaceTreeNode(fullPathMeta);
|
|
|
|
if (node != null && ChangedFileChecker.IsChanged(
|
|
node.LocalInfo, fullPath, false))
|
|
fullPaths.Add(fullPath);
|
|
|
|
if (nodeMeta != null && ChangedFileChecker.IsChanged(
|
|
nodeMeta.LocalInfo, fullPathMeta, false))
|
|
fullPaths.Add(fullPathMeta);
|
|
}
|
|
|
|
if (fullPaths.Count == 0)
|
|
return;
|
|
|
|
plasticApi.Checkout(
|
|
fullPaths.ToArray(),
|
|
CheckoutModifiers.None);
|
|
}
|
|
|
|
static AddOptions GetDefaultAddOptions()
|
|
{
|
|
AddOptions options = new AddOptions();
|
|
options.AddPrivateParents = true;
|
|
options.NeedCheckPlatformPath = true;
|
|
return options;
|
|
}
|
|
}
|
|
|
|
struct PathToMove
|
|
{
|
|
internal readonly string SrcPath;
|
|
internal readonly string DstPath;
|
|
|
|
internal PathToMove(string srcPath, string dstPath)
|
|
{
|
|
SrcPath = srcPath;
|
|
DstPath = dstPath;
|
|
}
|
|
}
|
|
|
|
object mLock = new object();
|
|
volatile bool mIsRunning;
|
|
volatile ManualResetEvent mResetEvent = new ManualResetEvent(false);
|
|
|
|
List<string> mAssetsProcessorPathsToAdd = new List<string>();
|
|
List<string> mAssetsProcessorPathsToDelete = new List<string>();
|
|
List<string> mAssetsProcessorPathsToCheckout = new List<string>();
|
|
List<PathToMove> mAssetsProcessorPathsToMove = new List<PathToMove>();
|
|
List<string> mPathsToCheckout = new List<string>();
|
|
|
|
PendingChangesTab mPendingChangesTab;
|
|
IIncomingChangesTab mIncomingChangesTab;
|
|
|
|
NewIncomingChangesUpdater mNewIncomingChangesUpdater;
|
|
ViewHost mViewHost;
|
|
IWorkspaceWindow mWorkspaceWindow;
|
|
|
|
readonly bool mIsGluonMode = false;
|
|
readonly IDisableAssetsProcessor mDisableAssetsProcessor;
|
|
readonly IPlasticAPI mPlasticAPI;
|
|
|
|
static readonly ILog mLog = LogManager.GetLogger("WorkspaceOperationsMonitor");
|
|
}
|
|
}
|