|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
namespace Microsoft.Build.Evaluation
{
/// <summary>
/// This class encapsulates the behavior and collection of built-in metadata. These metadatum
/// are inferred from the content of the include and sometimes the context of the project or
/// current directory.
/// </summary>
internal static class BuiltInMetadata
{
/// <summary>
/// Retrieves the count of built-in metadata.
/// </summary>
internal static int MetadataCount => ItemSpecModifiers.All.Length;
/// <summary>
/// Retrieves the list of metadata names.
/// </summary>
internal static ImmutableArray<string> MetadataNames => ItemSpecModifiers.All;
/// <summary>
/// Retrieves a built-in metadata value and caches it.
/// Never returns null.
/// </summary>
/// <param name="currentDirectory">
/// The current directory for evaluation. Null if this is being called from a task, otherwise
/// it should be the project's directory.
/// </param>
/// <param name="evaluatedIncludeBeforeWildcardExpansionEscaped">The evaluated include prior to wildcard expansion.</param>
/// <param name="evaluatedIncludeEscaped">The evaluated include for the item.</param>
/// <param name="definingProjectEscaped">The path to the project that defined this item</param>
/// <param name="name">The name of the metadata.</param>
/// <param name="cache">The generated full path, for caching</param>
/// <returns>The unescaped metadata value.</returns>
internal static string GetMetadataValue(
string currentDirectory,
string evaluatedIncludeBeforeWildcardExpansionEscaped,
string evaluatedIncludeEscaped,
string definingProjectEscaped,
string name,
ref ItemSpecModifiers.Cache cache)
=> EscapingUtilities.UnescapeAll(GetMetadataValueEscaped(currentDirectory, evaluatedIncludeBeforeWildcardExpansionEscaped, evaluatedIncludeEscaped, definingProjectEscaped, name, ref cache));
/// <summary>
/// Retrieves a built-in metadata value, caching derivable results in the provided per-item cache.
/// If value is not available, returns empty string.
/// </summary>
internal static string GetMetadataValueEscaped(
string currentDirectory,
string evaluatedIncludeBeforeWildcardExpansionEscaped,
string evaluatedIncludeEscaped,
string definingProjectEscaped,
string name,
ref ItemSpecModifiers.Cache cache)
{
if (ItemSpecModifiers.TryGetModifierKind(name, out ItemSpecModifierKind modifierKind))
{
return GetMetadataValueEscaped(currentDirectory, evaluatedIncludeBeforeWildcardExpansionEscaped, evaluatedIncludeEscaped, definingProjectEscaped, modifierKind, ref cache);
}
Debug.Fail($"Expected a valid item-spec modifier, got \"{name}\".");
return string.Empty;
}
/// <summary>
/// Retrieves a built-in metadata value, caching derivable results in the provided per-item cache.
/// If value is not available, returns empty string.
/// </summary>
internal static string GetMetadataValueEscaped(
string currentDirectory,
string evaluatedIncludeBeforeWildcardExpansionEscaped,
string evaluatedIncludeEscaped,
string definingProjectEscaped,
ItemSpecModifierKind modifierKind,
ref ItemSpecModifiers.Cache cache)
=> modifierKind is ItemSpecModifierKind.RecursiveDir
? GetRecursiveDirValue(evaluatedIncludeBeforeWildcardExpansionEscaped, evaluatedIncludeEscaped)
: ItemSpecModifiers.GetItemSpecModifier(evaluatedIncludeEscaped, modifierKind, currentDirectory, definingProjectEscaped, ref cache);
/// <summary>
/// Extract the value for "RecursiveDir", if any, from the Include.
/// If there is none, returns an empty string.
/// </summary>
/// <remarks>
/// Inputs to and outputs of this function are all escaped.
/// </remarks>
private static string GetRecursiveDirValue(string evaluatedIncludeBeforeWildcardExpansionEscaped, string evaluatedIncludeEscaped)
{
// If there were no wildcards, the two strings will be the same, and there is no recursivedir part.
if (String.Equals(evaluatedIncludeBeforeWildcardExpansionEscaped, evaluatedIncludeEscaped, StringComparison.OrdinalIgnoreCase))
{
return String.Empty;
}
// we're going to the file system, so unescape the include value here:
string evaluatedIncludeBeforeWildcardExpansion = EscapingUtilities.UnescapeAll(evaluatedIncludeBeforeWildcardExpansionEscaped);
string evaluatedInclude = EscapingUtilities.UnescapeAll(evaluatedIncludeEscaped);
FileMatcher.Result match = FileMatcher.Default.FileMatch(evaluatedIncludeBeforeWildcardExpansion, evaluatedInclude);
if (match.isLegalFileSpec && match.isMatch)
{
return EscapingUtilities.Escape(match.wildcardDirectoryPart);
}
return String.Empty;
}
}
}
|