Skip to content

Commit

Permalink
(cake-buildGH-1743) Implements functionality for downloading NuGet pa…
Browse files Browse the repository at this point in the history
…ckages

- Opt-in via NuGet_UseInProcessClient
- Opt-in load dependencies via NuGet_LoadDependencies
  or add LoadDependencies as parameter in directive
- Fixes cake-build#1743
  • Loading branch information
bjorkstromm authored and devlead committed Sep 9, 2017
1 parent eb2a801 commit c298b02
Show file tree
Hide file tree
Showing 13 changed files with 557 additions and 36 deletions.
9 changes: 9 additions & 0 deletions src/Cake.NuGet.Tests/Fixtures/NuGetModuleFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

using System;
using Cake.Core.Composition;
using Cake.Core.Configuration;
using Cake.Testing;
using NSubstitute;

namespace Cake.NuGet.Tests.Fixtures
Expand All @@ -12,17 +14,24 @@ internal sealed class NuGetModuleFixture<T>
{
public ICakeContainerRegistrar Registrar { get; }
public ICakeRegistrationBuilder Builder { get; }
public FakeConfiguration Configuration { get; }

public NuGetModuleFixture()
{
Registrar = Substitute.For<ICakeContainerRegistrar>();
Builder = Substitute.For<ICakeRegistrationBuilder>();
Configuration = new FakeConfiguration();

Registrar.RegisterType<T>().Returns(Builder);
Builder.As(Arg.Any<Type>()).Returns(Builder);
Builder.Singleton().Returns(Builder);
Builder.Transient().Returns(Builder);
Builder.AsSelf().Returns(Builder);
}

public NuGetModule CreateModule()
{
return new NuGetModule(Configuration);
}
}
}
25 changes: 6 additions & 19 deletions src/Cake.NuGet.Tests/Unit/NuGetLoadDirectiveProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,7 @@ public void Should_Return_True_If_Provider_Is_NuGet()

