dependabot-nuget 0.400.0 → 0.402.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +81 -31
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatibilityChecker.cs +403 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +148 -63
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionResult.cs +5 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +4 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequestDependency.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestVersionConverter.cs +22 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +580 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +117 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +244 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/JobTests.cs +61 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +50 -2
- metadata +6 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +0 -236
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 00434f51ff3cf781726cf8af2a49739342481e4d6d43d010077dac710be8f3e1
|
|
4
|
+
data.tar.gz: bb4d30f0ca2f0470f1aa45ff2d077fc934e79b86a709efd99a0bf4ed3a435c7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28bed39edb1dc2c63921fdeb933449f96931c7866f0096718ca8735cc4e4d18fc9f1cf3472c656aafe9ef1e6cd610af03e739ad0f52e32e6111feea56fcab05c
|
|
7
|
+
data.tar.gz: ca65ed03d6d0440e4ac70d537a41caf0ad25438d6e716d2d3e3cbeee969a8071623bf264e4b7befb7fb19308b25c479d1bfb23dc7dbee425cdb8b96c0ed593d6
|
|
@@ -4,6 +4,7 @@ using System.Text.Json;
|
|
|
4
4
|
using System.Text.Json.Serialization;
|
|
5
5
|
|
|
6
6
|
using NuGet.Frameworks;
|
|
7
|
+
using NuGet.Packaging.Core;
|
|
7
8
|
using NuGet.Versioning;
|
|
8
9
|
|
|
9
10
|
using NuGetUpdater.Core.Discover;
|
|
@@ -258,20 +259,21 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
258
259
|
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
259
260
|
CancellationToken cancellationToken)
|
|
260
261
|
{
|
|
261
|
-
var
|
|
262
|
-
|
|
262
|
+
var currentTime = DateTimeOffset.UtcNow;
|
|
263
|
+
var versionResult = await VersionFinder.GetCandidateVersionsAsync(
|
|
263
264
|
dependencyInfo,
|
|
264
|
-
|
|
265
|
+
currentTime,
|
|
265
266
|
nugetContext,
|
|
266
267
|
logger,
|
|
267
268
|
cancellationToken);
|
|
268
269
|
|
|
269
270
|
return await FindUpdatedVersionAsync(
|
|
270
271
|
packageIds,
|
|
271
|
-
dependencyInfo
|
|
272
|
+
dependencyInfo,
|
|
272
273
|
versionResult,
|
|
273
274
|
projectFrameworks,
|
|
274
275
|
findLowestVersion: dependencyInfo.IsVulnerable,
|
|
276
|
+
currentTime,
|
|
275
277
|
nugetContext,
|
|
276
278
|
logger,
|
|
277
279
|
candidateValidator,
|
|
@@ -280,10 +282,11 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
280
282
|
|
|
281
283
|
internal static async Task<NuGetVersion?> FindUpdatedVersionAsync(
|
|
282
284
|
ImmutableHashSet<string> packageIds,
|
|
283
|
-
|
|
285
|
+
DependencyInfo dependencyInfo,
|
|
284
286
|
VersionResult versionResult,
|
|
285
287
|
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
286
288
|
bool findLowestVersion,
|
|
289
|
+
DateTimeOffset currentTime,
|
|
287
290
|
NuGetContext nugetContext,
|
|
288
291
|
ILogger logger,
|
|
289
292
|
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
@@ -302,10 +305,11 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
302
305
|
|
|
303
306
|
return await FindFirstCompatibleVersion(
|
|
304
307
|
packageIds,
|
|
305
|
-
|
|
308
|
+
dependencyInfo,
|
|
306
309
|
versionResult,
|
|
307
310
|
orderedVersions,
|
|
308
311
|
projectFrameworks,
|
|
312
|
+
currentTime,
|
|
309
313
|
nugetContext,
|
|
310
314
|
logger,
|
|
311
315
|
candidateValidator,
|
|
@@ -314,58 +318,70 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
314
318
|
|
|
315
319
|
internal static async Task<NuGetVersion?> FindFirstCompatibleVersion(
|
|
316
320
|
ImmutableHashSet<string> packageIds,
|
|
317
|
-
|
|
321
|
+
DependencyInfo dependencyInfo,
|
|
318
322
|
VersionResult versionResult,
|
|
319
323
|
IEnumerable<NuGetVersion> orderedVersions,
|
|
320
324
|
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
325
|
+
DateTimeOffset currentTime,
|
|
321
326
|
NuGetContext nugetContext,
|
|
322
327
|
ILogger logger,
|
|
323
328
|
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
324
329
|
CancellationToken cancellationToken)
|
|
325
330
|
{
|
|
326
|
-
|
|
331
|
+
var checkSiblingCompatibility = true;
|
|
332
|
+
if (NuGetVersion.TryParse(dependencyInfo.Version, out var currentVersion))
|
|
327
333
|
{
|
|
328
|
-
|
|
334
|
+
checkSiblingCompatibility = await AreAllPackagesCompatibleAsync(
|
|
329
335
|
packageIds,
|
|
330
336
|
currentVersion,
|
|
331
337
|
projectFrameworks,
|
|
332
338
|
nugetContext,
|
|
333
339
|
logger,
|
|
334
340
|
cancellationToken);
|
|
335
|
-
|
|
336
|
-
if (!isCompatible)
|
|
337
|
-
{
|
|
338
|
-
// If the current package is incompatible, then don't check for compatibility.
|
|
339
|
-
foreach (var version in orderedVersions)
|
|
340
|
-
{
|
|
341
|
-
if (candidateValidator is null || await candidateValidator(version))
|
|
342
|
-
{
|
|
343
|
-
return version;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
341
|
}
|
|
350
342
|
|
|
351
343
|
foreach (var version in orderedVersions)
|
|
352
344
|
{
|
|
353
|
-
var
|
|
354
|
-
if (!
|
|
345
|
+
var primaryIdentity = new PackageIdentity(dependencyInfo.Name, version);
|
|
346
|
+
if (!await CompatibilityChecker.IsAvailableAndCompatibleAsync(
|
|
347
|
+
primaryIdentity,
|
|
348
|
+
projectFrameworks,
|
|
349
|
+
nugetContext,
|
|
350
|
+
logger,
|
|
351
|
+
cancellationToken))
|
|
355
352
|
{
|
|
356
353
|
continue;
|
|
357
354
|
}
|
|
358
355
|
|
|
359
|
-
|
|
360
|
-
|
|
356
|
+
if (!await AreSiblingPackagesAcceptableAsync(
|
|
357
|
+
dependencyInfo.Name,
|
|
358
|
+
packageIds,
|
|
359
|
+
version,
|
|
360
|
+
projectFrameworks,
|
|
361
|
+
checkSiblingCompatibility,
|
|
362
|
+
nugetContext,
|
|
363
|
+
logger,
|
|
364
|
+
cancellationToken))
|
|
365
|
+
{
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
var allowedSources = await VersionFinder.GetCooldownAllowedSourcesAsync(
|
|
370
|
+
dependencyInfo,
|
|
371
|
+
currentTime,
|
|
372
|
+
versionResult.CurrentVersion,
|
|
361
373
|
version,
|
|
362
|
-
|
|
374
|
+
versionResult.GetPackageSources(version),
|
|
363
375
|
nugetContext,
|
|
364
376
|
logger,
|
|
365
377
|
cancellationToken);
|
|
378
|
+
if (allowedSources.IsEmpty)
|
|
379
|
+
{
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
366
382
|
|
|
367
|
-
|
|
368
|
-
|
|
383
|
+
versionResult.SetPackageSources(version, allowedSources);
|
|
384
|
+
if (candidateValidator is null || await candidateValidator(version))
|
|
369
385
|
{
|
|
370
386
|
return version;
|
|
371
387
|
}
|
|
@@ -385,7 +401,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
385
401
|
{
|
|
386
402
|
foreach (var packageId in packageIds)
|
|
387
403
|
{
|
|
388
|
-
var isCompatible = await CompatibilityChecker.
|
|
404
|
+
var isCompatible = await CompatibilityChecker.ExistsAndIsCompatibleAsync(
|
|
389
405
|
new(packageId, currentVersion),
|
|
390
406
|
projectFrameworks,
|
|
391
407
|
nugetContext,
|
|
@@ -400,6 +416,40 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
400
416
|
return true;
|
|
401
417
|
}
|
|
402
418
|
|
|
419
|
+
internal static async Task<bool> AreSiblingPackagesAcceptableAsync(
|
|
420
|
+
string primaryPackageId,
|
|
421
|
+
ImmutableHashSet<string> packageIds,
|
|
422
|
+
NuGetVersion version,
|
|
423
|
+
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
424
|
+
bool checkCompatibility,
|
|
425
|
+
NuGetContext nugetContext,
|
|
426
|
+
ILogger logger,
|
|
427
|
+
CancellationToken cancellationToken)
|
|
428
|
+
{
|
|
429
|
+
foreach (var packageId in packageIds.Where(
|
|
430
|
+
packageId => !packageId.Equals(primaryPackageId, StringComparison.OrdinalIgnoreCase)))
|
|
431
|
+
{
|
|
432
|
+
var packageIdentity = new PackageIdentity(packageId, version);
|
|
433
|
+
var isAcceptable = checkCompatibility
|
|
434
|
+
? await CompatibilityChecker.IsAvailableAndCompatibleAsync(
|
|
435
|
+
packageIdentity,
|
|
436
|
+
projectFrameworks,
|
|
437
|
+
nugetContext,
|
|
438
|
+
logger,
|
|
439
|
+
cancellationToken)
|
|
440
|
+
: await CompatibilityChecker.ExistsAsync(
|
|
441
|
+
packageIdentity,
|
|
442
|
+
nugetContext,
|
|
443
|
+
cancellationToken);
|
|
444
|
+
if (!isAcceptable)
|
|
445
|
+
{
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
|
|
403
453
|
internal static async Task<ImmutableArray<Dependency>> FindUpdatedDependenciesAsync(
|
|
404
454
|
string repoRoot,
|
|
405
455
|
WorkspaceDiscoveryResult discovery,
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
using System.Collections.Immutable;
|
|
2
|
+
|
|
3
|
+
using NuGet.Common;
|
|
4
|
+
using NuGet.Configuration;
|
|
5
|
+
using NuGet.Frameworks;
|
|
6
|
+
using NuGet.Packaging;
|
|
7
|
+
using NuGet.Packaging.Core;
|
|
8
|
+
using NuGet.Protocol;
|
|
9
|
+
using NuGet.Protocol.Core.Types;
|
|
10
|
+
|
|
11
|
+
using NuGetUpdater.Core.FrameworkChecker;
|
|
12
|
+
|
|
13
|
+
namespace NuGetUpdater.Core.Analyze;
|
|
14
|
+
|
|
15
|
+
using PackageInfo = (bool IsDevDependency, ImmutableArray<NuGetFramework> Frameworks);
|
|
16
|
+
using PackageReaders = (IAsyncPackageCoreReader CoreReader, IAsyncPackageContentReader ContentReader);
|
|
17
|
+
|
|
18
|
+
internal static class CompatibilityChecker
|
|
19
|
+
{
|
|
20
|
+
public static async Task<bool> CheckAsync(
|
|
21
|
+
PackageIdentity package,
|
|
22
|
+
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
23
|
+
NuGetContext nugetContext,
|
|
24
|
+
ILogger logger,
|
|
25
|
+
CancellationToken cancellationToken)
|
|
26
|
+
{
|
|
27
|
+
var packageInfo = await GetPackageInfoAsync(
|
|
28
|
+
package,
|
|
29
|
+
nugetContext,
|
|
30
|
+
cancellationToken);
|
|
31
|
+
if (packageInfo is null)
|
|
32
|
+
{
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var (isDevDependency, packageFrameworks) = packageInfo.GetValueOrDefault();
|
|
37
|
+
return PerformCheck(package, projectFrameworks, isDevDependency, packageFrameworks, logger);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public static async Task<bool> ExistsAndIsCompatibleAsync(
|
|
41
|
+
PackageIdentity package,
|
|
42
|
+
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
43
|
+
NuGetContext nugetContext,
|
|
44
|
+
ILogger logger,
|
|
45
|
+
CancellationToken cancellationToken)
|
|
46
|
+
{
|
|
47
|
+
var packageInfo = await GetPackageInfoAsync(
|
|
48
|
+
package,
|
|
49
|
+
nugetContext,
|
|
50
|
+
cancellationToken);
|
|
51
|
+
if (packageInfo is null)
|
|
52
|
+
{
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// dotnet-tools.json and global.json packages won't specify a TFM, so existence is sufficient
|
|
57
|
+
if (projectFrameworks.IsEmpty)
|
|
58
|
+
{
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var (isDevDependency, packageFrameworks) = packageInfo.GetValueOrDefault();
|
|
63
|
+
return PerformCheck(package, projectFrameworks, isDevDependency, packageFrameworks, logger);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public static async Task<bool> IsAvailableAndCompatibleAsync(
|
|
67
|
+
PackageIdentity package,
|
|
68
|
+
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
69
|
+
NuGetContext nugetContext,
|
|
70
|
+
ILogger logger,
|
|
71
|
+
CancellationToken cancellationToken)
|
|
72
|
+
{
|
|
73
|
+
var packageInfo = await GetPackageInfoAsync(
|
|
74
|
+
package,
|
|
75
|
+
nugetContext,
|
|
76
|
+
requireSourceAvailability: true,
|
|
77
|
+
cancellationToken);
|
|
78
|
+
if (packageInfo is null)
|
|
79
|
+
{
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (projectFrameworks.IsEmpty)
|
|
84
|
+
{
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var (isDevDependency, packageFrameworks) = packageInfo.GetValueOrDefault();
|
|
89
|
+
return PerformCheck(package, projectFrameworks, isDevDependency, packageFrameworks, logger);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static async Task<bool> ExistsAsync(
|
|
93
|
+
PackageIdentity package,
|
|
94
|
+
NuGetContext nugetContext,
|
|
95
|
+
CancellationToken cancellationToken)
|
|
96
|
+
{
|
|
97
|
+
var readersOption = await GetPackageReadersAsync(
|
|
98
|
+
package,
|
|
99
|
+
nugetContext,
|
|
100
|
+
requireSourceAvailability: true,
|
|
101
|
+
cancellationToken);
|
|
102
|
+
if (readersOption is null)
|
|
103
|
+
{
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
var readers = readersOption.GetValueOrDefault();
|
|
108
|
+
DisposeReaders(readers);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
internal static bool PerformCheck(
|
|
113
|
+
PackageIdentity package,
|
|
114
|
+
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
115
|
+
bool isDevDependency,
|
|
116
|
+
ImmutableArray<NuGetFramework> packageFrameworks,
|
|
117
|
+
ILogger logger)
|
|
118
|
+
{
|
|
119
|
+
// development dependencies are packages such as analyzers which need to be compatible with the compiler not the
|
|
120
|
+
// project itself, but some packages that report themselves as development dependencies still contain target
|
|
121
|
+
// framework dependencies and should be checked for compatibility through the regular means
|
|
122
|
+
if (isDevDependency && packageFrameworks.Length == 0)
|
|
123
|
+
{
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (packageFrameworks.Length == 0 || projectFrameworks.Length == 0)
|
|
128
|
+
{
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var compatibilityService = new FrameworkCompatibilityService();
|
|
133
|
+
var compatibleFrameworks = compatibilityService.GetCompatibleFrameworks(packageFrameworks);
|
|
134
|
+
var packageSupportsAny = compatibleFrameworks.Any(f => f.IsAny);
|
|
135
|
+
if (packageSupportsAny)
|
|
136
|
+
{
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
var incompatibleFrameworks = projectFrameworks.Where(f => !compatibleFrameworks.Contains(f)).ToArray();
|
|
141
|
+
if (incompatibleFrameworks.Length > 0)
|
|
142
|
+
{
|
|
143
|
+
logger.Info($"The package {package} is not compatible. Incompatible project frameworks: {string.Join(", ", incompatibleFrameworks.Select(f => f.GetShortFolderName()))}");
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
internal static async Task<PackageReaders?> GetPackageReadersAsync(
|
|
151
|
+
PackageIdentity package,
|
|
152
|
+
NuGetContext nugetContext,
|
|
153
|
+
CancellationToken cancellationToken)
|
|
154
|
+
{
|
|
155
|
+
return await GetPackageReadersAsync(
|
|
156
|
+
package,
|
|
157
|
+
nugetContext,
|
|
158
|
+
requireSourceAvailability: false,
|
|
159
|
+
cancellationToken);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private static async Task<PackageReaders?> GetPackageReadersAsync(
|
|
163
|
+
PackageIdentity package,
|
|
164
|
+
NuGetContext nugetContext,
|
|
165
|
+
bool requireSourceAvailability,
|
|
166
|
+
CancellationToken cancellationToken)
|
|
167
|
+
{
|
|
168
|
+
var packagePath = GetPackagePath(package, nugetContext);
|
|
169
|
+
if (!requireSourceAvailability && File.Exists(packagePath))
|
|
170
|
+
{
|
|
171
|
+
return ReadPackage(packagePath);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (File.Exists(packagePath))
|
|
175
|
+
{
|
|
176
|
+
return await IsAvailableAsync(package, nugetContext, cancellationToken)
|
|
177
|
+
? ReadPackage(packagePath)
|
|
178
|
+
: null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return await DownloadPackageAsync(package, nugetContext, cancellationToken);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
internal static async Task<PackageInfo?> GetPackageInfoAsync(
|
|
185
|
+
PackageIdentity package,
|
|
186
|
+
NuGetContext nugetContext,
|
|
187
|
+
CancellationToken cancellationToken)
|
|
188
|
+
{
|
|
189
|
+
var readersOption = await GetPackageReadersAsync(package, nugetContext, cancellationToken);
|
|
190
|
+
return await ReadPackageInfoAsync(readersOption, cancellationToken);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private static async Task<PackageInfo?> GetPackageInfoAsync(
|
|
194
|
+
PackageIdentity package,
|
|
195
|
+
NuGetContext nugetContext,
|
|
196
|
+
bool requireSourceAvailability,
|
|
197
|
+
CancellationToken cancellationToken)
|
|
198
|
+
{
|
|
199
|
+
var readersOption = await GetPackageReadersAsync(
|
|
200
|
+
package,
|
|
201
|
+
nugetContext,
|
|
202
|
+
requireSourceAvailability,
|
|
203
|
+
cancellationToken);
|
|
204
|
+
return await ReadPackageInfoAsync(readersOption, cancellationToken);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private static async Task<PackageInfo?> ReadPackageInfoAsync(
|
|
208
|
+
PackageReaders? readersOption,
|
|
209
|
+
CancellationToken cancellationToken)
|
|
210
|
+
{
|
|
211
|
+
if (readersOption is null)
|
|
212
|
+
{
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
var readers = readersOption.GetValueOrDefault();
|
|
217
|
+
try
|
|
218
|
+
{
|
|
219
|
+
var nuspecStream = await readers.CoreReader.GetNuspecAsync(cancellationToken);
|
|
220
|
+
var reader = new NuspecReader(nuspecStream);
|
|
221
|
+
|
|
222
|
+
var isDevDependency = reader.GetDevelopmentDependency();
|
|
223
|
+
var tfms = new HashSet<NuGetFramework>();
|
|
224
|
+
var dependencyGroups = reader.GetDependencyGroups().ToArray();
|
|
225
|
+
|
|
226
|
+
foreach (var d in dependencyGroups)
|
|
227
|
+
{
|
|
228
|
+
if (!d.TargetFramework.IsAny)
|
|
229
|
+
{
|
|
230
|
+
tfms.Add(d.TargetFramework);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
var refItems = (await readers.ContentReader.GetReferenceItemsAsync(cancellationToken)).ToArray();
|
|
235
|
+
foreach (var refItem in refItems)
|
|
236
|
+
{
|
|
237
|
+
tfms.Add(refItem.TargetFramework);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
var libItems = (await readers.ContentReader.GetLibItemsAsync(cancellationToken)).ToArray();
|
|
241
|
+
foreach (var libItem in libItems)
|
|
242
|
+
{
|
|
243
|
+
tfms.Add(libItem.TargetFramework);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// if a package contains no assemblies that need to be referenced, we can consider it compatible with all frameworks
|
|
247
|
+
if (refItems.Length == 0 && libItems.Length == 0)
|
|
248
|
+
{
|
|
249
|
+
tfms.Clear();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!tfms.Any())
|
|
253
|
+
{
|
|
254
|
+
tfms.Add(NuGetFramework.AnyFramework);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return (isDevDependency, tfms.ToImmutableArray());
|
|
258
|
+
}
|
|
259
|
+
finally
|
|
260
|
+
{
|
|
261
|
+
DisposeReaders(readers);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private static void DisposeReaders(PackageReaders readers)
|
|
266
|
+
{
|
|
267
|
+
// The interfaces aren't disposable, but their implementations can be. The same object often implements both.
|
|
268
|
+
var coreReader = readers.CoreReader as IDisposable;
|
|
269
|
+
var contentReader = readers.ContentReader as IDisposable;
|
|
270
|
+
try
|
|
271
|
+
{
|
|
272
|
+
coreReader?.Dispose();
|
|
273
|
+
}
|
|
274
|
+
finally
|
|
275
|
+
{
|
|
276
|
+
if (!ReferenceEquals(coreReader, contentReader))
|
|
277
|
+
{
|
|
278
|
+
contentReader?.Dispose();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
internal static PackageReaders ReadPackage(string packagePath)
|
|
284
|
+
{
|
|
285
|
+
var stream = new FileStream(
|
|
286
|
+
packagePath,
|
|
287
|
+
FileMode.Open,
|
|
288
|
+
FileAccess.Read,
|
|
289
|
+
FileShare.Read,
|
|
290
|
+
bufferSize: 4096);
|
|
291
|
+
PackageArchiveReader archiveReader = new(stream);
|
|
292
|
+
return (archiveReader, archiveReader);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
internal static async Task<PackageReaders?> DownloadPackageAsync(
|
|
296
|
+
PackageIdentity package,
|
|
297
|
+
NuGetContext context,
|
|
298
|
+
CancellationToken cancellationToken)
|
|
299
|
+
{
|
|
300
|
+
foreach (var source in GetAllowedSources(package.Id, context))
|
|
301
|
+
{
|
|
302
|
+
FindPackageByIdResource feed;
|
|
303
|
+
try
|
|
304
|
+
{
|
|
305
|
+
var sourceRepository = context.GetSourceRepository(source);
|
|
306
|
+
feed = await sourceRepository.GetResourceAsync<FindPackageByIdResource>(cancellationToken)
|
|
307
|
+
?? throw new NotSupportedException($"Failed to get FindPackageByIdResource for {source.SourceUri}");
|
|
308
|
+
|
|
309
|
+
// a non-compliant v2 API returning 404 can cause this to throw
|
|
310
|
+
var exists = await feed.DoesPackageExistAsync(
|
|
311
|
+
package.Id,
|
|
312
|
+
package.Version,
|
|
313
|
+
context.SourceCacheContext,
|
|
314
|
+
NullLogger.Instance,
|
|
315
|
+
cancellationToken);
|
|
316
|
+
if (!exists)
|
|
317
|
+
{
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (FatalProtocolException)
|
|
322
|
+
{
|
|
323
|
+
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
var downloader = await feed.GetPackageDownloaderAsync(
|
|
328
|
+
package,
|
|
329
|
+
context.SourceCacheContext,
|
|
330
|
+
context.Logger,
|
|
331
|
+
cancellationToken);
|
|
332
|
+
|
|
333
|
+
var packagePath = GetPackagePath(package, context);
|
|
334
|
+
var isDownloaded = await downloader.CopyNupkgFileToAsync(packagePath, cancellationToken);
|
|
335
|
+
if (isDownloaded)
|
|
336
|
+
{
|
|
337
|
+
return (downloader.CoreReader, downloader.ContentReader);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private static async Task<bool> IsAvailableAsync(
|
|
345
|
+
PackageIdentity package,
|
|
346
|
+
NuGetContext context,
|
|
347
|
+
CancellationToken cancellationToken)
|
|
348
|
+
{
|
|
349
|
+
foreach (var source in GetAllowedSources(package.Id, context))
|
|
350
|
+
{
|
|
351
|
+
try
|
|
352
|
+
{
|
|
353
|
+
var sourceRepository = context.GetSourceRepository(source);
|
|
354
|
+
var feed = await sourceRepository.GetResourceAsync<FindPackageByIdResource>(cancellationToken)
|
|
355
|
+
?? throw new NotSupportedException($"Failed to get FindPackageByIdResource for {source.SourceUri}");
|
|
356
|
+
if (await feed.DoesPackageExistAsync(
|
|
357
|
+
package.Id,
|
|
358
|
+
package.Version,
|
|
359
|
+
context.SourceCacheContext,
|
|
360
|
+
NullLogger.Instance,
|
|
361
|
+
cancellationToken))
|
|
362
|
+
{
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch (FatalProtocolException)
|
|
367
|
+
{
|
|
368
|
+
// Try the next allowed source.
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private static ImmutableArray<PackageSource> GetAllowedSources(string packageId, NuGetContext context)
|
|
376
|
+
{
|
|
377
|
+
var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(context.Settings);
|
|
378
|
+
var packageSources = sourceMapping.GetConfiguredPackageSources(packageId).ToHashSet();
|
|
379
|
+
return packageSources.Count == 0
|
|
380
|
+
? context.PackageSources
|
|
381
|
+
: context.PackageSources
|
|
382
|
+
.Where(source => packageSources.Contains(source.Name))
|
|
383
|
+
.ToImmutableArray();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
internal static string GetPackagePath(PackageIdentity package, NuGetContext context)
|
|
387
|
+
{
|
|
388
|
+
// https://learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders
|
|
389
|
+
var nugetPackagesPath = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
|
|
390
|
+
if (nugetPackagesPath is null)
|
|
391
|
+
{
|
|
392
|
+
// n.b., this path should never be hit during a unit test
|
|
393
|
+
nugetPackagesPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
var normalizedName = package.Id.ToLowerInvariant();
|
|
397
|
+
var normalizedVersion = package.Version.ToNormalizedString().ToLowerInvariant();
|
|
398
|
+
var packageDirectory = Path.Join(nugetPackagesPath, normalizedName, normalizedVersion);
|
|
399
|
+
Directory.CreateDirectory(packageDirectory);
|
|
400
|
+
var packagePath = Path.Join(packageDirectory, $"{normalizedName}.{normalizedVersion}.nupkg");
|
|
401
|
+
return packagePath;
|
|
402
|
+
}
|
|
403
|
+
}
|