Skip to content

Commit

Permalink
Metadata versioning (#54)
Browse files Browse the repository at this point in the history
* Metadata tracking

* Verify metadata in tool

* fix

* more
  • Loading branch information
jaredpar authored Aug 23, 2023
1 parent 41e15e8 commit 7f6412c
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 18 deletions.
44 changes: 44 additions & 0 deletions src/Basic.CompilerLog.UnitTests/MetadataTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Basic.CompilerLog.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Basic.CompilerLog.UnitTests;

public sealed class MetadataTests
{
private static Metadata Parse(string content)
{
using var reader = new StringReader(content);
return Metadata.Read(reader);
}

[Fact]
public void ParseVersion0()
{
var content = """
count:50
""";
var metadata = Parse(content);
Assert.Equal(0, metadata.MetadataVersion);
Assert.Equal(50, metadata.Count);
Assert.Null(metadata.IsWindows);
}

[Fact]
public void ParseVersion1()
{
var content = """
version:1
count:50
windows:true
""";
var metadata = Parse(content);
Assert.Equal(1, metadata.MetadataVersion);
Assert.Equal(50, metadata.Count);
Assert.True(metadata.IsWindows);
}
}
3 changes: 2 additions & 1 deletion src/Basic.CompilerLog.Util/CompilerLogBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using static Basic.CompilerLog.Util.CommonUtil;
Expand Down Expand Up @@ -166,7 +167,7 @@ void WriteMetadata()
{
var entry = ZipArchive.CreateEntry(MetadataFileName, CompressionLevel.Optimal);
using var writer = Polyfill.NewStreamWriter(entry.Open(), ContentEncoding, leaveOpen: false);
writer.WriteLine($"count:{_compilationCount}");
Metadata.Create(_compilationCount).Write(writer);
}

void WriteAssemblyInfo()
Expand Down
34 changes: 23 additions & 11 deletions src/Basic.CompilerLog.Util/CompilerLogReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,27 @@
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using static Basic.CompilerLog.Util.CommonUtil;

namespace Basic.CompilerLog.Util;

public sealed class CompilerLogReader : IDisposable
{
private readonly Dictionary<Guid, MetadataReference> _refMap = new ();
public static int LatestMetadataVersion => Metadata.LatestMetadataVersion;

private readonly Dictionary<Guid, MetadataReference> _refMap = new();
private readonly Dictionary<Guid, (string FileName, AssemblyName AssemblyName)> _mvidToRefInfoMap = new();
private readonly Dictionary<string, BasicAnalyzerHost> _analyzersMap = new ();
private readonly Dictionary<string, BasicAnalyzerHost> _analyzersMap = new();
private readonly bool _ownsCompilerLogState;

public BasicAnalyzerHostOptions BasicAnalyzerHostOptions { get; }
internal CompilerLogState CompilerLogState { get; }
internal ZipArchive ZipArchive { get; set; }
internal int Count { get; }
internal ZipArchive ZipArchive { get; private set; }
internal Metadata Metadata { get; }
internal int Count => Metadata.Count;
public int MetadataVersion => Metadata.MetadataVersion;

private CompilerLogReader(Stream stream, bool leaveOpen, BasicAnalyzerHostOptions? basicAnalyzersOptions = null, CompilerLogState? state = null)
{
Expand All @@ -45,18 +50,25 @@ private CompilerLogReader(Stream stream, bool leaveOpen, BasicAnalyzerHostOption
}

BasicAnalyzerHostOptions = basicAnalyzersOptions ?? BasicAnalyzerHostOptions.Default;
Count = ReadMetadata();
Metadata = ReadMetadata();
ReadAssemblyInfo();

int ReadMetadata()
Metadata ReadMetadata()
{
var entry = ZipArchive.GetEntry(MetadataFileName) ?? throw GetInvalidCompilerLogFileException();
using var reader = Polyfill.NewStreamReader(entry.Open(), ContentEncoding, leaveOpen: false);
var line = reader.ReadLineOrThrow();
var items = line.Split(':', StringSplitOptions.RemoveEmptyEntries);
if (items.Length != 2 || !int.TryParse(items[1], out var count))
throw new InvalidOperationException();
return count;
var metadata = Metadata.Read(reader);

if (metadata.IsWindows is { } isWindows && isWindows != RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var produced = GetName(isWindows);
var current = GetName(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
throw new Exception("Compiler log created on {produced} cannot be consumed on {current}");

string GetName(bool isWindows) => isWindows ? "Windows" : "Unix";
}

return metadata;
}

void ReadAssemblyInfo()
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.Util/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal static byte[] ReadAllBytes(this ZipArchive zipArchive, string name)
return bytes;
}

internal static string ReadLineOrThrow(this StreamReader reader)
internal static string ReadLineOrThrow(this TextReader reader)
{
if (reader.ReadLine() is { } line)
{
Expand Down
77 changes: 77 additions & 0 deletions src/Basic.CompilerLog.Util/Metadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Basic.CompilerLog.Util;

internal sealed class Metadata
{
internal static readonly int LatestMetadataVersion = 1;

internal int MetadataVersion { get; }
internal int Count { get; }
internal bool? IsWindows { get; }

private Metadata(
int metadataVersion,
int count,
bool? isWindows)
{
MetadataVersion = metadataVersion;
Count = count;
IsWindows = isWindows;
}

internal static Metadata Create(int count) =>
new Metadata(
LatestMetadataVersion,
count,
RuntimeInformation.IsOSPlatform(OSPlatform.Windows));

internal static Metadata Read(TextReader reader)
{
try
{
var line = reader.ReadLineOrThrow();
if (line.StartsWith("count", StringComparison.Ordinal))
{
// This is a version 0, there is just a count method
var count = ParseLine(line, "count", int.Parse);
return new Metadata(metadataVersion: 0, count, isWindows: null);
}
else
{
var metadataVersion = ParseLine(line, "version", int.Parse);
var count = ParseLine(reader.ReadLineOrThrow(), "count", int.Parse);
var isWindows = ParseLine(reader.ReadLineOrThrow(), "windows", bool.Parse);
return new Metadata(
metadataVersion,
count,
isWindows);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("Cannot parse metadata", ex);
}

T ParseLine<T>(string line, string label, Func<string, T> func)
{
var items = line.Split(':', StringSplitOptions.RemoveEmptyEntries);
if (items.Length != 2 || items[0] != label)
throw new InvalidOperationException("Line has wrong format");

return func(items[1]);
}
}

internal void Write(StreamWriter writer)
{
writer.WriteLine($"version:{MetadataVersion}");
writer.WriteLine($"count:{Count}");
writer.WriteLine($"windows:{RuntimeInformation.IsOSPlatform(OSPlatform.Windows)}");
}
}
24 changes: 19 additions & 5 deletions src/Basic.CompilerLog/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Basic.CompilerLog.Util;
using Microsoft.CodeAnalysis;
using Mono.Options;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
using static Constants;
Expand Down Expand Up @@ -130,7 +131,7 @@ int RunAnalyzers(IEnumerable<string> args)
}

using var compilerLogStream = GetOrCreateCompilerLogStream(extra);
using var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen: true);
using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true);
var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls);

foreach (var compilerCall in compilerCalls)
Expand Down Expand Up @@ -215,7 +216,7 @@ int RunReferences(IEnumerable<string> args)
}

using var compilerLogStream = GetOrCreateCompilerLogStream(extra);
using var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen: true);
using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true);
var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls);

