| File: Validation\ValidationManager.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 Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Utils; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Validation { internal class ValidationManager { private SpinLock _spinLock; private IEngineEnvironmentSettings? _cachedSettings; private Dictionary<Guid, ITemplateValidator>? _cachedValidators; private ValidationManager() { } internal static ValidationManager Instance { get; } = new ValidationManager(); internal async Task ValidateTemplateAsync(IEngineEnvironmentSettings settings, ITemplateValidationInfo template, ValidationScope scope, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (scope == ValidationScope.None) { throw new ArgumentException($"{nameof(scope)} cannot be '{ValidationScope.None}'.", nameof(scope)); } if (!Enum.IsDefined(typeof(ValidationScope), scope)) { throw new ArgumentException($"{nameof(scope)} should be one of {string.Join(", ", Enum.GetNames(typeof(ValidationScope)).Skip(1))}.", nameof(scope)); } IEnumerable<ITemplateValidator> validators = await InitializeValidatorsAsync(settings, scope, cancellationToken).ConfigureAwait(false); validators.ForEach(v => v.ValidateTemplate(template)); } private async Task<IEnumerable<ITemplateValidator>> InitializeValidatorsAsync(IEngineEnvironmentSettings settings, ValidationScope scope, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); if (_cachedSettings == null || _cachedSettings != settings || _cachedValidators == null) { _cachedSettings = settings; IEnumerable<ITemplateValidatorFactory> factories = settings.Components.OfType<ITemplateValidatorFactory>(); IEnumerable<Task<ITemplateValidator>> tasks = factories .Where(f => f.Scope.HasFlag(scope)) .Select(f => f.CreateValidatorAsync(settings, cancellationToken)); ITemplateValidator[] validators = await Task.WhenAll(tasks).ConfigureAwait(false); _cachedValidators = validators.ToDictionary(v => v.Factory.Id, v => v); } else { IEnumerable<ITemplateValidatorFactory> factories = settings.Components.OfType<ITemplateValidatorFactory>(); List<Task<ITemplateValidator>> validatorsToCreate = new(); foreach (ITemplateValidatorFactory factory in factories.Where(f => f.Scope.HasFlag(scope))) { if (_cachedValidators.TryGetValue(factory.Id, out _)) { continue; } validatorsToCreate.Add(factory.CreateValidatorAsync(settings, cancellationToken)); } ITemplateValidator[] validators = await Task.WhenAll(validatorsToCreate).ConfigureAwait(false); foreach (ITemplateValidator templateValidator in validators) { _cachedValidators[templateValidator.Factory.Id] = templateValidator; } } return _cachedValidators .Values .Where(v => v.Factory.Scope.HasFlag(scope)); } finally { if (lockTaken) { _spinLock.Exit(); } } } } }