| File: Settings\SettingsLoadingContext.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Configuration\NuGet.Configuration.csproj (NuGet.Configuration) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Concurrent; using System.IO; using NuGet.Common; namespace NuGet.Configuration { /// <summary> /// Represents a cache context based on file paths when loading <see cref="SettingsFile" /> objects so that they are only read once. /// If the file changes on disk, it is not reloaded. /// </summary> public sealed class SettingsLoadingContext : IDisposable { private readonly ConcurrentDictionary<string, Lazy<SettingsFile>> _cache = new ConcurrentDictionary<string, Lazy<SettingsFile>>(PathUtility.GetStringComparerBasedOnOS()); private bool _isDisposed; /// <summary> /// Occurs when a file is read. /// </summary> internal event EventHandler<string>? FileRead; /// <inheritdoc cref="IDisposable.Dispose" /> public void Dispose() { if (!_isDisposed) { _isDisposed = true; _cache.Clear(); } GC.SuppressFinalize(this); } /// <summary> /// Gets or creates a settings file for the specified path. /// </summary> /// <param name="filePath">The file path to create a <see cref="SettingsFile" /> object for.</param> /// <param name="isMachineWide">An optional value indicating whether or not the settings file is machine-wide.</param> /// <param name="isReadOnly">An optional value indicating whether or not the settings file is read-only.</param> /// <returns></returns> /// <exception cref="ObjectDisposedException">When the current object has been disposed.</exception> /// <exception cref="ArgumentNullException">When <paramref name="filePath" /> is <see langword="null" />.</exception> internal SettingsFile GetOrCreateSettingsFile(string filePath, bool isMachineWide = false, bool isReadOnly = false) { if (_isDisposed) { throw new ObjectDisposedException(nameof(SettingsLoadingContext)); } if (filePath == null) { throw new ArgumentNullException(nameof(filePath)); } if (!Path.IsPathRooted(filePath)) { throw new ArgumentException("SettingsLoadingContext requires a rooted path", nameof(filePath)); } Lazy<SettingsFile> settingsLazy = _cache.GetOrAdd( filePath, (key) => new Lazy<SettingsFile>(() => { var fileInfo = new FileInfo(key); // Load the settings file, this will throw an exception if something is wrong with the file var settingsFile = new SettingsFile(fileInfo.DirectoryName!, fileInfo.Name, isMachineWide, isReadOnly); // Fire the FileRead event so unit tests can detect when a file was actually read versus cached FileRead?.Invoke(this, fileInfo.FullName); if (ConfigurationEventSource.Instance.IsEnabled()) ConfigurationEventSource.Instance.SettingsLoadingContext_FileRead(fileInfo.FullName, isMachineWide ? 1 : 0, isReadOnly ? 1 : 0); return settingsFile; })); return settingsLazy.Value; } } }