Skip to content

Commit c2d964b

Browse files
authored
Exclude default items from file-based apps in project dirs (#49999)
1 parent 1a8648b commit c2d964b

File tree

5 files changed

+101
-25
lines changed

5 files changed

+101
-25
lines changed

documentation/general/dotnet-run-file.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Additionally, the implicit project file has the following customizations:
4747

4848
- `FileBasedProgram` property is set to `true` and can be used by SDK targets to detect file-based apps.
4949

50+
- `DisableDefaultItemsInProjectFolder` property is set to `true` which results in `EnableDefaultItems=false` by default
51+
in case there is a project or solution in the same directory as the file-based app.
52+
This ensures that items from nested projects and artifacts are not included by the app.
53+
5054
## Grow up
5155

5256
When file-based programs reach an inflection point where build customizations in a project file are needed,
@@ -326,7 +330,7 @@ When disabled, [grow up](#grow-up) would generate projects in subdirectories
326330
similarly to [multi-entry-point scenarios](#multiple-entry-points) to preserve the program's behavior.
327331

328332
Including `.cs` files from nested folders which contain `.csproj`s might be unexpected,
329-
hence we could consider reporting an error in such situations.
333+
hence we could consider excluding items from nested project folders.
330334

331335
Similarly, we could report an error if there are many nested directories and files,
332336
so for example, if someone puts a C# file into `C:/sources` and executes `dotnet run C:/sources/file.cs` or opens that in the IDE,

src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,7 @@ public static void WriteProjectFile(
890890
{
891891
writer.WriteLine("""
892892
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
893+
<DisableDefaultItemsInProjectFolder>true</DisableDefaultItemsInProjectFolder>
893894
""");
894895
}
895896

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ Copyright (c) .NET Foundation. All rights reserved.
1313

1414
<!-- Don't get the default item globs by default when the flag is not set. -->
1515
<PropertyGroup Condition="'$(UsingNETSdkDefaults)' == 'true'">
16+
<!-- Given DisableDefaultItemsInProjectFolder=true, set EnableDefaultItems=false
17+
in case there is a solution/project in the current directory. -->
18+
<EnableDefaultItems Condition="'$(EnableDefaultItems)' == '' And
19+
'$(DisableDefaultItemsInProjectFolder)' == 'true' And
20+
('$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.sln&quot;).Length)' != '0' Or
21+
'$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.slnx&quot;).Length)' != '0' Or
22+
'$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.csproj&quot;).Length)' != '0')">false</EnableDefaultItems>
23+
1624
<EnableDefaultItems Condition=" '$(EnableDefaultItems)' == '' ">true</EnableDefaultItems>
1725
<EnableDefaultCompileItems Condition=" '$(EnableDefaultCompileItems)' == '' ">true</EnableDefaultCompileItems>
1826
<EnableDefaultEmbeddedResourceItems Condition=" '$(EnableDefaultEmbeddedResourceItems)' == '' ">true</EnableDefaultEmbeddedResourceItems>

test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,40 @@ class Util { public static string GetText() => "Hi from Util"; }
537537
.And.HaveStdOut(expectedOutput);
538538
}
539539

540+
/// <summary>
541+
/// Scripts in repo root should not include default items.
542+
/// Part of <see href="https://github.com/dotnet/sdk/issues/49826"/>.
543+
/// </summary>
544+
[Theory, CombinatorialData]
545+
public void DefaultItems_AlongsideProj([CombinatorialValues("sln", "slnx", "csproj", "vbproj", "shproj", "proj")] string ext)
546+
{
547+
bool considered = ext is "sln" or "slnx" or "csproj";
548+
549+
var testInstance = _testAssetsManager.CreateTestDirectory();
550+
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """
551+
Console.WriteLine();
552+
""");
553+
File.WriteAllText(Path.Join(testInstance.Path, "my.json"), "");
554+
File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), "");
555+
File.WriteAllText(Path.Join(testInstance.Path, "Util.cs"), "");
556+
File.WriteAllText(Path.Join(testInstance.Path, $"repo.{ext}"), "");
557+
558+
new DotnetCommand(Log, "project", "convert", "Program.cs")
559+
.WithWorkingDirectory(testInstance.Path)
560+
.Execute()
561+
.Should().Pass();
562+
563+
new DirectoryInfo(testInstance.Path)
564+
.EnumerateFileSystemInfos().Select(f => f.Name).Order()
565+
.Should().BeEquivalentTo(["Program", "Program.cs", "Resources.resx", "Util.cs", "my.json", $"repo.{ext}"]);
566+
567+
new DirectoryInfo(Path.Join(testInstance.Path, "Program"))
568+
.EnumerateFileSystemInfos().Select(f => f.Name).Order()
569+
.Should().BeEquivalentTo(considered
570+
? ["Program.csproj", "Program.cs"]
571+
: ["my.json", "Program.csproj", "Program.cs", "Resources.resx"]);
572+
}
573+
540574
/// <summary>
541575
/// When processing fails due to invalid directives, no conversion should be performed
542576
/// (e.g., the target directory should not be created).

test/dotnet.Tests/CommandTests/Run/RunFileTests.cs

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Cli.Run.Tests;
1515

