src/StructuredLogger/BinaryLog.cs (114 lines of code) (raw):
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace Microsoft.Build.Logging.StructuredLogger
{
public class BinaryLog
{
public static IEnumerable<Record> ReadRecords(string binLogFilePath)
{
var reader = new BinLogReader();
return reader.ReadRecords(binLogFilePath);
}
public static IEnumerable<Record> ReadRecords(Stream binlogStream)
{
var reader = new BinLogReader();
return reader.ReadRecords(binlogStream);
}
public static IEnumerable<Record> ReadRecords(byte[] binlogBytes)
{
var reader = new BinLogReader();
return reader.ReadRecords(binlogBytes);
}
public static Build ReadBuild(string filePath) => ReadBuild(filePath, progress: null);
public static Build ReadBuild(string filePath, Progress progress)
{
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var projectImportsZipFile = Path.ChangeExtension(filePath, ".ProjectImports.zip");
byte[] projectImportsArchive = null;
if (File.Exists(projectImportsZipFile))
{
projectImportsArchive = File.ReadAllBytes(projectImportsZipFile);
}
var build = ReadBuild(stream, progress, projectImportsArchive);
build.LogFilePath = filePath;
return build;
}
}
public static Build ReadBuild(Stream stream, byte[] projectImportsArchive = null)
=> ReadBuild(stream, progress: null, projectImportsArchive: projectImportsArchive);
internal const bool ReuseBinlogStrings = false;
public static Build ReadBuild(Stream stream, Progress progress, byte[] projectImportsArchive = null)
{
var eventSource = new BinLogReader();
Build build = null;
IEnumerable<string> strings = null;
eventSource.OnBlobRead += (kind, bytes) =>
{
if (kind == BinaryLogRecordKind.ProjectImportArchive)
{
projectImportsArchive = bytes;
}
};
eventSource.OnException += ex =>
{
if (build != null)
{
build.AddChild(new Error() { Text = "Error when reading the file: " + ex.ToString() });
}
};
eventSource.OnStringDictionaryComplete += s =>
{
strings = s;
};
StructuredLogger.SaveLogToDisk = false;
StructuredLogger.CurrentBuild = null;
var structuredLogger = new StructuredLogger();
structuredLogger.Parameters = "build.buildlog";
structuredLogger.Initialize(eventSource);
build = structuredLogger.Construction.Build;
eventSource.OnFileFormatVersionRead += fileFormatVersion =>
{
build.FileFormatVersion = fileFormatVersion;
// strings are deduplicated starting with version 10
if (fileFormatVersion >= 10)
{
build.StringTable.NormalizeLineEndings = false;
build.StringTable.HasDeduplicatedStrings = true;
if (ReuseBinlogStrings)
{
build.StringTable.DisableDeduplication = true;
}
}
};
var sw = Stopwatch.StartNew();
eventSource.Replay(stream, progress);
var elapsed = sw.Elapsed;
if (strings != null)
{
if (ReuseBinlogStrings)
{
// since strings are already deduplicated in the file, no need to do it again
build.StringTable.SetStrings(strings);
}
else
{
// intern all strings in one fell swoop here instead of interning multiple times
// one by one when processing task parameters
build.StringTable.Intern(strings);
}
}
structuredLogger.Shutdown();
build = StructuredLogger.CurrentBuild;
StructuredLogger.CurrentBuild = null;
if (build == null)
{
build = new Build() { Succeeded = false };
build.AddChild(new Error() { Text = "Error when opening the log file." });
}
if (build.SourceFilesArchive == null && projectImportsArchive != null)
{
build.SourceFilesArchive = projectImportsArchive;
}
// strings = build.StringTable.Instances.OrderBy(s => s).ToArray();
// Serialization.WriteStringsToFile(@"C:\temp\1.txt", strings.ToArray());
return build;
}
}
}