| File: FileSourceHierarchicalPathMatcher.cs | Web Access |
| Project: src\sdk\src\TemplateEngine\Microsoft.TemplateEngine.Orchestrator.RunnableProjects\Microsoft.TemplateEngine.Orchestrator.RunnableProjects.csproj (Microsoft.TemplateEngine.Orchestrator.RunnableProjects) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; using Microsoft.TemplateEngine.Core.Contracts; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects { [Flags] internal enum FileDispositionStates { None = 0, Include = 0x01, CopyOnly = 0x02, Exclude = 0x04 } internal static class EnumExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool Has(this FileDispositionStates value, FileDispositionStates check) { return (value & check) == check; } } internal class FileSourceHierarchicalPathMatcher { private readonly IReadOnlyList<FileSourceEvaluablePathMatcher> _evaluators; // Caching the most recent result. private string _cachedEvaluatedPath; private FileDispositionStates _cachedStatesForFile; internal FileSourceHierarchicalPathMatcher(FileSourceMatchInfo matchInfo) { List<FileSourceEvaluablePathMatcher> evaluators = new List<FileSourceEvaluablePathMatcher>(); for (int i = matchInfo.Modifiers.Count - 1; i >= 0; i--) { evaluators.Add(new FileSourceEvaluablePathMatcher(matchInfo.Modifiers[i])); } evaluators.Add(new FileSourceEvaluablePathMatcher(matchInfo.TopLevelEvaluable)); _evaluators = evaluators; _cachedEvaluatedPath = string.Empty; _cachedStatesForFile = FileDispositionStates.None; } internal FileDispositionStates Evaluate(string path) { if (!string.Equals(path, _cachedEvaluatedPath, StringComparison.Ordinal)) { _cachedStatesForFile = EvaluatePath(path); _cachedEvaluatedPath = path; } return _cachedStatesForFile; } private FileDispositionStates EvaluatePath(string path) { FileDispositionStates continuationReason = FileDispositionStates.None; foreach (FileSourceEvaluablePathMatcher evaluator in _evaluators) { FileDispositionStates state = evaluator.Evaluate(path); if (state.Has(FileDispositionStates.Exclude)) { return FileDispositionStates.Exclude; } else if (state.Has(FileDispositionStates.CopyOnly)) { if (state.Has(FileDispositionStates.Include)) { return FileDispositionStates.CopyOnly | FileDispositionStates.Include; } continuationReason = FileDispositionStates.CopyOnly; } else if (state.Has(FileDispositionStates.Include)) { if (continuationReason == FileDispositionStates.CopyOnly) { return FileDispositionStates.CopyOnly | FileDispositionStates.Include; } return FileDispositionStates.Include; } } return FileDispositionStates.None; } private class FileSourceEvaluablePathMatcher { private readonly IReadOnlyList<IPathMatcher> _include; private readonly IReadOnlyList<IPathMatcher> _exclude; private readonly IReadOnlyList<IPathMatcher> _copyOnly; internal FileSourceEvaluablePathMatcher(FileSourceEvaluable evaluable) { _include = SetupMatcherList(evaluable.Include); _exclude = SetupMatcherList(evaluable.Exclude); _copyOnly = SetupMatcherList(evaluable.CopyOnly); } internal FileDispositionStates Evaluate(string path) { if (_exclude.Any(x => x.IsMatch(path))) { return FileDispositionStates.Exclude; } bool include = _include.Any(x => x.IsMatch(path)); if (_copyOnly.Any(x => x.IsMatch(path))) { if (include) { return FileDispositionStates.CopyOnly | FileDispositionStates.Include; } else { return FileDispositionStates.CopyOnly; } } if (include) { return FileDispositionStates.Include; } return FileDispositionStates.None; } private static IReadOnlyList<IPathMatcher> SetupMatcherList(IReadOnlyList<string> fileSources) { int expect = fileSources?.Count ?? 0; List<IPathMatcher> paths = new List<IPathMatcher>(expect); if (fileSources != null && expect > 0) { foreach (string source in fileSources) { paths.Add(new GlobbingPatternMatcher(source, false)); } } return paths; } } } }