blob: 6e0187b2272ac1fc3fab0e3b94a5c6064e6d5aeb [file] [log] [blame]
#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!");
//}
}
}
}