430 lines
13 KiB
C#
430 lines
13 KiB
C#
|
using System;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
|
|||
|
using UnityEditor;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
using Codice.Client.BaseCommands;
|
|||
|
using Codice.Client.Common;
|
|||
|
using Codice.Client.Common.Connection;
|
|||
|
using Codice.Client.Common.Encryption;
|
|||
|
using Codice.Client.Common.EventTracking;
|
|||
|
using Codice.Client.Common.FsNodeReaders;
|
|||
|
using Codice.Client.Common.FsNodeReaders.Watcher;
|
|||
|
using Codice.Client.Common.Threading;
|
|||
|
using Codice.CM.Common;
|
|||
|
using Codice.CM.ConfigureHelper;
|
|||
|
using Codice.CM.WorkspaceServer;
|
|||
|
using Codice.LogWrapper;
|
|||
|
using Codice.Utils;
|
|||
|
using CodiceApp.EventTracking;
|
|||
|
using MacUI;
|
|||
|
using PlasticGui;
|
|||
|
using PlasticGui.EventTracking;
|
|||
|
using PlasticGui.WebApi;
|
|||
|
using PlasticPipe.Certificates;
|
|||
|
using Unity.PlasticSCM.Editor.Configuration;
|
|||
|
using Unity.PlasticSCM.Editor.Tool;
|
|||
|
using Unity.PlasticSCM.Editor.UI;
|
|||
|
|
|||
|
namespace Unity.PlasticSCM.Editor
|
|||
|
{
|
|||
|
internal static class PlasticApp
|
|||
|
{
|
|||
|
static PlasticApp()
|
|||
|
{
|
|||
|
ConfigureLogging();
|
|||
|
|
|||
|
RegisterDomainUnloadHandler();
|
|||
|
|
|||
|
mLog = GetLogger("PlasticApp");
|
|||
|
}
|
|||
|
|
|||
|
internal static ILog GetLogger(string name)
|
|||
|
{
|
|||
|
return LogManager.GetLogger(name);
|
|||
|
}
|
|||
|
|
|||
|
internal static bool HasRunningOperation()
|
|||
|
{
|
|||
|
if (mWorkspaceWindow != null &&
|
|||
|
mWorkspaceWindow.IsOperationInProgress())
|
|||
|
return true;
|
|||
|
|
|||
|
if (mWkInfo == null)
|
|||
|
return false;
|
|||
|
|
|||
|
return TransactionManager.Get().ExistsAnyWorkspaceTransaction(mWkInfo);
|
|||
|
}
|
|||
|
|
|||
|
internal static void InitializeIfNeeded()
|
|||
|
{
|
|||
|
if (mIsInitialized)
|
|||
|
return;
|
|||
|
|
|||
|
mIsInitialized = true;
|
|||
|
|
|||
|
mLog.Debug("InitializeIfNeeded");
|
|||
|
|
|||
|
// Ensures that the Edition Token is initialized from the UVCS installation regardless of if the PlasticWindow is opened
|
|||
|
UnityConfigurationChecker.SynchronizeUnityEditionToken();
|
|||
|
PlasticInstallPath.LogInstallationInfo();
|
|||
|
|
|||
|
if (!PlasticPlugin.IsUnitTesting)
|
|||
|
GuiMessage.Initialize(new UnityPlasticGuiMessage());
|
|||
|
|
|||
|
RegisterExceptionHandlers();
|
|||
|
RegisterBeforeAssemblyReloadHandler();
|
|||
|
RegisterEditorWantsToQuit();
|
|||
|
RegisterEditorQuitting();
|
|||
|
|
|||
|
InitLocalization();
|
|||
|
|
|||
|
if (!PlasticPlugin.IsUnitTesting)
|
|||
|
ThreadWaiter.Initialize(new UnityThreadWaiterBuilder());
|
|||
|
|
|||
|
ServicePointConfigurator.ConfigureServicePoint();
|
|||
|
CertificateUi.RegisterHandler(new ChannelCertificateUiImpl());
|
|||
|
|
|||
|
SetupFsWatcher();
|
|||
|
|
|||
|
// The plastic library holds an internal cache of slugs that relies on the file unityorgs.conf.
|
|||
|
// This file might contain outdated information or not exist at all, so we need to ensure
|
|||
|
// the cloud organizations are loaded and populated to the internal cache during the initialization.
|
|||
|
if (!PlasticPlugin.IsUnitTesting)
|
|||
|
SetupCloudOrganizations();
|
|||
|
|
|||
|
EditionManager.Get().DisableCapability(EnumEditionCapabilities.Extensions);
|
|||
|
|
|||
|
ClientHandlers.Register();
|
|||
|
|
|||
|
PlasticGuiConfig.SetConfigFile(PlasticGuiConfig.UNITY_GUI_CONFIG_FILE);
|
|||
|
|
|||
|
if (!PlasticPlugin.IsUnitTesting)
|
|||
|
{
|
|||
|
mEventSenderScheduler = EventTracking.Configure(
|
|||
|
(PlasticWebRestApi)PlasticGui.Plastic.WebRestAPI,
|
|||
|
ApplicationIdentifier.UnityPackage,
|
|||
|
IdentifyEventPlatform.Get());
|
|||
|
}
|
|||
|
|
|||
|
if (mEventSenderScheduler != null)
|
|||
|
{
|
|||
|
UVCPackageVersion.AsyncGetVersion();
|
|||
|
|
|||
|
mPingEventLoop = new PingEventLoop(
|
|||
|
BuildGetEventExtraInfoFunction.ForPingEvent());
|
|||
|
mPingEventLoop.Start();
|
|||
|
}
|
|||
|
|
|||
|
PlasticMethodExceptionHandling.InitializeAskCredentialsUi(
|
|||
|
new CredentialsUiImpl());
|
|||
|
ClientEncryptionServiceProvider.SetEncryptionPasswordProvider(
|
|||
|
new MissingEncryptionPasswordPromptHandler());
|
|||
|
}
|
|||
|
|
|||
|
internal static void SetWorkspace(WorkspaceInfo wkInfo)
|
|||
|
{
|
|||
|
mWkInfo = wkInfo;
|
|||
|
|
|||
|
RegisterApplicationFocusHandlers();
|
|||
|
|
|||
|
if (mEventSenderScheduler == null)
|
|||
|
return;
|
|||
|
|
|||
|
mPingEventLoop.SetWorkspace(mWkInfo);
|
|||
|
PlasticGui.Plastic.WebRestAPI.SetToken(
|
|||
|
CmConnection.Get().BuildWebApiTokenForCloudEditionDefaultUser());
|
|||
|
}
|
|||
|
|
|||
|
internal static void RegisterWorkspaceWindow(IWorkspaceWindow workspaceWindow)
|
|||
|
{
|
|||
|
mWorkspaceWindow = workspaceWindow;
|
|||
|
}
|
|||
|
|
|||
|
internal static void UnRegisterWorkspaceWindow()
|
|||
|
{
|
|||
|
mWorkspaceWindow = null;
|
|||
|
}
|
|||
|
|
|||
|
internal static void EnableMonoFsWatcherIfNeeded()
|
|||
|
{
|
|||
|
if (PlatformIdentifier.IsMac())
|
|||
|
return;
|
|||
|
|
|||
|
MonoFileSystemWatcher.IsEnabled = true;
|
|||
|
}
|
|||
|
|
|||
|
internal static void DisableMonoFsWatcherIfNeeded()
|
|||
|
{
|
|||
|
if (PlatformIdentifier.IsMac())
|
|||
|
return;
|
|||
|
|
|||
|
MonoFileSystemWatcher.IsEnabled = false;
|
|||
|
}
|
|||
|
|
|||
|
internal static void Dispose()
|
|||
|
{
|
|||
|
if (!mIsInitialized)
|
|||
|
return;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
mLog.Debug("Dispose");
|
|||
|
|
|||
|
UnRegisterExceptionHandlers();
|
|||
|
UnRegisterApplicationFocusHandlers();
|
|||
|
UnRegisterEditorWantsToQuit();
|
|||
|
UnRegisterEditorQuitting();
|
|||
|
|
|||
|
if (mEventSenderScheduler != null)
|
|||
|
{
|
|||
|
mPingEventLoop.Stop();
|
|||
|
// Launching and forgetting to avoid a timeout when sending events files and no
|
|||
|
// network connection is available.
|
|||
|
// This will be refactored once a better mechanism to send event is in place
|
|||
|
mEventSenderScheduler.EndAndSendEventsAsync();
|
|||
|
}
|
|||
|
|
|||
|
if (mWkInfo == null)
|
|||
|
return;
|
|||
|
|
|||
|
WorkspaceFsNodeReaderCachesCleaner.CleanWorkspaceFsNodeReader(mWkInfo);
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
mIsInitialized = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterDomainUnloadHandler()
|
|||
|
{
|
|||
|
AppDomain.CurrentDomain.DomainUnload += AppDomainUnload;
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterEditorWantsToQuit()
|
|||
|
{
|
|||
|
EditorApplication.wantsToQuit += OnEditorWantsToQuit;
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterEditorQuitting()
|
|||
|
{
|
|||
|
EditorApplication.quitting += OnEditorQuitting;
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterBeforeAssemblyReloadHandler()
|
|||
|
{
|
|||
|
AssemblyReloadEvents.beforeAssemblyReload += BeforeAssemblyReload;
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterApplicationFocusHandlers()
|
|||
|
{
|
|||
|
EditorWindowFocus.OnApplicationActivated += OnApplicationActivated;
|
|||
|
|
|||
|
EditorWindowFocus.OnApplicationDeactivated += OnApplicationDeactivated;
|
|||
|
}
|
|||
|
|
|||
|
static void RegisterExceptionHandlers()
|
|||
|
{
|
|||
|
AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
|
|||
|
|
|||
|
Application.logMessageReceivedThreaded += HandleLog;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterDomainUnloadHandler()
|
|||
|
{
|
|||
|
AppDomain.CurrentDomain.DomainUnload -= AppDomainUnload;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterEditorWantsToQuit()
|
|||
|
{
|
|||
|
EditorApplication.wantsToQuit -= OnEditorWantsToQuit;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterEditorQuitting()
|
|||
|
{
|
|||
|
EditorApplication.quitting -= OnEditorQuitting;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterBeforeAssemblyReloadHandler()
|
|||
|
{
|
|||
|
AssemblyReloadEvents.beforeAssemblyReload -= BeforeAssemblyReload;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterApplicationFocusHandlers()
|
|||
|
{
|
|||
|
EditorWindowFocus.OnApplicationActivated -= OnApplicationActivated;
|
|||
|
|
|||
|
EditorWindowFocus.OnApplicationDeactivated -= OnApplicationDeactivated;
|
|||
|
}
|
|||
|
|
|||
|
static void UnRegisterExceptionHandlers()
|
|||
|
{
|
|||
|
AppDomain.CurrentDomain.UnhandledException -= HandleUnhandledException;
|
|||
|
|
|||
|
Application.logMessageReceivedThreaded -= HandleLog;
|
|||
|
}
|
|||
|
|
|||
|
static void AppDomainUnload(object sender, EventArgs e)
|
|||
|
{
|
|||
|
mLog.Debug("AppDomainUnload");
|
|||
|
|
|||
|
UnRegisterDomainUnloadHandler();
|
|||
|
}
|
|||
|
|
|||
|
static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs args)
|
|||
|
{
|
|||
|
Exception ex = (Exception)args.ExceptionObject;
|
|||
|
|
|||
|
if (IsExitGUIException(ex) ||
|
|||
|
!IsPlasticStackTrace(ex.StackTrace))
|
|||
|
throw ex;
|
|||
|
|
|||
|
GUIActionRunner.RunGUIAction(delegate {
|
|||
|
ExceptionsHandler.HandleException("HandleUnhandledException", ex);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
static void HandleLog(string logString, string stackTrace, LogType type)
|
|||
|
{
|
|||
|
if (type != LogType.Exception)
|
|||
|
return;
|
|||
|
|
|||
|
if (!IsPlasticStackTrace(stackTrace))
|
|||
|
return;
|
|||
|
|
|||
|
GUIActionRunner.RunGUIAction(delegate {
|
|||
|
mLog.ErrorFormat("[HandleLog] Unexpected error: {0}", logString);
|
|||
|
mLog.DebugFormat("Stack trace: {0}", stackTrace);
|
|||
|
|
|||
|
string message = logString;
|
|||
|
if (ExceptionsHandler.DumpStackTrace())
|
|||
|
message += Environment.NewLine + stackTrace;
|
|||
|
|
|||
|
GuiMessage.ShowError(message);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
static void OnApplicationActivated()
|
|||
|
{
|
|||
|
mLog.Debug("OnApplicationActivated");
|
|||
|
|
|||
|
EnableMonoFsWatcherIfNeeded();
|
|||
|
}
|
|||
|
|
|||
|
static void OnApplicationDeactivated()
|
|||
|
{
|
|||
|
mLog.Debug("OnApplicationDeactivated");
|
|||
|
|
|||
|
DisableMonoFsWatcherIfNeeded();
|
|||
|
}
|
|||
|
|
|||
|
static void OnEditorQuitting()
|
|||
|
{
|
|||
|
mLog.Debug("OnEditorQuitting");
|
|||
|
|
|||
|
PlasticPlugin.Shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static bool OnEditorWantsToQuit()
|
|||
|
{
|
|||
|
mLog.Debug("OnEditorWantsToQuit");
|
|||
|
|
|||
|
if (!HasRunningOperation())
|
|||
|
return true;
|
|||
|
|
|||
|
return GuiMessage.ShowQuestion(
|
|||
|
PlasticLocalization.GetString(PlasticLocalization.Name.OperationRunning),
|
|||
|
PlasticLocalization.GetString(PlasticLocalization.Name.ConfirmClosingRunningOperation),
|
|||
|
PlasticLocalization.GetString(PlasticLocalization.Name.YesButton));
|
|||
|
}
|
|||
|
|
|||
|
static void BeforeAssemblyReload()
|
|||
|
{
|
|||
|
mLog.Debug("BeforeAssemblyReload");
|
|||
|
|
|||
|
UnRegisterBeforeAssemblyReloadHandler();
|
|||
|
|
|||
|
PlasticShutdown.Shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void InitLocalization()
|
|||
|
{
|
|||
|
string language = null;
|
|||
|
try
|
|||
|
{
|
|||
|
language = ClientConfig.Get().GetLanguage();
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
language = string.Empty;
|
|||
|
}
|
|||
|
|
|||
|
Localization.Init(language);
|
|||
|
PlasticLocalization.SetLanguage(language);
|
|||
|
}
|
|||
|
|
|||
|
static void SetupFsWatcher()
|
|||
|
{
|
|||
|
if (!PlatformIdentifier.IsMac())
|
|||
|
return;
|
|||
|
|
|||
|
WorkspaceWatcherFsNodeReadersCache.Get().SetMacFsWatcherBuilder(
|
|||
|
new MacFsWatcherBuilder());
|
|||
|
}
|
|||
|
|
|||
|
static void SetupCloudOrganizations()
|
|||
|
{
|
|||
|
if (!EditionToken.IsCloudEdition())
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
OrganizationsInformation.LoadCloudOrganizationsAsync();
|
|||
|
}
|
|||
|
|
|||
|
static bool IsPlasticStackTrace(string stackTrace)
|
|||
|
{
|
|||
|
if (stackTrace == null)
|
|||
|
return false;
|
|||
|
|
|||
|
string[] namespaces = new[] {
|
|||
|
"Codice.",
|
|||
|
"GluonGui.",
|
|||
|
"PlasticGui."
|
|||
|
};
|
|||
|
|
|||
|
return namespaces.Any(stackTrace.Contains);
|
|||
|
}
|
|||
|
|
|||
|
static bool IsExitGUIException(Exception ex)
|
|||
|
{
|
|||
|
return ex is ExitGUIException;
|
|||
|
}
|
|||
|
|
|||
|
static void ConfigureLogging()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
string log4netpath = ToolConfig.GetUnityPlasticLogConfigFile();
|
|||
|
|
|||
|
if (!File.Exists(log4netpath))
|
|||
|
WriteLogConfiguration.For(log4netpath);
|
|||
|
|
|||
|
XmlConfigurator.Configure(new FileInfo(log4netpath));
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
//it failed configuring the logging info; nothing to do.
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static bool mIsInitialized;
|
|||
|
static IWorkspaceWindow mWorkspaceWindow;
|
|||
|
static WorkspaceInfo mWkInfo;
|
|||
|
static EventSenderScheduler mEventSenderScheduler;
|
|||
|
static PingEventLoop mPingEventLoop;
|
|||
|
static ILog mLog;
|
|||
|
}
|
|||
|
}
|