Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit e08e58f

Browse files
mrwardmonojenkins
authored andcommitted
[Ide] Consider MSBuild item conditions in Solution pad
Creating an ASP.NET Core project when .NET Core 3.1 SDK was installed would result in .json files being displayed twice in the Solution pad. .NET Core 3.1 SDK defines .json files twice. <Content Include="**\*.json" ... Condition="'$(ExcludeConfigFilesFromBuildOutput)'!='true'" /> <Content Include="**\*.json" ... Condition="'$(ExcludeConfigFilesFromBuildOutput)'=='true'" /> Older .NET Core SDKs did not define the Content items more than once. The Condition was not considered when showing files in the Solution pad. To support conditional files the Solution pad asks the project for its visible files. The project uses the MSBuildEvaluationContext to evaluate the condition to see if the file is visible or not. Note that conditions on parent ItemGroups are currently not taken into account. Also that visible files are not updated if the active config is changed. Fixes VSTS #1005277 Create ASP.NET Core project, open Properties folder, there are two launchSettings.json files.
1 parent bb0a80f commit e08e58f

File tree

10 files changed

+391
-5
lines changed

10 files changed

+391
-5
lines changed

main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
using MonoDevelop.Projects;
3939
using System.Threading.Tasks;
4040
using MonoDevelop.Projects.MSBuild;
41+
using MonoDevelop.Projects.MSBuild.Conditions;
4142
using System.Xml;
4243
using MonoDevelop.Core.Instrumentation;
4344
using MonoDevelop.Core.Assemblies;
@@ -1216,6 +1217,36 @@ public bool IsFileInProject (string fileName)
12161217
return files.GetFile (fileName) != null;
12171218
}
12181219