baseOutputPath = GetBaseOutputPath(baseOutputPath);
Expand Down Expand Up @@ -301,7 +302,7 @@ int RunExport(IEnumerable<string> args)
}

using var compilerLogStream = GetOrCreateCompilerLogStream(extra);
using var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen: true);
using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true);
var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls);
var exportUtil = new ExportUtil(reader, includeAnalyzers: !excludeAnalyzers);

Expand Down Expand Up @@ -401,7 +402,7 @@ int RunEmit(IEnumerable<string> args, CancellationToken cancellationToken)
}

using var compilerLogStream = GetOrCreateCompilerLogStream(extra);
using var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen: true);
using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true);
var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls);
var allSucceeded = true;

Expand Down Expand Up @@ -467,7 +468,7 @@ int RunDiagnostics(IEnumerable<string> args)
}

using var compilerLogStream = GetOrCreateCompilerLogStream(extra);
using var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen: true);
using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true);
var compilationDatas = reader.ReadAllCompilationData(options.FilterCompilerCalls);

foreach (var compilationData in compilationDatas)
Expand Down Expand Up @@ -534,6 +535,19 @@ List<CompilerCall> GetCompilerCalls(List<string> extra, Func<CompilerCall, bool>
}
}

CompilerLogReader GetCompilerLogReader(Stream compilerLogStream, bool leaveOpen)
{
var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen);
if (reader.MetadataVersion > CompilerLogReader.LatestMetadataVersion)
{
WriteLine($"Compiler log version newer than toolset: {reader.MetadataVersion}");
WriteLine($"Consider upgrading to latest compiler log toolset");
WriteLine("dotnet tool update --global Basic.CompilerLog");
}

return reader;
}

Stream GetOrCreateCompilerLogStream(List<string> extra)
{
var logFilePath = GetLogFilePath(extra);
Expand Down

0 comments on commit 7f6412c

Please sign in to comment.