Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ref/Microsoft.Build/net/Microsoft.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ public ProjectInstance(string projectFile, System.Collections.Generic.IDictionar
public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
public System.Collections.Generic.List<string> DefaultTargets { get { throw null; } }
public string Directory { get { throw null; } }
public System.Collections.Generic.ICollection<string> EnvironmentVariableReads { get { throw null; } }
public System.Collections.Generic.List<Microsoft.Build.Construction.ProjectItemElement> EvaluatedItemElements { get { throw null; } }
public int EvaluationId { get { throw null; } set { } }
public string FullPath { get { throw null; } }
Expand All @@ -1109,6 +1110,7 @@ public ProjectInstance(string projectFile, System.Collections.Generic.IDictionar
public System.Collections.Generic.IDictionary<string, Microsoft.Build.Execution.ProjectTargetInstance> Targets { get { throw null; } }
public string ToolsVersion { get { throw null; } }
public bool TranslateEntireState { get { throw null; } set { } }
public System.Collections.Generic.ICollection<string> UninitializedPropertyReads { get { throw null; } }
public Microsoft.Build.Execution.ProjectItemInstance AddItem(string itemType, string evaluatedInclude) { throw null; }
public Microsoft.Build.Execution.ProjectItemInstance AddItem(string itemType, string evaluatedInclude, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> metadata) { throw null; }
public bool Build() { throw null; }
Expand Down Expand Up @@ -1425,9 +1427,12 @@ public ProjectGraph(string entryProjectFile, Microsoft.Build.Evaluation.ProjectC
public ProjectGraph(string entryProjectFile, System.Collections.Generic.IDictionary<string, string> globalProperties) { }
public ProjectGraph(string entryProjectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> EntryPointNodes { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> EnvironmentVariableReads { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> EnvironmentVariablesImpactingBuild { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> GraphRoots { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> ProjectNodes { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> ProjectNodesTopologicallySorted { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> UninitializedPropertyReads { get { throw null; } }
public System.Collections.Generic.IReadOnlyDictionary<Microsoft.Build.Experimental.Graph.ProjectGraphNode, System.Collections.Immutable.ImmutableList<string>> GetTargetLists(System.Collections.Generic.ICollection<string> entryProjectTargets) { throw null; }
public delegate Microsoft.Build.Execution.ProjectInstance ProjectInstanceFactoryFunc(string projectPath, System.Collections.Generic.Dictionary<string, string> globalProperties, Microsoft.Build.Evaluation.ProjectCollection projectCollection);
}
Expand Down
5 changes: 5 additions & 0 deletions ref/Microsoft.Build/netstandard/Microsoft.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ public ProjectInstance(string projectFile, System.Collections.Generic.IDictionar
public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
public System.Collections.Generic.List<string> DefaultTargets { get { throw null; } }
public string Directory { get { throw null; } }
public System.Collections.Generic.ICollection<string> EnvironmentVariableReads { get { throw null; } }
public System.Collections.Generic.List<Microsoft.Build.Construction.ProjectItemElement> EvaluatedItemElements { get { throw null; } }
public int EvaluationId { get { throw null; } set { } }
public string FullPath { get { throw null; } }
Expand All @@ -1103,6 +1104,7 @@ public ProjectInstance(string projectFile, System.Collections.Generic.IDictionar
public System.Collections.Generic.IDictionary<string, Microsoft.Build.Execution.ProjectTargetInstance> Targets { get { throw null; } }
public string ToolsVersion { get { throw null; } }
public bool TranslateEntireState { get { throw null; } set { } }
public System.Collections.Generic.ICollection<string> UninitializedPropertyReads { get { throw null; } }
public Microsoft.Build.Execution.ProjectItemInstance AddItem(string itemType, string evaluatedInclude) { throw null; }
public Microsoft.Build.Execution.ProjectItemInstance AddItem(string itemType, string evaluatedInclude, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> metadata) { throw null; }
public bool Build() { throw null; }
Expand Down Expand Up @@ -1419,9 +1421,12 @@ public ProjectGraph(string entryProjectFile, Microsoft.Build.Evaluation.ProjectC
public ProjectGraph(string entryProjectFile, System.Collections.Generic.IDictionary<string, string> globalProperties) { }
public ProjectGraph(string entryProjectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> EntryPointNodes { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> EnvironmentVariableReads { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> EnvironmentVariablesImpactingBuild { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> GraphRoots { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> ProjectNodes { get { throw null; } }
public System.Collections.Generic.IReadOnlyCollection<Microsoft.Build.Experimental.Graph.ProjectGraphNode> ProjectNodesTopologicallySorted { get { throw null; } }
public System.Collections.Generic.IEnumerable<string> UninitializedPropertyReads { get { throw null; } }
public System.Collections.Generic.IReadOnlyDictionary<Microsoft.Build.Experimental.Graph.ProjectGraphNode, System.Collections.Immutable.ImmutableList<string>> GetTargetLists(System.Collections.Generic.ICollection<string> entryProjectTargets) { throw null; }
public delegate Microsoft.Build.Execution.ProjectInstance ProjectInstanceFactoryFunc(string projectPath, System.Collections.Generic.Dictionary<string, string> globalProperties, Microsoft.Build.Evaluation.ProjectCollection projectCollection);
}
Expand Down
198 changes: 198 additions & 0 deletions src/Build.UnitTests/Graph/ProjectGraph_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,204 @@ public void InnerBuildsProducedByOuterBuildsCanBeReferencedByOtherInnerBuilds()
innerBuild1WithReferenceToInnerBuild2.ProjectReferences.ShouldBeEquivalentTo(new []{outerBuild2, innerBuild2});
}

[Fact]
public void EnvironmentVariablesReadReturnsNullWhenDisabled()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "");
var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>booyah</NotAnEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.ShouldBeNull();
}
}

[Fact]
public void EnvironmentVariablesReadReturnsNotNullWhenEnabled()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>booyah</NotAnEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.Count.ShouldBe(0);
}
}

[Fact]
public void EnvironmentVariablesReadReturnsNumActuallyRead()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>$(Path)</NotAnEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.Count.ShouldBe(1);
first.ProjectInstance.EnvironmentVariableReads.First().ShouldBe("Path");
}
}

[Fact]
public void EnvironmentVariablesReadIgnoresOverwrittenEnvVars()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");
env.SetEnvironmentVariable("SomeTestEnvVar", "SomeValue");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>$(Path)</NotAnEnvVar>
<SomeTestEnvVar>Overwritten!</SomeTestEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.Count.ShouldBe(1); // NOT TWO!
first.ProjectInstance.EnvironmentVariableReads.First().ShouldBe("Path");
}
}

[Fact]
public void EnvironmentVariablesReadReturnsNumActuallyReadMultiple()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>$(Path)</NotAnEnvVar>
<AlsoNotAnEnvVar>$(LocalAppData)</AlsoNotAnEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.EnvironmentVariableReads.ShouldNotBeNull();

string readEnvVars = string.Join(", ", first.ProjectInstance.EnvironmentVariableReads);
string allEnvVars = string.Join(", ", first.ProjectInstance.TestEnvironmentalProperties.Select(p => p.Name));
first.ProjectInstance.EnvironmentVariableReads.Count.ShouldBe(2, $"All: {allEnvVars} | Read: {readEnvVars}");
}
}

[Fact]
public void UninitializedVariablesNullWhenDisabled()
{
using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
<NotAnEnvVar>$(This_Should_Not_Exist)</NotAnEnvVar>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.UninitializedPropertyReads.ShouldBeNull();
}
}

[Fact]
public void UninitializedVariablesWithActualValues()
{
int defaultUninitPropCount = 0;

using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup>
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.UninitializedPropertyReads.ShouldNotBeNull();

// Determine how many uninitialized variables are present by default.
defaultUninitPropCount = first.ProjectInstance.UninitializedPropertyReads.Count;
}

using (var env = TestEnvironment.Create())
{
env.SetEnvironmentVariable("MSBUILDTRACKENVVARREADS", "1");

var projFile = env.CreateFile($"{Guid.NewGuid()}.proj", @"
<Project>
<PropertyGroup Condition=""'$(This_Should_Not_Exist)'=='Nope!'"">
</PropertyGroup>
</Project>");

var graph = new ProjectGraph(projFile.Path);
graph.ProjectNodes.ShouldNotBeNull();
graph.ProjectNodes.Count.ShouldBe(1);
var first = graph.ProjectNodes.First();
first.ProjectInstance.ShouldNotBeNull();
first.ProjectInstance.UninitializedPropertyReads.ShouldNotBeNull();
int count = first.ProjectInstance.UninitializedPropertyReads.Count;

first.ProjectInstance.UninitializedPropertyReads.Where(p => p.Equals("This_Should_Not_Exist")).FirstOrDefault().ShouldNotBeNull();
(count - defaultUninitPropCount).ShouldBe(1);
}
}

public static IEnumerable<object[]> AllNodesShouldHaveGraphBuildGlobalPropertyData
{
get
Expand Down
2 changes: 1 addition & 1 deletion src/Build/Definition/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3371,7 +3371,7 @@ public IItemDefinition<ProjectMetadata> GetItemDefinition(string itemType)
/// <summary>
/// Sets a property which is not derived from Xml.
/// </summary>
public ProjectProperty SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved)
public ProjectProperty SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved, bool isEnvVar = false)
{
ProjectProperty property = ProjectProperty.Create(Project, name, evaluatedValueEscaped, isGlobalProperty, mayBeReserved);
Properties.Set(property);
Expand Down
2 changes: 1 addition & 1 deletion src/Build/Evaluation/Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,7 @@ private ICollection<P> AddEnvironmentProperties()

foreach (ProjectPropertyInstance environmentProperty in _environmentProperties)
{
P property = _data.SetProperty(environmentProperty.Name, ((IProperty)environmentProperty).EvaluatedValueEscaped, false /* NOT global property */, false /* may NOT be a reserved name */);
P property = _data.SetProperty(environmentProperty.Name, ((IProperty)environmentProperty).EvaluatedValueEscaped, false /* NOT global property */, false /* may NOT be a reserved name */, true /* IS environment variable. */);
environmentPropertiesList.Add(property);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Build/Evaluation/IEvaluatorData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ List<ProjectItemElement> EvaluatedItemElements
/// <summary>
/// Sets a property which does not come from the Xml.
/// </summary>
P SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved);
P SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved, bool isEnvironmentVariable = false);

/// <summary>
/// Sets a property which comes from the Xml.
Expand Down
2 changes: 1 addition & 1 deletion src/Build/Evaluation/LazyItemEvaluator.EvaluatorData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ public P SetProperty(ProjectPropertyElement propertyElement, string evaluatedVal
return _wrappedData.SetProperty(propertyElement, evaluatedValueEscaped, predecessor);
}

public P SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved)
public P SetProperty(string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved, bool isEnvVar = false)
{
return _wrappedData.SetProperty(name, evaluatedValueEscaped, isGlobalProperty, mayBeReserved);
}
Expand Down
Loading