using System; using System.Diagnostics; using System.IO; using Codice.Client.BaseCommands.EventTracking; using Codice.CM.Common; using Codice.LogWrapper; using Codice.Utils; using Unity.PlasticSCM.Editor.Views; namespace Unity.PlasticSCM.Editor.Tool { internal static class LaunchTool { public interface IShowDownloadPlasticExeWindow { bool Show( WorkspaceInfo wkInfo, bool isGluonMode, string installCloudFrom, string installEnterpriseFrom, string cancelInstallFrom); bool Show( RepositorySpec repSpec, bool isGluonMode, string installCloudFrom, string installEnterpriseFrom, string cancelInstallFrom); } public interface IProcessExecutor { Process ExecuteGUI( string program, string args, string commandFileArg, string commandFileName, int processId); Process ExecuteWindowsGUI( string program, string args, int processId); Process ExecuteProcess(string program, string args); } internal static void OpenGUIForMode( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, WorkspaceInfo wkInfo, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( wkInfo, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenGUI, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenGUI, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenGUI)) return; mLog.DebugFormat( "Opening GUI on wkPath '{0}'.", wkInfo.ClientPath); TrackFeatureUseEvent.For( PlasticGui.Plastic.API.GetRepositorySpec(wkInfo), isGluonMode ? TrackFeatureUseEvent.Features.LaunchGluonTool : TrackFeatureUseEvent.Features.LaunchPlasticTool); if (isGluonMode) { Process gluonProcess = processExecutor.ExecuteGUI( PlasticInstallPath.GetGluonExePath(), string.Format( ToolConstants.Gluon.GUI_WK_EXPLORER_ARG, wkInfo.ClientPath), ToolConstants.Gluon.GUI_COMMAND_FILE_ARG, ToolConstants.Gluon.GUI_COMMAND_FILE, mGluonProcessId); if (gluonProcess != null) mGluonProcessId = gluonProcess.Id; return; } if (PlatformIdentifier.IsMac()) { Process plasticProcess = processExecutor.ExecuteGUI( PlasticInstallPath.GetPlasticExePath(), string.Format( ToolConstants.Plastic.GUI_MACOS_WK_EXPLORER_ARG, wkInfo.ClientPath), ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE_ARG, ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE, mPlasticProcessId); if (plasticProcess != null) mPlasticProcessId = plasticProcess.Id; return; } processExecutor.ExecuteProcess( PlasticInstallPath.GetPlasticExePath(), string.Format( ToolConstants.Plastic.GUI_WINDOWS_WK_ARG, wkInfo.ClientPath)); } internal static void OpenBranchExplorer( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, WorkspaceInfo wkInfo, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( wkInfo, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenBranchExplorer, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenBranchExplorer, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenBranchExplorer)) return; mLog.DebugFormat( "Opening Branch Explorer on wkPath '{0}'.", wkInfo.ClientPath); TrackFeatureUseEvent.For( PlasticGui.Plastic.API.GetRepositorySpec(wkInfo), TrackFeatureUseEvent.Features.LaunchBranchExplorer); if (PlatformIdentifier.IsMac()) { Process plasticProcess = processExecutor.ExecuteGUI( PlasticInstallPath.GetPlasticExePath(), string.Format( ToolConstants.Plastic.GUI_MACOS_BREX_ARG, wkInfo.ClientPath), ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE_ARG, ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE, mPlasticProcessId); if (plasticProcess != null) mPlasticProcessId = plasticProcess.Id; return; } Process brexProcess = processExecutor.ExecuteWindowsGUI( PlasticInstallPath.GetPlasticExePath(), string.Format( ToolConstants.Plastic.GUI_WINDOWS_BREX_ARG, wkInfo.ClientPath), mBrexProcessId); if (brexProcess != null) mBrexProcessId = brexProcess.Id; } internal static void OpenChangesetDiffs( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, RepositorySpec repSpec, string fullChangesetSpec, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( repSpec, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenChangesetDiffs, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenChangesetDiffs, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenChangesetDiffs)) return; mLog.DebugFormat( "Launching changeset diffs for '{0}'", fullChangesetSpec); string exePath = (isGluonMode) ? PlasticInstallPath.GetGluonExePath() : PlasticInstallPath.GetPlasticExePath(); string changesetDiffArg = (isGluonMode) ? ToolConstants.Gluon.GUI_CHANGESET_DIFF_ARG : ToolConstants.Plastic.GUI_CHANGESET_DIFF_ARG; processExecutor.ExecuteProcess(exePath, string.Format( changesetDiffArg, fullChangesetSpec)); } internal static void OpenSelectedChangesetsDiffs( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, RepositorySpec repSpec, string srcFullChangesetSpec, string dstFullChangesetSpec, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( repSpec, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenSelectedChangesetsDiffs, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenSelectedChangesetsDiffs, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenSelectedChangesetsDiffs)) return; mLog.DebugFormat( "Launching selected changesets diffs for '{0}' and '{1}'", srcFullChangesetSpec, dstFullChangesetSpec); string exePath = (isGluonMode) ? PlasticInstallPath.GetGluonExePath() : PlasticInstallPath.GetPlasticExePath(); string selectedChangesetsDiffArgs = (isGluonMode) ? ToolConstants.Gluon.GUI_SELECTED_CHANGESETS_DIFF_ARGS : ToolConstants.Plastic.GUI_SELECTED_CHANGESETS_DIFF_ARGS; processExecutor.ExecuteProcess(exePath, string.Format( selectedChangesetsDiffArgs, srcFullChangesetSpec, dstFullChangesetSpec)); } internal static void OpenBranchDiffs( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, RepositorySpec repSpec, string fullBranchSpec, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( repSpec, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenBranchDiff, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenBranchDiff, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenBranchDiff)) return; mLog.DebugFormat( "Launching branch diffs for '{0}'", fullBranchSpec); string exePath = (isGluonMode) ? PlasticInstallPath.GetGluonExePath() : PlasticInstallPath.GetPlasticExePath(); string branchDiffArg = (isGluonMode) ? ToolConstants.Gluon.GUI_BRANCH_DIFF_ARG : ToolConstants.Plastic.GUI_BRANCH_DIFF_ARG; processExecutor.ExecuteProcess(exePath, string.Format( branchDiffArg, fullBranchSpec)); } internal static void OpenWorkspaceConfiguration( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, WorkspaceInfo wkInfo, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( wkInfo, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenWorkspaceConfiguration, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenWorkspaceConfiguration, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenWorkspaceConfiguration)) return; mLog.DebugFormat( "Opening Workspace Configuration on wkPath '{0}'.", wkInfo.ClientPath); TrackFeatureUseEvent.For( PlasticGui.Plastic.API.GetRepositorySpec(wkInfo), TrackFeatureUseEvent.Features.LaunchPartialConfigure); Process gluonProcess = processExecutor.ExecuteGUI( PlasticInstallPath.GetGluonExePath(), string.Format( ToolConstants.Gluon.GUI_WK_CONFIGURATION_ARG, wkInfo.ClientPath), ToolConstants.Gluon.GUI_COMMAND_FILE_ARG, ToolConstants.Gluon.GUI_COMMAND_FILE, mGluonProcessId); if (gluonProcess == null) return; mGluonProcessId = gluonProcess.Id; } internal static void OpenMerge( IShowDownloadPlasticExeWindow showDownloadPlasticExeWindow, IProcessExecutor processExecutor, WorkspaceInfo wkInfo, bool isGluonMode) { if (showDownloadPlasticExeWindow.Show( wkInfo, isGluonMode, TrackFeatureUseEvent.Features.InstallPlasticCloudFromOpenMerge, TrackFeatureUseEvent.Features.InstallPlasticEnterpriseFromOpenMerge, TrackFeatureUseEvent.Features.CancelPlasticInstallationFromOpenMerge)) return; mLog.DebugFormat( "Opening Merge on wkPath '{0}'.", wkInfo.ClientPath); if (PlatformIdentifier.IsMac()) { Process plasticProcess = processExecutor.ExecuteGUI( PlasticInstallPath.GetPlasticExePath(), string.Format(ToolConstants.Plastic.GUI_MACOS_MERGE_ARG, wkInfo.ClientPath), ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE_ARG, ToolConstants.Plastic.GUI_MACOS_COMMAND_FILE, mPlasticProcessId); if (plasticProcess != null) mPlasticProcessId = plasticProcess.Id; return; } processExecutor.ExecuteProcess( PlasticInstallPath.GetPlasticExePath(), string.Format(ToolConstants.Plastic.GUI_WINDOWS_MERGE_ARG, wkInfo.ClientPath)); } static int mPlasticProcessId = -1; static int mGluonProcessId = -1; static int mBrexProcessId = -1; static readonly ILog mLog = LogManager.GetLogger("LaunchTool"); internal class ShowDownloadPlasticExeWindow : LaunchTool.IShowDownloadPlasticExeWindow { bool LaunchTool.IShowDownloadPlasticExeWindow.Show( WorkspaceInfo wkInfo, bool isGluonMode, string installCloudFrom, string installEnterpriseFrom, string cancelInstallFrom) { RepositorySpec repSpec = PlasticGui.Plastic.API.GetRepositorySpec(wkInfo); return ((LaunchTool.IShowDownloadPlasticExeWindow)this).Show( repSpec, isGluonMode, installCloudFrom, installEnterpriseFrom, cancelInstallFrom); } bool LaunchTool.IShowDownloadPlasticExeWindow.Show( RepositorySpec repSpec, bool isGluonMode, string installCloudFrom, string installEnterpriseFrom, string cancelInstallFrom) { if (IsExeAvailable.ForMode(isGluonMode)) return false; DownloadPlasticExeWindow.ShowWindow( repSpec, isGluonMode, installCloudFrom, installEnterpriseFrom, cancelInstallFrom); return true; } } internal class ProcessExecutor : LaunchTool.IProcessExecutor { Process LaunchTool.IProcessExecutor.ExecuteGUI( string program, string args, string commandFileArg, string commandFileName, int processId) { string commandFile = Path.Combine( Path.GetTempPath(), commandFileName); Process process = GetGUIProcess(program, processId); if (process == null) { mLog.DebugFormat("Executing {0} (new process).", program); return ((LaunchTool.IProcessExecutor)this).ExecuteProcess( program, args + string.Format(commandFileArg, commandFile)); } mLog.DebugFormat("Executing {0} (reuse process pid:{1}).", program, processId); using (StreamWriter writer = new StreamWriter(new FileStream( commandFile, FileMode.Append, FileAccess.Write, FileShare.Read))) { writer.WriteLine(args); } return process; } Process LaunchTool.IProcessExecutor.ExecuteWindowsGUI( string program, string args, int processId) { Process process = GetGUIProcess(program, processId); if (process == null) { mLog.DebugFormat("Executing {0} (new process).", program); return ((LaunchTool.IProcessExecutor)this).ExecuteProcess(program, args); } mLog.DebugFormat("Not executing {0} (existing process pid:{1}).", program, processId); BringWindowToFront.ForWindowsProcess(process.Id); return process; } Process LaunchTool.IProcessExecutor.ExecuteProcess(string program, string args) { mLog.DebugFormat("Execute process: '{0} {1}'", program, args); Process process = BuildProcess(program, args); try { process.Start(); return process; } catch (Exception ex) { mLog.ErrorFormat("Couldn't execute the program {0}: {1}", program, ex.Message); mLog.DebugFormat("Stack trace: {0}", ex.StackTrace); return null; } } Process BuildProcess(string program, string args) { Process result = new Process(); result.StartInfo.FileName = program; result.StartInfo.Arguments = args; result.StartInfo.CreateNoWindow = false; return result; } Process GetGUIProcess(string program, int processId) { if (processId == -1) return null; mLog.DebugFormat("Checking {0} process [pid:{1}].", program, processId); try { Process process = Process.GetProcessById(processId); if (process == null) return null; return process.HasExited ? null : process; } catch { // process is not running return null; } } readonly ILog mLog = LogManager.GetLogger("ProcessExecutor"); } } }