File: src\tasks\Common\FileCache.cs
Web Access
Project: src\src\tasks\AotCompilerTask\MonoAOTCompiler.csproj (MonoAOTCompiler)
// 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.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
 
#nullable enable
 
internal sealed class FileCache
{
    private CompilerCache? _newCache;
    private CompilerCache? _oldCache;
    private static readonly JsonSerializerOptions s_jsonOptions = new JsonSerializerOptions { WriteIndented = true };
 
    public bool Enabled { get; }
    public TaskLoggingHelper Log { get; }
 
    public FileCache(string? cacheFilePath, TaskLoggingHelper log)
    {
        Log = log;
        if (string.IsNullOrEmpty(cacheFilePath))
        {
            Log.LogMessage(MessageImportance.Low, $"Disabling cache, because CacheFilePath is not set");
            return;
        }
 
        Enabled = true;
        if (File.Exists(cacheFilePath))
        {
            _oldCache = JsonSerializer.Deserialize<CompilerCache>(File.ReadAllText(cacheFilePath), s_jsonOptions);
        }
 
        _oldCache ??= new();
        _newCache = new(_oldCache.FileHashes);
    }
 
    public bool UpdateAndCheckHasFileChanged(string filePath, string newHash)
    {
        if (!Enabled)
            throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set");
 
        _newCache!.FileHashes[filePath] = newHash;
        return !_oldCache!.FileHashes.TryGetValue(filePath, out string? oldHash) || oldHash != newHash;
    }
 
    public bool ShouldCopy(ProxyFile proxyFile, [NotNullWhen(true)] out string? cause)
    {
        if (!Enabled)
            throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set");
 
        cause = null;
 
        string newHash = Utils.ComputeHash(proxyFile.TempFile);
        _newCache!.FileHashes[proxyFile.TargetFile] = newHash;
 
        if (!File.Exists(proxyFile.TargetFile))
        {
            cause = $"the output file didn't exist";
            return true;
        }
 
        string? oldHash;
        if (!_oldCache!.FileHashes.TryGetValue(proxyFile.TargetFile, out oldHash))
            oldHash = Utils.ComputeHash(proxyFile.TargetFile);
 
        if (oldHash != newHash)
        {
            cause = $"hash for the file changed";
            return true;
        }
 
        return false;
    }
 
    public bool Save(string? cacheFilePath)
    {
        if (!Enabled || string.IsNullOrEmpty(cacheFilePath))
            return false;
 
        var json = JsonSerializer.Serialize (_newCache, s_jsonOptions);
        File.WriteAllText(cacheFilePath!, json);
        return true;
    }
 
    public ProxyFile NewFile(string targetFile) => new ProxyFile(targetFile, this);
}