| File: Projects\GeneratedFileWriter.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Aspire.Cli.Projects; /// <summary> /// Writes the files the CLI generates on every launch without disturbing files that have not changed. /// </summary> /// <remarks> /// Rewriting a file with identical content still moves its last-write time forward, and every /// incremental build the CLI sits in front of -- MSBuild, javac, Maven, Gradle, and the IDE builders /// that watch the same directories -- decides what to rebuild from those timestamps. Comparing before /// writing costs a read of a file that is almost always still in the page cache and keeps those /// timestamps stable across launches. /// </remarks> internal static class GeneratedFileWriter { /// <summary> /// Writes <paramref name="content" /> only when it differs from what is already on disk. /// </summary> /// <remarks> /// A file that cannot be read is rewritten rather than treated as current. The CLI owns these /// files, so an unreadable one is far more likely to be a transient hold -- an antivirus scanner /// on Windows, a mode a user changed on POSIX -- than a deliberate state worth preserving, and /// preserving it would silently launch against stale generated code. The write that follows /// surfaces the real error if the condition is not transient. /// </remarks> /// <returns><see langword="true" /> when the file was written.</returns> public static async Task<bool> WriteIfChangedAsync(string path, string content, CancellationToken cancellationToken) { if (File.Exists(path)) { try { var existing = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); if (string.Equals(existing, content, StringComparison.Ordinal)) { return false; } } catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) { } } await File.WriteAllTextAsync(path, content, cancellationToken).ConfigureAwait(false); return true; } }