Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
paulomorgado committed Oct 11, 2020
1 parent 79ab0d7 commit 389b673
Show file tree
Hide file tree
Showing 9 changed files with 590 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dlldata.c
BenchmarkDotNet.Artifacts/

# .NET Core
launchSettings.json
project.lock.json
project.fragment.lock.json
artifacts/
Expand Down
34 changes: 34 additions & 0 deletions DotnetMSBuildLog.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetMSBuildLog", "DotnetMSBuildLog\DotnetMSBuildLog.csproj", "{2A4802B0-10A4-4618-81DA-C927837CFF68}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|x64.Build.0 = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|x86.ActiveCfg = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Debug|x86.Build.0 = Debug|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|Any CPU.Build.0 = Release|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|x64.ActiveCfg = Release|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|x64.Build.0 = Release|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|x86.ActiveCfg = Release|Any CPU
{2A4802B0-10A4-4618-81DA-C927837CFF68}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
18 changes: 18 additions & 0 deletions DotnetMSBuildLog/CommandLine/Commands/CommandExtenions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PauloMorgado.DotnetMSBuildLog.CommandLine.Commands
{
internal static class CommandExtenions
{
/// <summary>
/// Allows the command handler to be included in the collection initializer.
/// </summary>
public static void Add(this Command command, ICommandHandler handler) => command.Handler = handler;
}
}
90 changes: 90 additions & 0 deletions DotnetMSBuildLog/CommandLine/Commands/ConvertCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using PauloMorgado.DotnetMSBuildLog.Converters;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.IO;
using System.IO;

namespace PauloMorgado.DotnetMSBuildLog.CommandLine.Commands
{
internal sealed class ConvertCommandArguments
{
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public IConsole Console { get; set; }
public FileInfo InputFileName { get; set; }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public MSBuildLogFileFormat Format { get; set; }
public FileInfo? OutputFileName { get; set; }
}

internal static class ConvertCommandHandler
{
private const string DefaultMSBuildLogFileName = "msbuild.binlog";

public static int ConvertFile(ConvertCommandArguments arguments)
{
if ((int)arguments.Format <= 0)
{
arguments.Console.Error.WriteLine("--format is required.");
return ErrorCodes.ArgumentError;
}

if (arguments.Format == MSBuildLogFileFormat.MSBuildBinaryLog)
{
arguments.Console.Error.WriteLine("Cannot convert a nettrace file to nettrace format.");
return ErrorCodes.ArgumentError;
}

if (!arguments.InputFileName.Exists)
{
arguments.Console.Error.WriteLine($"File '{arguments.InputFileName.FullName}' does not exist.");
return ErrorCodes.ArgumentError;
}

if (arguments.OutputFileName == null)
{
arguments.OutputFileName = arguments.InputFileName;
}

MSBuildLogFileFormatConverter.ConvertToFormat(arguments.Console, arguments.Format, arguments.InputFileName.FullName, arguments.OutputFileName.FullName);

return 0;
}

public static Command ConvertCommand() =>
new Command(
name: "convert",
description: "Converts MSBuild binary logs to alternate formats for use with alternate trace analysis tools. Can only convert from the nettrace format")
{
// Handler
CommandHandler.Create<ConvertCommandArguments>(ConvertFile),

// Arguments and Options
InputFileArgument(),
ConvertFormatOption(),
OutputOption(),
};

private static Argument InputFileArgument() =>
new Argument<FileInfo>(
name: "input-filename",
description: $"Input binary log file to be converted. Defaults to '{ConvertCommandHandler.DefaultMSBuildLogFileName}'.",
getDefaultValue: () => new FileInfo(ConvertCommandHandler.DefaultMSBuildLogFileName))
.ExistingOnly();

public static Option ConvertFormatOption() =>
new Option(
alias: "--format",
description: $"Sets the output format for the trace file conversion.")
{
Argument = new Argument<MSBuildLogFileFormat>(name: "trace-file-format")
};

private static Option OutputOption() =>
new Option(
aliases: new[] { "-o", "--output" },
description: "Output filename. Extension of target format will be added.")
{
Argument = new Argument<FileInfo>(name: "output-filename")
};
}
}
16 changes: 16 additions & 0 deletions DotnetMSBuildLog/CommandLine/Commands/ErrorCodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PauloMorgado.DotnetMSBuildLog.CommandLine.Commands
{
internal static class ErrorCodes
{
public const int SessionCreationError = 1;
public const int TracingError = 2;
public const int ArgumentError = 3;
public const int UnknownError = 4;
}
}
65 changes: 65 additions & 0 deletions DotnetMSBuildLog/Converters/MSBuildLogFileFormatConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections.Immutable;
using System.CommandLine;
using System.CommandLine.IO;
using System.IO;
using Microsoft.Build.Logging.StructuredLogger;
using PauloMorgado.DotnetMSBuildLog.Writers;

