Skip to content

Commit

Permalink
Rebase and fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Forgind committed Feb 25, 2021
1 parent bae7d8e commit 5949c20
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 11 deletions.
16 changes: 10 additions & 6 deletions src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs
Expand Up @@ -49,7 +49,7 @@ public class ResolveAssemblyReference : TaskExtension
/// <summary>
/// Cache of system state information, used to optimize performance.
/// </summary>
private SystemState _cache = null;
internal SystemState _cache = null;

/// <summary>
/// Construct
Expand Down Expand Up @@ -1884,23 +1884,27 @@ private void LogConflict(Reference reference, string fusionName, StringBuilder l
/// <summary>
/// Reads the state file (if present) into the cache.
/// </summary>
private void ReadStateFile()
internal void ReadStateFile(FileExists fileExists)
{
_cache = SystemState.DeserializeCacheByTranslator(_stateFile, Log);

// Construct the cache if necessary.
if (_cache == null)
{
_cache = new SystemState();
_cache = SystemState.DeserializePrecomputedCachesByTranslator(AssemblyInformationCachePaths ?? Array.Empty<ITaskItem>(), Log, fileExists);
}
}

/// <summary>
/// Write out the state file if a state name was supplied and the cache is dirty.
/// </summary>
private void WriteStateFile()
internal void WriteStateFile()
{
if (!string.IsNullOrEmpty(_stateFile) && _cache.IsDirty)
if (!String.IsNullOrEmpty(AssemblyInformationCacheOutputPath))
{
_cache.SerializePrecomputedCacheByTranslator(AssemblyInformationCacheOutputPath, Log);
}
else if (!string.IsNullOrEmpty(_stateFile) && _cache.IsDirty)
{
_cache.SerializeCacheByTranslator(_stateFile, Log);
}
Expand Down Expand Up @@ -2132,7 +2136,7 @@ ReadMachineTypeFromPEHeader readMachineTypeFromPEHeader
}

// Load any prior saved state.
ReadStateFile();
ReadStateFile(fileExists);
_cache.SetGetLastWriteTime(getLastWriteTime);
_cache.SetInstalledAssemblyInformation(installedAssemblyTableInfo);

Expand Down
83 changes: 78 additions & 5 deletions src/Tasks/SystemState.cs
Expand Up @@ -10,6 +10,7 @@
using System.Linq;
using System.Runtime.Versioning;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;
using Microsoft.Build.Tasks.AssemblyDependency;
Expand All @@ -35,7 +36,7 @@ internal sealed class SystemState : StateFileBase, ITranslatable
/// <summary>
/// Cache at the SystemState instance level. It is serialized and reused between instances.
/// </summary>
private Dictionary<string, FileState> instanceLocalFileStateCache = new Dictionary<string, FileState>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, FileState> instanceLocalFileStateCache = new Dictionary<string, FileState>(StringComparer.OrdinalIgnoreCase);

/// <summary>
/// LastModified information is purely instance-local. It doesn't make sense to
Expand Down Expand Up @@ -71,7 +72,7 @@ internal sealed class SystemState : StateFileBase, ITranslatable
/// <summary>
/// True if the contents have changed.
/// </summary>
private bool isDirty;
internal bool isDirty;

/// <summary>
/// Delegate used internally.
Expand Down Expand Up @@ -112,7 +113,7 @@ internal sealed class SystemState : StateFileBase, ITranslatable
/// Class that holds the current file state.
/// </summary>
[Serializable]
private sealed class FileState : ITranslatable
internal sealed class FileState : ITranslatable
{
/// <summary>
/// The last modified time for this file.
Expand Down Expand Up @@ -276,7 +277,7 @@ internal void SerializeCacheByTranslator(string stateFile, TaskLoggingHelper log
/// Read the contents of this object out to the specified file.
/// TODO: once all classes derived from StateFileBase adopt the new serialization, we should consider moving this into the base class
/// </summary>
internal static SystemState DeserializeCacheByTranslator(string stateFile, TaskLoggingHelper log)
internal static SystemState DeserializeCacheByTranslator(string stateFile, TaskLoggingHelper log, bool logWarning = true)
{
// First, we read the cache from disk if one exists, or if one does not exist, we create one.
try
Expand Down Expand Up @@ -309,7 +310,15 @@ internal static SystemState DeserializeCacheByTranslator(string stateFile, TaskL
// any exception imaginable. Catch them all here.
// Not being able to deserialize the cache is not an error, but we let the user know anyway.
// Don't want to hold up processing just because we couldn't read the file.
log.LogWarningWithCodeFromResources("General.CouldNotReadStateFile", stateFile, e.Message);
if (logWarning)
{
log.LogWarningWithCodeFromResources("General.CouldNotReadStateFile", stateFile, e.Message);
}
else
{
log.LogMessageFromResources("General.CouldNotReadStateFile", stateFile, e.Message);
}
return null;
}

return null;
Expand Down Expand Up @@ -337,6 +346,7 @@ public void Translate(ITranslator translator)
internal bool IsDirty
{
get { return isDirty; }
set { isDirty = value; }
}

/// <summary>
Expand Down Expand Up @@ -596,6 +606,69 @@ out fileState.frameworkName
frameworkName = fileState.frameworkName;
}

/// <summary>
/// Reads in cached data from stateFiles to build an initial cache. Avoids logging warnings or errors.
/// </summary>
/// <param name="stateFiles">List of locations of caches on disk.</param>
/// <param name="log">How to log</param>
/// <param name="fileExists">Whether a file exists</param>
/// <returns></returns>
internal static SystemState DeserializePrecomputedCachesByTranslator(ITaskItem[] stateFiles, TaskLoggingHelper log, FileExists fileExists)
{
SystemState retVal = new SystemState();
retVal.isDirty = stateFiles.Length > 0;
HashSet<string> assembliesFound = new HashSet<string>();

foreach (ITaskItem stateFile in stateFiles)
{
// Verify that it's a real stateFile. Log message but do not error if not.
SystemState sysState = DeserializeCacheByTranslator(stateFile.ToString(), log, false);
if (sysState == null)
{
continue;
}
foreach (KeyValuePair<string, FileState> kvp in sysState.instanceLocalFileStateCache)
{
string relativePath = kvp.Key;
if (!assembliesFound.Contains(relativePath))
{
FileState fileState = kvp.Value;
string fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(stateFile.ToString()), relativePath));
if (fileExists(fullPath))
{
// Correct file path
retVal.instanceLocalFileStateCache[fullPath] = fileState;
assembliesFound.Add(relativePath);
}
}
}
}

return retVal;
}

/// <summary>
/// Modifies this object to be more portable across machines, then writes it to filePath.
/// </summary>
/// <param name="stateFile">Path to which to write the precomputed cache</param>
/// <param name="log">How to log</param>
internal void SerializePrecomputedCacheByTranslator(string stateFile, TaskLoggingHelper log)
{
Dictionary<string, FileState> newInstanceLocalFileStateCache = new Dictionary<string, FileState>(instanceLocalFileStateCache.Count);
foreach (KeyValuePair<string, FileState> kvp in instanceLocalFileStateCache)
{
string relativePath = FileUtilities.MakeRelative(Path.GetDirectoryName(stateFile), kvp.Key);
newInstanceLocalFileStateCache[relativePath] = kvp.Value;
}
instanceLocalFileStateCache = newInstanceLocalFileStateCache;

if (FileUtilities.FileExistsNoThrow(stateFile))
{
log.LogWarningWithCodeFromResources("General.StateFileAlreadyPresent", stateFile);
}
SerializeCacheByTranslator(stateFile, log);
}

/// <summary>
/// Cached implementation of GetDirectories.
/// </summary>
Expand Down

0 comments on commit 5949c20

Please sign in to comment.