Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH1743: Implements functionality for downloading NuGet packages #1768

Merged
merged 1 commit into from Sep 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Cake.NuGet.Tests/Fixtures/NuGetModuleFixture.cs
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
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
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>();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cake-build/cake-team can anyone tell me why this test is failing here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above comment

fixture.Builder.Received(1).As<IPackageInstaller>();
fixture.Builder.Received(1).Singleton();
}
}
}
}
7 changes: 7 additions & 0 deletions src/Cake.NuGet/Cake.NuGet.csproj
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>
15 changes: 15 additions & 0 deletions src/Cake.NuGet/Constants.cs
Expand Up @@ -12,6 +12,21 @@ 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";
}

public static class Paths
{
public const string Tools = "Paths_Tools";
}
}
}
113 changes: 113 additions & 0 deletions src/Cake.NuGet/Install/NuGetFolderProject.cs
@@ -0,0 +1,113 @@
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;
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 IFileSystem _fileSystem;
private readonly INuGetContentResolver _contentResolver;
private readonly ICakeConfiguration _config;
private readonly ICakeLog _log;
private readonly PackagePathResolver _pathResolver;

private static readonly ISet<string> _blackListedPackages = new HashSet<string>(new[]
{
"Cake.Common",
"Cake.Core"
}, StringComparer.OrdinalIgnoreCase);

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

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

if (_fileSystem.Exist(new DirectoryPath(_pathResolver.GetInstallPath(packageIdentity))))
{
_log.Debug("Package {0} has already been installed.", packageIdentity.ToString());
return Task.FromResult(true);
}
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));
var installPath = new DirectoryPath(_pathResolver.GetInstallPath(package));

if (!_fileSystem.Exist(installPath))
{
_log.Warning("Package {0} is not installed.", packageReference.Package);
return Array.Empty<IFile>();
}

files.AddRange(_contentResolver.GetFiles(installPath, 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;
}

var dependencyInstallPath = new DirectoryPath(_pathResolver.GetInstallPath(package));

if (!_fileSystem.Exist(dependencyInstallPath))
{
_log.Warning("Package {0} is not installed.", dependency.Id);
continue;
}

files.AddRange(_contentResolver.GetFiles(dependencyInstallPath, packageReference, type));
}
}

return files;
}
}
}