2 using System.Collections.Generic;
\r
3 using System.Diagnostics;
\r
5 using System.Reflection;
\r
8 using System.Threading;
\r
10 namespace JetBrains.TeamCity.NuGetRunner
\r
12 public class NuGetRunner
\r
14 private readonly string myNuGetExe;
\r
15 private readonly Assembly myNuGetAssembly;
\r
16 private readonly List<EventHandler> myStartEvents = new List<EventHandler>();
\r
17 private readonly List<EventHandler> myFinishEvents = new List<EventHandler>();
\r
19 public NuGetRunner(string NuGetExe)
\r
21 myNuGetExe = NuGetExe;
\r
22 if (!File.Exists(NuGetExe))
\r
23 throw new NuGetLoadException("Failed to find NuGet.exe at " + myNuGetExe);
\r
27 myNuGetAssembly = Assembly.LoadFrom(myNuGetExe);
\r
31 throw new NuGetLoadException("Failed to load NuGet assembly into AppDomain. " + e.Message, e);
\r
34 NuGetExtensionsPath = new Lazy<string>(LocateNuGetExtensionsPath);
\r
37 private string LocateNuGetExtensionsPath()
\r
39 var mi = myNuGetAssembly.EntryPoint.DeclaringType;
\r
42 new Func<Type>[] {() => mi.DeclaringType, () => myNuGetAssembly.GetType("NuGet.Program")}.Select(Compute).
\r
43 Where(x => x != null))
\r
45 var field = type.GetField("ExtensionsDirectoryRoot",
\r
46 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
\r
47 if (field != null && field.FieldType == typeof (string))
\r
49 var extensionsPath = field.GetValue(null) as string;
\r
50 if (extensionsPath != null)
\r
51 return extensionsPath;
\r
54 //This is explicit path value taken from NuGet source code
\r
55 return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "NuGet", "Commands");
\r
58 public Lazy<string> NuGetExtensionsPath { get; private set; }
\r
60 public event EventHandler BeforeNuGetStarted { add { myStartEvents.Add(value); } remove { myStartEvents.Remove(value); } }
\r
61 public event EventHandler AfterNuGetFinished { add { myFinishEvents.Add(value); } remove { myFinishEvents.Remove(value); } }
\r
63 private void CallEvents(IEnumerable<EventHandler> handler)
\r
65 foreach (var h in handler)
\r
69 h(this, EventArgs.Empty);
\r
70 } catch (Exception e)
\r
72 Console.Error.WriteLine("Failed to execute event: " + e);
\r
77 public int Run(IEnumerable<string> argz)
\r
79 CallEvents(myStartEvents);
\r
83 var process = Process.Start(new ProcessStartInfo
\r
85 FileName = myNuGetExe,
\r
86 //TODO use escapring safe escaping here.
\r
87 Arguments = string.Join(" ", argz.Select(x=>x.IndexOfAny(" \t\n\r".ToCharArray()) >=0 ? "\"" + x + "\"" : x)),
\r
88 UseShellExecute = false,
\r
89 RedirectStandardInput = true,
\r
90 RedirectStandardError = true,
\r
91 RedirectStandardOutput = true,
\r
92 CreateNoWindow = true,
\r
95 process.StandardInput.Close();
\r
96 Func<StreamReader, TextWriter, Thread> readOutput = (si, so) =>
\r
98 var th = new Thread(delegate()
\r
101 while ((i = si.Read()) >= 0) so.Write((char)i);
\r
102 }) { Name = "Process output reader " + process.Id };
\r
107 var t1 = readOutput(process.StandardOutput, Console.Out);
\r
108 var t2 = readOutput(process.StandardError, Console.Error);
\r
110 process.WaitForExit();
\r
112 t1.Join(TimeSpan.FromMinutes(5));
\r
113 t2.Join(TimeSpan.FromMinutes(5));
\r
115 return process.ExitCode;
\r
116 /*AppDomain dom = AppDomain.CreateDomain("NuGet Launcher Domain");
\r
117 var result = dom.ExecuteAssembly(myNuGetExe, argz);
\r
118 return result is int ? (int) result : 0;*/
\r
122 CallEvents(Enumerable.Reverse(myFinishEvents));
\r
126 private static T Compute<T>(Func<T> func) where T : class
\r