diff --git a/documentation/general/dotnet-run-file.md b/documentation/general/dotnet-run-file.md index 9c9ed03ab167..dfcb07822795 100644 --- a/documentation/general/dotnet-run-file.md +++ b/documentation/general/dotnet-run-file.md @@ -236,18 +236,13 @@ The directives are processed as follows: where `{0}` is the directive's value and `{1}` is determined by its extension. The mapping can be customized by setting the MSBuild property `FileBasedProgramsItemMapping` which is by default set to `.cs=Compile;.resx=EmbeddedResource;.json=None;.razor=Content`. - (The mapping customization is currently gated under a feature flag that can be enabled by setting the MSBuild property `ExperimentalFileBasedProgramEnableItemMapping=true`.) It is an error if the value is empty. Relative paths are resolved relative to the file containing the directive. - This directive is currently gated under a feature flag that can be enabled by setting the MSBuild property `ExperimentalFileBasedProgramEnableIncludeDirective=true`. - - Each `#:exclude` is injected similarly to `#:include` but with `Remove="{0}"` instead of `Include="{0}"`. - This directive is currently gated under a feature flag that can be enabled by setting the MSBuild property `ExperimentalFileBasedProgramEnableExcludeDirective=true`. - - Other directive kinds result in an error, reserving them for future use. Directive values support MSBuild variables (like `$(..)`) normally as they are translated literally and left to MSBuild engine to process. diff --git a/src/Cli/Microsoft.DotNet.FileBasedPrograms/FileLevelDirectiveHelpers.cs b/src/Cli/Microsoft.DotNet.FileBasedPrograms/FileLevelDirectiveHelpers.cs index bee6360deaaf..65fd17f44bdb 100644 --- a/src/Cli/Microsoft.DotNet.FileBasedPrograms/FileLevelDirectiveHelpers.cs +++ b/src/Cli/Microsoft.DotNet.FileBasedPrograms/FileLevelDirectiveHelpers.cs @@ -693,11 +693,7 @@ public enum IncludeOrExcludeKind /// public sealed class IncludeOrExclude(in ParseInfo info) : Named(info) { - public const string ExperimentalFileBasedProgramEnableIncludeDirective = nameof(ExperimentalFileBasedProgramEnableIncludeDirective); - public const string ExperimentalFileBasedProgramEnableExcludeDirective = nameof(ExperimentalFileBasedProgramEnableExcludeDirective); public const string ExperimentalFileBasedProgramEnableTransitiveDirectives = nameof(ExperimentalFileBasedProgramEnableTransitiveDirectives); - public const string ExperimentalFileBasedProgramEnableItemMapping = nameof(ExperimentalFileBasedProgramEnableItemMapping); - public const string MappingPropertyName = "FileBasedProgramsItemMapping"; public static string DefaultMappingString => ".cs=Compile;.resx=EmbeddedResource;.json=None;.razor=Content"; diff --git a/src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt b/src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt index bbf3d44bc01b..d3a08eaa3a3e 100644 --- a/src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt +++ b/src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt @@ -1,6 +1,3 @@ -const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableExcludeDirective = "ExperimentalFileBasedProgramEnableExcludeDirective" -> string! -const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective = "ExperimentalFileBasedProgramEnableIncludeDirective" -> string! -const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableItemMapping = "ExperimentalFileBasedProgramEnableItemMapping" -> string! const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives = "ExperimentalFileBasedProgramEnableTransitiveDirectives" -> string! const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.IncludeOrExclude.MappingPropertyName = "FileBasedProgramsItemMapping" -> string! const Microsoft.DotNet.FileBasedPrograms.CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective = "ExperimentalFileBasedProgramEnableRefDirective" -> string! diff --git a/src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs b/src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs index 78ffdbcbf176..50f18abe9265 100644 --- a/src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs +++ b/src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs @@ -252,12 +252,10 @@ private ImmutableArray EvaluateDirectives( internal ImmutableArray<(string Extension, string ItemType)> GetItemMapping(ProjectInstance project, ErrorReporter reportError) { - return MSBuildUtilities.ConvertStringToBool(project.GetPropertyValue(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableItemMapping)) - ? CSharpDirective.IncludeOrExclude.ParseMapping( - project.GetPropertyValue(CSharpDirective.IncludeOrExclude.MappingPropertyName), - EntryPointSourceFile, - reportError) - : CSharpDirective.IncludeOrExclude.DefaultMapping; + return CSharpDirective.IncludeOrExclude.ParseMapping( + project.GetPropertyValue(CSharpDirective.IncludeOrExclude.MappingPropertyName), + EntryPointSourceFile, + reportError); } public static ProjectInstance CreateProjectInstance( @@ -439,8 +437,6 @@ private void CheckDirectives( ErrorReporter reportError) { bool? refEnabled = null; - bool? includeEnabled = null; - bool? excludeEnabled = null; bool? transitiveEnabled = null; foreach (var directive in directives) @@ -450,19 +446,6 @@ private void CheckDirectives( CheckFlagEnabled(ref refEnabled, CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective, directive); } - if (directive is CSharpDirective.IncludeOrExclude includeOrExcludeDirective) - { - if (includeOrExcludeDirective.Kind == CSharpDirective.IncludeOrExcludeKind.Include) - { - CheckFlagEnabled(ref includeEnabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective, directive); - } - else - { - Debug.Assert(includeOrExcludeDirective.Kind == CSharpDirective.IncludeOrExcludeKind.Exclude); - CheckFlagEnabled(ref excludeEnabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableExcludeDirective, directive); - } - } - if (directive.Info.SourceFile.Path != EntryPointSourceFile.Path) { CheckFlagEnabled(ref transitiveEnabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives, directive); diff --git a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs index c0e03300da4e..b06c4aae98f6 100644 --- a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs +++ b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs @@ -448,8 +448,7 @@ public void RefDirective_DuplicateFolderName_ViaInclude() <{CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective}>true - true - true + <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true """); @@ -1689,15 +1688,6 @@ public void Directives_IncludeExclude() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - true - - - """); - VerifyConversion( baseDirectory: testInstance.Path, evaluateDirectives: true, @@ -1742,8 +1732,6 @@ public void Directives_IncludeExclude_FilesCopied() { var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ - #:property ExperimentalFileBasedProgramEnableIncludeDirective=true - #:property ExperimentalFileBasedProgramEnableExcludeDirective=true #:include **/*.cs #:include *.json #:exclude my.json @@ -2632,7 +2620,6 @@ public void DeleteSource_WithIncludeDirective() // Create entry point file with #:include directive File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ - #:property ExperimentalFileBasedProgramEnableIncludeDirective=true #:include Util.cs Console.WriteLine("Test"); """); @@ -2662,7 +2649,6 @@ public void DeleteSource_WithIncludeDirective_NotDeleted() // Create entry point file with #:include directive File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ - #:property ExperimentalFileBasedProgramEnableIncludeDirective=true #:include Util.cs Console.WriteLine("Test"); """); @@ -2693,7 +2679,6 @@ public void DeleteSource_WithIncludeDirective_MultipleFiles() // Create entry point file with multiple #:include directives File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ - #:property ExperimentalFileBasedProgramEnableIncludeDirective=true #:include Util.cs #:include Helper.cs #:include config.json @@ -2730,9 +2715,8 @@ public void DeleteSource_WithIncludeDirective_Transitive() var testInstance = _testAssetsManager.CreateTestDirectory(); // Create entry point file with #:include directive - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ - #:property ExperimentalFileBasedProgramEnableIncludeDirective=true - #:property ExperimentalFileBasedProgramEnableTransitiveDirectives=true + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" + #:property {CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}=true #:include Util.cs Console.WriteLine("Test"); """); diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index 44356531c095..401dae81a289 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -995,10 +995,10 @@ public static class B public static string M() => "String from Util"; } """); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ + File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), $""" - true + <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true @@ -1727,14 +1727,6 @@ public void BinaryLog_EvaluationData_MultiFile() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" #!/usr/bin/env dotnet @@ -1900,15 +1892,6 @@ public void MissingShebangWarning() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - true - - - """); - // Single-file program without shebang should NOT produce CA2266 // (the warning only fires when there are multiple files via #:include). File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ @@ -3667,7 +3650,6 @@ public void RefDirective_WithInclude() <{CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective}>true - <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective}>true """); @@ -3847,7 +3829,6 @@ public void RefDirective_DuplicateRefFromIncludedFiles() <{CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective}>true - <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective}>true <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true @@ -3906,7 +3887,6 @@ public void RefDirective_DuplicateRefFromIncludedFiles_Subdirectories() <{CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective}>true - <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective}>true <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true @@ -3972,7 +3952,6 @@ public void RefDirective_IncludeAndRefSameFile() <{CSharpDirective.Ref.ExperimentalFileBasedProgramEnableRefDirective}>true - <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective}>true <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true @@ -4009,15 +3988,6 @@ public void IncludeDirective( { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - true - - - """); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" #!/usr/bin/env dotnet #:include {includePattern} @@ -4040,14 +4010,6 @@ public void IncludeDirective_WorkingDirectory() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - var srcDir = Path.Join(testInstance.Path, "src"); Directory.CreateDirectory(srcDir); @@ -4083,7 +4045,6 @@ static class B { public static string M() => "Hello from B"; } new DirectoryInfo(testInstance.Path) .Should().HaveSubtree(""" - Directory.Build.props src/ src/A.cs src/A/ @@ -4127,11 +4088,10 @@ public void IncludeDirective_Transitive() Directory.CreateDirectory(Path.Join(testInstance.Path, "dir1/dir2")); Directory.CreateDirectory(Path.Join(testInstance.Path, "dir3")); - File.WriteAllText(Path.Join(testInstance.Path, "dir1/Directory.Build.props"), """ + File.WriteAllText(Path.Join(testInstance.Path, "dir1/Directory.Build.props"), $""" - true - true + <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true """); @@ -4245,14 +4205,6 @@ public void IncludeDirective_FileNotFound() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - var programPath = Path.Join(testInstance.Path, "A.cs"); File.WriteAllText(programPath, """ @@ -4278,14 +4230,6 @@ public void IncludeDirective_UpToDate_Glob(string glob) { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - var programPath = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(programPath, $""" #!/usr/bin/env dotnet @@ -4345,14 +4289,6 @@ public void IncludeDirective_UpToDate_NoGlob() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - var programPath = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(programPath, $""" #!/usr/bin/env dotnet @@ -4410,11 +4346,10 @@ public void IncludeDirective_UpToDate_ProjectReference() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ + File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), $""" - true - true + <{CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives}>true """); @@ -4478,51 +4413,30 @@ class UtilClass Build(testInstance, BuildLevel.All, expectedOutput: expectedOutput, workDir: appDir); } + /// + /// Transitive directives (directives in non-entry-point files) are gated behind a feature flag. + /// [Fact] public void IncludeDirective_FeatureFlags() { var testInstance = _testAssetsManager.CreateTestDirectory(); - var programPath = Path.Join(testInstance.Path, "Program.cs"); - File.WriteAllText(programPath, $""" + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ #!/usr/bin/env dotnet - #:include *.cs - {s_programDependingOnUtil} + #:include Util.cs + Console.WriteLine(Util.M()); """); var utilPath = Path.Join(testInstance.Path, "Util.cs"); - File.WriteAllText(utilPath, $""" - #:exclude Other.cs - {s_util} + File.WriteAllText(utilPath, """ + #:property DefineConstants=MY_CONST + static class Util { public static string M() => "Hello from Util"; } """); new DotnetCommand(Log, "run", "Program.cs") .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() - .And.HaveStdErr($""" - {DirectiveError(programPath, 2, Resources.ExperimentalFeatureDisabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective)} - - {CliCommandStrings.RunCommandException} - """); - - new DotnetCommand(Log, "run", "Program.cs") - .WithWorkingDirectory(testInstance.Path) - .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective, "true") - .Execute() - .Should().Fail() - .And.HaveStdErr($""" - {DirectiveError(utilPath, 1, Resources.ExperimentalFeatureDisabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableExcludeDirective)} - - {CliCommandStrings.RunCommandException} - """); - - new DotnetCommand(Log, "run", "Program.cs") - .WithWorkingDirectory(testInstance.Path) - .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective, "true") - .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableExcludeDirective, "true") - .Execute() - .Should().Fail() .And.HaveStdErr($""" {DirectiveError(utilPath, 1, Resources.ExperimentalFeatureDisabled, CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives)} @@ -4531,12 +4445,10 @@ public void IncludeDirective_FeatureFlags() new DotnetCommand(Log, "run", "Program.cs") .WithWorkingDirectory(testInstance.Path) - .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableIncludeDirective, "true") - .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableExcludeDirective, "true") .WithEnvironmentVariable(CSharpDirective.IncludeOrExclude.ExperimentalFileBasedProgramEnableTransitiveDirectives, "true") .Execute() .Should().Pass() - .And.HaveStdOut("Hello, String from Util"); + .And.HaveStdOut("Hello from Util"); } [Fact] @@ -4544,15 +4456,6 @@ public void IncludeDirective_CustomMapping() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - true - - - """); - var programPath = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(programPath, $""" #!/usr/bin/env dotnet @@ -4607,15 +4510,6 @@ public void IncludeDirective_CustomMapping_ParseErrors() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - true - - - """); - var programPath = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(programPath, """ #:property FileBasedProgramsItemMapping=x @@ -6777,14 +6671,6 @@ public void Api_Evaluation() { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ - - - true - - - """); - var programPath = Path.Join(testInstance.Path, "A.cs"); File.WriteAllText(programPath, """ #:property P1=cs