1616
public sealed class RunFileTests(ITestOutputHelper log) : SdkTest(log)
1717
{
18-
private static readonly string s_program = """
18+
private static readonly string s_program = /* lang=C#-Test */ """
1919
if (args.Length > 0)
2020
{
2121
Console.WriteLine("echo args:" + string.Join(";", args));
@@ -29,15 +29,15 @@ public sealed class RunFileTests(ITestOutputHelper log) : SdkTest(log)
2929
#endif
3030
""";
3131

32-
private static readonly string s_programDependingOnUtil = """
32+
private static readonly string s_programDependingOnUtil = /* lang=C#-Test */ """
3333
if (args.Length > 0)
3434
{
3535
Console.WriteLine("echo args:" + string.Join(";", args));
3636
}
3737
Console.WriteLine("Hello, " + Util.GetMessage());
3838
""";
3939

40-
private static readonly string s_util = """
40+
private static readonly string s_util = /* lang=C#-Test */ """
4141
static class Util
4242
{
4343
public static string GetMessage()
@@ -47,6 +47,29 @@ public static string GetMessage()
4747
}
4848
""";
4949

50+
private static readonly string s_programReadingEmbeddedResource = /* lang=C#-Test */ """
51+
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
52+
var resourceName = assembly.GetManifestResourceNames().SingleOrDefault();
53+
54+
if (resourceName is null)
55+
{
56+
Console.WriteLine("Resource not found");
57+
return;
58+
}
59+
60+
using var stream = assembly.GetManifestResourceStream(resourceName)!;
61+
using var reader = new System.Resources.ResourceReader(stream);
62+
Console.WriteLine(reader.Cast<System.Collections.DictionaryEntry>().Single());
63+
""";
64+
65+
private static readonly string s_resx = """
66+
<root>
67+
<data name="MyString">
68+
<value>TestValue</value>
69+
</data>
70+
</root>
71+
""";
72+
5073
private static readonly string s_consoleProject = $"""
5174
<Project Sdk="Microsoft.NET.Sdk">
5275
<PropertyGroup>
@@ -1075,26 +1098,8 @@ public void BinaryLog_EvaluationData()
10751098
public void EmbeddedResource()
10761099
{
10771100
var testInstance = _testAssetsManager.CreateTestDirectory();
1078-
string code = """
1079-
using var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Program.Resources.resources");
1080-
1081-
if (stream is null)
1082-
{
1083-
Console.WriteLine("Resource not found");
1084-
return;
1085-
}
1086-
1087-
using var reader = new System.Resources.ResourceReader(stream);
1088-
Console.WriteLine(reader.Cast<System.Collections.DictionaryEntry>().Single());
1089-
""";
1090-
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code);
1091-
File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), """
1092-
<root>
1093-
<data name="MyString">
1094-
<value>TestValue</value>
1095-
</data>
1096-
</root>
1097-
""");
1101+
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource);
1102+
File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx);
10981103

10991104
new DotnetCommand(Log, "run", "Program.cs")
11001105
.WithWorkingDirectory(testInstance.Path)
@@ -1107,7 +1112,7 @@ public void EmbeddedResource()
11071112
// This behavior can be overridden.
11081113
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $"""
11091114
#:property EnableDefaultEmbeddedResourceItems=false
1110-
{code}
1115+
{s_programReadingEmbeddedResource}
11111116
""");
11121117

11131118
new DotnetCommand(Log, "run", "Program.cs")
@@ -1119,6 +1124,27 @@ Resource not found
11191124
""");
11201125
}
11211126

1127+
/// <summary>
1128+
/// Scripts in repo root should not include <c>.resx</c> files.
1129+
/// Part of <see href="https://github.com/dotnet/sdk/issues/49826"/>.
1130+
/// </summary>
1131+
[Theory, CombinatorialData]
1132+
public void EmbeddedResource_AlongsideProj([CombinatorialValues("sln", "slnx", "csproj", "vbproj", "shproj", "proj")] string ext)
1133+
{
1134+
bool considered = ext is "sln" or "slnx" or "csproj";
1135+
1136+
var testInstance = _testAssetsManager.CreateTestDirectory();
1137+
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource);
1138+
File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx);
1139+
File.WriteAllText(Path.Join(testInstance.Path, $"repo.{ext}"), "");
1140+
1141+
new DotnetCommand(Log, "run", "--file", "Program.cs")
1142+
.WithWorkingDirectory(testInstance.Path)
1143+
.Execute()
1144+
.Should().Pass()
1145+
.And.HaveStdOut(considered ? "Resource not found" : "[MyString, TestValue]");
1146+
}
1147+
11221148
[Fact]
11231149
public void NoRestore_01()
11241150
{
@@ -2674,6 +2700,7 @@ public void Api()
26742700
<Nullable>enable</Nullable>
26752701
<PublishAot>true</PublishAot>
26762702
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
2703+
<DisableDefaultItemsInProjectFolder>true</DisableDefaultItemsInProjectFolder>
26772704
<TargetFramework>net11.0</TargetFramework>
26782705
<LangVersion>preview</LangVersion>
26792706
<Features>$(Features);FileBasedProgram</Features>
@@ -2741,6 +2768,7 @@ public void Api_Diagnostic_01()
27412768
<Nullable>enable</Nullable>
27422769
<PublishAot>true</PublishAot>
27432770
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
2771+
<DisableDefaultItemsInProjectFolder>true</DisableDefaultItemsInProjectFolder>
27442772
<Features>$(Features);FileBasedProgram</Features>
27452773
</PropertyGroup>
27462774
@@ -2805,6 +2833,7 @@ public void Api_Diagnostic_02()
28052833
<Nullable>enable</Nullable>
28062834
<PublishAot>true</PublishAot>
28072835
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
2836+
<DisableDefaultItemsInProjectFolder>true</DisableDefaultItemsInProjectFolder>
28082837
<Features>$(Features);FileBasedProgram</Features>
28092838
</PropertyGroup>
28102839

0 commit comments

Comments
 (0)