Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion documentation/general/dotnet-run-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,9 @@ We do not limit these directives to appear only in entry point files because it
- which also makes it possible to share it independently or symlink it to multiple script folders,
- and it's similar to `global using`s which users usually put into a single file but don't have to.

We disallow duplicate `#:` directives to allow us design some deduplication mechanism in the future.
We disallow duplicate `#:` directives (except `#:project` and `#:ref`) to allow us design some deduplication mechanism in the future.
Comment thread
jjonescz marked this conversation as resolved.
Outdated
Specifically, directives are considered duplicate if their type and name (case insensitive) are equal.
`#:project` and `#:ref` duplicates are allowed because MSBuild handles deduplication of project references naturally.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe clarify that multiple <ProjectReference> directives are allowed? The current wording says that indirectly, but it could be more explicit about it.

Later with deduplication, separate "self-contained" utilities could reference overlapping sets of packages
even if they end up in the same compilation.
For example, properties could be concatenated via `;`, more specific package versions could override less specific ones.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,19 @@ public static void FindLeadingDirectives(

if (CSharpDirective.Parse(context) is { } directive)
{
// If the directive is already present, report an error.
if (deduplicated.TryGetValue(directive, out var existingDirective))
// Duplicate #:project and #:ref directives are allowed (MSBuild handles deduplication).
if (directive is not (CSharpDirective.Project or CSharpDirective.Ref))
{
var typeAndName = $"#:{existingDirective.GetType().Name.ToLowerInvariant()} {existingDirective.Name}";
context.ReportError(directive.Info.Span, string.Format(FileBasedProgramsResources.DuplicateDirective, typeAndName));
}
else
{
deduplicated.Add(directive, directive);
// If the directive is already present, report an error.
if (deduplicated.TryGetValue(directive, out var existingDirective))
{
var typeAndName = $"#:{existingDirective.GetType().Name.ToLowerInvariant()} {existingDirective.Name}";
context.ReportError(directive.Info.Span, string.Format(FileBasedProgramsResources.DuplicateDirective, typeAndName));
}
else
{
deduplicated.Add(directive, directive);
}
}

builder?.Add(directive);
Comment thread
jjonescz marked this conversation as resolved.
Outdated
Expand Down
14 changes: 6 additions & 8 deletions test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3507,6 +3507,7 @@ public void ProjectReference_Duplicate(string? subdir)
</Project>
""");

// Duplicate #:project directives are allowed (MSBuild handles deduplication).
File.WriteAllText(filePath, """
#:project dir/
#:project dir/
Expand All @@ -3516,16 +3517,15 @@ public void ProjectReference_Duplicate(string? subdir)
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
.Should().Fail()
.And.HaveStdErrContaining(DirectiveError(filePath, 2, FileBasedProgramsResources.DuplicateDirective, "#:project dir/"));
.Should().Pass()
.And.HaveStdOut("Hello");

File.WriteAllText(filePath, """
#:project dir/
#:project dir/proj1.csproj
Console.WriteLine("Hello");
""");

// https://github.com/dotnet/sdk/issues/51139: we should detect the duplicate project reference
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
Expand All @@ -3538,7 +3538,6 @@ public void ProjectReference_Duplicate(string? subdir)
Console.WriteLine("Hello");
""");

// https://github.com/dotnet/sdk/issues/51139: we should detect the duplicate project reference
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
Expand Down Expand Up @@ -3805,6 +3804,7 @@ public static class Greeter
}
""");

// Duplicate #:ref directives are allowed (MSBuild handles deduplication).
File.WriteAllText(filePath, """
#:ref lib.cs
#:ref lib.cs
Expand All @@ -3814,16 +3814,15 @@ public static class Greeter
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
.Should().Fail()
.And.HaveStdErrContaining(DirectiveError(filePath, 2, FileBasedProgramsResources.DuplicateDirective, "#:ref lib.cs"));
.Should().Pass()
.And.HaveStdOut("Hello!");

File.WriteAllText(filePath, """
#:ref lib.cs
#:ref ./lib.cs
Console.WriteLine(MyLib.Greeter.Greet());
""");

// https://github.com/dotnet/sdk/issues/51139: we should detect the duplicate ref
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
Expand All @@ -3836,7 +3835,6 @@ public static class Greeter
Console.WriteLine(MyLib.Greeter.Greet());
""");

// https://github.com/dotnet/sdk/issues/51139: we should detect the duplicate ref
new DotnetCommand(Log, "run", relativeFilePath)
.WithWorkingDirectory(testInstance.Path)
.Execute()
Expand Down
Loading