aspnetcore/build/tasks/JoinItems.cs

123 lines
4.5 KiB
C#

// 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);
}
}
}
}