| File: FindAppConfigFile.cs | Web Access |
| Project: src\msbuild\src\Tasks\Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core) |
// 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.IO; using Microsoft.Build.Framework; using Microsoft.Build.Shared; #nullable disable namespace Microsoft.Build.Tasks { /// <summary> /// Finds the app.config file, if any, in the provided lists. /// For compat reasons, it has to follow a particular arbitrary algorithm. /// It also adds the TargetPath metadata. /// </summary> [MSBuildMultiThreadableTask] public class FindAppConfigFile : TaskExtension { // The list to search through private ITaskItem[] _primaryList; private ITaskItem[] _secondaryList; // The target path metadata value to add to the found item // The item found, if any // What we're looking for private const string appConfigFile = "app.config"; /// <summary> /// The primary list to search through /// </summary> [Required] public ITaskItem[] PrimaryList { get { ArgumentNullException.ThrowIfNull(_primaryList, nameof(PrimaryList)); return _primaryList; } set => _primaryList = value; } /// <summary> /// The secondary list to search through /// </summary> [Required] public ITaskItem[] SecondaryList { get { ArgumentNullException.ThrowIfNull(_secondaryList, nameof(SecondaryList)); return _secondaryList; } set => _secondaryList = value; } /// <summary> /// The value to add as TargetPath metadata /// </summary> [Required] public string TargetPath { get; set; } /// <summary> /// The first matching item found in the list, if any /// </summary> [Output] public ITaskItem AppConfigFile { get; set; } /// <summary> /// Find the app config /// </summary> public override bool Execute() { // Look at the whole item spec first -- ie, // we want to prefer app.config files that are directly in the project folder. if (ConsultLists(true)) { return true; } // If that fails, fall back to app.config files anywhere in the project cone. if (ConsultLists(false)) { return true; } // Not found return true; } private bool ConsultLists(bool matchWholeItemSpec) { // Look at primary list first, then secondary list // We walk backwards on the list to find the last match (for historical reasons) for (int i = PrimaryList.Length - 1; i >= 0; i--) { if (IsMatchingItem(PrimaryList[i], matchWholeItemSpec)) { return true; } } for (int i = SecondaryList.Length - 1; i >= 0; i--) { if (IsMatchingItem(SecondaryList[i], matchWholeItemSpec)) { return true; } } return false; } /// <summary> /// Examines the item to see if it matches what we are looking for. /// If it does, returns true. /// </summary> private bool IsMatchingItem(ITaskItem item, bool matchWholeItemSpec) { try { string filename = (matchWholeItemSpec ? item.ItemSpec : Path.GetFileName(item.ItemSpec)); if (String.Equals(filename, appConfigFile, StringComparison.OrdinalIgnoreCase)) { AppConfigFile = item; // Originally the app.config was found in such a way that it's "OriginalItemSpec" // metadata was cleared out. Although it doesn't really matter, for compatibility, // we'll clear it out here. AppConfigFile.SetMetadata("OriginalItemSpec", item.ItemSpec); AppConfigFile.SetMetadata(ItemMetadataNames.targetPath, TargetPath); Log.LogMessageFromResources(MessageImportance.Low, "FindInList.Found", AppConfigFile.ItemSpec); return true; } } catch (ArgumentException ex) { // Just log this: presumably this item spec is not intended to be // a file path Log.LogMessageFromResources(MessageImportance.Low, "FindInList.InvalidPath", item.ItemSpec, ex.Message); } return false; } } }