-
Notifications
You must be signed in to change notification settings - Fork 391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle ref assemblies in up-to-date check #2414
Merged
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
fb019db
Handle ref assemblies
panopticoncentral bfc28f4
Merge upstream/master
panopticoncentral a839b33
Move to item rather than property
panopticoncentral 2d0f843
Fix issue.
panopticoncentral 32b9b66
Fix marker check
panopticoncentral 9355c9e
Fix problem with non-existent marker files
panopticoncentral e88ebd5
Some more fixes
panopticoncentral File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,13 +60,17 @@ private void Log(LogLevel level, string message, params object[] values) | |
|
||
private static ImmutableHashSet<string> ReferenceSchemas => ImmutableHashSet<string>.Empty | ||
.Add(ResolvedAnalyzerReference.SchemaName) | ||
.Add(ResolvedAssemblyReference.SchemaName) | ||
.Add(ResolvedCOMReference.SchemaName) | ||
.Add(ResolvedProjectReference.SchemaName); | ||
.Add(ResolvedCompilationReference.SchemaName); | ||
|
||
private static ImmutableHashSet<string> UpToDateSchemas => ImmutableHashSet<string>.Empty | ||
.Add(CopyUpToDateMarker.SchemaName) | ||
.Add(UpToDateCheckInput.SchemaName) | ||
.Add(UpToDateCheckOutput.SchemaName); | ||
|
||
private static ImmutableHashSet<string> ProjectPropertiesSchemas => ImmutableHashSet<string>.Empty | ||
.Add(ConfigurationGeneral.SchemaName) | ||
.Union(ReferenceSchemas); | ||
.Union(ReferenceSchemas) | ||
.Union(UpToDateSchemas); | ||
|
||
private readonly IProjectSystemOptions _projectSystemOptions; | ||
private readonly ConfiguredProject _configuredProject; | ||
|
@@ -79,11 +83,15 @@ private void Log(LogLevel level, string message, params object[] values) | |
private bool _isDisabled = true; | ||
private bool _itemsChangedSinceLastCheck = true; | ||
private string _msBuildProjectFullPath; | ||
private string _markerFile; | ||
private HashSet<string> _imports = new HashSet<string>(); | ||
private HashSet<string> _itemTypes = new HashSet<string>(); | ||
private Dictionary<string, HashSet<string>> _items = new Dictionary<string, HashSet<string>>(); | ||
private Dictionary<string, HashSet<string>> _references = new Dictionary<string, HashSet<string>>(); | ||
private HashSet<string> _customInputs = new HashSet<string>(); | ||
private HashSet<string> _customOutputs = new HashSet<string>(); | ||
private HashSet<string> _analyzerReferences = new HashSet<string>(); | ||
private HashSet<string> _compilationReferences = new HashSet<string>(); | ||
private HashSet<string> _referenceMarkerFiles = new HashSet<string>(); | ||
private Dictionary<string, HashSet<string>> _outputGroups = new Dictionary<string, HashSet<string>>(); | ||
|
||
[ImportingConstructor] | ||
|
@@ -117,14 +125,51 @@ private void OnProjectChanged(IProjectSubscriptionUpdate e) | |
_isDisabled = disableFastUpToDateCheckString != null && string.Equals(disableFastUpToDateCheckString, TrueValue, StringComparison.OrdinalIgnoreCase); | ||
|
||
_msBuildProjectFullPath = e.CurrentState.GetPropertyOrDefault(ConfigurationGeneral.SchemaName, ConfigurationGeneral.MSBuildProjectFullPathProperty, _msBuildProjectFullPath); | ||
foreach (var referenceSchema in ReferenceSchemas) | ||
|
||
if (e.ProjectChanges.TryGetValue(ResolvedAnalyzerReference.SchemaName, out var changes) && | ||
changes.Difference.AnyChanges) | ||
{ | ||
if (e.ProjectChanges.TryGetValue(referenceSchema, out var changes) && | ||
changes.Difference.AnyChanges) | ||
_analyzerReferences = new HashSet<string>(changes.After.Items.Select(item => item.Value[ResolvedPath])); | ||
} | ||
|
||
if (e.ProjectChanges.TryGetValue(ResolvedCompilationReference.SchemaName, out changes) && | ||
changes.Difference.AnyChanges) | ||
{ | ||
_compilationReferences.Clear(); | ||
_referenceMarkerFiles.Clear(); | ||
|
||
foreach (var item in changes.After.Items) | ||
{ | ||
_references[referenceSchema] = new HashSet<string>(changes.After.Items.Select(item => item.Value[ResolvedPath])); | ||
_compilationReferences.Add(item.Value[ResolvedPath]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And also _compilationReferences.Add(item.Value[OriginalPath]); if it exists? |
||
if (!string.IsNullOrWhiteSpace(item.Value[CopyUpToDateMarker.SchemaName])) | ||
{ | ||
_referenceMarkerFiles.Add(item.Value[CopyUpToDateMarker.SchemaName]); | ||
} | ||
} | ||
} | ||
|
||
if (e.ProjectChanges.TryGetValue(UpToDateCheckInput.SchemaName, out var inputs) && | ||
inputs.Difference.AnyChanges) | ||
{ | ||
_customInputs = new HashSet<string>(inputs.After.Items.Select(item => item.Value[FullPath])); | ||
} | ||
|
||
if (e.ProjectChanges.TryGetValue(UpToDateCheckOutput.SchemaName, out var outputs) && | ||
outputs.Difference.AnyChanges) | ||
{ | ||
_customOutputs = new HashSet<string>(outputs.After.Items.Select(item => item.Value[FullPath])); | ||
} | ||
|
||
if (e.ProjectChanges.TryGetValue(CopyUpToDateMarker.SchemaName, out var upToDateMarkers) && | ||
upToDateMarkers.Difference.AnyChanges && | ||
upToDateMarkers.After.Items.Count == 1) | ||
{ | ||
_markerFile = upToDateMarkers.After.Items.Single().Value[FullPath]; | ||
} | ||
else | ||
{ | ||
_markerFile = null; | ||
} | ||
} | ||
|
||
private void OnProjectImportsChanged(IProjectImportTreeSnapshot e) | ||
|
@@ -161,12 +206,6 @@ private void OnSourceItemChanged(IProjectSubscriptionUpdate e, IProjectItemSchem | |
_items[itemType.Key] = new HashSet<string>(items); | ||
_itemsChangedSinceLastCheck = true; | ||
} | ||
|
||
if (e.ProjectChanges.TryGetValue(UpToDateCheckOutput.SchemaName, out var outputs) && | ||
outputs.Difference.AnyChanges) | ||
{ | ||
_customOutputs = new HashSet<string>(outputs.After.Items.Select(item => item.Value[FullPath])); | ||
} | ||
} | ||
|
||
private void OnOutputGroupChanged(IImmutableDictionary<string, IOutputGroup> e) | ||
|
@@ -289,10 +328,9 @@ private HashSet<string> CollectInputs(Logger logger) | |
AddInputs(logger, inputs, pair.Value, pair.Key); | ||
} | ||
|
||
foreach (var pair in _references) | ||
{ | ||
AddInputs(logger, inputs, pair.Value, pair.Key); | ||
} | ||
AddInputs(logger, inputs, _analyzerReferences, ResolvedAnalyzerReference.SchemaName); | ||
AddInputs(logger, inputs, _compilationReferences, ResolvedCompilationReference.SchemaName); | ||
AddInputs(logger, inputs, _customInputs, UpToDateCheckInput.SchemaName); | ||
|
||
return inputs; | ||
} | ||
|
@@ -306,20 +344,20 @@ private HashSet<string> CollectOutputs(Logger logger) | |
AddOutputs(logger, outputs, pair.Value, pair.Key); | ||
} | ||
|
||
AddOutputs(logger, outputs, _customOutputs, "UpToDateCheckOutput"); | ||
AddOutputs(logger, outputs, _customOutputs, UpToDateCheckOutput.SchemaName); | ||
|
||
return outputs; | ||
} | ||
|
||
private (DateTime? time, string path) GetLatestInput(HashSet<string> inputs, IDictionary<string, DateTime> timestampCache) | ||
private (DateTime? time, string path) GetLatestInput(HashSet<string> inputs, IDictionary<string, DateTime> timestampCache, bool ignoreMissing = false) | ||
{ | ||
DateTime? latest = DateTime.MinValue; | ||
string latestPath = null; | ||
|
||
foreach (var input in inputs) | ||
{ | ||
var time = GetTimestamp(input, timestampCache); | ||
if (latest != null && (time == null || time > latest)) | ||
if (latest != null && (time == null && !ignoreMissing || time > latest)) | ||
{ | ||
latest = time; | ||
latestPath = input; | ||
|
@@ -347,6 +385,50 @@ private HashSet<string> CollectOutputs(Logger logger) | |
return (earliest, earliestPath); | ||
} | ||
|
||
// 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(Logger logger, IDictionary<string, DateTime> timestampCache) | ||
{ | ||
if (string.IsNullOrWhiteSpace(_markerFile) || !_referenceMarkerFiles.Any()) | ||
{ | ||
return true; | ||
} | ||
|
||
foreach (var referenceMarkerFile in _referenceMarkerFiles) | ||
{ | ||
logger.Verbose("Found possible input marker '{0}'.", referenceMarkerFile); | ||
} | ||
|
||
logger.Verbose("Found possible output marker '{0}'.", _markerFile); | ||
|
||
var latestInputMarker = GetLatestInput(_referenceMarkerFiles, timestampCache, true); | ||
var outputMarkerTime = GetTimestamp(_markerFile, timestampCache); | ||
|
||
if (latestInputMarker.time != null) | ||
{ | ||
logger.Info("Lastest write timestamp on input marker is {0} on '{1}'.", latestInputMarker.time.Value, latestInputMarker.path); | ||
} | ||
else | ||
{ | ||
logger.Info("No input markers exist, skipping marker check."); | ||
} | ||
|
||
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 latestInputMarker.time == null || outputMarkerTime == null || outputMarkerTime > latestInputMarker.time; | ||
} | ||
|
||
public async Task<bool> IsUpToDateAsync(BuildAction buildAction, TextWriter logWriter, CancellationToken cancellationToken = default(CancellationToken)) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
@@ -385,7 +467,13 @@ private HashSet<string> CollectOutputs(Logger logger) | |
} | ||
|
||
// We are up to date if the earliest output write happened after the latest input write | ||
var isUpToDate = latestInput.time != null && earliestOutput.time != null && earliestOutput.time > latestInput.time; | ||
var markersUpToDate = CheckMarkers(logger, timestampCache); | ||
var isUpToDate = | ||
latestInput.time != null | ||
&& earliestOutput.time != null | ||
&& earliestOutput.time > latestInput.time | ||
&& markersUpToDate; | ||
|
||
logger.Info("Project is{0} up to date.", (!isUpToDate ? " not" : "")); | ||
|
||
return isUpToDate; | ||
|
12 changes: 12 additions & 0 deletions
12
src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/CopyUpToDateMarker.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Microsoft.VisualStudio.ProjectSystem | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
[SuppressMessage("Style", "IDE0016:Use 'throw' expression")] | ||
partial class CopyUpToDateMarker | ||
{ | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/CopyUpToDateMarker.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!--Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.--> | ||
<Rule | ||
Name="CopyUpToDateMarker" | ||
DisplayName="Up-to-date check marker for reference assemblies" | ||
PageTemplate="generic" | ||
Description="File Properties" | ||
xmlns="http://schemas.microsoft.com/build/2009/properties"> | ||
<Rule.DataSource> | ||
<DataSource Persistence="ProjectFile" HasConfigurationCondition="False" ItemType="CopyUpToDateMarker" SourceOfDefaultValue="AfterContext" /> | ||
</Rule.DataSource> | ||
<Rule.Categories> | ||
<Category Name="Advanced" DisplayName="Advanced" /> | ||
<Category Name="Misc" DisplayName="Misc" /> | ||
</Rule.Categories> | ||
|
||
<StringProperty | ||
Name="FullPath" | ||
DisplayName="Full Path" | ||
ReadOnly="true" | ||
Category="Misc" | ||
Description="Location of the file."> | ||
<StringProperty.DataSource> | ||
<DataSource Persistence="Intrinsic" ItemType="CopyUpToDateMarker" PersistedName="FullPath" SourceOfDefaultValue="AfterContext" /> | ||
</StringProperty.DataSource> | ||
</StringProperty> | ||
|
||
<BoolProperty Name="Visible" Default="false" Visible="false" /> | ||
</Rule> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
...ft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/ResolvedCompilationReference.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Microsoft.VisualStudio.ProjectSystem | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
[SuppressMessage("Style", "IDE0016:Use 'throw' expression")] | ||
partial class ResolvedCompilationReference | ||
{ | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
....VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/ResolvedCompilationReference.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. --> | ||
<Rule | ||
Name="ResolvedCompilationReference" | ||
DisplayName="Resolved Compilation Reference" | ||
PageTemplate="generic" | ||
Description="Resolved Compilation Reference Properties" | ||
xmlns="http://schemas.microsoft.com/build/2009/properties"> | ||
<Rule.DataSource> | ||
<DataSource Persistence="ResolvedReference" ItemType="ReferencePathWithRefAssemblies" HasConfigurationCondition="False" SourceOfDefaultValue="AfterContext" | ||
SourceType="TargetResults" MSBuildTarget="CollectResolvedCompilationReferencesDesignTime"/> | ||
</Rule.DataSource> | ||
|
||
<StringProperty Name="ResolvedPath" ReadOnly="True" DisplayName="Path" Description="Location of the referenced assembly."> | ||
<StringProperty.DataSource> | ||
<DataSource PersistedName="Identity" SourceOfDefaultValue="AfterContext" /> | ||
</StringProperty.DataSource> | ||
</StringProperty> | ||
|
||
<StringProperty Name="CopyUpToDateMarker" ReadOnly="True" Visible="False"/> | ||
</Rule> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which sort of string comparison do we want to use for this
HashSet
?