private IEnumerable <string> CollectOutputs(BuildUpToDateCheckLogger logger, State state) { if (state.CustomOutputs.Count != 0) { logger.Verbose("Adding " + UpToDateCheckOutput.SchemaName + " outputs:"); // TODO remove pragmas when https://github.com/dotnet/roslyn/issues/37040 is fixed #pragma warning disable CS8622 foreach (string output in state.CustomOutputs.Select(_configuredProject.UnconfiguredProject.MakeRooted)) #pragma warning restore CS8622 { logger.Verbose(" '{0}'", output); yield return(output); } } if (state.BuiltOutputs.Count != 0) { logger.Verbose("Adding " + UpToDateCheckBuilt.SchemaName + " outputs:"); // TODO remove pragmas when https://github.com/dotnet/roslyn/issues/37040 is fixed #pragma warning disable CS8622 foreach (string output in state.BuiltOutputs.Select(_configuredProject.UnconfiguredProject.MakeRooted)) #pragma warning restore CS8622 { logger.Verbose(" '{0}'", output); yield return(output); } } }
private bool CheckMarkers(BuildUpToDateCheckLogger logger, IDictionary <string, DateTime> timestampCache, State state) { // Reference assembly copy markers are strange. The property is always going to be present on // references to SDK-based projects, regardless of whether or not those referenced projects // will actually produce a marker. And an item always will be present in an SDK-based project, // regardless of whether or not the project produces a marker. So, basically, we only check // here if the project actually produced a marker and we only check it against references that // actually produced a marker. if (string.IsNullOrWhiteSpace(state.MarkerFile) || !state.CopyReferenceInputs.Any()) { return(true); } string markerFile = _configuredProject.UnconfiguredProject.MakeRooted(state.MarkerFile); logger.Verbose("Adding input reference copy markers:"); foreach (string referenceMarkerFile in state.CopyReferenceInputs) { logger.Verbose(" '{0}'", referenceMarkerFile); } logger.Verbose("Adding output reference copy marker:"); logger.Verbose(" '{0}'", markerFile); (DateTime latestInputMarkerTime, string?latestInputMarkerPath) = GetLatestInput(state.CopyReferenceInputs, timestampCache); if (latestInputMarkerPath != null) { logger.Info("Latest write timestamp on input marker is {0} on '{1}'.", latestInputMarkerTime, latestInputMarkerPath); } else { logger.Info("No input markers exist, skipping marker check."); return(true); } DateTime?outputMarkerTime = GetTimestampUtc(markerFile, timestampCache); if (outputMarkerTime != null) { logger.Info("Write timestamp on output marker is {0} on '{1}'.", outputMarkerTime, markerFile); } else { logger.Info("Output marker '{0}' does not exist, skipping marker check.", markerFile); return(true); } if (outputMarkerTime < latestInputMarkerTime) { return(Fail(logger, "Marker", "Input marker is newer than output marker, not up to date.")); } return(true); }
// Reference assembly copy markers are strange. The property is always going to be present on // references to SDK-based projects, regardless of whether or not those referenced projects // will actually produce a marker. And an item always will be present in an SDK-based project, // regardless of whether or not the project produces a marker. So, basically, we only check // here if the project actually produced a marker and we only check it against references that // actually produced a marker. private bool CheckMarkers(BuildUpToDateCheckLogger logger, IDictionary <string, DateTime> timestampCache, State state) { if (string.IsNullOrWhiteSpace(state.MarkerFile) || !state.CopyReferenceInputs.Any()) { return(true); } string markerFile = _configuredProject.UnconfiguredProject.MakeRooted(state.MarkerFile); logger.Verbose("Adding input reference copy markers:"); foreach (string referenceMarkerFile in state.CopyReferenceInputs) { logger.Verbose(" '{0}'", referenceMarkerFile); } logger.Verbose("Adding output reference copy marker:"); logger.Verbose(" '{0}'", markerFile); (DateTime latestInputMarkerTime, string?latestInputMarkerPath) = GetLatestInput(state.CopyReferenceInputs, timestampCache); if (latestInputMarkerPath != null) { logger.Info("Latest write timestamp on input marker is {0} on '{1}'.", latestInputMarkerTime, latestInputMarkerPath); } else { logger.Info("No input markers exist, skipping marker check."); return(true); } DateTime?outputMarkerTime = GetTimestampUtc(markerFile, timestampCache); if (outputMarkerTime != null) { logger.Info("Write timestamp on output marker is {0} on '{1}'.", outputMarkerTime, markerFile); } else { logger.Info("Output marker '{0}' does not exist, skipping marker check.", markerFile); return(true); } if (outputMarkerTime < latestInputMarkerTime) { return(Fail(logger, "Marker", "Input marker is newer than output marker, not up to date.")); } return(true); }
public Task <bool> IsUpToDateAsync(BuildAction buildAction, TextWriter logWriter, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); return(ExecuteUnderLockAsync(IsUpToDateInternalAsync, cancellationToken)); async Task <bool> IsUpToDateInternalAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); var sw = Stopwatch.StartNew(); await InitializeAsync(token); LogLevel requestedLogLevel = await _projectSystemOptions.GetFastUpToDateLoggingLevelAsync(token); var logger = new BuildUpToDateCheckLogger(logWriter, requestedLogLevel, _configuredProject.UnconfiguredProject.FullPath); try { State state = _state; if (!CheckGlobalConditions(buildAction, logger, state)) { return(false); } // Short-lived cache of timestamp by path var timestampCache = new Dictionary <string, DateTime>(StringComparers.Paths); if (!CheckInputsAndOutputs(logger, timestampCache, state) || !CheckMarkers(logger, timestampCache, state) || !CheckCopyToOutputDirectoryFiles(logger, timestampCache, state) || !CheckCopiedOutputFiles(logger, timestampCache, state)) { return(false); } _telemetryService.PostEvent(TelemetryEventName.UpToDateCheckSuccess); logger.Info("Project is up to date."); return(true); } finally { lock (_stateLock) { _state = _state.WithLastCheckedAtUtc(DateTime.UtcNow); } logger.Verbose("Up to date check completed in {0:N1} ms", sw.Elapsed.TotalMilliseconds); } } }
private IEnumerable <string> CollectOutputs(BuildUpToDateCheckLogger logger, State state) { if (state.CustomOutputs.Count != 0) { logger.Verbose("Adding " + UpToDateCheckOutput.SchemaName + " outputs:"); foreach (string output in state.CustomOutputs.Select(_configuredProject.UnconfiguredProject.MakeRooted)) { logger.Verbose(" '{0}'", output); yield return(output); } } if (state.BuiltOutputs.Count != 0) { logger.Verbose("Adding " + UpToDateCheckBuilt.SchemaName + " outputs:"); foreach (string output in state.BuiltOutputs.Select(_configuredProject.UnconfiguredProject.MakeRooted)) { logger.Verbose(" '{0}'", output); yield return(output); } } }
private IEnumerable <string> CollectInputs(BuildUpToDateCheckLogger logger, State state) { if (state.MSBuildProjectFullPath != null) { logger.Verbose("Adding project file inputs:"); logger.Verbose(" '{0}'", state.MSBuildProjectFullPath); yield return(state.MSBuildProjectFullPath); } if (state.NewestImportInput != null) { logger.Verbose("Adding newest import input:"); logger.Verbose(" '{0}'", state.NewestImportInput); yield return(state.NewestImportInput); } foreach ((string itemType, ImmutableHashSet <(string path, string?link, CopyToOutputDirectoryType copyType)> changes) in state.ItemsByItemType) { if (!NonCompilationItemTypes.Contains(itemType)) { logger.Verbose("Adding {0} inputs:", itemType); foreach (string input in changes.Select(item => _configuredProject.UnconfiguredProject.MakeRooted(item.path))) { logger.Verbose(" '{0}'", input); yield return(input); } } } if (state.AnalyzerReferences.Count != 0) { logger.Verbose("Adding " + ResolvedAnalyzerReference.SchemaName + " inputs:"); foreach (string input in state.AnalyzerReferences) { logger.Verbose(" '{0}'", input); yield return(input); } } if (state.CompilationReferences.Count != 0) { logger.Verbose("Adding " + ResolvedCompilationReference.SchemaName + " inputs:"); foreach (string input in state.CompilationReferences) { logger.Verbose(" '{0}'", input); yield return(input); } } if (state.CustomInputs.Count != 0) { logger.Verbose("Adding " + UpToDateCheckInput.SchemaName + " inputs:"); foreach (string input in state.CustomInputs.Select(_configuredProject.UnconfiguredProject.MakeRooted)) { logger.Verbose(" '{0}'", input); yield return(input); } } }