public sealed class TheLoadMethod
{
[RuntimeFact(TestRuntime.CoreClr)]
public void Should_Throw_On_NET_Core()
{
// Given
var fixture = new NuGetLoadDirectiveProviderFixture();

// When
var result = Record.Exception(() => fixture.Load());

// Then
AssertEx.IsExceptionWithMessage<NotSupportedException>(result, "The NuGet provider for #load is not supported on .NET Core.");
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Install_Package()
{
// Given
Expand All @@ -57,7 +44,7 @@ public void Should_Install_Package()
Assert.Equal("nuget:?package=Cake.Recipe&include=./**/*.cake", result.Package.OriginalString);
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Install_Correct_Package_Type()
{
// Given
Expand All @@ -70,7 +57,7 @@ public void Should_Install_Correct_Package_Type()
Assert.Equal(PackageType.Tool, result.PackageType);
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Install_Package_In_The_Tools_Directory()
{
// Given
Expand All @@ -83,7 +70,7 @@ public void Should_Install_Package_In_The_Tools_Directory()
Assert.Equal("/Working/tools", result.InstallPath.FullPath);
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Install_Package_In_Custom_Tools_Directory_If_Specified_In_Configuration()
{
// Given
Expand All @@ -97,7 +84,7 @@ public void Should_Install_Package_In_Custom_Tools_Directory_If_Specified_In_Con
Assert.Equal("/Working/Bar", result.InstallPath.FullPath);
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Analyze_Installed_Cake_Scripts()
{
// Given
Expand All @@ -113,7 +100,7 @@ public void Should_Analyze_Installed_Cake_Scripts()
Assert.Equal("/Working/tools/Cake.Recipe/file.cake", result.AnalyzedFiles[0].FullPath);
}

[RuntimeFact(TestRuntime.Clr)]
[Fact]
public void Should_Write_To_Log_If_No_Scripts_Were_Found()
{
// Given
Expand Down
65 changes: 58 additions & 7 deletions src/Cake.NuGet.Tests/Unit/NuGetModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Cake.Core.Packaging;
using Cake.Core.Scripting.Processors.Loading;
using Cake.NuGet.Tests.Fixtures;
using Cake.Testing.Xunit;
using NSubstitute;
using Xunit;

Expand All @@ -20,7 +21,7 @@ public void Should_Register_The_NuGet_Content_Resolver()
{
// Given
var fixture = new NuGetModuleFixture<NuGetContentResolver>();
var module = new NuGetModule();
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);
Expand All @@ -31,13 +32,12 @@ public void Should_Register_The_NuGet_Content_Resolver()
fixture.Builder.Received(1).Singleton();
}

#if !NETCORE
[Fact]
[RuntimeFact(TestRuntime.Clr)]
public void Should_Register_The_NuGet_Load_Directive_Provider()
{
// Given
var fixture = new NuGetModuleFixture<NuGetLoadDirectiveProvider>();
var module = new NuGetModule();
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);
Expand All @@ -47,14 +47,47 @@ public void Should_Register_The_NuGet_Load_Directive_Provider()
fixture.Builder.Received(1).As<ILoadDirectiveProvider>();
fixture.Builder.Received(1).Singleton();
}
#endif

[RuntimeFact(TestRuntime.CoreClr)]
public void Should_Register_The_NuGet_Load_Directive_Provider_When_Using_In_Process_Client()
{
// Given
var fixture = new NuGetModuleFixture<NuGetLoadDirectiveProvider>();
fixture.Configuration.SetValue(Constants.NuGet.UseInProcessClient, bool.TrueString);
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);

// Then
fixture.Registrar.Received(1).RegisterType<NuGetLoadDirectiveProvider>();
fixture.Builder.Received(1).As<ILoadDirectiveProvider>();
fixture.Builder.Received(1).Singleton();
}

[RuntimeFact(TestRuntime.CoreClr)]
public void Should_Not_Register_The_NuGet_Load_Directive_Provider_When_Not_Using_In_Process_Client()
{
// Given
var fixture = new NuGetModuleFixture<NuGetLoadDirectiveProvider>();
fixture.Configuration.SetValue(Constants.NuGet.UseInProcessClient, bool.FalseString);
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);

// Then
fixture.Registrar.Received(0).RegisterType<NuGetLoadDirectiveProvider>();
fixture.Builder.Received(0).As<ILoadDirectiveProvider>();
fixture.Builder.Received(0).Singleton();
}

[Fact]
public void Shouls_Register_The_NuGet_Package_Installer()
public void Should_Register_The_NuGet_Package_Installer()
{
// Given
var fixture = new NuGetModuleFixture<NuGetPackageInstaller>();
var module = new NuGetModule();
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);
Expand All @@ -65,6 +98,24 @@ public void Shouls_Register_The_NuGet_Package_Installer()
fixture.Builder.Received(1).As<IPackageInstaller>();
fixture.Builder.Received(1).Singleton();
}

[Fact]
public void Should_Register_The_In_Process_NuGet_Package_Installer_If_Set_In_Configuration()
{
// Given
var fixture = new NuGetModuleFixture<Install.NuGetPackageInstaller>();
fixture.Configuration.SetValue(Constants.NuGet.UseInProcessClient, bool.TrueString);
var module = fixture.CreateModule();

// When
module.Register(fixture.Registrar);

// Then
fixture.Registrar.Received(1).RegisterType<Install.NuGetPackageInstaller>();
fixture.Builder.Received(1).As<INuGetPackageInstaller>();
fixture.Builder.Received(1).As<IPackageInstaller>();
fixture.Builder.Received(1).Singleton();
}
}
}
}
7 changes: 7 additions & 0 deletions src/Cake.NuGet/Cake.NuGet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@
<ItemGroup>
<PackageReference Include="NuGet.Frameworks" Version="4.3.0" />
<PackageReference Include="NuGet.Versioning" Version="4.3.0" />
<PackageReference Include="NuGet.ProjectModel" Version="4.3.0" />
</ItemGroup>

