Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 24 additions & 1 deletion src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using System.CommandLine;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Build.Evaluation;
Expand Down Expand Up @@ -71,7 +72,7 @@ public override int Execute()
{
using var stream = File.Open(projectFile, FileMode.Create, FileAccess.Write);
using var writer = new StreamWriter(stream, Encoding.UTF8);
VirtualProjectBuildingCommand.WriteProjectFile(writer, directives, isVirtualProject: false,
VirtualProjectBuildingCommand.WriteProjectFile(writer, UpdateDirectives(directives), isVirtualProject: false,
userSecretsId: DetermineUserSecretsId());
}

Expand Down Expand Up @@ -161,6 +162,28 @@ void CopyFile(string source, string target)
var actualValue = projectInstance.GetPropertyValue("UserSecretsId");
return implicitValue == actualValue ? actualValue : null;
}

ImmutableArray<CSharpDirective> UpdateDirectives(ImmutableArray<CSharpDirective> directives)
{
var result = ImmutableArray.CreateBuilder<CSharpDirective>(directives.Length);

foreach (var directive in directives)
{
// Fixup relative project reference paths (they need to be relative to the output directory instead of the source directory).
if (directive is CSharpDirective.Project project &&
!Path.IsPathFullyQualified(project.Name))
{
var modified = project.WithName(Path.GetRelativePath(relativeTo: targetDirectory, path: project.Name));
result.Add(modified);
}
else
{
result.Add(directive);
}
}

return result.DrainToImmutable();
}
}

private string DetermineOutputDirectory(string file)
Expand Down
11 changes: 10 additions & 1 deletion src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1885,7 +1885,11 @@ public sealed class Project(in ParseInfo info) : Named(info)
if (Directory.Exists(resolvedProjectPath))
{
var fullFilePath = MsbuildProject.GetProjectFileFromDirectory(resolvedProjectPath).FullName;
directiveText = Path.GetRelativePath(relativeTo: sourceDirectory, fullFilePath);

// Keep a relative path only if the original directive was a relative path.
directiveText = Path.IsPathFullyQualified(directiveText)
? fullFilePath
: Path.GetRelativePath(relativeTo: sourceDirectory, fullFilePath);
}
else if (!File.Exists(resolvedProjectPath))
{
Expand All @@ -1903,6 +1907,11 @@ public sealed class Project(in ParseInfo info) : Named(info)
};
}

public Project WithName(string name)
{
return new Project(Info) { Name = name };
}

public override string ToString() => $"#:project {Name}";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,125 @@ public void SameAsTemplate()
.And.StartWith("""<Project Sdk="Microsoft.NET.Sdk">""");
}

[Theory] // https://github.com/dotnet/sdk/issues/50832
[InlineData("File", "Lib", "../Lib", "Project", "../Lib/lib.csproj")]
[InlineData(".", "Lib", "./Lib", "Project", "../Lib/lib.csproj")]
[InlineData(".", "Lib", "Lib/../Lib", "Project", "../Lib/lib.csproj")]
[InlineData("File", "Lib", "../Lib", "File/Project", "../../Lib/lib.csproj")]
Copy link
Member

Choose a reason for hiding this comment

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

Consider also testing a case where the original path has redundant ..s in it, such as Lib/../Lib, I would expect such paths to get normalized (be treated as equivalent to just Lib).

Copy link
Member

Choose a reason for hiding this comment

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

Consider also testing both windows and unix path separators.

[InlineData("File", "Lib", "..\\Lib", "File/Project", "../../Lib/lib.csproj")]
public void ProjectReference_RelativePaths(string fileDir, string libraryDir, string reference, string outputDir, string convertedReference)
{
var testInstance = _testAssetsManager.CreateTestDirectory();

var libraryDirFullPath = Path.Join(testInstance.Path, libraryDir);
Directory.CreateDirectory(libraryDirFullPath);
File.WriteAllText(Path.Join(libraryDirFullPath, "lib.cs"), """
public static class C
{
public static void M()
{
System.Console.WriteLine("Hello from library");
}
}
""");
File.WriteAllText(Path.Join(libraryDirFullPath, "lib.csproj"), $"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework>
</PropertyGroup>
</Project>
""");

var fileDirFullPath = Path.Join(testInstance.Path, fileDir);
Directory.CreateDirectory(fileDirFullPath);
File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $"""
#:project {reference}
C.M();
""");

var expectedOutput = "Hello from library";

new DotnetCommand(Log, "run", "app.cs")
.WithWorkingDirectory(fileDirFullPath)
.Execute()
.Should().Pass()
.And.HaveStdOut(expectedOutput);

var outputDirFullPath = Path.Join(testInstance.Path, outputDir);
new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath)
.WithWorkingDirectory(fileDirFullPath)
.Execute()
.Should().Pass();

new DotnetCommand(Log, "run")
.WithWorkingDirectory(outputDirFullPath)
.Execute()
.Should().Pass()
.And.HaveStdOut(expectedOutput);

File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj"))
.Should().Contain($"""
<ProjectReference Include="{convertedReference.Replace('/', Path.DirectorySeparatorChar)}" />
""");
}

[Fact] // https://github.com/dotnet/sdk/issues/50832
public void ProjectReference_FullPath()
{
var testInstance = _testAssetsManager.CreateTestDirectory();

var libraryDirFullPath = Path.Join(testInstance.Path, "Lib");
Directory.CreateDirectory(libraryDirFullPath);
File.WriteAllText(Path.Join(libraryDirFullPath, "lib.cs"), """
public static class C
{
public static void M()
{
System.Console.WriteLine("Hello from library");
}
}
""");
File.WriteAllText(Path.Join(libraryDirFullPath, "lib.csproj"), $"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework>
</PropertyGroup>
</Project>
""");

var fileDirFullPath = Path.Join(testInstance.Path, "File");
Directory.CreateDirectory(fileDirFullPath);
File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $"""
#:project {libraryDirFullPath}
C.M();
""");

var expectedOutput = "Hello from library";

new DotnetCommand(Log, "run", "app.cs")
.WithWorkingDirectory(fileDirFullPath)
.Execute()
.Should().Pass()
.And.HaveStdOut(expectedOutput);

var outputDirFullPath = Path.Join(testInstance.Path, "File/Project");
new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath)
.WithWorkingDirectory(fileDirFullPath)
.Execute()
.Should().Pass();

new DotnetCommand(Log, "run")
.WithWorkingDirectory(outputDirFullPath)
.Execute()
.Should().Pass()
.And.HaveStdOut(expectedOutput);

File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj"))
.Should().Contain($"""
<ProjectReference Include="{Path.Join(libraryDirFullPath, "lib.csproj")}" />
""");
}

[Fact]
public void DirectoryAlreadyExists()
{
Expand Down