Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions src/RepoM.Api/Git/DefaultRepositoryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace RepoM.Api.Git;
using System.Linq;
using LibGit2Sharp;
using RepoM.Api.Common;
using IRepository = RepoM.Core.Plugin.Repository.IRepository;

public class DefaultRepositoryWriter : IRepositoryWriter
{
Expand All @@ -16,7 +17,7 @@ public DefaultRepositoryWriter(IGitCommander gitCommander, IAppSettingsService a
_appSettingsService = appSettingsService ?? throw new ArgumentNullException(nameof(appSettingsService));
}

public bool Checkout(Repository repository, string branchName)
public bool Checkout(IRepository repository, string branchName)
{
using var repo = new LibGit2Sharp.Repository(repository.Path);
Branch branch;
Expand Down Expand Up @@ -45,33 +46,30 @@ public bool Checkout(Repository repository, string branchName)
return branch.FriendlyName == branchName;
}

public void Fetch(Repository repository)
public void Fetch(IRepository repository)
{
var arguments = _appSettingsService.PruneOnFetch
? new string[]
{
"fetch", "--all", "--prune",
}
: new string[] { "fetch", "--all", };
? new[] { "fetch", "--all", "--prune", }
: new[] { "fetch", "--all", };

_gitCommander.Command(repository, arguments);
}

public void Pull(Repository repository)
public void Pull(IRepository repository)
{
var arguments = _appSettingsService.PruneOnFetch
? new string[] { "pull", "--prune", }
: new string[] { "pull", };
? new[] { "pull", "--prune", }
: new[] { "pull", };

_gitCommander.Command(repository, arguments);
}

public void Push(Repository repository)
public void Push(IRepository repository)
{
_gitCommander.Command(repository, "push");
}

private void SetUpstream(Repository repository, string localBranchName, string upstreamBranchName)
private void SetUpstream(IRepository repository, string localBranchName, string upstreamBranchName)
{
_gitCommander.Command(repository, "branch", $"--set-upstream-to={upstreamBranchName}", localBranchName);
}
Expand Down
9 changes: 4 additions & 5 deletions src/RepoM.Api/Git/IGitCommander.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
namespace RepoM.Api.Git;

using System;
using RepoM.Core.Plugin.Repository;

public interface IGitCommander
{
string Command(Repository repository, params string[] command);
string Command(IRepository repository, params string[] command);

string CommandOneline(Repository repository, params string[] command);
void CommandNoisy(IRepository repository, params string[] command);

void CommandNoisy(Repository repository, params string[] command);

void CommandOutputPipe(Repository repository, Action<string> handleOutput, params string[] command);
void CommandOutputPipe(IRepository repository, Action<string> handleOutput, params string[] command);
}
94 changes: 94 additions & 0 deletions src/RepoM.Api/Git/IRepositoryActionProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
namespace RepoM.Api.Git;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Extensions.Logging;

public interface IRepositoryActionProvider
{
Expand All @@ -9,4 +13,94 @@ public interface IRepositoryActionProvider
RepositoryActionBase? GetSecondaryAction(Repository repository);

IEnumerable<RepositoryActionBase> GetContextMenuActions(Repository repository);
}

public sealed class LoggingRepositoryActionProviderDecorator : IRepositoryActionProvider
{
private readonly IRepositoryActionProvider _provider;

public LoggingRepositoryActionProviderDecorator(IRepositoryActionProvider provider, ILogger logger)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));

_ = logger ?? throw new ArgumentNullException(nameof(logger));

if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogInformation("IRepositoryActionProvider logging enabled.");
_provider = new LoggingDecorator(provider, logger);
}
else
{
logger.LogInformation("IRepositoryActionProvider logging disabled.");
}
}

public RepositoryActionBase? GetPrimaryAction(Repository repository)
{
return _provider.GetPrimaryAction(repository);
}

public RepositoryActionBase? GetSecondaryAction(Repository repository)
{
return _provider.GetSecondaryAction(repository);
}

public IEnumerable<RepositoryActionBase> GetContextMenuActions(Repository repository)
{
return _provider.GetContextMenuActions(repository);
}

private sealed class LoggingDecorator : IRepositoryActionProvider
{
private readonly IRepositoryActionProvider _provider;
private readonly ILogger _logger;

public LoggingDecorator(IRepositoryActionProvider provider, ILogger logger)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public RepositoryActionBase? GetPrimaryAction(Repository repository)
{
return _provider.GetPrimaryAction(repository);
}

public RepositoryActionBase? GetSecondaryAction(Repository repository)
{
return _provider.GetSecondaryAction(repository);
}

public IEnumerable<RepositoryActionBase> GetContextMenuActions(Repository repository)
{
using IDisposable _ = Measure(repository);
return _provider.GetContextMenuActions(repository).ToArray();
}

private IDisposable Measure(Repository repository)
{
return new MeasureLog(_logger, repository);
}

private sealed class MeasureLog : IDisposable
{
private readonly Stopwatch _sw;
private readonly ILogger _logger;
private readonly Repository _repo;

public MeasureLog(ILogger logger, Repository repo)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_repo = repo ?? throw new ArgumentNullException(nameof(repo));
_sw = Stopwatch.StartNew();
}

public void Dispose()
{
_sw.Stop();
_logger.LogDebug("GetContextMenuActions {repository} took {time}", _repo.Name, _sw.Elapsed);
}
}
}
}
10 changes: 6 additions & 4 deletions src/RepoM.Api/Git/IRepositoryWriter.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace RepoM.Api.Git;

using RepoM.Core.Plugin.Repository;

public interface IRepositoryWriter
{
bool Checkout(Repository repository, string branchName);
bool Checkout(IRepository repository, string branchName);

void Fetch(Repository repository);
void Fetch(IRepository repository);

void Pull(Repository repository);
void Pull(IRepository repository);

void Push(Repository repository);
void Push(IRepository repository);
}
30 changes: 15 additions & 15 deletions src/RepoM.Api/Git/ProcessExecution/ProcessExecutingGitCommander.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ namespace RepoM.Api.Git.ProcessExecution;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.Extensions.Logging;
using RepoM.Core.Plugin.Repository;

