Skip to content

Commit

Permalink
Fix bug around unix paths (#156)
Browse files Browse the repository at this point in the history
* Fix bug around unix paths

Unix paths were accidentally being treated as options when exporting the
RSP file. This lead to the RSP file being invalid as it had paths that
weren't available the local machine (or even valid paths when crossing
between operating systems).

The fix was fairly simple but testing it caused a decent amount of churn
in the repository. Had to add APIs to make it possible to build up a
compiler log in memory instead of off of disk.

* more

* more

* more
  • Loading branch information
jaredpar authored Sep 12, 2024
1 parent 6cbd280 commit 0e1ff2c
Show file tree
Hide file tree
Showing 27 changed files with 500 additions and 99 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/artifacts/bin/Basic.CompilerLog/debug_net8.0/Basic.CompilerLog.dll",
"args": ["print", ".\\msbuild.binlog" ],
"cwd": "e:\\temp\\console",
"args": ["export", "C:\\Users\\jaredpar\\Downloads\\Build1.complog"],
"cwd": "C:\\Users\\jaredpar\\Downloads",
// "cwd": "${workspaceFolder}/src/Basic.CompilerLog",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"jaredpar",
"msbuild",
"Mvid",
"NETCOREAPP",
"NET",
"netstandard",
"ondisk",
"Relogger",
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/BasicAnalyzerHostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@



#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif

Expand All @@ -27,7 +27,7 @@ public void Supported()
{
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.OnDisk));
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.None));
#if NETCOREAPP
#if NET
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.InMemory));
#else
Assert.False(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.InMemory));
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System.IO.Pipelines;
using System.Linq;
using System.Runtime.InteropServices;
#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif
using System.Text;
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/BinaryLogUtilTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using System.Threading.Tasks;
using Xunit;

#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif

Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/CommonUtilTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
using Basic.CompilerLog.Util;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif

namespace Basic.CompilerLog.UnitTests;

public sealed class CommonUtilTests
{
#if NETCOREAPP
#if NET

[Fact]
public void GetAssemlbyLoadContext()
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/CompilerLogBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void AddMissingFile()

var compilerCall = BinaryLogUtil.ReadAllCompilerCalls(binlogStream).First(x => x.IsCSharp);
compilerCall = compilerCall.ChangeArguments(["/sourcelink:does-not-exist.txt"]);
Assert.Throws<Exception>(() => builder.Add(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall)));
Assert.Throws<Exception>(() => builder.AddFromDisk(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall)));
}

[Fact]
Expand All @@ -44,7 +44,7 @@ public void AddWithMissingCompilerFilePath()
isCSharp: true,
new Lazy<IReadOnlyCollection<string>>(() => args),
null);
builder.Add(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall));
builder.AddFromDisk(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall));
}

[Fact]
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/CompilerLogReaderExTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System.IO.Pipelines;
using System.Linq;
using System.Runtime.InteropServices;
#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif
using System.Text;
Expand Down Expand Up @@ -51,7 +51,7 @@ private CompilerLogReader ConvertConsole(Func<CompilerCall, CompilerCall> func,
var diagnostics = new List<string>();
var stream = new MemoryStream();
var builder = new CompilerLogBuilder(stream, diagnostics);
builder.Add(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall));
builder.AddFromDisk(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall));
builder.Close();
stream.Position = 0;
return CompilerLogReader.Create(stream, basicAnalyzerKind, State, leaveOpen: false);
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System.IO.Pipelines;
using System.Linq;
using System.Runtime.InteropServices;
#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif
using System.Text;
Expand Down Expand Up @@ -249,7 +249,7 @@ public void AnalyzerLoadDispose(BasicAnalyzerKind kind)
Assert.True(data.BasicAnalyzerHost.IsDisposed);
}

#if NETCOREAPP
#if NET