1220+
/// <summary>
1221+
/// Return non-hidden files based on the configuration.
1222+
/// </summary>
1223+
/// <param name="configuration">Configuration.</param>
1224+
/// <returns>Files that should be displayed in the Solution window for a project.</returns>
1225+
public IEnumerable<ProjectFile> GetVisibleFiles (ConfigurationSelector configuration)
1226+
{
1227+
MSBuildEvaluationContext ctx = null;
1228+
1229+
foreach (ProjectFile file in Files) {
1230+
if (!file.Visible || file.IsHidden) {
1231+
continue;
1232+
} else if (string.IsNullOrEmpty (file.Condition)) {
1233+
yield return file;
1234+
continue;
1235+
}
1236+
1237+
if (ctx == null) {
1238+
ctx = new MSBuildEvaluationContext ();
1239+
ctx.InitEvaluation (MSBuildProject);
1240+
var config = (ProjectConfiguration)GetConfiguration (configuration);
1241+
foreach (var prop in config.Properties.GetProperties ())
1242+
ctx.SetPropertyValue (prop.Name, prop.Value);
1243+
}
1244+
1245+
if (ConditionParser.ParseAndEvaluate (file.Condition, ctx))
1246+
yield return file;
1247+
}
1248+
}
1249+
12191250
/// <summary>
12201251
/// Gets a list of build actions supported by this project
12211252
/// </summary>

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,9 @@ void GetFolderContent (Project project, string folder, out List<ProjectFile> fil
8484
files = new List<ProjectFile> ();
8585
folders = new List<string> ();
8686

87-
foreach (ProjectFile file in project.Files)
88-
{
87+
foreach (ProjectFile file in project.GetVisibleFiles (IdeApp.Workspace.ActiveConfiguration)) {
8988
string dir;
9089

91-
if (!file.Visible || file.Flags.HasFlag (ProjectItemFlags.Hidden))
92-
continue;
93-
9490
if (file.Subtype != Subtype.Directory) {
9591
// If file depends on something other than a directory, continue
9692
if ((file.DependsOnFile != null && file.DependsOnFile.Subtype != Subtype.Directory) || FileNestingService.HasParent (file))
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//
2+
// ProjectNodeBuilderTests.cs
3+
//
4+
// Author:
5+
// Matt Ward <[email protected]>
6+
//
7+
// Copyright (c) 2019 Microsoft Corporation
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System.Linq;
28+
using System.Threading.Tasks;
29+
using MonoDevelop.Core;
30+
using MonoDevelop.Ide.Gui.Pads.ProjectPad;
31+
using MonoDevelop.Projects;
32+
using NUnit.Framework;
33+
using UnitTests;
34+
35+
namespace MonoDevelop.Ide.Projects
36+
{
37+
[TestFixture]
38+
[RequireService (typeof (RootWorkspace))]
39+
class ProjectNodeBuilderTests : IdeTestBase
40+
{
41+
[Test]
42+
public async Task ConditionalFiles ()
43+
{
44+
FilePath solutionFile = Util.GetSampleProject ("ConditionalFiles", "ConditionalFiles.sln");
45+
46+
using (var solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFile)) {
47+
var p = solution.GetAllProjects ().OfType<DotNetProject> ().Single ();
48+
49+
// Debug configuration.
50+
IdeApp.Workspace.ActiveConfigurationId = "Debug";
51+
52+
var treeBuilder = new TestTreeBuilder ();
53+
treeBuilder.ParentDataItem [typeof (Project)] = p;
54+
55+
var nodeBuilder = new ProjectNodeBuilder ();
56+
nodeBuilder.BuildChildNodes (treeBuilder, p);
57+
58+
var debugFiles = treeBuilder.ChildNodes.OfType<ProjectFile> ().ToList ();
59+
var debugFileNames = debugFiles.Select (f => f.FilePath.FileName).ToList ();
60+
Assert.That (debugFileNames, Has.Member ("MyClass.cs"));
61+
Assert.That (debugFileNames, Has.Member ("MyClass-Debug.cs"));
62+
Assert.That (debugFileNames, Has.No.Member ("MyClass-Release.cs"));
63+
Assert.AreEqual (2, debugFiles.Count);
64+
65+
// Release configuration.
66+
IdeApp.Workspace.ActiveConfigurationId = "Release";
67+
68+
treeBuilder.ChildNodes.Clear ();
69+
nodeBuilder.BuildChildNodes (treeBuilder, p);
70+
var releaseFiles = treeBuilder.ChildNodes.OfType<ProjectFile> ().ToList ();
71+
var releaseFileNames = releaseFiles.Select (f => f.FilePath.FileName).ToList ();
72+
Assert.That (releaseFileNames, Has.Member ("MyClass.cs"));
73+
Assert.That (releaseFileNames, Has.Member ("MyClass-Release.cs"));
74+
Assert.That (releaseFileNames, Has.No.Member ("MyClass-Debug.cs"));
75+
Assert.AreEqual (2, releaseFiles.Count);
76+
}
77+
}
78+
}
79+
80+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
//
2+
// TestTreeBuilder.cs
3+
//
4+
// Author:
5+
// Matt Ward <[email protected]>
6+
//
7+
// Copyright (c) 2019 Microsoft Corporation
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System;
28+
using System.Collections;
29+
using System.Collections.Generic;
30+
using MonoDevelop.Ide.Gui.Components;
31+
32+
namespace MonoDevelop.Ide.Projects
33+
{
34+
class TestTreeBuilder : ITreeBuilder
35+
{
36+
public object DataItem { get; set; }
37+
public string NodeName { get; set; }
38+
public bool Selected { get; set; }
39+
public bool Expanded { get; set; }
40+
public ITreeOptions Options { get; }
41+
public TypeNodeBuilder TypeNodeBuilder { get; }
42+
public NodePosition CurrentPosition { get; }
43+
public bool Filled { get; }
44+
45+
public List<object> ChildNodes = new List<object> ();
46+
47+
public void AddChild (object dataObject)
48+
{
49+
ChildNodes.Add (dataObject);
50+
}
51+
52+
public void AddChild (object dataObject, bool moveToChild)
53+
{
54+
ChildNodes.Add (dataObject);
55+
}
56+
57+
public void AddChildren (IEnumerable dataObjects)
58+
{
59+
foreach (object dataObject in dataObjects) {
60+
ChildNodes.Add (dataObject);
61+
}
62+
}
63+
64+
public ITreeNavigator Clone ()
65+
{
66+
throw new NotImplementedException ();
67+
}
68+
69+
public void ExpandToNode ()
70+
{
71+
}
72+
73+
public bool FindChild (object dataObject)
74+
{
75+
throw new NotImplementedException ();
76+
}
77+
78+
public bool FindChild (object dataObject, bool recursive)
79+
{
80+
throw new NotImplementedException ();
81+
}
82+
83+
public Dictionary<Type, object> ParentDataItem = new Dictionary<Type, object> ();
84+
85+
public object GetParentDataItem (Type type, bool includeCurrent)
86+
{
87+
if (ParentDataItem.TryGetValue (type, out object parent)) {
88+
return parent;
89+
}
90+
91+
return null;
92+
}
93+
94+
public T GetParentDataItem<T> (bool includeCurrent)
95+
{
96+
throw new NotImplementedException ();
97+
}
98+
99+
public bool HasChild (string name, Type dataType)
100+
{
101+
throw new NotImplementedException ();
102+
}
103+
104+
public bool HasChildren ()
105+
{
106+
throw new NotImplementedException ();
107+
}
108+
109+
public bool MoveNext ()
110+
{
111+
throw new NotImplementedException ();
112+
}
113+
114+
public bool MoveToChild (string name, Type dataType)
115+
{
116+
throw new NotImplementedException ();
117+
}
118+
119+
public bool MoveToFirstChild ()
120+
{
121+
throw new NotImplementedException ();
122+
}
123+
124+
public bool MoveToNextObject ()
125+
{
126+
throw new NotImplementedException ();
127+
}
128+
129+
public bool MoveToObject (object dataObject)
130+
{
131+
throw new NotImplementedException ();
132+
}
133+
134+
public bool MoveToParent ()
135+
{
136+
throw new NotImplementedException ();
137+
}
138+
139+
public bool MoveToParent (Type type)
140+
{
141+
throw new NotImplementedException ();
142+
}
143+
144+
public bool MoveToPosition (NodePosition position)
145+
{
146+
throw new NotImplementedException ();
147+
}
148+
149+
public bool MoveToRoot ()
150+
{
151+
throw new NotImplementedException ();
152+
}
153+
154+
public void Remove ()
155+
{
156+
}
157+
158+
public void Remove (bool moveToParent)
159+
{
160+
}
161+
162+
public void RestoreState (NodeState state)
163+
{
164+
}
165+
166+
public NodeState SaveState ()
167+
{
168+
throw new NotImplementedException ();
169+
}
170+
171+
public void ScrollToNode ()
172+
{
173+
}
174+
175+
public void Update ()
176+
{
177+
}
178+
179+
public void UpdateAll ()
180+
{
181+
}
182+
183+
public void UpdateChildren ()
184+
{
185+
}
186+
}
187+
}

main/tests/Ide.Tests/MonoDevelop.Ide.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@
132132
<Compile Include="MonoDevelop.Ide.Gui\GLibLoggingTests.cs" />
133133
<Compile Include="MonoDevelop.Ide.Projects.OptionPanels\OutputOptionsPanelTests.cs" />
134134
<Compile Include="MonoDevelop.Components.AutoTest\AppResultTests.cs" />
135+
<Compile Include="MonoDevelop.Ide.Projects\ProjectNodeBuilderTests.cs" />
136+
<Compile Include="MonoDevelop.Ide.Projects\TestTreeBuilder.cs" />
135137
</ItemGroup>
136138
<ItemGroup>
137139
<ProjectReference Include="..\..\src\core\MonoDevelop.Ide\MonoDevelop.Ide.csproj">
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6+
<ProjectGuid>{200DD006-C60F-4A2F-BB12-E2496F88CA65}</ProjectGuid>
7+
<OutputType>Library</OutputType>
8+
<RootNamespace>ConditionalFiles</RootNamespace>
9+
<AssemblyName>ConditionalFiles</AssemblyName>
10+
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
11+
<MyClassEnabled>true</MyClassEnabled>
12+
</PropertyGroup>
13+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14+
<DebugSymbols>true</DebugSymbols>
15+
<DebugType>full</DebugType>
16+
<Optimize>false</Optimize>
17+
<OutputPath>bin\Debug</OutputPath>
18+
<DefineConstants>DEBUG;</DefineConstants>
19+
<ErrorReport>prompt</ErrorReport>
20+
<WarningLevel>4</WarningLevel>
21+
<ConsolePause>false</ConsolePause>
22+
<MyClassDebugEnabled>true</MyClassDebugEnabled>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<Optimize>true</Optimize>
26+
<OutputPath>bin\Release</OutputPath>
27+
<ErrorReport>prompt</ErrorReport>
28+
<WarningLevel>4</WarningLevel>
29+
<ConsolePause>false</ConsolePause>
30+
</PropertyGroup>
31+
<ItemGroup>
32+
<Reference Include="System" />
33+
</ItemGroup>
34+
<ItemGroup>
35+
<Compile Include="MyClass-Release.cs" Condition="'$(MyClassDebugEnabled)' != 'true'" />
36+
<Compile Include="MyClass-Debug.cs" Condition="'$(MyClassDebugEnabled)' == 'true'"/>
37+
<Compile Include="MyClass.cs" Condition="'$(MyClassEnabled)' == 'true'"/>
38+
</ItemGroup>
39+
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
40+
</Project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConditionalFiles", "ConditionalFiles.csproj", "{200DD006-C60F-4A2F-BB12-E2496F88CA65}"
5+
EndProject
6+
Global
7+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8+
Debug|Any CPU = Debug|Any CPU
9+
Release|Any CPU = Release|Any CPU
10+
EndGlobalSection
11+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
12+
{200DD006-C60F-4A2F-BB12-E2496F88CA65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13+
{200DD006-C60F-4A2F-BB12-E2496F88CA65}.Debug|Any CPU.Build.0 = Debug|Any CPU
14+
{200DD006-C60F-4A2F-BB12-E2496F88CA65}.Release|Any CPU.ActiveCfg = Release|Any CPU
15+
{200DD006-C60F-4A2F-BB12-E2496F88CA65}.Release|Any CPU.Build.0 = Release|Any CPU
16+
EndGlobalSection
17+
EndGlobal

0 commit comments

Comments
 (0)