nuget runner and nuget extensions + some integration tests
authorEugene.Petrenko <eugene.petrenko@gmail.com>
Wed, 13 Jul 2011 16:25:42 +0000 (20:25 +0400)
committerEugene.Petrenko <eugene.petrenko@gmail.com>
Wed, 13 Jul 2011 16:25:42 +0000 (20:25 +0400)
15 files changed:
nuget-extensions/nuget-commands/nuget-commands.csproj
nuget-extensions/nuget-commands/nuget-commands.csproj.ReSharper [new file with mode: 0644]
nuget-extensions/nuget-commands/src/NuGetTeamCityPingCommand.cs [new file with mode: 0644]
nuget-extensions/nuget-runner/nuget-runner.csproj
nuget-extensions/nuget-runner/nuget-runner.csproj.ReSharper [new file with mode: 0644]
nuget-extensions/nuget-runner/src/AssemblyHelper.cs [moved from nuget-extensions/nuget-tests/src/AssemblyHelper.cs with 72% similarity]
nuget-extensions/nuget-runner/src/NuGetInstallExtensions.cs [new file with mode: 0644]
nuget-extensions/nuget-runner/src/NuGetLoadException.cs [new file with mode: 0644]
nuget-extensions/nuget-runner/src/NuGetRunMutex.cs [new file with mode: 0644]
nuget-extensions/nuget-runner/src/NuGetRunner.cs [new file with mode: 0644]
nuget-extensions/nuget-runner/src/Program.cs
nuget-extensions/nuget-tests/nuget-tests.csproj
nuget-extensions/nuget-tests/src/NuGet.cs
nuget-extensions/nuget-tests/src/NuGetRunnerTest.cs
nuget-extensions/nuget-tests/src/ProcessExecutor.cs

index fb870f02b87793c58b3d52f73fa38b41c970f695..8701210a0bc203b92826278f998d043906b8f911 100644 (file)
@@ -17,7 +17,7 @@
     <DebugSymbols>true</DebugSymbols>\r
     <DebugType>full</DebugType>\r
     <Optimize>false</Optimize>\r
-    <OutputPath>bin\Debug\</OutputPath>\r
+    <OutputPath>..\bin\</OutputPath>\r
     <DefineConstants>DEBUG;TRACE</DefineConstants>\r
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
@@ -25,7 +25,7 @@
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
     <DebugType>pdbonly</DebugType>\r
     <Optimize>true</Optimize>\r
-    <OutputPath>bin\Release\</OutputPath>\r
+    <OutputPath>..\bin\</OutputPath>\r
     <DefineConstants>TRACE</DefineConstants>\r
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
@@ -45,6 +45,7 @@
   <ItemGroup>\r
     <Compile Include="src\NuGetTeamCityListCommand.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
+    <Compile Include="src\NuGetTeamCityPingCommand.cs" />\r
   </ItemGroup>\r
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
diff --git a/nuget-extensions/nuget-commands/nuget-commands.csproj.ReSharper b/nuget-extensions/nuget-commands/nuget-commands.csproj.ReSharper
new file mode 100644 (file)
index 0000000..1bad51a
--- /dev/null
@@ -0,0 +1,5 @@
+<Configuration>\r
+  <NamespaceFolders>\r
+    <SkipFolder>8FA969EA-85C0-464E-9745-66B9820121A9/d:src</SkipFolder>\r
+  </NamespaceFolders>\r
+</Configuration>
\ No newline at end of file
diff --git a/nuget-extensions/nuget-commands/src/NuGetTeamCityPingCommand.cs b/nuget-extensions/nuget-commands/src/NuGetTeamCityPingCommand.cs
new file mode 100644 (file)
index 0000000..765e872
--- /dev/null
@@ -0,0 +1,16 @@
+using NuGet;\r
+using NuGet.Commands;\r
+\r
+namespace JetBrains.TeamCity.NuGet.ExtendedCommands\r
+{\r
+  [Command("TeamCity.Ping", "Command that dump NuGet and TeamCity extension versions. It is used to check NuGet<->TeamCity communications")]\r
+  public class NuGetTeamCityPingCommand : Command\r
+  {\r
+    public override void ExecuteCommand()\r
+    {\r
+      System.Console.Out.WriteLine("TeamCity NuGet Extension is available.");\r
+      System.Console.Out.WriteLine("NuGet Version = {0}", typeof(Command).Assembly.GetName().Version);\r
+      System.Console.Out.WriteLine("TeamCity Extension Version = {0}", GetType().Assembly.GetName().Version);\r
+    }\r
+  }\r
+}
\ No newline at end of file
index 2686d74319230fc22ff3d0949ef937bbe4c9cdc8..54d3922c985e1532ccafb6f031330c16a03004fe 100644 (file)
@@ -8,8 +8,8 @@
     <ProjectGuid>{B79E58CB-F8FD-4CD6-8B62-10EBA0DF592B}</ProjectGuid>\r
     <OutputType>Exe</OutputType>\r
     <AppDesignerFolder>Properties</AppDesignerFolder>\r
