豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit 8614255

Browse files
committed
Improvements for nuget.exe install
* Allow updating packages when -ExcludeVersion is used * Improved detection of already installed packages when -ExcludeVersion is used * Adding -Framework switch to allow setting the target framework used when resolving dependencies. * Remove NU1000 code from packages.config restore errors. * Avoid unneeded downloads when a version is not given and the package is cached. * Disable parallel for mono * Display errors and return a non-zero exit when install on packages.config fails * Remove old files during upgrades with -ExcludeVersion Fixes NuGet/Home#5743 Fixes NuGet/Home#5737 Fixes NuGet/Home#5736 Fixes NuGet/Home#5741 Fixes NuGet/Home#5017 Fixes NuGet/Home#3957 Fixes NuGet/Home#2405
1 parent 53ae653 commit 8614255

File tree

13 files changed

+816
-380
lines changed

13 files changed

+816
-380
lines changed

src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -45,6 +45,11 @@ public ICollection<string> Source
4545
[Option(typeof(NuGetCommand), "CommandPackageSaveMode")]
4646
public string PackageSaveMode { get; set; }
4747

48+
/// <summary>
49+
/// If true the global packages folder NOT will be added as a source.
50+
/// </summary>
51+
internal bool ExcludeCacheAsSource { get; set; }
52+
4853
internal void CalculateEffectivePackageSaveMode()
4954
{
5055
string packageSaveModeValue = PackageSaveMode;
@@ -117,7 +122,7 @@ internal void CalculateEffectivePackageSaveMode()
117122
var availableSources = SourceProvider.LoadPackageSources().Where(source => source.IsEnabled);
118123
var packageSources = new List<Configuration.PackageSource>();
119124

120-
if (!NoCache)
125+
if (!NoCache && !ExcludeCacheAsSource)
121126
{
122127
// Add the v3 global packages folder
123128
var globalPackageFolder = SettingsUtility.GetGlobalPackagesFolder(settings);

src/NuGet.Clients/NuGet.CommandLine/Commands/InstallCommand.cs

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Concurrent;
6+
using System.Collections.Generic;
57
using System.ComponentModel.Composition;
68
using System.Globalization;
79
using System.IO;
@@ -10,6 +12,7 @@
1012
using System.Threading.Tasks;
1113
using NuGet.Common;
1214
using NuGet.Configuration;
15+
using NuGet.Frameworks;
1316
using NuGet.PackageManagement;
1417
using NuGet.Packaging;
1518
using NuGet.Packaging.Core;
@@ -36,6 +39,9 @@ public class InstallCommand : DownloadCommandBase
3639
[Option(typeof(NuGetCommand), "InstallCommandDependencyVersion")]
3740
public string DependencyVersion { get; set; }
3841

42+
[Option(typeof(NuGetCommand), "InstallCommandFrameworkDescription")]
43+
public string Framework { get; set; }
44+
3945
[Option(typeof(NuGetCommand), "InstallCommandExcludeVersionDescription", AltName = "x")]
4046
public bool ExcludeVersion { get; set; }
4147

@@ -51,24 +57,25 @@ public class InstallCommand : DownloadCommandBase
5157
[ImportingConstructor]
5258
protected internal InstallCommand()
5359
{
54-
// On mono, parallel builds are broken for some reason. See https://gist.github.com/4201936 for the errors
55-
// That are thrown.
56-
DisableParallelProcessing = RuntimeEnvironmentHelper.IsMono;
5760
}
5861

5962
public override Task ExecuteCommandAsync()
6063
{
64+
// On mono, parallel builds are broken for some reason. See https://gist.github.com/4201936 for the errors
65+
// That are thrown.
66+
DisableParallelProcessing |= RuntimeEnvironmentHelper.IsMono;
67+
6168
if (DisableParallelProcessing)
6269
{
6370
HttpSourceResourceProvider.Throttle = SemaphoreSlimThrottle.CreateBinarySemaphore();
6471
}
6572

6673
CalculateEffectivePackageSaveMode();
6774
CalculateEffectiveSettings();
68-
string installPath = ResolveInstallPath();
75+
var installPath = ResolveInstallPath();
6976

70-
string configFilePath = Path.GetFullPath(Arguments.Count == 0 ? Constants.PackageReferenceFile : Arguments[0]);
71-
string configFileName = Path.GetFileName(configFilePath);
77+
var configFilePath = Path.GetFullPath(Arguments.Count == 0 ? Constants.PackageReferenceFile : Arguments[0]);
78+
var configFileName = Path.GetFileName(configFilePath);
7279

7380
// If the first argument is a packages.xxx.config file, install everything it lists
7481
// Otherwise, treat the first argument as a package Id
@@ -80,27 +87,27 @@ public override Task ExecuteCommandAsync()
8087
if (Console != null && RequireConsent &&
8188
new PackageRestoreConsent(Settings).IsGranted)
8289
{
83-
string message = String.Format(
90+
var message = string.Format(
8491
CultureInfo.CurrentCulture,
8592
LocalizedResourceManager.GetString("RestoreCommandPackageRestoreOptOutMessage"),
8693
NuGetResources.PackageRestoreConsentCheckBoxText.Replace("&", ""));
8794
Console.WriteLine(message);
8895
}
8996

90-
return PerformV2Restore(configFilePath, installPath);
97+
return PerformV2RestoreAsync(configFilePath, installPath);
9198
}
9299
else
93100
{
94101
var packageId = Arguments[0];
95102
var version = Version != null ? new NuGetVersion(Version) : null;
96-
return InstallPackage(packageId, version, installPath);
103+
return InstallPackageAsync(packageId, version, installPath);
97104
}
98105
}
99106

100107
private void CalculateEffectiveSettings()
101108
{
102109
// If the SolutionDir is specified, use the .nuget directory under it to determine the solution-level settings
103-
if (!String.IsNullOrEmpty(SolutionDirectory))
110+
if (!string.IsNullOrEmpty(SolutionDirectory))
104111
{
105112
var path = Path.Combine(SolutionDirectory.TrimEnd(Path.DirectorySeparatorChar), NuGetConstants.NuGetSolutionSettingsFolder);
106113

@@ -119,20 +126,20 @@ private void CalculateEffectiveSettings()
119126

120127
internal string ResolveInstallPath()
121128
{
122-
if (!String.IsNullOrEmpty(OutputDirectory))
129+
if (!string.IsNullOrEmpty(OutputDirectory))
123130
{
124131
// Use the OutputDirectory if specified.
125132
return OutputDirectory;
126133
}
127134

128-
string installPath = SettingsUtility.GetRepositoryPath(Settings);
129-
if (!String.IsNullOrEmpty(installPath))
135+
var installPath = SettingsUtility.GetRepositoryPath(Settings);
136+
if (!string.IsNullOrEmpty(installPath))
130137
{
131138
// If a value is specified in config, use that.
132139
return installPath;
133140
}
134141

135-
if (!String.IsNullOrEmpty(SolutionDirectory))
142+
if (!string.IsNullOrEmpty(SolutionDirectory))
136143
{
137144
// For package restore scenarios, deduce the path of the packages directory from the solution directory.
138145
return Path.Combine(SolutionDirectory, CommandLineConstants.PackagesDirectoryName);
@@ -142,7 +149,7 @@ internal string ResolveInstallPath()
142149
return CurrentDirectory;
143150
}
144151

145-
private async Task PerformV2Restore(string packagesConfigFilePath, string installPath)
152+
private async Task PerformV2RestoreAsync(string packagesConfigFilePath, string installPath)
146153
{
147154
var sourceRepositoryProvider = GetSourceRepositoryProvider();
148155
var nuGetPackageManager = new NuGetPackageManager(sourceRepositoryProvider, Settings, installPath, ExcludeVersion);
@@ -158,15 +165,17 @@ private async Task PerformV2Restore(string packagesConfigFilePath, string instal
158165
isMissing: true));
159166

160167
var packageSources = GetPackageSources(Settings);
161-
168+
162169
Console.PrintPackageSources(packageSources);
163170

171+
var failedEvents = new ConcurrentQueue<PackageRestoreFailedEventArgs>();
172+
164173
var packageRestoreContext = new PackageRestoreContext(
165174
nuGetPackageManager,
166175
packageRestoreData,
167176
CancellationToken.None,
168177
packageRestoredEvent: null,
169-
packageRestoreFailedEvent: null,
178+
packageRestoreFailedEvent: (sender, args) => { failedEvents.Enqueue(args); },
170179
sourceRepositories: packageSources.Select(sourceRepositoryProvider.CreateRepository),
171180
maxNumberOfParallelTasks: DisableParallelProcessing ? 1 : PackageManagementConstants.DefaultMaxDegreeOfParallelism);
172181

@@ -189,7 +198,7 @@ private async Task PerformV2Restore(string packagesConfigFilePath, string instal
189198

190199
var downloadContext = new PackageDownloadContext(cacheContext, installPath, DirectDownload);
191200

192-
await PackageRestoreManager.RestoreMissingPackagesAsync(
201+
var result = await PackageRestoreManager.RestoreMissingPackagesAsync(
193202
packageRestoreContext,
194203
new ConsoleProjectContext(Console),
195204
downloadContext);
@@ -198,6 +207,17 @@ await PackageRestoreManager.RestoreMissingPackagesAsync(
198207
{
199208
GetDownloadResultUtility.CleanUpDirectDownloads(downloadContext);
200209
}
210+
211+
if (!result.Restored || failedEvents.Count > 0)
212+
{
213+
// Log errors if they exist
214+
foreach (var message in failedEvents.Select(e => new RestoreLogMessage(LogLevel.Error, NuGetLogCode.Undefined, e.Exception.Message)))
215+
{
216+
await Console.LogAsync(message);
217+
}
218+
219+
throw new ExitCodeException(1);
220+
}
201221
}
202222
}
203223

@@ -221,9 +241,9 @@ private DependencyBehavior TryGetDependencyBehavior(string behaviorStr)
221241
private DependencyBehavior GetDependencyBehavior()
222242
{
223243
// If dependencyVersion is not set by either the config or commandline, default dependency behavior is 'Lowest'.
224-
DependencyBehavior dependencyBehavior = DependencyBehavior.Lowest;
244+
var dependencyBehavior = DependencyBehavior.Lowest;
225245

226-
string settingsDependencyVersion = SettingsUtility.GetConfigValue(Settings, "dependencyVersion");
246+
var settingsDependencyVersion = SettingsUtility.GetConfigValue(Settings, "dependencyVersion");
227247

228248
// Check to see if commandline flag is set. Else check for dependencyVersion in .config.
229249
if (!string.IsNullOrEmpty(DependencyVersion))
@@ -238,28 +258,33 @@ private DependencyBehavior GetDependencyBehavior()
238258
return dependencyBehavior;
239259
}
240260

241-
private async Task InstallPackage(
261+
private async Task InstallPackageAsync(
242262
string packageId,
243263
NuGetVersion version,
244264
string installPath)
245265
{
246266
if (version == null)
247267
{
248-
NoCache = true;
268+
// Avoid searching for the highest version in the global packages folder,
269+
// it needs to come from the feeds instead. Once found it may come from
270+
// the global packages folder unless NoCache is true.
271+
ExcludeCacheAsSource = true;
249272
}
250273

251-
var folderProject = new FolderNuGetProject(
252-
installPath,
253-
new PackagePathResolver(installPath, !ExcludeVersion));
274+
var framework = GetTargetFramework();
275+
276+
// Create the project and set the framework if available.
277+
var project = new InstallCommandProject(
278+
root: installPath,
279+
packagePathResolver: new PackagePathResolver(installPath, !ExcludeVersion),
280+
targetFramework: framework);
254281

255282
var sourceRepositoryProvider = GetSourceRepositoryProvider();
256283
var packageManager = new NuGetPackageManager(sourceRepositoryProvider, Settings, installPath);
257284

258285
var packageSources = GetPackageSources(Settings);
259-
260-
Console.PrintPackageSources(packageSources);
261-
262286
var primaryRepositories = packageSources.Select(sourceRepositoryProvider.CreateRepository);
287+
Console.PrintPackageSources(packageSources);
263288

264289
var allowPrerelease = Prerelease || (version != null && version.IsPrerelease);
265290

@@ -273,10 +298,15 @@ private async Task InstallPackage(
273298

274299
if (version == null)
275300
{
301+
// Write out a helpful message before the http messages are shown
302+
Console.Log(LogLevel.Minimal, string.Format(
303+
CultureInfo.CurrentCulture,
304+
LocalizedResourceManager.GetString("InstallPackageMessage"), packageId, installPath));
305+
276306
// Find the latest version using NuGetPackageManager
277307
var resolvePackage = await NuGetPackageManager.GetLatestVersionAsync(
278308
packageId,
279-
folderProject,
309+
project,
280310
resolutionContext,
281311
primaryRepositories,
282312
Console,
@@ -295,9 +325,23 @@ private async Task InstallPackage(
295325
version = resolvePackage.LatestVersion;
296326
}
297327

328+
// Get a list of packages already in the folder.
329+
var installedPackages = await project.GetFolderPackagesAsync(CancellationToken.None);
330+
331+
// Find existing versions of the package
332+
var alreadyInstalledVersions = new HashSet<NuGetVersion>(installedPackages
333+
.Where(e => StringComparer.OrdinalIgnoreCase.Equals(packageId, e.PackageIdentity.Id))
334+
.Select(e => e.PackageIdentity.Version));
335+
298336
var packageIdentity = new PackageIdentity(packageId, version);
299337

300-
if (folderProject.PackageExists(packageIdentity))
338+
// Check if the package already exists or a higher version exists already.
339+
var skipInstall = project.PackageExists(packageIdentity);
340+
341+
// For SxS allow other versions to install. For non-SxS skip if a higher version exists.
342+
skipInstall |= (ExcludeVersion && alreadyInstalledVersions.Any(e => e >= version));
343+
344+
if (skipInstall)
301345
{
302346
var message = string.Format(
303347
CultureInfo.CurrentCulture,
@@ -318,15 +362,15 @@ private async Task InstallPackage(
318362
projectContext.PackageExtractionContext.PackageSaveMode = EffectivePackageSaveMode;
319363
}
320364

321-
using(var cacheContext = new SourceCacheContext())
365+
using (var cacheContext = new SourceCacheContext())
322366
{
323367
cacheContext.NoCache = NoCache;
324368
cacheContext.DirectDownload = DirectDownload;
325369

326370
var downloadContext = new PackageDownloadContext(cacheContext, installPath, DirectDownload);
327371

328372
await packageManager.InstallPackageAsync(
329-
folderProject,
373+
project,
330374
packageIdentity,
331375
resolutionContext,
332376
projectContext,
@@ -342,5 +386,30 @@ await packageManager.InstallPackageAsync(
342386
}
343387
}
344388
}
389+
390+
/// <summary>
391+
/// Parse the Framework parameter or use Any as the default framework.
392+
/// </summary>
393+
private NuGetFramework GetTargetFramework()
394+
{
395+
var targetFramework = NuGetFramework.AnyFramework;
396+
397+
if (!string.IsNullOrEmpty(Framework))
398+
{
399+
targetFramework = NuGetFramework.Parse(Framework);
400+
}
401+
402+
if (targetFramework.IsUnsupported)
403+
{
404+
// Fail with a helpful message if the user provided an invalid framework.
405+
var message = string.Format(CultureInfo.CurrentCulture,
406+
LocalizedResourceManager.GetString("UnsupportedFramework"),
407+
Framework);
408+
409+
throw new ArgumentException(message);
410+
}
411+
412+
return targetFramework;
413+
}
345414
}
346415
}

src/NuGet.Clients/NuGet.CommandLine/Commands/RestoreCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ private async Task<RestoreSummary> PerformNuGetV2RestoreAsync(PackageRestoreInpu
333333
Settings.Priority.Select(x => Path.Combine(x.Root, x.FileName)),
334334
packageSources.Select(x => x.Source),
335335
installCount,
336-
collectorLogger.Errors.Concat(failedEvents.Select(e => new RestoreLogMessage(LogLevel.Error, e.Exception.Message))));
336+
collectorLogger.Errors.Concat(failedEvents.Select(e => new RestoreLogMessage(LogLevel.Error, NuGetLogCode.Undefined, e.Exception.Message))));
337337
}
338338
}
339339

0 commit comments

Comments
 (0)