-
-
Notifications
You must be signed in to change notification settings - Fork 251
/
Copy pathNodeExecutorBase.cs
145 lines (121 loc) · 5.33 KB
/
NodeExecutorBase.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web.Helpers;
namespace MadsKristensen.EditorExtensions
{
public abstract class NodeExecutorBase
{
protected static readonly string WebEssentialsResourceDirectory = Path.Combine(Path.GetDirectoryName(typeof(NodeExecutorBase).Assembly.Location), @"Resources");
private static readonly string NodePath = Path.Combine(WebEssentialsResourceDirectory, @"nodejs\node.exe");
///<summary>If set, the executor will not try to use the VS project system.</summary>
public static bool InUnitTests { get; set; }
protected abstract string ServiceName { get; }
protected abstract string CompilerPath { get; }
protected virtual Regex ErrorParsingPattern { get { return null; } }
protected virtual Func<string, IEnumerable<CompilerError>> ParseErrors { get { return ParseErrorsWithRegex; } }
public async Task<CompilerResult> Compile(string sourceFileName, string targetFileName)
{
var scriptArgs = GetArguments(sourceFileName, targetFileName);
var errorOutputFile = Path.GetTempFileName();
var cmdArgs = string.Format("\"{0}\" \"{1}\"", NodePath, CompilerPath);
cmdArgs = string.Format("/c \"{0} {1} > \"{2}\" 2>&1\"", cmdArgs, scriptArgs, errorOutputFile);
ProcessStartInfo start = new ProcessStartInfo("cmd")
{
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = Path.GetDirectoryName(sourceFileName),
Arguments = cmdArgs,
UseShellExecute = false,
CreateNoWindow = true
};
try
{
using (var process = await start.ExecuteAsync())
{
string errorText = "";
if (File.Exists(errorOutputFile) && process.ExitCode != 0)
errorText = File.ReadAllText(errorOutputFile);
return ProcessResult(process, errorText, sourceFileName, targetFileName);
}
}
finally
{
File.Delete(errorOutputFile);
}
}
private CompilerResult ProcessResult(Process process, string errorText, string sourceFileName, string targetFileName)
{
CompilerResult result = new CompilerResult(sourceFileName);
ValidateResult(process, targetFileName, errorText, result);
if (result.IsSuccess)
{
result.Result = PostProcessResult(result.Result, sourceFileName, targetFileName);
if (!InUnitTests)
ProjectHelpers.AddFileToProject(sourceFileName, targetFileName);
}
else
{
Logger.Log(ServiceName + ": " + Path.GetFileName(sourceFileName) + " compilation failed.");
}
return result;
}
private void ValidateResult(Process process, string outputFile, string errorText, CompilerResult result)
{
try
{
if (process.ExitCode == 0)
{
result.Result = File.ReadAllText(outputFile);
result.IsSuccess = true;
}
else
{
result.Errors = ParseErrors(errorText.Replace("\r", ""));
}
}
catch (FileNotFoundException missingFileException)
{
Logger.Log(ServiceName + ": " + Path.GetFileName(outputFile) + " compilation failed. " + missingFileException.Message);
}
}
protected IEnumerable<CompilerError> ParseErrorsWithJson(string error)
{
if (string.IsNullOrEmpty(error))
return null;
try
{
CompilerError[] results = Json.Decode<CompilerError[]>(error);
if (results.Length == 0)
Logger.Log(ServiceName + " parse error: " + error);
return results;
}
catch (ArgumentException)
{
Logger.Log(ServiceName + " parse error: " + error);
return new[] { new CompilerError() { Message = error } };
}
}
protected IEnumerable<CompilerError> ParseErrorsWithRegex(string error)
{
var match = ErrorParsingPattern.Match(error);
if (!match.Success)
{
Logger.Log(ServiceName + " parse error: " + error);
yield return new CompilerError { Message = error };
}
yield return new CompilerError
{
FileName = match.Groups["fileName"].Value,
Message = match.Groups["message"].Value,
Column = int.Parse(match.Groups["column"].Value, CultureInfo.CurrentCulture),
Line = int.Parse(match.Groups["line"].Value, CultureInfo.CurrentCulture)
};
}
protected abstract string GetArguments(string sourceFileName, string targetFileName);
protected abstract string PostProcessResult(string resultSource, string sourceFileName, string targetFileName);
}
}