/// <summary> /// Returns a string indicating why an incremental build is occurring. /// </summary> private static string GetIncrementalBuildReason(DependencyAnalysisLogDetail logDetail) { string reason = null; if (logDetail.Reason == OutofdateReason.NewerInput) { // One of the inputs was newer than its corresponding output reason = ResourceUtilities.FormatResourceString("BuildTargetPartiallyInputNewer", logDetail.InputItemName, logDetail.Input, logDetail.Output); } else if (logDetail.Reason == OutofdateReason.MissingOutput) { // One of the outputs was missing reason = ResourceUtilities.FormatResourceString("BuildTargetPartiallyOutputDoesntExist", logDetail.OutputItemName, logDetail.Input, logDetail.Output); } else if (logDetail.Reason == OutofdateReason.MissingInput) { // One of the inputs was missing reason = ResourceUtilities.FormatResourceString("BuildTargetPartiallyInputDoesntExist", logDetail.InputItemName, logDetail.Input, logDetail.Output); } return reason; }
/// <summary> /// Compares the set of files/directories designated as "inputs" against the set of files/directories designated as /// "outputs", and indicates if any "output" file/directory is out-of-date w.r.t. any "input" file/directory. /// </summary> /// <remarks> /// NOTE: Internal for unit test purposes only. /// </remarks> /// <owner>danmose</owner> /// <param name="inputs"></param> /// <param name="outputs"></param> /// <returns>true, if any "input" is newer than any "output", or if any input or output does not exist.</returns> internal static bool IsAnyOutOfDate(out DependencyAnalysisLogDetail dependencyAnalysisDetailEntry, string projectDirectory, IList inputs, IList outputs) { ErrorUtilities.VerifyThrow((inputs.Count > 0) && (outputs.Count > 0), "Need to specify inputs and outputs."); // Algorithm: walk through all the outputs to find the oldest output // walk through the inputs as far as we need to until we find one that's newer (if any) // PERF -- we could change this to ensure that we walk the shortest list first (because we walk that one entirely): // possibly the outputs list isn't actually the shortest list. However it always is the shortest // in the cases I've seen, and adding this optimization would make the code hard to read. string oldestOutput = EscapingUtilities.UnescapeAll((string)outputs[0]); FileInfo oldestOutputInfo = null; try { string oldestOutputFullPath = Path.Combine(projectDirectory, oldestOutput); oldestOutputInfo = FileUtilities.GetFileInfoNoThrow(oldestOutputFullPath); } catch (Exception e) { if (ExceptionHandling.NotExpectedException(e)) { throw; } // Output does not exist oldestOutputInfo = null; } if (oldestOutputInfo == null) { // First output is missing: we must build the target string arbitraryInput = EscapingUtilities.UnescapeAll((string)inputs[0]); dependencyAnalysisDetailEntry = new DependencyAnalysisLogDetail(arbitraryInput, oldestOutput, null, null, OutofdateReason.MissingOutput); return true; } for (int i = 1; i < outputs.Count; i++) { string candidateOutput = EscapingUtilities.UnescapeAll((string)outputs[i]); FileInfo candidateOutputInfo = null; try { string candidateOutputFullPath = Path.Combine(projectDirectory, candidateOutput); candidateOutputInfo = FileUtilities.GetFileInfoNoThrow(candidateOutputFullPath); } catch (Exception e) { if (ExceptionHandling.NotExpectedException(e)) { throw; } // Output does not exist candidateOutputInfo = null; } if (candidateOutputInfo == null) { // An output is missing: we must build the target string arbitraryInput = EscapingUtilities.UnescapeAll((string)inputs[0]); dependencyAnalysisDetailEntry = new DependencyAnalysisLogDetail(arbitraryInput, candidateOutput, null, null, OutofdateReason.MissingOutput); return true; } if (oldestOutputInfo.LastWriteTime > candidateOutputInfo.LastWriteTime) { // This output is older than the previous record holder oldestOutputInfo = candidateOutputInfo; oldestOutput = candidateOutput; } } // Now compare the oldest output with each input and break out if we find one newer. foreach (string input in inputs) { string unescapedInput = EscapingUtilities.UnescapeAll(input); FileInfo inputInfo = null; try { string unescapedInputFullPath = Path.Combine(projectDirectory, unescapedInput); inputInfo = FileUtilities.GetFileInfoNoThrow(unescapedInputFullPath); } catch (Exception e) { if (ExceptionHandling.NotExpectedException(e)) { throw; } // Output does not exist inputInfo = null; } if (inputInfo == null) { // An input is missing: we must build the target dependencyAnalysisDetailEntry = new DependencyAnalysisLogDetail(unescapedInput, oldestOutput, null, null, OutofdateReason.MissingInput); return true; } else { if (inputInfo.LastWriteTime > oldestOutputInfo.LastWriteTime) { // This input is newer than the oldest output: we must build the target dependencyAnalysisDetailEntry = new DependencyAnalysisLogDetail(unescapedInput, oldestOutput, null, null, OutofdateReason.NewerInput); return true; } } } // All exist and no inputs are newer than any outputs; up to date dependencyAnalysisDetailEntry = null; return false; }
/// <summary> /// Returns a string indicating why a full build is occurring. /// </summary> internal static string GetFullBuildReason(DependencyAnalysisLogDetail logDetail) { string reason = null; if (logDetail.Reason == OutofdateReason.NewerInput) { // One of the inputs was newer than all of the outputs reason = ResourceUtilities.FormatResourceString("BuildTargetCompletelyInputNewer", logDetail.Input, logDetail.Output); } else if (logDetail.Reason == OutofdateReason.MissingOutput) { // One of the outputs was missing reason = ResourceUtilities.FormatResourceString("BuildTargetCompletelyOutputDoesntExist", logDetail.Output); } else if (logDetail.Reason == OutofdateReason.MissingInput) { // One of the inputs was missing reason = ResourceUtilities.FormatResourceString("BuildTargetCompletelyInputDoesntExist", logDetail.Input); } return reason; }