Skip to content

Commit b2b15d0

Browse files
committed
Add output PackageDependenciesDesignTime to cache file
1 parent 799f6de commit b2b15d0

File tree

1 file changed

+144
-1
lines changed

1 file changed

+144
-1
lines changed

src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,30 @@ public sealed class ResolvePackageAssets : TaskBase
162162
/// </summary>
163163
public bool DesignTimeBuild { get; set; }
164164

165+
/// <summary>
166+
/// Eg: "Microsoft.NETCore.App;NETStandard.Library"
167+
/// </summary>
168+
[Required]
169+
public string DefaultImplicitPackages { get; set; }
170+
171+
/// <summary>
172+
/// Items with metadata "ParentTarget" and "ParentPackage", which allows determining the hierarchy of package references.
173+
/// </summary>
174+
[Required]
175+
public ITaskItem[] InputPackageDependencies { get; set; }
176+
177+
/// <summary>
178+
/// Information about each package in the project, with metadata:
179+
/// - Name = "MetadataExtractor"
180+
/// - Path = "metadataextractor/1.0.0"
181+
/// - ResolvedPath = "C:\Users\drnoakes\.nuget\packages\metadataextractor\1.0.0"
182+
/// - Type = "package"
183+
/// - Version = "2.3.0"
184+
/// - DiagnosticLevel = ""
185+
/// </summary>
186+
[Required]
187+
public ITaskItem[] PackageDefinitions { get; set; }
188+
165189
#endregion
166190

167191
#region Output Items
@@ -238,6 +262,17 @@ public sealed class ResolvePackageAssets : TaskBase
238262
[Output]
239263
public ITaskItem[] PackageDependencies { get; private set; }
240264

265+
/// <summary>
266+
/// Filters and projects items produced by <see cref="ResolvePackageDependencies"/> for consumption by
267+
/// the dependencies tree, via design-time builds.
268+
/// </summary>
269+
/// <remarks>
270+
/// Changes to the implementation of output must be coordinated with <c>PackageRuleHandler</c>
271+
/// in the dotnet/project-system repo.
272+
/// </remarks>
273+
[Output]
274+
public ITaskItem[] PackageDependenciesDesignTime { get; private set; }
275+
241276
/// <summary>
242277
/// List of symbol files (.pdb) related to NuGet packages.
243278
/// </summary>
@@ -311,7 +346,7 @@ public sealed class ResolvePackageAssets : TaskBase
311346
////////////////////////////////////////////////////////////////////////////////////////////////////
312347

313348
private const int CacheFormatSignature = ('P' << 0) | ('K' << 8) | ('G' << 16) | ('A' << 24);
314-
private const int CacheFormatVersion = 11;
349+
private const int CacheFormatVersion = 12;
315350
private static readonly Encoding TextEncoding = Encoding.UTF8;
316351
private const int SettingsHashLength = 256 / 8;
317352
private HashAlgorithm CreateSettingsHash() => SHA256.Create();
@@ -343,6 +378,7 @@ private void ReadItemGroups()
343378
FrameworkReferences = reader.ReadItemGroup();
344379
NativeLibraries = reader.ReadItemGroup();
345380
PackageDependencies = reader.ReadItemGroup();
381+
PackageDependenciesDesignTime = reader.ReadItemGroup();
346382
PackageFolders = reader.ReadItemGroup();
347383
ReferenceDocumentationFiles = reader.ReadItemGroup();
348384
ResourceAssemblies = reader.ReadItemGroup();
@@ -660,6 +696,7 @@ private ITaskItem ReadItem()
660696
internal sealed class CacheWriter : IDisposable
661697
{
662698
private const int InitialStringTableCapacity = 32;
699+
private const string ResolvedMetadata = "Resolved";
663700

664701
private ResolvePackageAssets _task;
665702
private BinaryWriter _writer;
@@ -814,6 +851,7 @@ private void WriteItemGroups()
814851
WriteItemGroup(WriteFrameworkReferences);
815852
WriteItemGroup(WriteNativeLibraries);
816853
WriteItemGroup(WritePackageDependencies);
854+
WriteItemGroup(WritePackageDependenciesDesignTime);
817855
WriteItemGroup(WritePackageFolders);
818856
WriteItemGroup(WriteReferenceDocumentationFiles);
819857
WriteItemGroup(WriteResourceAssemblies);
@@ -1408,6 +1446,111 @@ private void WritePackageDependencies()
14081446
}
14091447
}
14101448

