Skip to content

Commit

Permalink
Fix deferred
Browse files Browse the repository at this point in the history
  • Loading branch information
coenm committed Sep 10, 2023
1 parent 64a40f6 commit 915c197
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 37 deletions.
58 changes: 56 additions & 2 deletions src/RepoM.Api/Git/RepositoryAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace RepoM.Api.Git;

using System;
using System.Collections.Generic;
using RepoM.Api.IO.Variables;
using RepoM.Core.Plugin.Repository;
using RepoM.Core.Plugin.RepositoryActions;
using RepoM.Core.Plugin.RepositoryActions.Actions;
Expand All @@ -14,6 +15,61 @@ public RepositorySeparatorAction(IRepository repository)
}
}

public class DeferredRepositoryAction : RepositoryAction
{
private readonly Func<RepositoryActionBase[]>? _action;
private readonly Dictionary<string, string> _envVars;
private readonly Scope? _scope;
private IRepository _repository;

public DeferredRepositoryAction(string name, IRepository repository, bool captureScope)

Check warning on line 25 in src/RepoM.Api/Git/RepositoryAction.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable field '_envVars' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 25 in src/RepoM.Api/Git/RepositoryAction.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable field '_envVars' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
: base(name, repository)
{
_repository = repository;

if (captureScope)
{
_envVars = EnvironmentVariableStore.Get(_repository);
_scope = RepoMVariableProviderStore.VariableScope.Value?.Clone();
}
}

public Func<RepositoryActionBase[]>? DeferredSubActionsEnumerator
{
get
{
if (_action == null)
{
return null;
}

return () =>
{
using IDisposable _ = EnvironmentVariableStore.Set(_envVars);
using IDisposable __ = _scope == null ? CreateDummy() : RepoMVariableProviderStore.Set(_scope);
return _action.Invoke();
};
}
init
{
_action = value;
}
}

private static IDisposable CreateDummy()
{
return new DummyIDisposable();
}

private sealed class DummyIDisposable : IDisposable
{
public void Dispose()
{
// intentionally do nothing
}
}
}

