private static void LogFileChanges()

in Sharpmake.Application/Program.cs [734:819]


        private static void LogFileChanges(List<BuildContext.RegressionTest.OutputInfo> fileChanges, bool showRegressionDiff)
        {
            if (fileChanges.Count == 0)
                return;

            var diffs = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            object dictionaryAccess = new object();


            string diffExecutable = LocateDiffExecutable();
            if (!showRegressionDiff || diffExecutable == null)
            {
                DebugWriteLine($"  {fileChanges.Count} files have changed from the reference:");
                fileChanges.ForEach(x =>
                {
                    DebugWriteLine($"    Exp: {x.ReferencePath}");
                    DebugWriteLine($"    Was: {x.OutputPath}");
                });
            }
            else
            {
                DebugWriteLine($"  {fileChanges.Count} files have changed from the reference. Aggregating diff using '{diffExecutable}'");
                Parallel.ForEach(fileChanges, x =>
                {
                    bool refFileExists = File.Exists(x.ReferencePath);
                    bool outFileExists = File.Exists(x.OutputPath);

                    if (refFileExists && outFileExists)
                    {
                        Process process = new Process();
                        process.StartInfo.FileName = diffExecutable;
                        process.StartInfo.UseShellExecute = false;
                        process.StartInfo.CreateNoWindow = true;
                        process.StartInfo.RedirectStandardOutput = true;

                        // -i, --ignore-case               ignore case differences in file contents
                        // -u, -U NUM, --unified[=NUM]   output NUM (default 3) lines of unified context
                        // -w, --ignore-all-space          ignore all white space
                        process.StartInfo.Arguments = $"-i -u -w {x.ReferencePath} {x.OutputPath}";

                        process.Start();

                        var output = process.StandardOutput.ReadToEnd();
                        process.WaitForExit();

                        var lines = output.Split('\n').Where(l => (l.Length > 1 && (l[0] == '+' || l[0] == '-') && !l.StartsWith("--- ") && !l.StartsWith("+++ ")));
                        var diff = string.Concat(lines);
                        lock (dictionaryAccess)
                        {
                            List<string> currentList = null;
                            if (!diffs.TryGetValue(diff, out currentList))
                                diffs[diff] = new List<string> { x.OutputPath };
                            else
                                currentList.Add(x.OutputPath);
                        }
                    }
                    else if (!refFileExists)
                        DebugWriteLine($"    ExtraFileGenerated: {x.OutputPath}");
                    else if (!outFileExists)
                        DebugWriteLine($"    MissingFileInOutput: {x.ReferencePath}");
                });

                int i = 0;
                foreach (var diff in diffs.OrderByDescending(d => d.Value.Count))
                {
                    DebugWriteLine(
                        $"    Diff block {++i}/{diffs.Count}"
                        + (diff.Value.Count > 1 ? $" shared by {diff.Value.Count} files:" : " only in '" + diff.Value.First() + "':")
                    );
                    int j = 0;
                    foreach (var file in diff.Value.OrderBy(f => f))
                        DebugWriteLine($"      {++j}/{diff.Value.Count}  {file}");

                    var diffLines = diff.Key.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    if (diffLines.Length == 0)
                    {
                        DebugWriteLine("        // only whitespace or casing changes");
                    }
                    else
                    {
                        foreach (var diffLine in diffLines)
                            DebugWriteLine($"    {diffLine}");
                    }
                }
            }
        }