/// <summary>
/// Ensure that diagnostics are raised when the analyzer can't properly load all of the types
Expand Down
35 changes: 34 additions & 1 deletion src/Basic.CompilerLog.UnitTests/ExportUtilTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private void TestExport(string compilerLogFilePath, int? expectedCount, bool inc
internal static void TestExport(ITestOutputHelper testOutputHelper, string compilerLogFilePath, int? expectedCount, bool includeAnalyzers = true, Action<string>? verifyExportCallback = null, bool runBuild = true)
{
using var reader = CompilerLogReader.Create(compilerLogFilePath);
#if NETCOREAPP
#if NET
var sdkDirs = SdkUtil.GetSdkDirectories();
#else
var sdkDirs = SdkUtil.GetSdkDirectories(@"c:\Program Files\dotnet");
Expand Down Expand Up @@ -206,6 +206,39 @@ public void ExportAllBadPath()
Assert.Throws<ArgumentException>(() => exportUtil.ExportAll(@"relative/path", SdkUtil.GetSdkDirectories()));
}

/// <summary>
/// Make sure that unix paths aren't confused as options when exporting the RSP file
/// </summary>
[Fact]
public void ExportUnixPaths()
{
string[] args =
[
"/workspace/runtime/test.cs",
"/debug:full",
];
var reader = CreateReader(builder =>
{
var compilerCall = new CompilerCall(
compilerFilePath: "app",
projectFilePath: "/src/app.csproj",
CompilerCallKind.Regular,
targetFramework: "net5.0",
isCSharp: true,
arguments: new (() => args));

builder.AddContent(compilerCall, ["Console.WriteLine()"]);
});

var exportUtil = new ExportUtil(reader, includeAnalyzers: false);
var dir = Root.NewDirectory("export-test");
exportUtil.Export(reader.ReadCompilerCall(0), dir, []);

var lines = File.ReadAllLines(path: Path.Combine(dir, "build.rsp"));
Assert.DoesNotContain(args[0], lines);
Assert.Contains(args[1], lines);
}

private void EmbedLineCore(string contentFilePath)
{
RunDotNet($"new console --name example --output .");
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/ExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void AddRange()
Assert.Equal([42, 13], list);
}

#if NETCOREAPP
#if NET

[Fact]
public void GetFailureString()
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/FilterOptionSetTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NETCOREAPP
#if NET
using Xunit;

namespace Basic.CompilerLog.UnitTests;
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/LogReaderState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Xunit;
using Xunit.Abstractions;

#if NETCOREAPP
#if NET
using System.Runtime.Loader;
#endif

Expand Down Expand Up @@ -38,7 +38,7 @@ public void DisposeDirectoryLocked()
fileStream.Dispose();
}

#if NETCOREAPP
#if NET
[Fact]
public void CustomAssemblyLoadContext()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/ProgramTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NETCOREAPP
#if NET
using Basic.CompilerLog.Util;
using Basic.CompilerLog.Util.Serialize;
using MessagePack;
Expand Down
125 changes: 125 additions & 0 deletions src/Basic.CompilerLog.UnitTests/StringStreamTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Text;
using Basic.CompilerLog.Util;
using DotUtils.StreamUtils;
using Xunit;
using Xunit.Abstractions;

namespace Basic.CompilerLog.UnitTests;

public class StringStreamTests
{
private static readonly Encoding[] Encodings =
[
Encoding.UTF8,
Encoding.UTF32
];

private void RoundTripByteByByte(string input)
{
foreach (var encoding in Encodings)
{
using var inputStream = new StringStream(input, encoding);
using var memoryStream = new MemoryStream();
while (inputStream.ReadByte() is int b && b != -1)
{
memoryStream.WriteByte((byte)b);
}

memoryStream.Position = 0;
var actual = encoding.GetString(memoryStream.ToArray());
Assert.Equal(input, actual);
}
}

private void RoundTripCopy(string input)
{
foreach (var encoding in Encodings)
{
using var inputStream = new StringStream(input, encoding);
using var memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);

memoryStream.Position = 0;
var actual = encoding.GetString(memoryStream.ToArray());
Assert.Equal(input, actual);
}
}

