Skip to content

Commit faed16d

Browse files
jjonesczCopilot
andauthored
Clarify some aspects of dotnet run - (#52132)
Co-authored-by: Copilot <[email protected]>
1 parent 7e68568 commit faed16d

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

documentation/general/dotnet-run-file.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ and working directory is not changed (e.g., `cd /x/ && dotnet run /y/file.cs` ru
104104
If a dash (`-`) is given instead of the target path (i.e., `dotnet run -`), the C# file to be executed is read from the standard input.
105105
In this case, the current working directory is not used to search for other files (launch profiles, other sources in case of multi-file apps);
106106
the compilation consists solely of the single file read from the standard input.
107+
However, the current working directory is still used as the working directory for building and executing the program.
108+
To reference projects relative to the current working directory (instead of relative to the temporary directory the file is isolated in),
109+
you can use something like `#:project $(MSBuildStartupDirectory)/relative/path`.
107110

108111
`dotnet path.cs` is a shortcut for `dotnet run --file path.cs` provided that `path.cs` is a valid [target path](#target-path) (`dotnet -` is currently not supported)
109112
and it is not a DLL path, built-in command, or a NuGet tool (e.g., `dotnet watch` invokes the `dotnet-watch` tool

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

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,19 +469,118 @@ public void Precedence_NuGetTool()
469469
[Fact]
470470
public void ReadFromStdin()
471471
{
472+
var testInstance = _testAssetsManager.CreateTestDirectory();
472473
new DotnetCommand(Log, "run", "-")
474+
.WithWorkingDirectory(testInstance.Path)
473475
.WithStandardInput("""
474476
Console.WriteLine("Hello from stdin");
475477
Console.WriteLine("Read: " + (Console.ReadLine() ?? "null"));
478+
Console.WriteLine("Working directory: " + Environment.CurrentDirectory);
476479
""")
477480
.Execute()
478481
.Should().Pass()
479-
.And.HaveStdOut("""
482+
.And.HaveStdOut($"""
480483
Hello from stdin
481484
Read: null
485+
Working directory: {testInstance.Path}
482486
""");
483487
}
484488

489+
/// <summary>
490+
/// <c>Directory.Build.props</c> doesn't have any effect on <c>dotnet run -</c>.
491+
/// </summary>
492+
[Fact]
493+
public void ReadFromStdin_BuildProps()
494+
{
495+
var testInstance = _testAssetsManager.CreateTestDirectory();
496+
497+
File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """
498+
<Project>
499+
<PropertyGroup>
500+
<ImplicitUsings>disable</ImplicitUsings>
501+
</PropertyGroup>
502+
</Project>
503+
""");
504+
505+
new DotnetCommand(Log, "run", "-")
506+
.WithWorkingDirectory(testInstance.Path)
507+
.WithStandardInput("""
508+
Console.WriteLine("Hello from stdin");
509+
""")
510+
.Execute()
511+
.Should().Pass()
512+
.And.HaveStdOut("Hello from stdin");
513+
514+
new DotnetCommand(Log, "run", "-")
515+
.WithWorkingDirectory(testInstance.Path)
516+
.WithStandardInput("""
517+
#:property ImplicitUsings=disable
518+
Console.WriteLine("Hello from stdin");
519+
""")
520+
.Execute()
521+
.Should().Fail()
522+
// error CS0103: The name 'Console' does not exist in the current context
523+
.And.HaveStdOutContaining("error CS0103");
524+
}
525+
526+
/// <summary>
527+
/// <c>Directory.Build.props</c> doesn't have any effect on <c>dotnet run -</c>.
528+
/// </summary>
529+
[Fact]
530+
public void ReadFromStdin_ProjectReference()
531+
{
532+
var testInstance = _testAssetsManager.CreateTestDirectory();
533+
534+
var libDir = Path.Join(testInstance.Path, "lib");
535+
Directory.CreateDirectory(libDir);
536+
537+
File.WriteAllText(Path.Join(libDir, "Lib.csproj"), $"""
538+
<Project Sdk="Microsoft.NET.Sdk">
539+
<PropertyGroup>
540+
<TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework>
541+
</PropertyGroup>
542+
</Project>
543+
""");
544+
545+
File.WriteAllText(Path.Join(libDir, "Lib.cs"), """
546+
namespace Lib;
547+
public class LibClass
548+
{
549+
public static string GetMessage() => "Hello from Lib";
550+
}
551+
""");
552+
553+
var appDir = Path.Join(testInstance.Path, "app");
554+
Directory.CreateDirectory(appDir);
555+
556+
new DotnetCommand(Log, "run", "-")
557+
.WithWorkingDirectory(appDir)
558+
.WithStandardInput($"""
559+
#:project $(MSBuildStartupDirectory)/../lib
560+
Console.WriteLine(Lib.LibClass.GetMessage());
561+
""")
562+
.Execute()
563+
.Should().Pass()
564+
.And.HaveStdOut("Hello from Lib");
565+
566+
// Relative paths are resolved from the isolated temp directory, hence they don't work.
567+
568+
var errorParts = DirectiveError("app.cs", 1, FileBasedProgramsResources.InvalidProjectDirective,
569+
string.Format(FileBasedProgramsResources.CouldNotFindProjectOrDirectory, "{}")).Split("{}");
570+
errorParts.Should().HaveCount(2);
571+
572+
new DotnetCommand(Log, "run", "-")
573+
.WithWorkingDirectory(appDir)
574+
.WithStandardInput($"""
575+
#:project ../lib
576+
Console.WriteLine(Lib.LibClass.GetMessage());
577+
""")
578+
.Execute()
579+
.Should().Fail()
580+
.And.HaveStdErrContaining(errorParts[0])
581+
.And.HaveStdErrContaining(errorParts[1]);
582+
}
583+
485584
[Fact]
486585
public void ReadFromStdin_NoBuild()
487586
{

0 commit comments

Comments
 (0)