283 lines
8.9 KiB
C#
283 lines
8.9 KiB
C#
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"));
|
|
}
|
|
|
|
} |