// pad right printed public static string Prp(this string text, int totalWidth, char paddingChar) => text.PadRight(totalWidth + (text.Length - Palette.StripColours(text).Length), paddingChar);
private async Task Results() { // whitespace (e.g. can change to '·' for debugging) var ws = ' '; var totalDuration = results.Sum(i => i.Value.DurationMilliseconds ?? 0 + i.Value.InputResults.Sum(i2 => i2.DurationMilliseconds)); var rows = new List <Tuple <string, string, string, string> > { Tuple.Create($"{p.Default}Duration{p.Reset}", "", $"{p.Default}Outcome{p.Reset}", $"{p.Default}Target{p.Reset}") }; foreach (var item in results.OrderBy(i => i.Value.DurationMilliseconds)) { var duration = $"{p.Timing}{ToStringFromMilliseconds(item.Value.DurationMilliseconds, true)}{p.Reset}"; var percentage = item.Value.DurationMilliseconds.HasValue && totalDuration > 0 ? $"{p.Timing}{100 * item.Value.DurationMilliseconds / totalDuration:N1}%{p.Reset}" : ""; var outcome = item.Value.Outcome == TargetOutcome.Failed ? $"{p.Failed}Failed!{p.Reset}" : item.Value.Outcome == TargetOutcome.NoInputs ? $"{p.Warning}No inputs!{p.Reset}" : $"{p.Succeeded}Succeeded{p.Reset}"; var target = $"{p.Target}{item.Key}{p.Reset}"; rows.Add(Tuple.Create(duration, percentage, outcome, target)); var index = 0; foreach (var result in item.Value.InputResults.OrderBy(r => r.DurationMilliseconds)) { var inputDuration = $"{(index < item.Value.InputResults.Count - 1 ? p.TreeFork : p.TreeCorner)}{p.Timing}{ToStringFromMilliseconds(result.DurationMilliseconds, true)}{p.Reset}"; var inputPercentage = totalDuration > 0 ? $"{(index < item.Value.InputResults.Count - 1 ? p.TreeFork : p.TreeCorner)}{p.Timing}{100 * result.DurationMilliseconds / totalDuration:N1}%{p.Reset}" : ""; var inputOutcome = result.Outcome == TargetInputOutcome.Failed ? $"{p.Failed}Failed!{p.Reset}" : $"{p.Succeeded}Succeeded{p.Reset}"; var input = $"{ws}{ws}{p.Input}{result.Input}{p.Reset}"; rows.Add(Tuple.Create(inputDuration, inputPercentage, inputOutcome, input)); ++index; } } // time column width var timW = rows.Count > 1 ? rows.Skip(1).Max(row => Palette.StripColours(row.Item1).Length) : 0; // percentage column width var perW = rows.Max(row => Palette.StripColours(row.Item2).Length); // duration column width (time and percentage) var durW = Max(Palette.StripColours(rows[0].Item1).Length, timW + 2 + perW); // expand percentage column width to ensure time and percentage are as wide as duration perW = Max(durW - timW - 2, perW); // outcome column width var outW = rows.Max(row => Palette.StripColours(row.Item3).Length); // target name column width var tarW = rows.Max(row => Palette.StripColours(row.Item4).Length); // summary start separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(durW + 2 + outW + 2 + tarW, p.Dash)}{p.Reset}").Tax(); // header await this.writer.WriteLineAsync($"{GetPrefix()}{rows[0].Item1.Prp(durW, ws)}{ws}{ws}{rows[0].Item3.Prp(outW, ws)}{ws}{ws}{rows[0].Item4.Prp(tarW, ws)}").Tax(); // header separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(durW, p.Dash)}{p.Reset}{ws}{ws}{p.Default}{"".Prp(outW, p.Dash)}{p.Reset}{ws}{ws}{p.Default}{"".Prp(tarW, p.Dash)}{p.Reset}").Tax(); // targets foreach (var row in rows.Skip(1)) { await this.writer.WriteLineAsync($"{GetPrefix()}{row.Item1.Prp(timW, ws)}{p.Reset}{ws}{ws}{row.Item2.Prp(perW, ws)}{p.Reset}{ws}{ws}{row.Item3.Prp(outW, ws)}{p.Reset}{ws}{ws}{row.Item4.Prp(tarW, ws)}{p.Reset}").Tax(); } // summary end separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(durW + 2 + outW + 2 + tarW, p.Dash)}{p.Reset}").Tax(); }
private async Task Results() { // whitespace (e.g. can change to '·' for debugging) var ws = ' '; var rows = new List <SummaryRow> { new SummaryRow { TargetOrInput = $"{p.Default}Target{p.Reset}", Outcome = $"{p.Default}Outcome{p.Reset}", Duration = $"{p.Default}Duration{p.Reset}", Percentage = "" } }; foreach (var item in results.OrderBy(i => i.Value.Ordinal)) { var target = $"{p.Target}{item.Key}{p.Reset}"; var outcome = item.Value.Outcome == TargetOutcome.Failed ? $"{p.Failed}Failed!{p.Reset}" : item.Value.Outcome == TargetOutcome.NoInputs ? $"{p.Warning}No inputs!{p.Reset}" : $"{p.Succeeded}Succeeded{p.Reset}"; var duration = item.Value.Duration.HasValue ? $"{p.Timing}{item.Value.Duration.Humanize()}{p.Reset}" : ""; var percentage = item.Value.Duration.HasValue && totalDuration.HasValue && totalDuration.Value > TimeSpan.Zero ? $"{p.Timing}{100 * item.Value.Duration.Value.TotalMilliseconds / totalDuration.Value.TotalMilliseconds:N1}%{p.Reset}" : ""; rows.Add(new SummaryRow { TargetOrInput = target, Outcome = outcome, Duration = duration, Percentage = percentage }); var index = 0; foreach (var result in item.Value.InputResults.Values.OrderBy(result => result.Ordinal)) { var input = $"{ws}{ws}{p.Input}{result.Input}{p.Reset}"; var inputOutcome = result.Outcome == TargetInputOutcome.Failed ? $"{p.Failed}Failed!{p.Reset}" : $"{p.Succeeded}Succeeded{p.Reset}"; var inputDuration = result.Duration.HasValue ? $"{(index < item.Value.InputResults.Count - 1 ? p.TreeFork : p.TreeCorner)}{p.Timing}{result.Duration.Humanize()}{p.Reset}" : ""; var inputPercentage = result.Duration.HasValue && totalDuration.HasValue && totalDuration.Value > TimeSpan.Zero ? $"{(index < item.Value.InputResults.Count - 1 ? p.TreeFork : p.TreeCorner)}{p.Timing}{100 * result.Duration.Value.TotalMilliseconds / totalDuration.Value.TotalMilliseconds:N1}%{p.Reset}" : ""; rows.Add(new SummaryRow { TargetOrInput = input, Outcome = inputOutcome, Duration = inputDuration, Percentage = inputPercentage }); ++index; } } // target or input column width var tarW = rows.Max(row => Palette.StripColours(row.TargetOrInput).Length); // outcome column width var outW = rows.Max(row => Palette.StripColours(row.Outcome).Length); // duration column width var durW = rows.Count > 1 ? rows.Skip(1).Max(row => Palette.StripColours(row.Duration).Length) : 0; // percentage column width var perW = rows.Max(row => Palette.StripColours(row.Percentage).Length); // timing column width (duration and percentage) var timW = Max(Palette.StripColours(rows[0].Duration).Length, durW + 2 + perW); // expand percentage column width to ensure time and percentage are as wide as duration perW = Max(timW - durW - 2, perW); // summary start separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(tarW + 2 + outW + 2 + timW, p.Dash)}{p.Reset}").Tax(); // header await this.writer.WriteLineAsync($"{GetPrefix()}{rows[0].TargetOrInput.Prp(tarW, ws)}{ws}{ws}{rows[0].Outcome.Prp(outW, ws)}{ws}{ws}{rows[0].Duration.Prp(timW, ws)}").Tax(); // header separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(tarW, p.Dash)}{p.Reset}{ws}{ws}{p.Default}{"".Prp(outW, p.Dash)}{p.Reset}{ws}{ws}{p.Default}{"".Prp(timW, p.Dash)}{p.Reset}").Tax(); // targets foreach (var row in rows.Skip(1)) { await this.writer.WriteLineAsync($"{GetPrefix()}{row.TargetOrInput.Prp(tarW, ws)}{p.Reset}{ws}{ws}{row.Outcome.Prp(outW, ws)}{p.Reset}{ws}{ws}{row.Duration.Prp(durW, ws)}{p.Reset}{ws}{ws}{row.Percentage.Prp(perW, ws)}{p.Reset}").Tax(); } // summary end separator await this.writer.WriteLineAsync($"{GetPrefix()}{p.Default}{"".Prp(tarW + 2 + outW + 2 + timW, p.Dash)}{p.Reset}").Tax(); }
private string List(TargetCollection targets, List <string> rootTargets, int maxDepth, int maxDepthToShowInputs, bool listInputs, string startingPrefix) { var lines = new List <(string, string)>(); foreach (var rootTarget in rootTargets) { Append(new List <string> { rootTarget }, new Stack <string>(), true, "", 0); } var maxColumn1Width = lines.Max(line => Palette.StripColours(line.Item1).Length); return(string.Join("", lines.Select(line => $"{line.Item1.PadRight(maxColumn1Width + line.Item1.Length - Palette.StripColours(line.Item1).Length)} {line.Item2}{Environment.NewLine}"))); void Append(List <string> names, Stack <string> seenTargets, bool isRoot, string previousPrefix, int depth) { if (depth > maxDepth) { return; } foreach (var item in names.Select((name, index) => new { name, index })) { var circularDependency = seenTargets.Contains(item.name); seenTargets.Push(item.name); try { var prefix = isRoot ? startingPrefix ?? "" : $"{previousPrefix.Replace(p.TreeCorner, " ").Replace(p.TreeFork, p.TreeDown)}{(item.index == names.Count - 1 ? p.TreeCorner : p.TreeFork)}"; var isMissing = !targets.Contains(item.name); var line = $"{prefix}{p.Target}{item.name}"; if (isMissing) { lines.Add((line + $"{p.Reset} {p.Failed}(missing){p.Reset}", null)); continue; } if (circularDependency) { lines.Add((line + $"{p.Reset} {p.Failed}(circular dependency){p.Reset}", targets[item.name].Description)); continue; } lines.Add((line + p.Reset, targets[item.name].Description)); var target = targets[item.name]; if (listInputs && depth <= maxDepthToShowInputs && target is IHaveInputs hasInputs) { foreach (var inputItem in hasInputs.Inputs.Select((input, index) => new { input, index })) { var inputPrefix = $"{prefix.Replace(p.TreeCorner, " ").Replace(p.TreeFork, p.TreeDown)}{(target.Dependencies.Any() && depth + 1 <= maxDepth ? p.TreeDown : " ")}"; lines.Add(($"{inputPrefix}{p.Input}{inputItem.input}{p.Reset}", null)); } } Append(target.Dependencies, seenTargets, false, prefix, depth + 1); } finally { seenTargets.Pop(); } } } }