in src/Utilities/TrackedDependencies/CanonicalTrackedOutputFiles.cs [106:277]
private void ConstructOutputTable()
{
string tLogRootingMarker = null;
try
{
// construct a rooting marker from the tlog files
tLogRootingMarker = DependencyTableCache.FormatNormalizedTlogRootingMarker(_tlogFiles);
}
catch (ArgumentException e)
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
return;
}
// Record the current directory (which under normal circumstances will be the project directory)
// so that we can compare tracked paths against it for inclusion in the dependency graph
string currentProjectDirectory = FileUtilities.EnsureTrailingSlash(Directory.GetCurrentDirectory());
if (!_tlogAvailable)
{
FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingLogNotAvailable");
lock (DependencyTableCache.DependencyTable)
{
// The tracking logs are not available, they may have been deleted at some point.
// Be safe and remove any references from the cache.
if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
{
DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
}
}
return;
}
DependencyTableCacheEntry cachedEntry = null;
lock (DependencyTableCache.DependencyTable)
{
// Look in the dependency table cache to see if its available and up to date
cachedEntry = DependencyTableCache.GetCachedEntry(tLogRootingMarker);
}
// We have an up to date cached entry
if (cachedEntry != null)
{
_dependencyTable = (Dictionary<string, System.Collections.Generic.Dictionary<string, System.DateTime>>)cachedEntry.DependencyTable;
// Log information about what we're using
FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_WriteTrackingCached");
foreach (ITaskItem tlogItem in cachedEntry.TlogFiles)
{
FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogItem.ItemSpec);
}
return;
}
FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_WriteTrackingLogs");
// Now we need to construct the rest of the table from the TLOG files
// If there are any errors in the tlogs, we want to warn, stop parsing tlogs, and empty
// out the dependency table, essentially forcing a rebuild.
bool encounteredInvalidTLogContents = false;
bool exceptionCaught = false;
string invalidTLogName = null;
foreach (ITaskItem tlogFileName in _tlogFiles)
{
FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogFileName.ItemSpec);
try
{
using (StreamReader tlog = File.OpenText(tlogFileName.ItemSpec))
{
string tlogEntry = tlog.ReadLine();
while (tlogEntry != null)
{
if (tlogEntry.Length == 0)
{
encounteredInvalidTLogContents = true;
invalidTLogName = tlogFileName.ItemSpec;
break;
}
if (tlogEntry[0] == '^') // This is a rooting record, follow the outputs for it
{
Dictionary<string, DateTime> dependencies;
tlogEntry = tlogEntry.Substring(1);
if (tlogEntry.Length == 0)
{
encounteredInvalidTLogContents = true;
invalidTLogName = tlogFileName.ItemSpec;
break;
}
if (!_dependencyTable.TryGetValue(tlogEntry, out dependencies))
{
dependencies = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);
_dependencyTable.Add(tlogEntry, dependencies);
}
// Process each file encountered until we hit a rooting marker
do
{
tlogEntry = tlog.ReadLine();
if (tlogEntry != null)
{
if (tlogEntry.Length == 0)
{
encounteredInvalidTLogContents = true;
invalidTLogName = tlogFileName.ItemSpec;
break;
}
else if ((tlogEntry[0] != '^') && (tlogEntry[0] != '#') && (!dependencies.ContainsKey(tlogEntry)))
{
// Allows incremental build of projects existing under temp, only for those reads / writes that
// either are not under temp, or are recursively beneath the current project directory.
if (FileTracker.FileIsUnderPath(tlogEntry, currentProjectDirectory) || !FileTracker.FileIsExcludedFromDependencies(tlogEntry))
{
DateTime fileModifiedTime = NativeMethodsShared.GetLastWriteFileUtcTime(tlogEntry);
dependencies.Add(tlogEntry, fileModifiedTime);
}
}
}
} while ((tlogEntry != null) && (tlogEntry[0] != '^'));
if (encounteredInvalidTLogContents)
{
break;
}
}
else // don't know what this entry is, so skip it
{
tlogEntry = tlog.ReadLine();
}
}
}
}
catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
break;
}
if (encounteredInvalidTLogContents)
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLogContents", invalidTLogName);
break;
}
}
lock (DependencyTableCache.DependencyTable)
{
// There were problems with the tracking logs -- we've already warned or errored; now we want to make
// sure that we essentially force a rebuild of this particular root.
if (encounteredInvalidTLogContents || exceptionCaught)
{
if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
{
DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
}
_dependencyTable = new Dictionary<string, Dictionary<string, DateTime>>(StringComparer.OrdinalIgnoreCase);
}
else
{
// Record the newly built valid dependency table in the cache
DependencyTableCache.DependencyTable[tLogRootingMarker] = new DependencyTableCacheEntry(_tlogFiles, _dependencyTable);
}
}
}