private static CacheMissAnalysisResult AnalyzeFingerprints( Func <PipRecordingSession> oldSessionFunc, Func <PipRecordingSession> newSessionFunc, TextWriter writer) { var result = CacheMissAnalysisResult.Invalid; // While a PipRecordingSession is in scope, any pip information retrieved from the fingerprint store is // automatically written out to per-pip files. using (var oldPipSession = oldSessionFunc()) using (var newPipSession = newSessionFunc()) { bool missingPipEntry = false; if (!oldPipSession.EntryExists) { WriteLine("No fingerprint computation data found from old build.", writer, oldPipSession.PipWriter); WriteLine("This may be the first execution where pip outputs were stored to the cache.", writer, oldPipSession.PipWriter); // Write to just the old pip file WriteLine(RepeatedStrings.DisallowedFileAccessesOrPipFailuresPreventCaching, oldPipSession.PipWriter); missingPipEntry = true; result = CacheMissAnalysisResult.MissingFromOldBuild; WriteLine(string.Empty, writer, oldPipSession.PipWriter); } if (!newPipSession.EntryExists) { // Cases: // 1. ScheduleProcessNotStoredToCacheDueToFileMonitoringViolations // 2. ScheduleProcessNotStoredDueToMissingOutputs // 3. ScheduleProcessNotStoredToWarningsUnderWarnAsError // 4. ScheduleProcessNotStoredToCacheDueToInherentUncacheability WriteLine("No fingerprint computation data found from new build.", writer, newPipSession.PipWriter); // Write to just the new pip file WriteLine(RepeatedStrings.DisallowedFileAccessesOrPipFailuresPreventCaching, newPipSession.PipWriter); missingPipEntry = true; result = CacheMissAnalysisResult.MissingFromNewBuild; WriteLine(string.Empty, writer, newPipSession.PipWriter); } if (missingPipEntry) { // Only write once to the analysis file WriteLine(RepeatedStrings.DisallowedFileAccessesOrPipFailuresPreventCaching, writer); // Nothing to compare if an entry is missing return(result); } if (oldPipSession.FormattedSemiStableHash != newPipSession.FormattedSemiStableHash) { WriteLine(RepeatedStrings.FormattedSemiStableHashChanged, writer); // Make a trivial change list so the print looks like the rest of the diff var changeList = new ChangeList <string>(new string[] { oldPipSession.FormattedSemiStableHash }, new string[] { newPipSession.FormattedSemiStableHash }); WriteLine(changeList.ToString(), writer); } // Diff based off the actual fingerprints instead of the PipCacheMissType // to avoid shared cache diff confusion. // // In the following shared cache scenario: // Local cache: WeakFingerprint miss // Remote cache: WeakFingerprint hit, StrongFingerprint miss // // The pip cache miss type will be a strong fingerprint miss, // but the data in the fingerprint store will not match the // remote cache's, so we diff based off what we have in the fingerprint store. if (oldPipSession.WeakFingerprint != newPipSession.WeakFingerprint) { WriteLine("WeakFingerprint", writer); WriteLine(JsonTree.PrintTreeDiff(oldPipSession.GetWeakFingerprintTree(), newPipSession.GetWeakFingerprintTree()), writer); result = CacheMissAnalysisResult.WeakFingerprintMismatch; } else if (oldPipSession.StrongFingerprint != newPipSession.StrongFingerprint) { WriteLine("StrongFingerprint", writer); WriteLine(JsonTree.PrintTreeDiff(oldPipSession.GetStrongFingerprintTree(), newPipSession.GetStrongFingerprintTree()), writer); result = CacheMissAnalysisResult.StrongFingerprintMismatch; } else { WriteLine("The fingerprints from both builds matched and no cache retrieval errors occurred.", writer); WriteLine(RepeatedStrings.DisallowedFileAccessesOrPipFailuresPreventCaching, writer, oldPipSession.PipWriter, newPipSession.PipWriter); result = CacheMissAnalysisResult.UncacheablePip; } } return(result); }