Innovenergy_trunk/csharp/app/FossilTui/Program.cs

283 lines
8.9 KiB
C#
Raw Normal View History

2023-02-16 12:57:06 +00:00
using CliWrap;
using CliWrap.Buffered;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.FossilTui;
public static class Program
{
private static readonly Command Fossil = Cli.Wrap("fossil");
public static async Task Main()
{
Console.CancelKeyPress += (_, _) => "aborted".WriteLine();
while (true)
{
var needsUpdate = await NeedsUpdate();
var changes = await GetChanges();
var status = await GetStatus();
if (!changes.Any())
{
Console.Clear();
status.WriteLine(Environment.NewLine);
"No Changes".WriteLine(ConsoleColor.Green);
return;
}
var selectedChange = changes.First();
while (true)
{
Console.Clear();
status.WriteLine(Environment.NewLine);
if (needsUpdate)
{
"Update available for your branch".WriteLine(ConsoleColor.Red);
"Press U to Update".WriteLine(Environment.NewLine);
}
ShowChanges(changes, selectedChange);
var key = Console.ReadKey().Key;
if (key == ConsoleKey.DownArrow)
{
selectedChange = changes.GetNext(selectedChange);
}
else if (key == ConsoleKey.UpArrow)
{
selectedChange = changes.GetPrevious(selectedChange);
}
else if (key == ConsoleKey.RightArrow)
{
selectedChange.SelectNextAction(!needsUpdate);
}
else if (key == ConsoleKey.LeftArrow)
{
selectedChange.SelectPreviousAction(!needsUpdate);
}
else if (key == ConsoleKey.D && selectedChange.State == FossilState.Edited)
{
var fossilGetDiff = Fossil.WithArguments("gdiff " + selectedChange.File);
await fossilGetDiff.ExecuteBufferedAsync();
}
else if (key == ConsoleKey.U)
{
await FossilUpdate();
break;
}
else if (key == ConsoleKey.Spacebar)
{
//
}
else if (key == ConsoleKey.Escape)
{
Console.Clear();
return;
}
else if (key == ConsoleKey.Enter)
{
await ApplyActions(changes, needsUpdate);
break;
}
Console.Clear();
}
}
}
private static async Task<IReadOnlyList<Change>> GetChanges()
{
var result = await Fossil
.WithArguments("changes --differ")
.ExecuteBufferedAsync();
return result
.StandardOutput
.SplitLines()
.Unless(String.IsNullOrWhiteSpace)
//.Unless(f => f.Contains("FossilTui")) // TODO: remove
.Select(l => l.Split(' ', StringSplitOptions.RemoveEmptyEntries))
.Select(t => new Change(FossilState.Parse(t[0]), t[1]))
.ToList();
}
private static async Task<String> GetStatus()
{
var statusResult = await Fossil
.WithArguments("status")
.ExecuteBufferedAsync();
return statusResult
.StandardOutput
.SplitLines()
.Unless(String.IsNullOrWhiteSpace)
.Where(l => l[0] is >= 'a' and <= 'z')
.JoinNonEmptyLines();
}
private static async Task FossilUpdate()
{
var result = await Fossil
.WithArguments("update")
.WithValidation(CommandResultValidation.None)
.ExecuteBufferedAsync();
if (result.ExitCode != 0)
{
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
}
}
private static async Task ApplyActions(IReadOnlyList<Change> changes, Boolean needsUpdate)
{
await DeleteFiles(changes);
await AddFiles(changes); // must run before CommitFiles
await RevertFiles(changes);
await CommitFiles(changes, needsUpdate);
}
private static async Task CommitFiles(IReadOnlyList<Change> changes, Boolean needsUpdate)
{
var filesToCheckIn = changes.GetFilesWithAction(FossilAction.Commit);
if (!filesToCheckIn.Any())
return;
if (needsUpdate)
{
"Would fork".WriteLine(ConsoleColor.Red);
"Not committing selected files".WriteLine();
"Please update first".WriteLine();
}
else
{
var msg = RequestCommitMessage().Quote();
var files = filesToCheckIn.JoinWith(" ");
var result = await Fossil
.WithArguments($"ci -m {msg} {files}")
.ExecuteBufferedAsync();
if (result.ExitCode != 0)
{
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
}
}
}
private static String RequestCommitMessage()
{
while(true)
{
Console.WriteLine("Write your Commit message:");
var msg = Console.ReadLine();
if (msg.IsNullOrWhiteSpace())
continue;
return msg!;
}
}
private static async Task RevertFiles(IReadOnlyList<Change> changes)
{
var filesToRevert = changes.GetFilesWithAction(FossilAction.Revert);
if (!filesToRevert.Any())
return;
var args = filesToRevert.Aggregate("revert", (a, b) => a + " " + b);
var result = await Fossil.WithArguments(args).ExecuteBufferedAsync();
if (result.ExitCode != 0)
{
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
}
}
private static async Task AddFiles(IReadOnlyList<Change> changes)
{
var args = changes
.Where(c => c.SelectedAction == FossilAction.Add)
.Select(c => c.File)
.Aggregate("add", (a, b) => a + " " + b);
var result = await Fossil.WithArguments(args).ExecuteBufferedAsync();
if (result.ExitCode != 0)
{
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
}
}
private static async Task DeleteFiles(IReadOnlyCollection<Change> changes)
{
foreach (var file in changes.GetFilesWithAction(FossilAction.Delete))
{
var result = await Fossil.WithArguments($"rm {file}").WithValidation(CommandResultValidation.None).ExecuteBufferedAsync();
if (result.ExitCode != 0)
{
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
}
try
{
File.Delete(file);
}
catch (Exception e)
{
Console.WriteLine($"Failed to delete file {file}");
Console.WriteLine(e);
}
}
}
private static IReadOnlyList<String> GetFilesWithAction(this IEnumerable<Change> changes, FossilAction fossilAction)
{
return changes
.Where(c => c.SelectedAction == fossilAction)
.Select(c => c.File)
.ToList();
}
private static void ShowChanges(IReadOnlyList<Change> changes, Change selectedChange)
{
foreach (var change in changes)
{
const ConsoleColor bg = ConsoleColor.Black;
const ConsoleColor fg = ConsoleColor.Gray;
var state = change.State;
var stateFgColor = state.Color;
var selected = change.File == selectedChange.File;
state.Name.PadRight(10).Write(stateFgColor, bg, selected);
change.SelectedAction.ToString().PadRight(10).Write(fg, bg, selected);
change.File.Write(fg, bg, selected);
Console.WriteLine();
}
}
private static async Task<Boolean> NeedsUpdate()
{
var result = await Fossil
.WithArguments("update -n")
.ExecuteBufferedAsync();
return result
.StandardOutput
.SplitLines()
.Any(l => l.StartsWith("updated-to"));
}
}