1449+
private void WritePackageDependenciesDesignTime()
1450+
{
1451+
var implicitPackageReferences = GetImplicitPackageReferences(_task.DefaultImplicitPackages);
1452+
1453+
// We have two types of data:
1454+
//
1455+
// 1) "PackageDependencies" which place a package in a given target/hierarchy
1456+
// 2) "PackageDefinitions" which provide general metadata about a package
1457+
//
1458+
// First, we scan PackageDependencies to build the set of packages in our target.
1459+
1460+
var allowItemSpecs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
1461+
1462+
foreach (var dependency in _task.InputPackageDependencies)
1463+
{
1464+
if (dependency.HasMetadataValue(MetadataKeys.ParentPackage))
1465+
{
1466+
// ignore non-top-level packages (those with ParentPackage)
1467+
continue;
1468+
}
1469+
1470+
var target = dependency.GetMetadata(MetadataKeys.ParentTarget);
1471+
1472+
if (!StringComparer.OrdinalIgnoreCase.Equals(target, _task.TargetFramework))
1473+
{
1474+
// skip dependencies for other targets
1475+
continue;
1476+
}
1477+
1478+
allowItemSpecs.Add(dependency.ItemSpec);
1479+
}
1480+
1481+
// Second, find PackageDefinitions that match our allowed item specs
1482+
1483+
var outputItems = new List<ITaskItem>(allowItemSpecs.Count);
1484+
1485+
foreach (var packageDef in _task.PackageDefinitions)
1486+
{
1487+
if (!allowItemSpecs.Contains(packageDef.ItemSpec))
1488+
{
1489+
// We are not interested in this definition (not top-level, or wrong target)
1490+
continue;
1491+
}
1492+
1493+
var dependencyType = GetDependencyType(packageDef.GetMetadata(MetadataKeys.Type));
1494+
1495+
if (dependencyType == DependencyType.Package ||
1496+
dependencyType == DependencyType.Unresolved)
1497+
{
1498+
var name = packageDef.GetMetadata(MetadataKeys.Name);
1499+
1500+
if (string.IsNullOrEmpty(name))
1501+
{
1502+
// Name is required
1503+
continue;
1504+
}
1505+
1506+
var version = packageDef.GetMetadata(MetadataKeys.Version) ?? string.Empty;
1507+
var resolvedPath = packageDef.GetMetadata(MetadataKeys.ResolvedPath);
1508+
var resolved = !string.IsNullOrEmpty(resolvedPath);
1509+
var path = (resolved
1510+
? resolvedPath
1511+
: packageDef.GetMetadata(MetadataKeys.Path)) ?? string.Empty;
1512+
var isImplicitlyDefined = implicitPackageReferences.Contains(name);
1513+
var diagnosticLevel = packageDef.GetMetadata(MetadataKeys.DiagnosticLevel) ?? string.Empty;
1514+
1515+
WriteItem(packageDef.ItemSpec);
1516+
WriteMetadata(MetadataKeys.Name, name);
1517+
WriteMetadata(MetadataKeys.Version, version);
1518+
WriteMetadata(MetadataKeys.Path, path);
1519+
WriteMetadata(MetadataKeys.IsImplicitlyDefined, isImplicitlyDefined.ToString());
1520+
WriteMetadata(MetadataKeys.DiagnosticLevel, diagnosticLevel);
1521+
WriteMetadata(ResolvedMetadata, resolved.ToString());
1522+
}
1523+
}
1524+
1525+
static HashSet<string> GetImplicitPackageReferences(string defaultImplicitPackages)
1526+
{
1527+
var implicitPackageReferences = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
1528+
if (string.IsNullOrEmpty(defaultImplicitPackages))
1529+
{
1530+
return implicitPackageReferences;
1531+
}
1532+
1533+
var packageNames = defaultImplicitPackages.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
1534+
if (packageNames.Length == 0)
1535+
{
1536+
return implicitPackageReferences;
1537+
}
1538+
1539+
foreach (var packageReference in packageNames)
1540+
{
1541+
implicitPackageReferences.Add(packageReference);
1542+
}
1543+
1544+
return implicitPackageReferences;
1545+
}
1546+
1547+
static DependencyType GetDependencyType(string dependencyTypeString)
1548+
{
1549+
Enum.TryParse(dependencyTypeString, ignoreCase: true, out DependencyType dependencyType);
1550+
return dependencyType;
1551+
}
1552+
}
1553+
14111554
private void WriteResourceAssemblies()
14121555
{
14131556
WriteItems(

0 commit comments

Comments
 (0)