-    <RootNamespace>nuget_runner</RootNamespace>\r
-    <AssemblyName>nuget-runner</AssemblyName>\r
+    <RootNamespace>JetBrains.TeamCity.NuGetRunner</RootNamespace>\r
+    <AssemblyName>JetBrains.TeamCity.NuGetRunner</AssemblyName>\r
     <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>\r
     <TargetFrameworkProfile>Client</TargetFrameworkProfile>\r
     <FileAlignment>512</FileAlignment>\r
@@ -19,7 +19,7 @@
     <DebugSymbols>true</DebugSymbols>\r
     <DebugType>full</DebugType>\r
     <Optimize>false</Optimize>\r
-    <OutputPath>bin\Debug\</OutputPath>\r
+    <OutputPath>..\bin\</OutputPath>\r
     <DefineConstants>DEBUG;TRACE</DefineConstants>\r
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
@@ -28,7 +28,7 @@
     <PlatformTarget>x86</PlatformTarget>\r
     <DebugType>pdbonly</DebugType>\r
     <Optimize>true</Optimize>\r
-    <OutputPath>bin\Release\</OutputPath>\r
+    <OutputPath>..\bin\</OutputPath>\r
     <DefineConstants>TRACE</DefineConstants>\r
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
     <Reference Include="System.Xml" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="src\AssemblyHelper.cs" />\r
+    <Compile Include="src\NuGetInstallExtensions.cs" />\r
+    <Compile Include="src\NuGetLoadException.cs" />\r
+    <Compile Include="src\NuGetRunMutex.cs" />\r
+    <Compile Include="src\NuGetRunner.cs" />\r
     <Compile Include="src\Program.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
   </ItemGroup>\r
diff --git a/nuget-extensions/nuget-runner/nuget-runner.csproj.ReSharper b/nuget-extensions/nuget-runner/nuget-runner.csproj.ReSharper
new file mode 100644 (file)
index 0000000..d9e09ac
--- /dev/null
@@ -0,0 +1,5 @@
+<Configuration>\r
+  <NamespaceFolders>\r
+    <SkipFolder>B79E58CB-F8FD-4CD6-8B62-10EBA0DF592B/d:src</SkipFolder>\r
+  </NamespaceFolders>\r
+</Configuration>
\ No newline at end of file
similarity index 72%
rename from nuget-extensions/nuget-tests/src/AssemblyHelper.cs
rename to nuget-extensions/nuget-runner/src/AssemblyHelper.cs
index f5614c269b1e4fe82e7191312ecf47d02b3fd9f8..145432bd13f03239b116fd4a12b1e3045ae031d7 100644 (file)
@@ -2,7 +2,7 @@ using System;
 using System.IO;\r
 using System.Reflection;\r
 \r
-namespace JetBrains.TeamCity.NuGet.Tests\r
+namespace JetBrains.TeamCity.NuGetRunner\r
 {\r
   public static class AssemblyHelper\r
   {\r
@@ -20,5 +20,10 @@ namespace JetBrains.TeamCity.NuGet.Tests
     {\r
       return GetAssemblyDirectory(type.Assembly);\r
     }\r
+    \r
+    public static string GetAssemblyPath(this Type type)\r
+    {\r
+      return GetAssemblyPath(type.Assembly);\r
+    }\r
   }\r
 }
