forked from dotnet/java-interop
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProcessRocks.cs
More file actions
187 lines (150 loc) · 5.34 KB
/
Copy pathProcessRocks.cs
File metadata and controls
187 lines (150 loc) · 5.34 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace MonoDroid.Utils {
public static class ProcessRocks {
public static IEnumerable<string> ReadStandardOutput (IEnumerable<string> commandLine, bool printCommandLine)
{
var psi = new ProcessStartInfo () {
FileName = commandLine.First (),
Arguments = "\"" + string.Join ("\" \"", commandLine.Skip (1).ToArray ()) + "\"",
};
return ReadStandardOutput (psi, printCommandLine);
}
public static IEnumerable<string> ReadStandardOutput (ProcessStartInfo psi, bool printCommandLine)
{
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
if (printCommandLine)
Console.WriteLine ("Running command: {0} {1}", psi.FileName, psi.Arguments);
var timer = Stopwatch.StartNew ();
using (Process p = Process.Start (psi)) {
var stderr = new StringBuilder ();
Func<string> readStderrLine = p.StandardError.ReadLine;
AsyncCallback appendStderr = null;
IAsyncResult r;
appendStderr = ar => {
try {
string l = readStderrLine.EndInvoke (ar);
if (l == null) {
r = null;
return;
}
stderr.Append (l).Append (Environment.NewLine);
r = readStderrLine.BeginInvoke (appendStderr, null);
}
catch (ObjectDisposedException) {
r = null;
// ignore; 'p' was disposed while we were blocking on stderr.
}
};
r = readStderrLine.BeginInvoke (appendStderr, null);
string line;
while ((line = p.StandardOutput.ReadLine ()) != null) {
yield return line;
}
IAsyncResult _r;
while ((_r = r) != null && !_r.IsCompleted)
_r.AsyncWaitHandle.WaitOne ();
p.WaitForExit ();
if (p.ExitCode != 0) {
_r = r;
if (_r != null && !_r.IsCompleted)
_r.AsyncWaitHandle.WaitOne ();
string e = stderr.ToString ();
throw new CommandFailedException (psi.FileName, psi.Arguments, e, p.ExitCode);
}
}
timer.Stop ();
if (printCommandLine)
Console.WriteLine ("\tProcess executed in: {0}", timer.Elapsed);
}
}
static class MessageUtils {
internal static string MapGeneratedToProjectFile (string filename)
{
// At this point, all we have is something like this:
// ...\MonoDroidApplication22\obj\Debug\res\layout\main.axml
// We are going to best guess it back to the original file:
// ...\MonoDroidApplication22\Resources\Layout\Main.axml
try {
// Find the root, by stripping off \obj and beyond
string root = filename.Substring (0, filename.IndexOf (string.Format ("{0}obj{0}", Path.DirectorySeparatorChar)));
var files = FindFileInDirectory (root, Path.GetFileName (filename));
// This pretty much only works if there is only 1 matching file
// name, which should be the commong case
if (files.Count == 1)
return files[0];
// We couldn't successfully map, return only the file name,
// and let the user figure it out.
return Path.GetFileName (filename);
} catch (Exception) {
return Path.GetFileName (filename);
}
}
private static List<string> FindFileInDirectory (string directory, string filename)
{
var results = new List<string> ();
// Recurse
foreach (var dir in Directory.GetDirectories (directory)) {
// Don't go into obj or bin directories
if (Path.GetFileName (dir).ToLowerInvariant () == "obj" || Path.GetFileName (dir).ToLowerInvariant () == "bin")
continue;
results.AddRange (FindFileInDirectory (dir, filename));
}
// Check this directory for the file
foreach (var file in Directory.GetFiles (directory)) {
if (Path.GetFileName (file).ToLowerInvariant () == filename.ToLowerInvariant ())
results.Add (file);
}
return results;
}
}
class CommandFailedException : InvalidOperationException
{
public string FileName { get; private set; }
public string Arguments { get; private set; }
public string ErrorLog { get; private set; }
public int ExitCode { get; private set; }
public new string Message { get; private set; }
public CommandFailedException () : base ()
{
}
public CommandFailedException (string message) : base (message)
{
}
public CommandFailedException (string filename, string arguments, string errorLog, int exitCode)
{
FileName = filename;
Arguments = arguments;
ErrorLog = errorLog;
ExitCode = exitCode;
Message = "Command failed. Command: " + FileName + " " + Arguments + "\n" +
"\t" + (string.IsNullOrEmpty (ErrorLog) ? "<none>\n" : ErrorLog);
}
public string VSFormattedErrorLog {
get { return FormatForVS (ErrorLog); }
}
private string FormatForVS (string text)
{
Regex regex = new Regex (@"(?<FileName>.+):(?<LineNumber>\d+): error: Error: (?<Error>.+)");
if (!regex.IsMatch (text))
return text;
var match = regex.Match (text);
string filename = match.Groups["FileName"].Value;
string line = match.Groups["LineNumber"].Value;
string error = match.Groups["Error"].Value;
int line_no;
if (!int.TryParse (line, out line_no))
return text;
// Fix off by one error
line_no++;
return string.Format ("{0}({1}): error 1: {2}", MessageUtils.MapGeneratedToProjectFile (filename), line_no, error);
}
}
}