Created
March 7, 2018 22:06
-
-
Save natemcmaster/abc882abae0f567eca6496624dc02c63 to your computer and use it in GitHub Desktop.
Custom restore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>netcoreapp2.0</TargetFramework> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.1.1" /> | |
<PackageReference Include="NuGet.Build.Tasks" Version="4.5.0" /> | |
</ItemGroup> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading.Tasks; | |
using McMaster.Extensions.CommandLineUtils; | |
using NuGet.Common; | |
namespace custom_restore | |
{ | |
internal class MyNuGetLogger : LoggerBase | |
{ | |
private IReporter _reporter; | |
public MyNuGetLogger(IReporter reporter) | |
{ | |
this._reporter = reporter; | |
} | |
public override void Log(ILogMessage message) | |
{ | |
LogAsync(message); | |
} | |
public override Task LogAsync(ILogMessage message) | |
{ | |
if (message.Level == LogLevel.Warning) | |
{ | |
_reporter.Warn(message.FormatWithCode()); | |
} | |
else if (message.Level == LogLevel.Error) | |
{ | |
_reporter.Error(message.FormatWithCode()); | |
} | |
else if (message.Level > LogLevel.Information) | |
{ | |
_reporter.Output(message.FormatWithCode()); | |
} | |
else | |
{ | |
_reporter.Verbose(message.FormatWithCode()); | |
} | |
return Task.CompletedTask; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel.DataAnnotations; | |
using System.IO; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using McMaster.Extensions.CommandLineUtils; | |
using NuGet.Commands; | |
using NuGet.Configuration; | |
using NuGet.Versioning; | |
namespace custom_restore | |
{ | |
class Program | |
{ | |
static void Main(string[] args) => CommandLineApplication.Execute<Program>(args); | |
[Argument(0)] | |
[Required] | |
public string PackageId { get; set; } | |
[Option("--version")] | |
public string Version { get; set; } | |
[Option("--verbose")] | |
public bool Verbose { get; set; } | |
[Option] | |
public bool Prerelease { get; set; } | |
private async Task<int> OnExecuteAsync() | |
{ | |
var reporter = new ConsoleReporter(PhysicalConsole.Singleton) | |
{ | |
IsVerbose = Verbose | |
}; | |
var installDir = Path.Combine(Directory.GetCurrentDirectory(), "packages"); | |
var tempFilePath = Path.Combine(AppContext.BaseDirectory, "projectThatNeverExists.csproj"); | |
ISettings settings = Settings.LoadDefaultSettings(tempFilePath); | |
VersionRange versionRange; | |
if (!string.IsNullOrEmpty(Version)) | |
{ | |
if (!VersionRange.TryParse(Version, out versionRange)) | |
{ | |
reporter.Error($"Invalid nuget version '{Version}'"); | |
return 1; | |
} | |
} | |
else | |
{ | |
versionRange = Prerelease | |
? VersionRange.AllFloating | |
: VersionRange.AllStableFloating; | |
} | |
var logger = new MyNuGetLogger(reporter); | |
var results = await RestoreRunnerEx.RunWithoutCommit(tempFilePath, installDir, PackageId, versionRange, settings, logger); | |
var success = false; | |
foreach (var result in results) | |
{ | |
if (result.Result.Success) | |
{ | |
var installedVersion = result.Result.LockFile.Libraries.FirstOrDefault(l => string.Equals(PackageId, l.Name, StringComparison.OrdinalIgnoreCase)); | |
if (installedVersion != null) | |
{ | |
var path = installedVersion.Path; | |
reporter.Output($"Installed {installedVersion.Name} {installedVersion.Version}"); | |
foreach(var file in installedVersion.Files) | |
{ | |
reporter.Verbose("Package file: " + file); | |
} | |
success = true; | |
break; | |
} | |
} | |
else | |
{ | |
foreach (var unresolved in result.Result.GetAllUnresolved()) | |
{ | |
reporter.Warn($"Could not find a package {unresolved.Name} {unresolved.VersionRange}"); | |
} | |
} | |
} | |
if (success) | |
{ | |
reporter.Output("Installation succeeded"); | |
return 0; | |
} | |
reporter.Error("Installation failed"); | |
return success ? 1 : 0; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// copied from https://github.com/Microsoft/msbuild/blob/master/src/NuGetSdkResolver/RestoreRunnerEx.cs with a few tweaks | |
// Copyright (c) Microsoft. All rights reserved. | |
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | |
using NuGet.Configuration; | |
using NuGet.Frameworks; | |
using NuGet.LibraryModel; | |
using NuGet.ProjectModel; | |
using NuGet.Protocol; | |
using NuGet.Protocol.Core.Types; | |
using NuGet.Versioning; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using ILogger = NuGet.Common.ILogger; | |
namespace NuGet.Commands | |
{ | |
/// <summary> | |
/// An extension of the NuGet.Commands.RestoreRunner class that contains APIs we do not yet have. | |
/// https://github.com/NuGet/Home/issues/5919 | |
/// </summary> | |
internal static class RestoreRunnerEx | |
{ | |
// NuGet requires at least one framework, we use .NET Standard here just to get the API to do work. The framework is not actually used. | |
private static readonly List<NuGetFramework> TargetFrameworks = new List<NuGetFramework> | |
{ | |
FrameworkConstants.CommonFrameworks.NetStandard | |
}; | |
/// <summary> | |
/// Restores a package by querying, downloading, and unzipping it without generating any other files (like project.assets.json). | |
/// </summary> | |
/// <param name="projectPath">The full path to the project.</param> | |
/// <param name="id">The ID of the package.</param> | |
/// <param name="version">The version of the package.</param> | |
/// <param name="settings">The NuGet settings to use.</param> | |
/// <param name="logger">An <see cref="ILogger"/> to use for logging.</param> | |
/// <returns></returns> | |
public static Task<IReadOnlyList<RestoreResultPair>> RunWithoutCommit(string projectPath, string outputPath, string id, VersionRange version, ISettings settings, ILogger logger) | |
{ | |
using (SourceCacheContext sourceCacheContext = new SourceCacheContext | |
{ | |
IgnoreFailedSources = true, | |
}) | |
{ | |
// The package spec details what packages to restore | |
PackageSpec packageSpec = new PackageSpec(TargetFrameworks.Select(i => new TargetFrameworkInformation | |
{ | |
FrameworkName = i, | |
}).ToList()) | |
{ | |
Dependencies = new List<LibraryDependency> | |
{ | |
new LibraryDependency | |
{ | |
LibraryRange = new LibraryRange(id, version, LibraryDependencyTarget.Package), | |
SuppressParent = LibraryIncludeFlags.All, | |
AutoReferenced = true, | |
IncludeType = LibraryIncludeFlags.None, | |
Type = LibraryDependencyType.Build | |
} | |
}, | |
RestoreMetadata = new ProjectRestoreMetadata | |
{ | |
ProjectPath = projectPath, | |
ProjectName = Path.GetFileNameWithoutExtension(projectPath), | |
ProjectStyle = ProjectStyle.PackageReference, | |
ProjectUniqueName = projectPath, | |
OutputPath = Path.GetTempPath(), | |
OriginalTargetFrameworks = TargetFrameworks.Select(i => i.ToString()).ToList(), | |
ConfigFilePaths = SettingsUtility.GetConfigFilePaths(settings).ToList(), | |
PackagesPath = outputPath, | |
Sources = SettingsUtility.GetEnabledSources(settings).ToList(), | |
FallbackFolders = SettingsUtility.GetFallbackPackageFolders(settings).ToList() | |
}, | |
FilePath = projectPath, | |
Name = Path.GetFileNameWithoutExtension(projectPath), | |
}; | |
DependencyGraphSpec dependencyGraphSpec = new DependencyGraphSpec(); | |
dependencyGraphSpec.AddProject(packageSpec); | |
dependencyGraphSpec.AddRestore(packageSpec.RestoreMetadata.ProjectUniqueName); | |
IPreLoadedRestoreRequestProvider requestProvider = new DependencyGraphSpecRequestProvider(new RestoreCommandProvidersCache(), dependencyGraphSpec); | |
RestoreArgs restoreArgs = new RestoreArgs | |
{ | |
AllowNoOp = true, | |
CacheContext = sourceCacheContext, | |
CachingSourceProvider = new CachingSourceProvider(new PackageSourceProvider(settings)), | |
Log = logger, | |
}; | |
// Create requests from the arguments | |
IReadOnlyList<RestoreSummaryRequest> requests = requestProvider.CreateRequests(restoreArgs).Result; | |
// Restore the package without generating extra files | |
return RestoreRunner.RunWithoutCommit(requests, restoreArgs); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment