Skip to content

Commit

Permalink
fix: use inline caching #23
Browse files Browse the repository at this point in the history
  • Loading branch information
alirezanet committed Jan 29, 2022
1 parent df670d6 commit 540ccdb
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 32 deletions.
49 changes: 17 additions & 32 deletions src/Husky/TaskRunner/StagedTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using CliFx.Exceptions;
using Husky.Services.Contracts;
using Husky.Stdout;
using Husky.Utils;

namespace Husky.TaskRunner;

Expand Down Expand Up @@ -39,38 +40,33 @@ public override async Task<double> Execute()

private async Task<double> PartialExecution(List<FileArgumentInfo> partialStagedFiles)
{
// create tmp folder
var huskyPath = await _git.GetHuskyPathAsync();
var cache = Path.Combine(huskyPath, "_", "cache");
if (!_fileSystem.Directory.Exists(cache))
_fileSystem.Directory.CreateDirectory(cache);

var arguments = TaskInfo.Arguments.ToList();
var tmpFiles = new List<DiffRecord>();

var stagedRecord = await GetStagedRecord();
foreach (var psf in partialStagedFiles)
{
var record = stagedRecord.First(q => q.src_path == psf.RelativePath);

// first, we need to create a temporary file
var tmpFile = Path.Combine(cache, _fileSystem.FileInfo.FromFileName(psf.RelativePath).Name);
using var scope = new DisposableScope(() => "Cleaning up ...".LogVerbose());

if (psf.PathMode == PathModes.Absolute)
tmpFile = Path.GetFullPath(tmpFile);
foreach (var psf in partialStagedFiles)
{
// create temp file
var tmpFile = scope.Using(new TemporaryFile(_fileSystem, psf));

// find the diff record for the file
var record = stagedRecord.First(q => q.src_path == psf.RelativePath);
var hash = record.dst_hash;

// add staged content to temp file
{
await using var output = _fileSystem.File.Create(tmpFile);
await (
_cliWrap.Wrap("git").WithArguments(new[] { "cat-file", "blob", hash }!)
| output
).ExecuteAsync();
await (_cliWrap.Wrap("git").WithArguments(new[] { "cat-file", "blob", hash }!) | output).ExecuteAsync();
}

// insert the temporary file into the arguments
var index = arguments.FindIndex(q => q == psf.Argument);
arguments.Insert(index, tmpFile);

// keep track of the temporary files and diff records
tmpFiles.Add(record with { tmp_path = tmpFile });
}

Expand All @@ -90,9 +86,6 @@ private async Task<double> PartialExecution(List<FileArgumentInfo> partialStaged
// check if the partial hash exists
if (string.IsNullOrEmpty(newHash))
{
if (_fileSystem.File.Exists(tf.tmp_path))
_fileSystem.File.Delete(tf.tmp_path);

throw new CommandException(
"Failed to hash temp file. Please check the partial staged files."
);
Expand All @@ -109,23 +102,15 @@ await _git.ExecAsync(
{
$"file {tf.src_path} did not changed by formatters".LogVerbose();
}

// remove the temporary file
if (_fileSystem.File.Exists(tf.tmp_path))
_fileSystem.File.Delete(tf.tmp_path);
}

// clean up the cache folder
if (_fileSystem.Directory.Exists(cache))
_fileSystem.Directory.Delete(cache, true);

// re-staged staged files
await ReStageFiles(partialStagedFiles);

return executionTime;
}

private async Task ReStageFiles(List<FileArgumentInfo> partialStagedFiles)
private async Task ReStageFiles(IEnumerable<FileArgumentInfo> partialStagedFiles)
{
var stagedFiles = TaskInfo.ArgumentInfo
.OfType<FileArgumentInfo>()
Expand Down Expand Up @@ -159,7 +144,7 @@ private async Task<List<DiffRecord>> GetStagedRecord()
return stagedRecord;
}

private DiffRecord ParseDiff(string diff)
private static DiffRecord ParseDiff(string diff)
{
// Format: src_mode dst_mode src_hash dst_hash status/score? src_path dst_path?
var diff_pat = new Regex(
Expand All @@ -186,7 +171,7 @@ private DiffRecord ParseDiff(string diff)
/// returns `None`
/// </summary>
/// <param name="s"></param>
private string? UnlessZeroed(string s)
private static string? UnlessZeroed(string s)
{
var zeroed_pat = new Regex(@"^0+$");
return zeroed_pat.IsMatch(s) ? null : s;
Expand All @@ -201,6 +186,6 @@ private record DiffRecord(
int? score,
string? src_path,
string? dst_path,
string? tmp_path = null
TemporaryFile? tmp_path = null
);
}
35 changes: 35 additions & 0 deletions src/Husky/TaskRunner/TemporaryFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.IO.Abstractions;

namespace Husky.TaskRunner;

public sealed class TemporaryFile : IDisposable
{
private readonly IFileSystem _fileSystem;
private readonly string _filePath;

public TemporaryFile(IFileSystem fileSystem, FileArgumentInfo fileArgumentInfo)
{
_fileSystem = fileSystem;

var path = fileArgumentInfo.PathMode == PathModes.Absolute
? fileArgumentInfo.AbsolutePath
: fileArgumentInfo.RelativePath;

var fileInfo = _fileSystem.FileInfo.FromFileName(path);
var guid = Guid.NewGuid().ToString()[..5];
_filePath = path.Replace(fileInfo.Name, $"{guid}_{fileInfo.Name}");
}

public static implicit operator string(TemporaryFile temporaryFile) => temporaryFile._filePath;

public void Dispose()
{
if (_fileSystem.File.Exists(_filePath))
_fileSystem.File.Delete(_filePath);
}

public override string ToString()
{
return _filePath;
}
}
41 changes: 41 additions & 0 deletions src/Husky/Utils/DisposableScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Husky.Stdout;

namespace Husky.Utils;
public sealed class DisposableScope : IDisposable
{
private readonly Action? _beforeDispose;
private readonly Action? _afterDispose;

// you can use ConcurrentQueue if you need thread-safe solution
private readonly Queue<IDisposable> _disposables = new();

public DisposableScope(Action? beforeDispose = default, Action? afterDispose = default)
{
_beforeDispose = beforeDispose;
_afterDispose = afterDispose;
}

public T Using<T>(T disposable) where T : IDisposable
{
_disposables.Enqueue(disposable);
return disposable;
}

public void Dispose()
{
_beforeDispose?.Invoke();
foreach (var item in _disposables)
{
try
{
item.Dispose();
}
catch (Exception e)
{
e.Message.LogVerbose(ConsoleColor.DarkRed);
}
}
_afterDispose?.Invoke();
}
}

0 comments on commit 540ccdb

Please sign in to comment.