public class RepositoryAction : RepositoryActionBase
{
public RepositoryAction(string name, IRepository repository):
Expand All @@ -40,7 +96,5 @@ protected RepositoryActionBase(IRepository repository)

public bool CanExecute { get; init; } = true;

public Func<RepositoryActionBase[]>? DeferredSubActionsEnumerator { get; init; }

public IEnumerable<RepositoryActionBase>? SubActions { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(Repository
return null;
}

return new Git.RepositoryAction(actionName, repository)
return new Git.DeferredRepositoryAction(actionName, repository, false)
{
DeferredSubActionsEnumerator = () =>
GetFiles(repository, filePattern)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ private IEnumerable<RepositoryAction> Map(RepositoryActionBrowseRepositoryV1? ac
return CreateProcessRunnerAction(actionName, repository.Remotes[0].Url, repository);
}

return new RepositoryAction(actionName, repository)
return new DeferredRepositoryAction(actionName, repository, false)
{
DeferredSubActionsEnumerator = () => repository.Remotes
.Take(50)
.Select(remote => CreateProcessRunnerAction(remote.Name, remote.Url, repository))
.ToArray(),
.Take(50)
.Select(remote => CreateProcessRunnerAction(remote.Name, remote.Url, repository))
.ToArray(),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(Repository
return Map(action as RepositoryActionFolderV1, repository, actionMapperComposition);
}

private IEnumerable<RepoM.Api.Git.RepositoryAction> Map(RepositoryActionFolderV1? action, Repository repository, ActionMapperComposition actionMapperComposition)
private IEnumerable<Git.RepositoryAction> Map(RepositoryActionFolderV1? action, Repository repository, ActionMapperComposition actionMapperComposition)
{
if (action == null)
{
Expand All @@ -49,25 +49,25 @@ IEnumerable<RepositoryActionBase> IActionToRepositoryActionMapper.Map(Repository

if (deferred)
{
yield return new RepoM.Api.Git.RepositoryAction(name, repository)
yield return new DeferredRepositoryAction(name, repository, true)
{
CanExecute = true,
DeferredSubActionsEnumerator = () =>
action.Items
.Where(x => _expressionEvaluator.EvaluateBooleanExpression(x.Active, repository))
.SelectMany(x => actionMapperComposition.Map(x, repository))
.ToArray(),
.Where(repoAction => _expressionEvaluator.EvaluateBooleanExpression(repoAction.Active, repository))
.SelectMany(repoAction => actionMapperComposition.Map(repoAction, repository))
.ToArray(),
};
}
else
{
yield return new RepoM.Api.Git.RepositoryAction(name, repository)
yield return new Git.RepositoryAction(name, repository)
{
CanExecute = true,
SubActions = action.Items
.Where(x => _expressionEvaluator.EvaluateBooleanExpression(x.Active, repository))
.SelectMany(x => actionMapperComposition.Map(x, repository))
.ToArray(),
.Where(repoAction => _expressionEvaluator.EvaluateBooleanExpression(repoAction.Active, repository))
.SelectMany(repoAction => actionMapperComposition.Map(repoAction, repository))
.ToArray(),
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private IEnumerable<RepositoryActionBase> Map(RepositoryActionGitCheckoutV1? act
name = _translationService.Translate("Checkout");
}

yield return new Git.RepositoryAction(name, repository)
yield return new DeferredRepositoryAction(name, repository, false)
{
DeferredSubActionsEnumerator = () =>
repository.LocalBranches
Expand All @@ -65,7 +65,7 @@ private IEnumerable<RepositoryActionBase> Map(RepositoryActionGitCheckoutV1? act
.Union(new RepositoryActionBase[]
{
new RepositorySeparatorAction(repository), // doesn't work todo
new Git.RepositoryAction(_translationService.Translate("Remote branches"), repository)
new DeferredRepositoryAction(_translationService.Translate("Remote branches"), repository, false)
{
DeferredSubActionsEnumerator = () =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public sealed class RepositoryActionFolderV1 : RepositoryAction
[PropertyType(typeof(List<RepositoryAction>))]
public List<RepositoryAction> Items { get; set; } = new List<RepositoryAction>();

// This property has no xml documentation because then it is skipped when generating the documentation.
// IsDeferred is used to indicate that the items in the folder are genereted lazy. This is used to improve performance.
// The problem is that variables at this deferred geneartion are not available anymore resulting in unwanted behaviour.
// At this moment, IsDeferred is not suggested to be used.
/// <summary>
/// Menu is deferred. This will speed up visualisation.
/// </summary>
[EvaluatedProperty]
[PropertyType(typeof(bool))]
[PropertyDefaultBoolValue(false)]
public string? IsDeferred { get; set; }
}
6 changes: 3 additions & 3 deletions src/RepoM.Api/IO/VariableProviders/RepoMVariableProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ public bool CanProvide(string key)
envSearchKey = envKey[..index];
}

var ph = new PropertyHandler();
var ah = new ArrayHandler();

Scope? scope = RepoMVariableProviderStore.VariableScope.Value;

while (true)
Expand All @@ -149,9 +152,6 @@ public bool CanProvide(string key)
IEnumerable<IItem> selectors = FindSelectors(envKey[index..]);
var r = result;

var ph = new PropertyHandler();
var ah = new ArrayHandler();

foreach (IItem selector in selectors)
{
if (selector is PropertySelector ps)
Expand Down
6 changes: 6 additions & 0 deletions src/RepoM.Api/IO/Variables/RepoMVariableProviderStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ public static IDisposable Push(List<EvaluatedVariable> vars)
VariableScope.Value = new Scope(VariableScope.Value, vars);
return VariableScope.Value;
}

public static IDisposable Set(Scope scope)
{
VariableScope.Value = scope;
return VariableScope.Value;
}
}
6 changes: 6 additions & 0 deletions src/RepoM.Api/IO/Variables/Scope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ public void Dispose()
_isDisposed = true;
}
}

public Scope Clone()
{
// this is not a real clone as it uses a reference to Variables. this is ok.
return new Scope(Parent?.Clone(), Variables);
}
}
17 changes: 5 additions & 12 deletions src/RepoM.App/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,14 @@ private bool LstRepositoriesContextMenuOpening(object sender, ContextMenu ctxMen
items.Add(new Separator());
}
}
else if (action is RepositoryAction _)
else
{
Control? controlItem = CreateMenuItem(sender, action, vm);
if (controlItem != null)
{
items.Add(controlItem);
}
}
else
{
// do nothing.
// log?
}
}

return true;
Expand Down Expand Up @@ -418,7 +413,7 @@ private void ShowUpdateIfAvailable()

Action<object, object> clickAction = (object clickSender, object clickArgs) =>
{
if (repositoryAction?.Action == null || repositoryAction.Action is NullAction)
if (repositoryAction?.Action is null or NullAction)
{
return;
}
Expand Down Expand Up @@ -446,7 +441,7 @@ private void ShowUpdateIfAvailable()
// this is a deferred submenu. We want to make sure that the context menu can pop up
// fast, while submenus are not evaluated yet. We don't want to make the context menu
// itself slow because the creation of the submenu items takes some time.
if (repositoryAction?.DeferredSubActionsEnumerator != null)
if (repositoryAction is DeferredRepositoryAction deferredRepositoryAction && deferredRepositoryAction.DeferredSubActionsEnumerator != null)
{
// this is a template submenu item to enable submenus under the current
// menu item. this item gets removed when the real subitems are created
Expand All @@ -457,21 +452,19 @@ void SelfDetachingEventHandler(object _, RoutedEventArgs evtArgs)
item.SubmenuOpened -= SelfDetachingEventHandler;
item.Items.Clear();

foreach (RepositoryActionBase subAction in repositoryAction.DeferredSubActionsEnumerator())
foreach (RepositoryActionBase subAction in deferredRepositoryAction.DeferredSubActionsEnumerator())
{
Control? controlItem = CreateMenuItem(sender, subAction);
if (controlItem != null)
{
item.Items.Add(controlItem);
}
}

Console.WriteLine($"Added {item.Items.Count} deferred sub action(s).");
}

item.SubmenuOpened += SelfDetachingEventHandler;
}
else if (repositoryAction?.SubActions != null)
else if (repositoryAction.SubActions != null)
{
foreach (RepositoryActionBase subAction in repositoryAction.SubActions)
{
Expand Down

0 comments on commit 915c197

Please sign in to comment.