public partial class ProcessExecutingGitCommander : IGitCommander
{
private readonly ILogger _logger;
private const string GIT_EXE = "git";

/// <summary>
/// Starting with version 1.7.10, Git uses UTF-8.
/// Use this encoding for Git input and output.
Expand All @@ -18,20 +23,15 @@ public partial class ProcessExecutingGitCommander : IGitCommander

private static readonly Regex _validCommandName = ValidCommandNameRegex();

/// <summary>
/// Runs the given git command, and returns the contents of its STDOUT.
/// </summary>
public string Command(Repository repository, params string[] command)
public ProcessExecutingGitCommander(ILogger logger)
{
var retVal = string.Empty;
CommandOutputPipe(repository, output => retVal = output, command);
return retVal;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

/// <summary>
/// Runs the given git command, and returns the first line of its STDOUT.
/// Runs the given git command, and returns the contents of its STDOUT.
/// </summary>
public string CommandOneline(Repository repository, params string[] command)
public string Command(IRepository repository, params string[] command)
{
var retVal = string.Empty;
CommandOutputPipe(repository, output => retVal = output, command);
Expand All @@ -41,15 +41,15 @@ public string CommandOneline(Repository repository, params string[] command)
/// <summary>
/// Runs the given git command, and passes STDOUT through to the current process's STDOUT.
/// </summary>
public void CommandNoisy(Repository repository, params string[] command)
public void CommandNoisy(IRepository repository, params string[] command)
{
CommandOutputPipe(repository, output => Trace.TraceInformation(output), command);
}

/// <summary>
/// Runs the given git command, and redirects STDOUT to the provided action.
/// </summary>
public void CommandOutputPipe(Repository repository, Action<string> handleOutput, params string[] command)
public void CommandOutputPipe(IRepository repository, Action<string> handleOutput, params string[] command)
{
Time(command, () =>
{
Expand Down Expand Up @@ -81,7 +81,7 @@ public static StreamWriter NewStreamWithEncoding(StreamWriter stream, Encoding e
return new StreamWriter(stream.BaseStream, encoding);
}

private static void Time(string[] command, Action action)
private void Time(string[] command, Action action)
{
DateTime start = DateTime.Now;

Expand All @@ -92,7 +92,7 @@ private static void Time(string[] command, Action action)
finally
{
DateTime end = DateTime.Now;
Trace.WriteLine($"[{end - start}] {string.Join(" ", command)}", "git command time");
_logger.LogTrace("git command '{command}' time took {duration}", string.Join(" ", command), end - start);
}
}

Expand All @@ -108,13 +108,13 @@ private static void RedirectStderr(ProcessStartInfo startInfo)
startInfo.StandardErrorEncoding = _encoding;
}

private static string Start(Repository repository, string[] command, Action<ProcessStartInfo> initialize)
private static string Start(IRepository repository, string[] command, Action<ProcessStartInfo> initialize)
{
var timeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;

var psi = new ProcessStartInfo
{
FileName = "git",
FileName = GIT_EXE,
WorkingDirectory = repository.Path,
};

Expand Down
3 changes: 2 additions & 1 deletion src/RepoM.Api/Git/RepositoryViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public RepositoryViewModel(Repository repository, IRepositoryMonitor monitor)
_monitor = monitor ?? throw new ArgumentNullException(nameof(monitor));
Repository = repository ?? throw new ArgumentNullException(nameof(repository));
UpdateStampUtc = DateTime.UtcNow;
Tags = Repository.Tags.Select(tag => new TagViewModel(tag)).ToArray();
}

public override bool Equals(object? obj)
Expand Down Expand Up @@ -88,7 +89,7 @@ private void EnsureStatusCache()

public bool HasUnpushedChanges => Repository.HasUnpushedChanges;

public TagViewModel[] Tags => Repository.Tags.Select(x => new TagViewModel(x)).ToArray() ?? Array.Empty<TagViewModel>();
public TagViewModel[] Tags { get; }

public override int GetHashCode()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public bool EvaluateBooleanExpression(string? value, IRepository? repository)

try
{
object? result = _expressionExecutor.Execute(RepositoryContext.Create(repository), value!);
var result = _expressionExecutor.Execute(RepositoryContext.Create(repository), value);

if (result is null)
{
Expand Down Expand Up @@ -77,13 +77,7 @@ public string EvaluateStringExpression(string value, IRepository? repository)
{
try
{
object? result = _expressionExecutor.Execute(RepositoryContext.Create(repository), value);

// seems to be possible
if (result == null)
{
return string.Empty;
}
var result = _expressionExecutor.Execute(RepositoryContext.Create(repository), value);

if (result is string s)
{
Expand Down
19 changes: 19 additions & 0 deletions src/RepoM.Api/IO/Methods/IsNullMethod.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace RepoM.Api.IO.Methods;

using System;
using ExpressionStringEvaluator.Methods;
using JetBrains.Annotations;

[UsedImplicitly]
public class IsNullMethod : IMethod
{
public bool CanHandle(string method)
{
return "IsNull".Equals(method, StringComparison.CurrentCultureIgnoreCase);
}

public object? Handle(string method, params object?[] args)
{
return args == null || Array.Exists(args, arg => arg is null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,9 @@ bool IActionToRepositoryActionMapper.CanMap(RepositoryAction action)
return action is RepositoryActionAssociateFileV1;
}

public bool CanHandleMultipleRepositories()
IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(RepositoryAction action, Repository repository, ActionMapperComposition actionMapperComposition)
{
return false;
}

IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(RepositoryAction action, IEnumerable<Repository> repository, ActionMapperComposition actionMapperComposition)
{
return Map(action as RepositoryActionAssociateFileV1, repository.First());
return Map(action as RepositoryActionAssociateFileV1, repository);
}

private IEnumerable<Git.RepositoryAction> Map(RepositoryActionAssociateFileV1? action, Repository repository)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,9 @@ bool IActionToRepositoryActionMapper.CanMap(Data.RepositoryAction action)
return action is RepositoryActionBrowseRepositoryV1;
}

bool IActionToRepositoryActionMapper.CanHandleMultipleRepositories()
IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(Data.RepositoryAction action, Repository repository, ActionMapperComposition actionMapperComposition)
{
return false;
}

IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(Data.RepositoryAction action, IEnumerable<Repository> repository, ActionMapperComposition actionMapperComposition)
{
return Map(action as RepositoryActionBrowseRepositoryV1, repository.First());
return Map(action as RepositoryActionBrowseRepositoryV1, repository);
}

private IEnumerable<RepositoryAction> Map(RepositoryActionBrowseRepositoryV1? action, Repository repository)
Expand Down
Loading