\ No newline at end of file
diff --git a/nuget-extensions/nuget-runner/src/NuGetInstallExtensions.cs b/nuget-extensions/nuget-runner/src/NuGetInstallExtensions.cs
new file mode 100644 (file)
index 0000000..d0d53b9
--- /dev/null
@@ -0,0 +1,32 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+\r
+namespace JetBrains.TeamCity.NuGetRunner\r
+{\r
+  public class NuGetInstallExtensions\r
+  {\r
+    public NuGetInstallExtensions(NuGetRunner runner, IEnumerable<string> extensions)\r
+    {\r
+      Func<string> computeHome = () => Path.Combine(runner.NuGetExtensionsPath.Value, "TeamCity.Extensions");\r
+      runner.BeforeNuGetStarted += (_, __) =>\r
+                                     {\r
+                                       string home = computeHome();\r
+                                       if (!Directory.Exists(home))\r
+                                         Directory.CreateDirectory(home);\r
+\r
+                                       foreach (var ext in extensions)\r
+                                       {\r
+                                         File.Copy(ext, Path.Combine(home, Path.GetFileName(ext)));\r
+                                       }\r
+                                     };\r
+\r
+      runner.AfterNuGetFinished += (_, __) =>\r
+                                     {\r
+                                       string home = computeHome();\r
+                                       if (Directory.Exists(home))\r
+                                         Directory.Delete(home, true);\r
+                                     };\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/nuget-extensions/nuget-runner/src/NuGetLoadException.cs b/nuget-extensions/nuget-runner/src/NuGetLoadException.cs
new file mode 100644 (file)
index 0000000..9dd5f4c
--- /dev/null
@@ -0,0 +1,15 @@
+using System;\r
+\r
+namespace JetBrains.TeamCity.NuGetRunner\r
+{\r
+  public class NuGetLoadException : Exception\r
+  {\r
+    public NuGetLoadException(string message) : base(message)\r
+    {\r
+    }\r
+\r
+    public NuGetLoadException(string message, Exception innerException) : base(message, innerException)\r
+    {\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/nuget-extensions/nuget-runner/src/NuGetRunMutex.cs b/nuget-extensions/nuget-runner/src/NuGetRunMutex.cs
new file mode 100644 (file)
index 0000000..c80f5d5
--- /dev/null
@@ -0,0 +1,14 @@
+using System.Threading;\r
+\r
+namespace JetBrains.TeamCity.NuGetRunner\r
+{\r
+  public class NuGetRunMutex\r
+  {\r
+    public NuGetRunMutex(NuGetRunner runner)\r
+    {\r
+      var m = new Mutex(false, "JetBrains.TeamCity.NuGet.RunMutex");\r
+      runner.BeforeNuGetStarted += (_, __) => m.WaitOne();\r
+      runner.BeforeNuGetStarted += (_, __) => m.ReleaseMutex();\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/nuget-extensions/nuget-runner/src/NuGetRunner.cs b/nuget-extensions/nuget-runner/src/NuGetRunner.cs
new file mode 100644 (file)
index 0000000..e27d300
--- /dev/null
@@ -0,0 +1,104 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Reflection;\r
+using System.Linq;\r
+\r
+namespace JetBrains.TeamCity.NuGetRunner\r
+{\r
+  public class NuGetRunner\r
+  {\r
+    private readonly string myNuGetExe;\r
+    private readonly Assembly myNuGetAssembly;\r
+    private readonly List<EventHandler> myStartEvents = new List<EventHandler>();\r
+    private readonly List<EventHandler> myFinishEvents = new List<EventHandler>();\r
+\r
+    public NuGetRunner(string NuGetExe)\r
+    {\r
+      myNuGetExe = NuGetExe;\r
+      if (!File.Exists(NuGetExe))\r
+        throw new NuGetLoadException("Failed to find NuGet.exe at " + myNuGetExe);\r
+\r
+      try\r
+      {\r
+        myNuGetAssembly = Assembly.LoadFrom(myNuGetExe);\r
+      }\r
+      catch (Exception e)\r
+      {\r
+        throw new NuGetLoadException("Failed to load NuGet assembly into AppDomain. " + e.Message, e);\r
+      }\r
+\r
+      NuGetExtensionsPath = new Lazy<string>(LocateNuGetExtensionsPath);\r
+    }\r
+\r
+    private string LocateNuGetExtensionsPath()\r
+    {\r
+      var mi = myNuGetAssembly.EntryPoint.DeclaringType;\r
+      foreach (\r
+        var type in\r
+          new Func<Type>[] {() => mi.DeclaringType, () => myNuGetAssembly.GetType("NuGet.Program")}.Select(Compute).\r
+            Where(x => x != null))\r
+      {\r
+        var field = type.GetField("ExtensionsDirectoryRoot",\r
+                                  BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);\r
+        if (field != null && field.FieldType == typeof (string))\r
+        {\r
+          var extensionsPath = field.GetValue(null) as string;\r
+          if (extensionsPath != null)\r
+            return extensionsPath;\r
+        }\r
+      }\r
+      //This is explicit path value taken from NuGet source code\r
+      return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "NuGet", "Commands");\r
+    }\r
+\r
+    public Lazy<string> NuGetExtensionsPath { get; private set; }\r
+\r
+    public event EventHandler BeforeNuGetStarted { add { myStartEvents.Add(value); } remove { myStartEvents.Remove(value);  } }\r
+    public event EventHandler AfterNuGetFinished { add { myFinishEvents.Add(value); } remove { myFinishEvents.Remove(value); } }\r
+\r
+    private void CallEvents(IEnumerable<EventHandler> handler)\r
+    {\r
+      foreach (var h in handler)\r
+      {\r
+        try\r
+        {\r
+          h(this, EventArgs.Empty);\r
+        } catch (Exception e)\r
+        {\r
+          Console.Error.WriteLine("Failed to execute event: " + e);\r
+        }\r
+      }\r
+    }\r
+\r
+    public int Run(string[] argz)\r
+    {\r
+      CallEvents(myStartEvents);\r
+\r
+      try\r
+      {\r
+        var result = myNuGetAssembly.EntryPoint.Invoke(null, new[] {argz});\r
+\r
+        if (result is int)\r
+          return (int) result;\r
+\r
+        return 0;\r
+      } finally\r
+      {\r
+        CallEvents(myFinishEvents);\r
+      }\r
+    }\r
+\r
+    private static T Compute<T>(Func<T> func) where T : class\r
+    {\r
+      try\r
+      {\r
+        return func();\r
+      }\r
+      catch\r
+      {\r
+        return null;\r
+      }\r
+    }\r
+  }\r
+}
\ No newline at end of file
index b8b3888475f2960f0c0b6abcff0ec02f7039d3bd..08ff135cb6be505132c541b50f0bcfc1847d4bf0 100644 (file)
@@ -1,27 +1,54 @@
 ´╗┐using System;\r
+using System.IO;\r
 using System.Linq;\r
-using System.Reflection;\r
 \r
-namespace nuget_runner\r
+namespace JetBrains.TeamCity.NuGetRunner\r
 {\r
   public class Program\r
   {\r
     static int Main(string[] args)\r
+    {\r
+      try\r
+      {\r
+        return Main2(args);\r
+      } catch(Exception e)\r
+      {\r
+        Console.Error.Write("NuGet Runner Failed");\r
+        Console.Error.Write(e);\r
+        return 2;\r
+      }\r
+    }\r
+\r
+    static int Main2(string[] args)\r
     {\r
       Console.Out.WriteLine("JetBrains TeamCity NuGet Runner " + typeof(Program).Assembly.GetName().Version);\r
       Console.Out.WriteLine("Starting NuGet with additional commands");\r
       if (args.Length < 2) return Usage();\r
 \r
       string nuget = args[0];\r
-      string[] nugetArgs = args.Skip(1).ToArray();\r
+      var runner = new NuGetRunner(nuget);\r
+      ConfigureExtensions(runner);\r
 \r
-      var nugetAssembly = Assembly.LoadFrom(nuget);\r
-      var result = nugetAssembly.EntryPoint.Invoke(null, new[] {nugetArgs});\r
-\r
-      if (result is int)\r
-        return (int) result;\r
+      switch(args[1])\r
+      {\r
+        case "---TeamCity.DumpExtensionsPath":\r
+          Console.Out.WriteLine("ExtensionsPath: {0}", runner.NuGetExtensionsPath.Value);\r
+          return 0;\r
+        \r
+        default:\r
+          return runner.Run(args.Skip(1).ToArray());\r
+      }\r
+    }\r
 \r
-      return 0;\r
+    private static void ConfigureExtensions(NuGetRunner runner)\r
+    {\r
+      new NuGetRunMutex(runner);\r
+      new NuGetInstallExtensions(runner,\r
+                                 new[]\r
+                                   {\r
+                                     Path.Combine(runner.GetType().GetAssemblyDirectory(),\r
+                                                  "JetBrains.TeamCity.NuGet.ExtendedCommands.dll")\r
+                                   });\r
     }\r
 \r
     static int Usage()\r
index a952d59d7a792d9b182d43cc369e5ed9317cc7b5..f88b905b232d0c5f57beef5a0e3720e48fb63a33 100644 (file)
@@ -21,6 +21,7 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>\r
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
+    <PlatformTarget>x86</PlatformTarget>\r
   </PropertyGroup>\r
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
     <DebugType>pdbonly</DebugType>\r
@@ -46,7 +47,6 @@
     <Reference Include="System.Xml" />\r
   </ItemGroup>\r
   <ItemGroup>\r
-    <Compile Include="src\AssemblyHelper.cs" />\r
     <Compile Include="src\NuGet.cs" />\r
     <Compile Include="src\NuGetRunnerTest.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
index 70b9818b187b78f08b4886cc963677fb45011143..3449ec8b2b875334ad5f75f2a269b1cb3e701cb3 100644 (file)
@@ -1,5 +1,6 @@
 using System;\r
 using System.IO;\r
+using JetBrains.TeamCity.NuGetRunner;\r
 \r
 namespace JetBrains.TeamCity.NuGet.Tests\r
 {\r
index 1c792d4e6f34fcdcbd9a1037b34747892c1376b5..4e2301350bba9953f4356d2760b99982464e1fac 100644 (file)
@@ -1,5 +1,5 @@
 ´╗┐using System;\r
-using System.Linq;\r
+using JetBrains.TeamCity.NuGetRunner;\r
 using NUnit.Framework;\r
 \r
 namespace JetBrains.TeamCity.NuGet.Tests\r
@@ -7,13 +7,34 @@ namespace JetBrains.TeamCity.NuGet.Tests
   [TestFixture]\r
   public class NuGetRunnerTest\r
   {\r
+    private readonly Lazy<string> myRunnerPath = new Lazy<string>(()=>typeof (Program).Assembly.GetAssemblyPath());\r
+\r
     [Test]\r
     public void TestExcuteNuGet()\r
     {\r
-      var r = ProcessExecutor.ExecuteProcess(NuGet.NuGetPath, "help");\r
+      var r = ProcessExecutor.ExecuteProcess(myRunnerPath.Value, NuGet.NuGetPath, "help");\r
+      Console.Out.WriteLine(r);\r
+\r
+      Assert.IsTrue(r.ExitCode == 0);\r
+    }\r
+\r
+    [Test]\r
+    public void TestDumpExtensionsPath()\r
+    {\r
+      var r = ProcessExecutor.ExecuteProcess(myRunnerPath.Value, NuGet.NuGetPath, "---TeamCity.DumpExtensionsPath");\r
       Console.Out.WriteLine(r);\r
 \r
       Assert.IsTrue(r.ExitCode == 0);\r
     }\r
+\r
+    [Test]\r
+    public void TestCommand_TeamCityPing()\r
+    {\r
+      ProcessExecutor.ExecuteProcess(myRunnerPath.Value, NuGet.NuGetPath, "TeamCity.Ping")\r
+        .Dump()\r
+        .AssertExitedSuccessfully()\r
+        .AssertNoErrorOutput()\r
+        .AssertOutputContains("TeamCity NuGet Extension is available.");\r
+    }\r
   }\r
 }\r
index c2b47af2848afc5fc0775d6b3acdde657d95ea57..56490556c8140fb3d81162774362f069e69a13be 100644 (file)
@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.IO;\r
 using System.Text;\r
 using System.Threading;\r
+using NUnit.Framework;\r
 \r
 namespace JetBrains.TeamCity.NuGet.Tests\r
 {\r
@@ -59,16 +60,52 @@ namespace JetBrains.TeamCity.NuGet.Tests
         ExitCode = exitCode;\r
       }\r
 \r
+      public Result AssertOutputContains(params string[] text)\r
+      {\r
+        foreach (var _ in text)\r
+        {\r
+          var s = _.Trim();\r
+          Assert.IsTrue(Output.Contains(s), "Process Output must contain {0}. Output: {1}", s, Output);\r
+        }\r
+        return this;\r
+      }\r
+\r
+      public Result AssertNoErrorOutput()\r
+      {\r
+        Assert.IsTrue(string.IsNullOrWhiteSpace(Error));\r
+        return this;\r
+      }\r
+\r
+      public Result AssertExitedSuccessfully()\r
+      {\r
+        Assert.That(ExitCode, Is.EqualTo(0));\r
+        return this;\r
+      }\r
+\r
+      public Result Dump()\r
+      {\r
+        Console.Out.WriteLine(this);\r
+        return this;\r
+      }\r
+\r
       public override string ToString()\r
       {\r
-        return new StringBuilder()\r
-          .AppendFormat("ExitCode: {0}\r\n", ExitCode)\r
-          .Append("Output:\n")\r
-          .Append(Output)\r
-          .Append("\n")\r
-          .Append("Error:\n")\r
-          .Append(Error)\r
-          .ToString();\r
+        var sb = new StringBuilder();\r
+        sb.AppendFormat("ExitCode: {0}\r\n", ExitCode);\r
+        if (!string.IsNullOrWhiteSpace(Output))\r
+        {\r
+          sb\r
+            .Append("Output:\n")\r
+            .Append(Output)\r
+            .Append("\n");\r
+        }\r
+        if (!string.IsNullOrWhiteSpace(Error))\r
+        {\r
+          sb\r
+            .Append("Error:\n")\r
+            .Append(Error);\r
+        }\r
+        return sb.ToString();\r
       }\r
     }\r
   }\r