using System; using System.Collections.Generic; using System.Text; using System.IO; using EnvDTE; using EnvDTE80; using System.Runtime.CompilerServices; using System.Threading; using System.Diagnostics; using System.Text.RegularExpressions; namespace NPanday.Utils { public class MavenRunner { OutputWindowPane output; System.Diagnostics.Process currentProcess; DTE2 dte2; bool stopCalled; System.Threading.Thread outputThread; System.Threading.Thread outputErrorThread; bool running; ManualResetEvent outputThreadEvent; ManualResetEvent outputErrorThreadEvent; public event EventHandler RunnerStopped; protected void onRunnerStopped() { if (RunnerStopped != null) RunnerStopped(this, new EventArgs()); } public MavenRunner(DTE2 dte2) { this.dte2 = dte2; output = MakeOutputWindow(); outputThreadEvent = null; // create a worker thread for outputing the process console out puts running = true; System.Threading.ThreadStart outputThreadStart = new System.Threading.ThreadStart(OutputThreadDelegate); outputThread = new System.Threading.Thread(outputThreadStart); outputThread.Start(); // create a separate worker thread for outputing the Process.StandardError System.Threading.ThreadStart outputErrorThreadStart = new System.Threading.ThreadStart(OutputErrorThreadDelegate); outputErrorThread = new System.Threading.Thread(outputErrorThreadStart); outputErrorThread.Start(); } public void ClearOutputWindow() { output.Clear(); } public void Quit() { running = false; if (IsRunning) { stop(); } } private void DeleteBinDir() { Solution2 solution = (Solution2)dte2.Solution; Projects projs = solution.Projects; bool isFlatProject = true; string[] directoryPartial = solution.FullName.Split("\\".ToCharArray()); string pathPartial = directoryPartial[directoryPartial.Length - 1]; string path = solution.FullName.Substring(0, solution.FullName.Length - pathPartial.Length); path = path.Replace("\\", "//"); string baseDirectory = path; path = path + "/bin"; string[] directories = Directory.GetDirectories(baseDirectory); //searching for pom file to determine whether the project is flat or not foreach (string dir in directories) { string[] dirFiles = Directory.GetFiles(dir); foreach (string f in dirFiles) { if (f.Contains("pom.xml")) { isFlatProject = false; break; } } if (!isFlatProject) { break; } } //searching for target folders to delete the temp directories generated foreach (string dir in directories) { //projects string[] dirFolders = Directory.GetDirectories(baseDirectory); foreach (string dirFolder in dirFolders) { string[] projectFolders = Directory.GetDirectories(dirFolder); //folders in projects foreach (string projectFolder in projectFolders) { if (projectFolder.Contains("target")) { string[] targetFolders = Directory.GetDirectories(projectFolder); foreach (string targetFolder in targetFolders) { string targetChange = targetFolder.Replace("\\", "//"); string[] targetPartial = targetChange.Split("//".ToCharArray()); string targetPath = targetPartial[targetPartial.Length - 1]; if (IsAllDigit(targetPath)) { try { Directory.Delete(targetChange, true); } catch (Exception e) { output.OutputString("\n[delete error]"+e.Message); } } } } } } if (!isFlatProject) { break; } } //Delete the temp bin generated if (Directory.Exists(path) && !isFlatProject) { Directory.Delete(path, true); } } // Function To test for temp folder private bool IsAllDigit(String strToCheck) { bool isValid = true; foreach (char item in strToCheck) { if (!Char.IsDigit(item)) { isValid = false; break; } } return isValid; } private void OutputErrorThreadDelegate() { while (running) { // assign to a local variable to avoid raise exception System.Diagnostics.Process proc = currentProcess; if (!IsRunning) { // no process, make the thread pasivate to save cpu usage; outputErrorThreadEvent = new ManualResetEvent(false); outputErrorThreadEvent.WaitOne(); continue; } StreamReader mvnErrorOutput = proc.StandardError; if (mvnErrorOutput.Peek() != 0) { string value = mvnErrorOutput.ReadLine(); if (!string.IsNullOrEmpty(value) && !"".Equals(value.Trim())) { if (!stopCalled) output.OutputString("\n" + value); } } } } private void OutputThreadDelegate() { while (running) { // assign to a local variable to avoid raise exception System.Diagnostics.Process proc = currentProcess; if (!IsRunning) { // no process, make the thread pasivate to save cpu usage; outputThreadEvent = new ManualResetEvent(false); outputThreadEvent.WaitOne(); continue; } StreamReader mvnOutput = proc.StandardOutput; if (mvnOutput.Peek() != 0) { string value = mvnOutput.ReadLine(); if (!string.IsNullOrEmpty(value) && !"".Equals(value.Trim())) { if(!stopCalled) output.OutputString("\n" + value); } } } } private OutputWindowPane MakeOutputWindow() { // _applicationObject is from the main class try { Window win = dte2.Windows.Item(EnvDTE.Constants.vsWindowKindOutput); OutputWindow outputWindow = (OutputWindow)win.Object; OutputWindowPane outputPane = null; OutputWindowPanes panes = outputWindow.OutputWindowPanes; // Reuse the existing pane (if it exists) for (int i = 1; i <= panes.Count; i++) { outputPane = panes.Item(i); if (outputPane.Name == "NPanday Execution Output:") return outputPane; } OutputWindowPane output = outputWindow.OutputWindowPanes.Add("NPanday Execution Output:"); return output; } catch (Exception e) { throw new Exception("Error In Generation Output Window: " + e.Message); } } [MethodImpl(MethodImplOptions.Synchronized)] private void InitializeMavenRunner() { output.Clear(); output.Activate(); stopCalled = false; } public void execute(string pomFile, string goal) { execute(pomFile, goal, null); } public void execute(string pomFile, string goal, string[] parameters) { InitializeMavenRunner(); if (!(new FileInfo(pomFile)).Exists) { string errStr = string.Format("Pom File {0} not found!", pomFile); output.OutputString(errStr); throw new Exception(errStr); } List paramList = new List(); paramList.Add(pomFile); paramList.Add(goal); if (!"pom.xml".Equals(Path.GetFileName(pomFile), StringComparison.OrdinalIgnoreCase)) { paramList.Add(string.Format("-f\"{0}\"", Path.GetFileName(pomFile))); } if (parameters != null) { paramList.AddRange(parameters); } ExecuteMaven(paramList.ToArray()); } [MethodImpl(MethodImplOptions.Synchronized)] private void ExecuteMaven(string[] param) { // use local variable to avoid raise exception System.Diagnostics.Process process = null; try { process = StartNewMavenProcess((string[])param); currentProcess = process; if (outputThreadEvent != null) { outputThreadEvent.Set(); } if (outputErrorThreadEvent != null) { outputErrorThreadEvent.Set(); } } catch (Exception e) { output.OutputString("Error in Starting Maven Process: " + e.Message); return; } } [MethodImpl(MethodImplOptions.Synchronized)] private System.Diagnostics.Process StartNewMavenProcess(string[] args) { if (this.IsRunning) { throw new Exception("A Maven: Process Is still Running!"); } string pomFile = args[0]; string goal = args[1]; string arguments = null; if (args.Length > 2) { arguments = string.Join(" ", args, 2, args.Length - 2); } if (!string.IsNullOrEmpty(arguments)) { arguments = string.Format("{0} {1}", goal, arguments); } else { arguments = goal; } System.Diagnostics.Process process = new System.Diagnostics.Process(); string mvn_file = Path.Combine(System.Environment.GetEnvironmentVariable("M2_HOME"),@"bin\mvn.bat"); output.OutputString("\n------------------------------------------------------------------"); output.OutputString("\nExecuting Maven"); output.OutputString("\nPom File: " + pomFile); output.OutputString("\nGoal: " + goal); output.OutputString("\nArguments: " + arguments); output.OutputString(string.Format("\nNPanday Command: {0} {1}\n\n", mvn_file, arguments)); output.OutputString("\n------------------------------------------------------------------\n\n"); System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(mvn_file); procInfo.Arguments = arguments; procInfo.WorkingDirectory = Path.GetDirectoryName(pomFile); procInfo.RedirectStandardOutput = true; procInfo.RedirectStandardError = true; procInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; procInfo.CreateNoWindow = true; procInfo.UseShellExecute = false; process.StartInfo = procInfo; process.EnableRaisingEvents = true; process.Exited += new EventHandler(mvn_process_exited); process.Start(); return process; } public bool IsRunning { get { if (currentProcess == null) return false; return !currentProcess.HasExited; } } [MethodImpl(MethodImplOptions.Synchronized)] public void stop() { try { stopCalled = true; output.OutputString("\nStopping current NPanday process."); if (outputThreadEvent != null) { outputThreadEvent.WaitOne(); } currentProcess.Kill(); currentProcess.WaitForExit(); } catch (Exception e) { output.OutputString("Error in Stopping Maven Process: " + e.Message); } } private void mvn_process_exited(object sender, System.EventArgs e) { System.Diagnostics.Process process = (System.Diagnostics.Process)sender; // flush the remaining output StreamReader mvnOutput = process.StandardOutput; if (stopCalled) { output.OutputString("\nNPanday execution stopped successfully."); onRunnerStopped(); return; } if (mvnOutput.Peek() != 0) { string value = mvnOutput.ReadToEnd(); if (!string.IsNullOrEmpty(value) && !"".Equals(value.Trim())) { output.OutputString("\n" + value); } } int exitCode = process.ExitCode; if (exitCode == 0) { output.OutputString("\nNPanday Execution is Successful!"); DeleteBinDir(); } else { output.OutputString("\nNPanday Execution Failed!, with exit code: " + exitCode); DeleteBinDir(); } onRunnerStopped(); // dont display any failed execution if stop //else if (exitCode == -1) //{ // output.OutputString("\nNPanday Execution Failed!"); //} } } }