<!-- .NET Framework packages -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="NuGet.PackageManagement" Version="4.3.0" />
</ItemGroup>

<!-- .NET Core packages -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.6' ">
<PackageReference Include="NuGet.PackageManagement.NetStandard" Version="4.3.0" />
</ItemGroup>

</Project>
10 changes: 10 additions & 0 deletions src/Cake.NuGet/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ public static class NuGet
/// The config key name for overriding the default nuget package source
/// </summary>
public const string Source = "NuGet_Source";

/// <summary>
/// The config key name for using the in process client for installing packages
/// </summary>
public const string UseInProcessClient = "NuGet_UseInProcessClient";

/// <summary>
/// The config key name for enabling loading of nuget package dependencies
/// </summary>
public const string LoadDependencies = "NuGet_LoadDependencies";
}
}
}
78 changes: 78 additions & 0 deletions src/Cake.NuGet/Install/NuGetFolderProject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Cake.Core.Configuration;
using Cake.Core.Diagnostics;
using Cake.Core.IO;
using NuGet.Packaging.Core;
using NuGet.ProjectManagement;
using NuGet.Protocol.Core.Types;
using PackageReference = Cake.Core.Packaging.PackageReference;
using PackageType = Cake.Core.Packaging.PackageType;

namespace Cake.NuGet.Install
{
internal sealed class NugetFolderProject : FolderNuGetProject
{
private readonly ISet<PackageIdentity> _installedPackages;
private readonly INuGetContentResolver _contentResolver;
private readonly ICakeConfiguration _config;
private readonly ICakeLog _log;
private static readonly ISet<string> _blackListedPackages = new HashSet<string>(new[]
{
"Cake.Common",
"Cake.Core"
}, StringComparer.OrdinalIgnoreCase);

public NugetFolderProject(INuGetContentResolver contentResolver, ICakeConfiguration config, ICakeLog log, string root) : base(root)
{
_contentResolver = contentResolver ?? throw new ArgumentNullException(nameof(contentResolver));
_config = config ?? throw new ArgumentNullException(nameof(config));
_log = log ?? throw new ArgumentNullException(nameof(log));
_installedPackages = new HashSet<PackageIdentity>();
}

public override Task<bool> InstallPackageAsync(PackageIdentity packageIdentity, DownloadResourceResult downloadResourceResult,
INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
_installedPackages.Add(packageIdentity);
return base.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token);
}

public IReadOnlyCollection<IFile> GetFiles(DirectoryPath directoryPath, PackageReference packageReference, PackageType type)
{
bool loadDependencies;
if (packageReference.Parameters.ContainsKey("LoadDependencies"))
{
bool.TryParse(packageReference.Parameters["LoadDependencies"].FirstOrDefault() ?? bool.TrueString, out loadDependencies);
}
else
{
bool.TryParse(_config.GetValue(Constants.NuGet.LoadDependencies) ?? bool.FalseString, out loadDependencies);
}

var files = new List<IFile>();
var package = _installedPackages.First(p => p.Id.Equals(packageReference.Package, StringComparison.OrdinalIgnoreCase));
files.AddRange(_contentResolver.GetFiles(new FilePath(GetInstalledManifestFilePath(package)).GetDirectory(), packageReference, type));

if (loadDependencies)
{
foreach (var dependency in _installedPackages
.Where(p => !p.Id.Equals(packageReference.Package, StringComparison.OrdinalIgnoreCase)))
{
if (_blackListedPackages.Contains(dependency.Id))
{
_log.Warning("Package {0} depends on package {1}. Will not load this dependency...",
packageReference.Package, dependency.ToString());
continue;
}
files.AddRange(_contentResolver.GetFiles(new FilePath(GetInstalledManifestFilePath(dependency)).GetDirectory(), packageReference, type));
}
}

return files;
}
}
}
Loading

0 comments on commit c298b02

Please sign in to comment.