| #region Apache License, Version 2.0 |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| #endregion |
| |
| using System; |
| using System.Collections.Generic; |
| using System.IO; |
| using System.Runtime.CompilerServices; |
| using System.Threading; |
| using EnvDTE; |
| using EnvDTE80; |
| |
| namespace NPanday.VisualStudio.Addin |
| { |
| 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; |
| |
| 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<string> paramList = new List<string>(); |
| 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!"); |
| //} |
| } |
| } |
| } |