diff --git a/build/PackageArchive.targets b/build/PackageArchive.targets
index d01ed8cf94..4970e4bb95 100644
--- a/build/PackageArchive.targets
+++ b/build/PackageArchive.targets
@@ -49,6 +49,26 @@
Targets="Restore"
Properties="RestorePackagesPath=$(FallbackStagingDir);RuntimeFrameworkVersion=$(MicrosoftNETCoreApp21PackageVersion);DotNetRestoreSourcePropsPath=$(GeneratedFallbackRestoreSourcesPropsPath);AspNetUniverseBuildOffline=true" />
+
+
+
+
+
+
+
+
+ <_DotnetToolPackages Update="@(_DotnetToolPackages)">
+ $([System.String]::new('%(PackageId).%(Version)').ToLowerInvariant())
+ $([System.String]::new('%(PackageId)/%(Version)').ToLowerInvariant())
+
+
+
+
+
+
+
diff --git a/build/artifacts.props b/build/artifacts.props
index 0ab44a8d54..a5f2f7f01f 100644
--- a/build/artifacts.props
+++ b/build/artifacts.props
@@ -2,20 +2,31 @@
+
false
+
false
- false
+
false
+
+ false
+
false
- false
+
+ Dependency
-
-
-
-
+
+
+
+
@@ -202,7 +213,7 @@
-
+
@@ -282,7 +293,7 @@
-
+
diff --git a/build/external-dependencies.props b/build/external-dependencies.props
index b1f53f578b..dd6cb16618 100644
--- a/build/external-dependencies.props
+++ b/build/external-dependencies.props
@@ -13,16 +13,9 @@
false
false
-
- false
-
- false
-
- false
-
- false
+
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json
diff --git a/build/repo.targets b/build/repo.targets
index 67c6ade26d..3285a78ab1 100644
--- a/build/repo.targets
+++ b/build/repo.targets
@@ -196,10 +196,7 @@
-
-
-
p.GetMetadata("LZMA") == "true");
- var externalArchiveTools = ExternalDependencies.Where(p => p.GetMetadata("LZMATools") == "true");
- var archiveArtifacts = PackageArtifacts.Where(p => p.GetMetadata("LZMA") == "true");
- var archiveTools = PackageArtifacts.Where(p => p.GetMetadata("LZMATools") == "true");
+ var externalArchiveArtifacts = ExternalDependencies.Where(p => p.GetMetadata("LZMA") == "true" && p.GetMetadata("PackageType") == "Dependency");
+ var externalArchiveTools = ExternalDependencies.Where(p => p.GetMetadata("LZMA") == "true" && p.GetMetadata("PackageType") == "DotnetCliTool");
+ var archiveArtifacts = PackageArtifacts.Where(p => p.GetMetadata("LZMA") == "true" && p.GetMetadata("PackageType") == "Dependency");
+ var archiveTools = PackageArtifacts.Where(p => p.GetMetadata("LZMA") == "true" && p.GetMetadata("PackageType") == "DotnetCliTool");
var buildArtifacts = BuildArtifacts.Select(ArtifactInfo.Parse)
.OfType()
.Where(p => !p.IsSymbolsArtifact);
diff --git a/build/tasks/JoinItems.cs b/build/tasks/JoinItems.cs
new file mode 100644
index 0000000000..facfd4fa53
--- /dev/null
+++ b/build/tasks/JoinItems.cs
@@ -0,0 +1,122 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace RepoTasks
+{
+ public class JoinItems : Task
+ {
+ [Required]
+ public ITaskItem[] Left { get; set; }
+
+ [Required]
+ public ITaskItem[] Right { get; set; }
+
+ // The metadata to use as the new item spec. If not specified, LeftKey is used.
+ public string LeftItemSpec { get; set; }
+
+ // LeftKey and RightKey: The metadata to join on. If not set, then use the ItemSpec
+ public string LeftKey { get; set; }
+
+ public string RightKey { get; set; }
+
+
+ // LeftMetadata and RightMetadata: The metadata names to include in the result. Specify "*" to include all metadata
+ public string[] LeftMetadata { get; set; }
+
+ public string[] RightMetadata { get; set; }
+
+
+ [Output]
+ public ITaskItem[] JoinResult { get; private set; }
+
+ public override bool Execute()
+ {
+ bool useAllLeftMetadata = LeftMetadata != null && LeftMetadata.Length == 1 && LeftMetadata[0] == "*";
+ bool useAllRightMetadata = RightMetadata != null && RightMetadata.Length == 1 && RightMetadata[0] == "*";
+ var newItemSpec = string.IsNullOrEmpty(LeftItemSpec)
+ ? LeftKey
+ : LeftItemSpec;
+
+ JoinResult = Left.Join(Right,
+ item => GetKeyValue(LeftKey, item),
+ item => GetKeyValue(RightKey, item),
+ (left, right) =>
+ {
+ // If including all metadata from left items and none from right items, just return left items directly
+ if (useAllLeftMetadata &&
+ string.IsNullOrEmpty(LeftKey) &&
+ string.IsNullOrEmpty(LeftItemSpec) &&
+ (RightMetadata == null || RightMetadata.Length == 0))
+ {
+ return left;
+ }
+
+ // If including all metadata from right items and none from left items, just return the right items directly
+ if (useAllRightMetadata &&
+ string.IsNullOrEmpty(RightKey) &&
+ string.IsNullOrEmpty(LeftItemSpec) &&
+ (LeftMetadata == null || LeftMetadata.Length == 0))
+ {
+ return right;
+ }
+
+ var ret = new TaskItem(GetKeyValue(newItemSpec, left));
+
+ // Weird ordering here is to prefer left metadata in all cases, as CopyToMetadata doesn't overwrite any existing metadata
+ if (useAllLeftMetadata)
+ {
+ // CopyMetadata adds an OriginalItemSpec, which we don't want. So we subsequently remove it
+ left.CopyMetadataTo(ret);
+ ret.RemoveMetadata("OriginalItemSpec");
+ }
+
+ if (!useAllRightMetadata && RightMetadata != null)
+ {
+ foreach (string name in RightMetadata)
+ {
+ ret.SetMetadata(name, right.GetMetadata(name));
+ }
+ }
+
+ if (!useAllLeftMetadata && LeftMetadata != null)
+ {
+ foreach (string name in LeftMetadata)
+ {
+ ret.SetMetadata(name, left.GetMetadata(name));
+ }
+ }
+
+ if (useAllRightMetadata)
+ {
+ // CopyMetadata adds an OriginalItemSpec, which we don't want. So we subsequently remove it
+ right.CopyMetadataTo(ret);
+ ret.RemoveMetadata("OriginalItemSpec");
+ }
+
+ return (ITaskItem)ret;
+ },
+ StringComparer.OrdinalIgnoreCase).ToArray();
+
+ return true;
+ }
+
+ static string GetKeyValue(string key, ITaskItem item)
+ {
+ if (string.IsNullOrEmpty(key))
+ {
+ return item.ItemSpec;
+ }
+ else
+ {
+ return item.GetMetadata(key);
+ }
+ }
+ }
+}
diff --git a/build/tasks/RepoTasks.tasks b/build/tasks/RepoTasks.tasks
index 1176f79344..d579d64845 100644
--- a/build/tasks/RepoTasks.tasks
+++ b/build/tasks/RepoTasks.tasks
@@ -12,6 +12,7 @@
+