namespace PauloMorgado.DotnetMSBuildLog.Converters
{
internal enum MSBuildLogFileFormat { MSBuildBinaryLog, Speedscope };

internal static class MSBuildLogFileFormatConverter
{
private static ImmutableDictionary<MSBuildLogFileFormat, string> TraceFileFormatExtensions = GetTraceFileFormatExtensions();

private static ImmutableDictionary<MSBuildLogFileFormat, string> GetTraceFileFormatExtensions()
{
var builder = ImmutableDictionary.CreateBuilder<MSBuildLogFileFormat, string>();
builder.Add(MSBuildLogFileFormat.MSBuildBinaryLog, "binlog");
builder.Add(MSBuildLogFileFormat.Speedscope, "speedscope.json");
return builder.ToImmutable();
}

internal static void ConvertToFormat(IConsole console, MSBuildLogFileFormat format, string fileToConvertFilePath, string outputFilePath)
{
if (string.IsNullOrWhiteSpace(outputFilePath))
{
outputFilePath = fileToConvertFilePath;
}

outputFilePath = Path.ChangeExtension(outputFilePath, TraceFileFormatExtensions[format]);
console.Out.WriteLine($"Writing:\t{outputFilePath}");

switch (format)
{
case MSBuildLogFileFormat.MSBuildBinaryLog:
break;
case MSBuildLogFileFormat.Speedscope:
Convert(format, fileToConvertFilePath, outputFilePath);
break;
default:
// Validation happened way before this, so we shoud never reach this...
throw new ArgumentException($"Invalid TraceFileFormat \"{format}\"");
}

console.Out.WriteLine("Conversion complete");
}

private static void Convert(MSBuildLogFileFormat format, string fileToConvertFilePath, string outputFilePath)
{
var build = Serialization.Read(fileToConvertFilePath);

switch (format)
{
case MSBuildLogFileFormat.Speedscope:
SpeedscopeMSBuildLogWriter.WriteTo(build, outputFilePath);
break;
default:
// we should never get here
throw new ArgumentException($"Invalid MSBuildLogFileFormat: {format}");
}
}
}
}
18 changes: 18 additions & 0 deletions DotnetMSBuildLog/DotnetMSBuildLog.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>dotnet-msbuildlog</ToolCommandName>
<Nullable>enable</Nullable>
<AssemblyName>dotnet-msbuild</AssemblyName>
<RootNamespace>PauloMorgado.DotnetMSBuildLog</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20371.2" />
<PackageReference Include="MSBuild.StructuredLogger" Version="2.1.176" />
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions DotnetMSBuildLog/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using PauloMorgado.DotnetMSBuildLog.CommandLine.Commands;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;

namespace PauloMorgado.DotnetMSBuildLog
{
static class Program
{
static int Main(string[] args)
{
var parser = new CommandLineBuilder()
.AddCommand(ConvertCommandHandler.ConvertCommand())
.UseDefaults()
.Build();

return parser.Invoke(args);
}
}
}
Loading

0 comments on commit 389b673

Please sign in to comment.