private void RoundTripReset(string input)
{
foreach (var encoding in Encodings)
{
using var inputStream = new StringStream(input, encoding);
using var memoryStream = new MemoryStream();
inputStream.Position = 0;
memoryStream.Position = 0;
inputStream.CopyTo(memoryStream);

memoryStream.Position = 0;
var actual = encoding.GetString(memoryStream.ToArray());
Assert.Equal(input, actual);
}
}

private void RoundTripAll(string input)
{
RoundTripByteByByte(input);
RoundTripCopy(input);
RoundTripReset(input);
}

[Fact]
public void Behaviors()
{
var stream = new StringStream("hello", Encoding.UTF8);
Assert.True(stream.CanRead);
Assert.False(stream.CanWrite);
Assert.False(stream.CanSeek);
Assert.Throws<NotSupportedException>(() => stream.Seek(0, SeekOrigin.Begin));
Assert.Throws<NotSupportedException>(() => stream.Write(Array.Empty<byte>(), 0, 0));
Assert.Throws<NotSupportedException>(() => stream.SetLength(1));
stream.Flush(); // no-op
}

[Fact]
public void PositionReset()
{
var stream = new StringStream("hello", Encoding.UTF8);
var bytes1 = stream.ReadToEnd();
stream.Position = 0;
var bytes2 = stream.ReadToEnd();
Assert.Equal(bytes1, bytes2);
}

[Fact]
public void PositionSetToMiddle()
{
var stream = new StringStream("hello", Encoding.UTF8);
var bytes1 = stream.ReadToEnd();
stream.Position = 0;
Assert.Throws<NotSupportedException>(() => stream.Position = 1);
}

[Theory]
[InlineData("Hello, world!")]
[InlineData("")]
[InlineData("lets try this value")]
public void RoundTrip(string input) => RoundTripAll(input);

[Fact]
public void RoundTripGenerated()
{
RoundTripAll(new string('a', 1000));
RoundTripAll(new string('a', 10_000));
}

[Fact]
public void ReadEmpty()
{
var stream = new StringStream("hello world", Encoding.UTF8);
Assert.Equal(0, stream.Read(Array.Empty<byte>(), 0, 0));
#if NET
Assert.Equal(0, stream.Read(Array.Empty<byte>().AsSpan()));
#endif
}
}
11 changes: 11 additions & 0 deletions src/Basic.CompilerLog.UnitTests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ protected CompilerLogReader GetReader(bool emptyDirectory = true )
return reader;
}

private protected CompilerLogReader CreateReader(Action<CompilerLogBuilder> action, LogReaderState? state = null)
{
var stream = new MemoryStream();
var diagnostics = new List<string>();
var builder = new CompilerLogBuilder(stream, diagnostics);
action(builder);
builder.Close();
stream.Position = 0;
return CompilerLogReader.Create(stream, state, leaveOpen: false);
}

/// <summary>
/// Run the build.cmd / .sh generated from an export command
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net472;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0;net472;netstandard2.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DebugType>embedded</DebugType>
Expand All @@ -10,6 +10,7 @@
<Packable>true</Packable>
<NoWarn>$(NoWarn);RS2008;CS1591</NoWarn>
<PackageReadmeFile>README.md</PackageReadmeFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.Util/BasicAnalyzerHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static BasicAnalyzerKind DefaultKind
{
get
{
#if NETCOREAPP
#if NET
return BasicAnalyzerKind.InMemory;
#else
return BasicAnalyzerKind.OnDisk;
Expand Down Expand Up @@ -117,7 +117,7 @@ protected void CheckDisposed()

public static bool IsSupported(BasicAnalyzerKind kind)
{
#if NETCOREAPP
#if NET
return true;
#else
return kind is BasicAnalyzerKind.OnDisk or BasicAnalyzerKind.None;
Expand Down
Loading

0 comments on commit 0e1ff2c

Please sign in to comment.