// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable enable using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Security; namespace Microsoft.CodeAnalysis.BuildTasks { /// /// General utilities. /// internal static class Utilities { private const string MSBuildRoslynFolderName = "Roslyn"; /// /// Copied from msbuild. ItemSpecs are normalized using this method. /// public static string FixFilePath(string path) => string.IsNullOrEmpty(path) || Path.DirectorySeparatorChar == '\\' ? path : path.Replace('\\', '/'); /// /// Convert a task item metadata to bool. Throw an exception if the string is badly formed and can't /// be converted. /// /// If the metadata is not found, then set metadataFound to false and then return false. /// /// The item that contains the metadata. /// The name of the metadata. /// The resulting boolean value. internal static bool TryConvertItemMetadataToBool(ITaskItem item, string itemMetadataName) { string metadataValue = item.GetMetadata(itemMetadataName); if (metadataValue == null || metadataValue.Length == 0) { return false; } try { return ConvertStringToBool(metadataValue); } catch (System.ArgumentException e) { throw Utilities.GetLocalizedArgumentException( e, ErrorString.General_InvalidAttributeMetadata, item.ItemSpec, itemMetadataName, metadataValue, "bool"); } } /// /// Converts a string to a bool. We consider "true/false", "on/off", and /// "yes/no" to be valid boolean representations in the XML. /// /// The string to convert. /// Boolean true or false, corresponding to the string. internal static bool ConvertStringToBool(string parameterValue) { if (ValidBooleanTrue(parameterValue)) { return true; } else if (ValidBooleanFalse(parameterValue)) { return false; } else { // Unsupported boolean representation. throw Utilities.GetLocalizedArgumentException( ErrorString.General_CannotConvertStringToBool, parameterValue); } } /// /// Returns true if the string can be successfully converted to a bool, /// such as "on" or "yes" /// internal static bool CanConvertStringToBool(string parameterValue) => ValidBooleanTrue(parameterValue) || ValidBooleanFalse(parameterValue); /// /// Returns true if the string represents a valid MSBuild boolean true value, /// such as "on", "!false", "yes" /// private static bool ValidBooleanTrue(string parameterValue) => String.Compare(parameterValue, "true", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "on", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "yes", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!false", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!off", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!no", StringComparison.OrdinalIgnoreCase) == 0; /// /// Returns true if the string represents a valid MSBuild boolean false value, /// such as "!on" "off" "no" "!true" /// private static bool ValidBooleanFalse(string parameterValue) => String.Compare(parameterValue, "false", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "off", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "no", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!true", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!on", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(parameterValue, "!yes", StringComparison.OrdinalIgnoreCase) == 0; internal static string GetFullPathNoThrow(string path) { try { path = Path.GetFullPath(path); } catch (Exception e) when (IsIoRelatedException(e)) { } return path; } internal static void DeleteNoThrow(string path) { try { File.Delete(path); } catch (Exception e) when (IsIoRelatedException(e)) { } } internal static bool IsIoRelatedException(Exception e) => e is UnauthorizedAccessException || e is NotSupportedException || (e is ArgumentException && !(e is ArgumentNullException)) || e is SecurityException || e is IOException; internal static Exception GetLocalizedArgumentException(Exception e, string errorString, params object[] args) { return new ArgumentException(string.Format(CultureInfo.CurrentCulture, errorString, args), e); } internal static Exception GetLocalizedArgumentException(string errorString, params object[] args) { return new ArgumentException(string.Format(CultureInfo.CurrentCulture, errorString, args)); } internal static string? TryGetAssemblyPath(Assembly assembly) { if (assembly.GlobalAssemblyCache) { return null; } if (assembly.CodeBase is { } codebase) { var uri = new Uri(codebase); return uri.IsFile ? uri.LocalPath : assembly.Location; } return null; } /// /// Generate the full path to the tool that is deployed with our build tasks. /// internal static string GenerateFullPathToTool(string toolName) { var buildTask = typeof(Utilities).GetTypeInfo().Assembly; var assemblyPath = buildTask.Location; var assemblyDirectory = Path.GetDirectoryName(assemblyPath); return RuntimeHostInfo.IsDesktopRuntime ? Path.Combine(assemblyDirectory!, toolName) : Path.Combine(assemblyDirectory!, "bincore", toolName); } } }