-
-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for forward compatible binlog format
- Loading branch information
1 parent
dd38153
commit 9481a34
Showing
30 changed files
with
1,452 additions
and
434 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Microsoft.Build.Logging.StructuredLogger; | ||
|
||
namespace BinlogTool | ||
{ | ||
public abstract class BinlogToolCommandBase | ||
{ | ||
public ForwardCompatibilityReadingHandler CompatibilityHandler { protected get; init; } | ||
|
||
protected Build ReadBuild(string binLogFilePath, bool throwOnPathNotFound = true) | ||
{ | ||
if (string.IsNullOrEmpty(binLogFilePath) || !File.Exists(binLogFilePath)) | ||
{ | ||
if(throwOnPathNotFound) | ||
{ | ||
throw new FileNotFoundException("Specified binlog was not found.", binLogFilePath); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
return CompatibilityHandler?.ReadBuild(binLogFilePath) ?? BinaryLog.ReadBuild(binLogFilePath); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using Microsoft.Build.Logging.StructuredLogger; | ||
|
||
namespace BinlogTool | ||
{ | ||
public class ForwardCompatibilityReadingHandler | ||
{ | ||
private enum Mode | ||
{ | ||
Disallow, | ||
FailOnError, | ||
LogErrorsSummary, | ||
LogErrorsDetailed, | ||
IgnoreErrors, | ||
Invalid | ||
} | ||
|
||
private bool _isInitialized; | ||
private Mode _mode; | ||
|
||
private void CheckInitialized() | ||
{ | ||
if (!_isInitialized) | ||
{ | ||
throw new InvalidOperationException("ForwardCompatibilityReadingHandler is not initialized"); | ||
} | ||
} | ||
|
||
public bool ForwardCompatibilityExplicitlyConfigured { get; private set; } | ||
|
||
public bool ProcessCommandLine(ref string[] args) | ||
{ | ||
_isInitialized = true; | ||
|
||
var compatArgs = args | ||
.Where(arg => | ||
arg.StartsWith("--forwardCompatibility", StringComparison.CurrentCultureIgnoreCase) || | ||
arg.StartsWith("-fwd", StringComparison.CurrentCultureIgnoreCase)) | ||
.ToList(); | ||
|
||
if (compatArgs.Count == 0) | ||
{ | ||
return true; | ||
} | ||
|
||
ForwardCompatibilityExplicitlyConfigured = true; | ||
|
||
if (compatArgs.Count > 1) | ||
{ | ||
Console.Error.WriteLine("Only one --forwardCompatibility/-fwd argument is allowed"); | ||
return false; | ||
} | ||
|
||
var compatArg = compatArgs[0]; | ||
args = args.Where(arg => arg != compatArg).ToArray(); | ||
|
||
int colonIndex = compatArg.IndexOf(':'); | ||
|
||
if (colonIndex == -1) | ||
{ | ||
_mode = Mode.LogErrorsSummary; | ||
return true; | ||
} | ||
|
||
_mode = compatArg.Substring(colonIndex + 1).ToLowerInvariant() switch | ||
{ | ||
"d" or "disallow" => Mode.Disallow, | ||
"f" or "failonerror" => Mode.FailOnError, | ||
"l" or "logerrorssummary" => Mode.LogErrorsSummary, | ||
"lv" or "logerrorsdetailed" => Mode.LogErrorsDetailed, | ||
"i" or "ignoreerrors" => Mode.IgnoreErrors, | ||
_ => Mode.Invalid | ||
}; | ||
|
||
if (_mode == Mode.Invalid) | ||
{ | ||
Console.Error.WriteLine("Invalid forward compatibility mode"); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public Build ReadBuild(string binLogFilePath) | ||
{ | ||
if (string.IsNullOrEmpty(binLogFilePath) || !File.Exists(binLogFilePath)) | ||
{ | ||
return null; | ||
} | ||
|
||
binLogFilePath = Path.GetFullPath(binLogFilePath); | ||
|
||
var build = BinaryLog.ReadBuild(binLogFilePath, this.AllowForwardCompatibilityDelegate); | ||
if (_compatibilityException != null) | ||
{ | ||
throw _compatibilityException; | ||
} | ||
return build; | ||
} | ||
|
||
private Exception _compatibilityException = null; | ||
public IForwardCompatibilityReadSettings AllowForwardCompatibilityDelegate | ||
{ | ||
get | ||
{ | ||
CheckInitialized(); | ||
|
||
IForwardCompatibilityReadSettings allowCompatSettings = | ||
((AllowForwardCompatibilityDelegate)(_ => true)).WithDefaultHandler(); | ||
|
||
return _mode switch | ||
{ | ||
Mode.Disallow => null, | ||
Mode.FailOnError => allowCompatSettings.WithCustomErrorHandler(err => | ||
throw (_compatibilityException = new Exception(err.GetFormattedMessage()))), | ||
_ => allowCompatSettings | ||
}; | ||
} | ||
} | ||
|
||
public void HandleBuildResults(Build build) | ||
{ | ||
CheckInitialized(); | ||
|
||
if (_mode != Mode.LogErrorsSummary && _mode != Mode.LogErrorsDetailed) | ||
{ | ||
return; | ||
} | ||
|
||
var errors = build.RecoverableReadingErrors; | ||
if (errors == null || errors.Count == 0) | ||
{ | ||
return; | ||
} | ||
|
||
IEnumerable<string> summaryLines; | ||
|
||
if (_mode == Mode.LogErrorsSummary) | ||
{ | ||
summaryLines = errors | ||
.GroupBy(e => e.errorType) | ||
.Select(g => | ||
$"{SpacedReaderErrorType(g.Key)}: {g.Sum(e => e.count)} Total errors (in {g.GroupBy(f => f.recordKind).Count()} distinct types of records)"); | ||
} | ||
else | ||
{ | ||
summaryLines = errors | ||
.Select(e => $"| {SpacedReaderErrorType(e.errorType)} | {e.recordKind} | {e.count} |") | ||
.Prepend($"| :{new string('-', _maxErrorTypeLength-1)} | :---------- | -----------: |") | ||
.Prepend($"| {SpacedReaderErrorType("Error Type")} | Record Kind | Errors Count |"); | ||
} | ||
|
||
var summary = string.Join(Environment.NewLine, summaryLines); | ||
|
||
Console.Error.WriteLine(); | ||
Console.Error.WriteLine($"Forward compatibility recoverable errors summary:"); | ||
Console.Error.WriteLine(); | ||
Console.Error.WriteLine(summary); | ||
} | ||
|
||
private static readonly int _maxErrorTypeLength = Enum.GetNames(typeof(ReaderErrorType)).Max(s => s.Length); | ||
private string SpacedReaderErrorType(ReaderErrorType errorType) | ||
=> SpacedReaderErrorType(errorType.ToString()); | ||
|
||
private string SpacedReaderErrorType(string text) | ||
=> string.Format("{0,-" + _maxErrorTypeLength + "}", text); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,18 @@ | ||
using System.Linq; | ||
using System.Linq; | ||
using Microsoft.Build.Logging.StructuredLogger; | ||
|
||
namespace BinlogTool | ||
{ | ||
public class SaveStrings | ||
public class SaveStrings : BinlogToolCommandBase | ||
{ | ||
public void Run(string binLogFilePath, string outputFilePath) | ||
{ | ||
var build = BinaryLog.ReadBuild(binLogFilePath); | ||
var build = this.ReadBuild(binLogFilePath); | ||
var strings = build.StringTable.Instances.OrderBy(s => s).ToArray(); | ||
|
||
Serialization.WriteStringsToFile(outputFilePath, strings); | ||
|
||
this.CompatibilityHandler?.HandleBuildResults(build); | ||
} | ||
} | ||
} |
Oops, something went wrong.