diff --git a/RepoM.sln.DotSettings b/RepoM.sln.DotSettings
index 4ae60fb1..024a8c7f 100644
--- a/RepoM.sln.DotSettings
+++ b/RepoM.sln.DotSettings
@@ -1,6 +1,7 @@
True
True
+ True
True
True
True
@@ -11,5 +12,6 @@
True
True
True
+ True
True
True
\ No newline at end of file
diff --git a/src/RepoM.Api/Git/DefaultRepositoryInformationAggregator.cs b/src/RepoM.Api/Git/DefaultRepositoryInformationAggregator.cs
index 703b013d..2913c523 100644
--- a/src/RepoM.Api/Git/DefaultRepositoryInformationAggregator.cs
+++ b/src/RepoM.Api/Git/DefaultRepositoryInformationAggregator.cs
@@ -28,6 +28,7 @@ public void Add(IRepository repository, IRepositoryMonitor repositoryMonitor)
throw new NotImplementedException("We expect a Repository object.");
}
+ // TODO: crashes here
_dispatcher.Invoke(() =>
{
var view = new RepositoryViewModel(repo, repositoryMonitor);
diff --git a/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs b/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
index 8dc4f26d..786eebc0 100644
--- a/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
+++ b/src/RepoM.Api/Git/DefaultRepositoryMonitor.cs
@@ -97,7 +97,7 @@ private void ScanRepositoriesFromStoreAsync()
foreach (var head in _repositoryStore.Get())
{
_logger.LogDebug("{Method} - repo {Head}", nameof(ScanRepositoriesFromStoreAsync), head);
- OnCheckKnownRepository(head, KnownRepositoryNotifications.WhenFound);
+ _ = OnCheckKnownRepository(head, KnownRepositoryNotifications.WhenFound);
}
});
}
@@ -198,6 +198,7 @@ public void Reset()
{
Stop();
+ // TODO: this is not thread safe. Needs urgent fixing
foreach (IRepositoryObserver observer in _repositoryObservers.Values)
{
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
@@ -261,6 +262,7 @@ private void CreateRepositoryObserver(IRepository repo, string path)
if (!_repositoryObservers.TryAdd(path, observer))
{
+ // TODO NOT THREAD SAFE
observer.Dispose();
return;
}
@@ -304,7 +306,7 @@ private void OnRepositoryChangeDetected(IRepository repo)
private void OnRepositoryObserverChange(IRepository repository)
{
_logger.LogDebug("{Method} - repo {Path}", nameof(OnRepositoryObserverChange), repository.Path);
- OnCheckKnownRepository(repository.Path, KnownRepositoryNotifications.WhenFound | KnownRepositoryNotifications.WhenNotFound);
+ _ = OnCheckKnownRepository(repository.Path, KnownRepositoryNotifications.WhenFound | KnownRepositoryNotifications.WhenNotFound);
}
private void DestroyRepositoryObserver(string path)
diff --git a/src/RepoM.App/ActionMenuCore/RepositoryTagsFactoryV2.cs b/src/RepoM.App/ActionMenuCore/RepositoryTagsFactoryV2.cs
index 1bcb1a9d..d3ac879b 100644
--- a/src/RepoM.App/ActionMenuCore/RepositoryTagsFactoryV2.cs
+++ b/src/RepoM.App/ActionMenuCore/RepositoryTagsFactoryV2.cs
@@ -27,8 +27,5 @@ public RepositoryTagsFactoryV2(
_filename = fileSystem.Path.Combine(appDataPathProvider.AppDataPath, "TagsV2.yaml");
}
- public Task> GetTagsAsync(Repository repository)
- {
- return _newStyleActionMenuFactory.GetTagsAsync(repository, _filename);
- }
-}
\ No newline at end of file
+ public Task> GetTagsAsync(Repository repository) => _newStyleActionMenuFactory.GetTagsAsync(repository,_filename);
+}
diff --git a/src/RepoM.App/App.xaml b/src/RepoM.App/App.xaml
index d47a215c..91a24b3c 100644
--- a/src/RepoM.App/App.xaml
+++ b/src/RepoM.App/App.xaml
@@ -1,109 +1,54 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/RepoM.App/App.xaml.cs b/src/RepoM.App/App.xaml.cs
index c8770aaf..42e7eba0 100644
--- a/src/RepoM.App/App.xaml.cs
+++ b/src/RepoM.App/App.xaml.cs
@@ -2,39 +2,70 @@
namespace RepoM.App;
+using Application = System.Windows.Application;
+using Container = SimpleInjector.Container;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
using System;
+using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using System.Windows;
+using System.Windows.Markup;
using Hardcodet.Wpf.TaskbarNotification;
-using RepoM.Api.Git;
-using RepoM.Api.IO;
-using RepoM.App.i18n;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using RepoM.Api;
+using RepoM.Api.Git;
+using RepoM.Api.IO;
using RepoM.Api.Plugins;
+using RepoM.App.i18n;
using RepoM.App.Plugins;
+using RepoM.App.Services;
using Serilog;
using Serilog.Core;
-using ILogger = Microsoft.Extensions.Logging.ILogger;
-using RepoM.App.Services;
-using Container = SimpleInjector.Container;
-using RepoM.App.Services.HotKey;
-using RepoM.Api;
+using SimpleInjector;
+using HotKeyService = RepoM.App.Services.HotKeyService;
///
-/// Interaction logic for App.xaml
+/// Interaction logic for App.xaml
///
public partial class App : Application
{
- private static Mutex? _mutex;
+ private static Mutex? _mutex;
private static IRepositoryMonitor? _repositoryMonitor;
- private TaskbarIcon? _notifyIcon;
- private ModuleService? _moduleService;
- private HotKeyService? _hotKeyService;
+ private static App? _app;
+
+ private HotKeyService? _hotKeyService;
+ private Window? _mainWindow;
+ private ModuleService? _moduleService;
+ private TaskbarIcon? _notifyIcon;
private WindowSizeService? _windowSizeService;
+ public static string? AvailableUpdate
+ {
+ // TODO: This does nothing. Fix it.
+ get;
+ }
+
+ public Window? MainWindowInstance
+ {
+ get
+ {
+ return _app?.MainWindow ?? _mainWindow;
+ }
+
+ set
+ {
+ if (_app != null)
+ {
+ _app.MainWindow = value;
+ }
+
+ _mainWindow = value;
+ }
+ }
+
[STAThread]
public static void Main()
{
@@ -44,9 +75,16 @@ public static void Main()
}
Thread.CurrentThread.Name ??= "UI";
- var app = new App();
- app.InitializeComponent();
- app.Run();
+ _app = new App();
+ _app.InitializeComponent();
+
+ /*
+ * Run is called to start an application.
+ * Set properties and attach events before calling Run.
+ * Once run has been called - an application's OnStartup event
+ * is called immediately afterwards.
+ */
+ _app.Run();
}
protected override async void OnStartup(StartupEventArgs e)
@@ -57,39 +95,45 @@ protected override async void OnStartup(StartupEventArgs e)
// By default, WPF uses en-US as the culture, regardless of the system settings.
// see: https://stackoverflow.com/a/520334/704281
FrameworkElement.LanguageProperty.OverrideMetadata(
- typeof(FrameworkElement),
- new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)));
+ typeof(FrameworkElement),
+ new FrameworkPropertyMetadata(
+ XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
- Application.Current.Resources.MergedDictionaries[0] = ResourceDictionaryTranslationService.ResourceDictionary;
- _notifyIcon = FindResource("NotifyIcon") as TaskbarIcon;
+ Current.Resources.MergedDictionaries[0] = ResourceDictionaryTranslationService.ResourceDictionary;
+ _notifyIcon = FindResource("NotifyIcon") as TaskbarIcon;
var fileSystem = new FileSystem();
// Create instance without DI, because we need it before the last registration of services.
IHmacService hmacService = new HmacSha256Service();
- IPluginFinder pluginFinder = new PluginFinder(fileSystem, hmacService);
+ IPluginFinder pluginFinder = new PluginFinder(fileSystem,
+ hmacService);
- IConfiguration config = SetupConfiguration();
+ IConfiguration config = SetupConfiguration();
ILoggerFactory loggerFactory = CreateLoggerFactory(config);
- ILogger logger = loggerFactory.CreateLogger(nameof(App));
+ ILogger logger = loggerFactory.CreateLogger(nameof(App));
logger.LogInformation("Started");
Bootstrapper.RegisterLogging(loggerFactory);
Bootstrapper.RegisterServices(fileSystem);
- await Bootstrapper.RegisterPlugins(pluginFinder, fileSystem, loggerFactory).ConfigureAwait(true);
+ await Bootstrapper.RegisterPlugins(pluginFinder,
+ fileSystem,
+ loggerFactory)
+ .ConfigureAwait(true);
-#if DEBUG
- Bootstrapper.Container.Verify(SimpleInjector.VerificationOption.VerifyAndDiagnose);
-#else
- Bootstrapper.Container.Options.EnableAutoVerification = false;
-#endif
+ #if DEBUG
+ Bootstrapper.Container.Verify(VerificationOption.VerifyAndDiagnose);
+ #else
+ Bootstrapper.Container.Options.EnableAutoVerification = false;
+ #endif
EnsureStartup ensureStartup = Bootstrapper.Container.GetInstance();
- await ensureStartup.EnsureFilesAsync().ConfigureAwait(true);
-
+ await ensureStartup.EnsureFilesAsync()
+ .ConfigureAwait(true);
+
UseRepositoryMonitor(Bootstrapper.Container);
- _moduleService = Bootstrapper.Container.GetInstance();
- _hotKeyService = Bootstrapper.Container.GetInstance();
+ _moduleService = Bootstrapper.Container.GetInstance();
+ _hotKeyService = Bootstrapper.Container.GetInstance();
_windowSizeService = Bootstrapper.Container.GetInstance();
_hotKeyService.Register();
@@ -97,25 +141,27 @@ protected override async void OnStartup(StartupEventArgs e)
try
{
- await _moduleService.StartAsync().ConfigureAwait(false); // don't care about ui thread
+ await _moduleService.StartAsync()
+ .ConfigureAwait(false); // don't care about ui thread
}
catch (Exception exception)
{
- logger.LogError(exception, "Could not start all modules.");
+ logger.LogError(exception,
+ "Could not start all modules.");
}
}
-
+
protected override void OnExit(ExitEventArgs e)
{
_windowSizeService?.Unregister();
-
- _moduleService?.StopAsync().GetAwaiter().GetResult();
+
+ _moduleService?.StopAsync()
+ .GetAwaiter()
+ .GetResult();
_hotKeyService?.Unregister();
-// #pragma warning disable CA1416 // Validate platform compatibility
_notifyIcon?.Dispose();
-// #pragma warning restore CA1416 // Validate platform compatibility
ReleaseAndDisposeMutex();
@@ -125,12 +171,15 @@ protected override void OnExit(ExitEventArgs e)
private static IConfiguration SetupConfiguration()
{
const string FILENAME = "appsettings.serilog.json";
- var fullFilename = Path.Combine(DefaultAppDataPathProvider.Instance.AppDataPath, FILENAME);
+ var fullFilename = Path.Combine(DefaultAppDataPathProvider.Instance.AppDataPath,
+ FILENAME);
IConfigurationBuilder builder = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
- .AddJsonFile(fullFilename, optional: true, reloadOnChange: false)
- .AddEnvironmentVariables();
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile(fullFilename,
+ true,
+ false)
+ .AddEnvironmentVariables();
return builder.Build();
}
@@ -139,10 +188,11 @@ private static ILoggerFactory CreateLoggerFactory(IConfiguration config)
ILoggerFactory loggerFactory = new LoggerFactory();
LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
- .Enrich.WithThreadId()
- .Enrich.WithThreadName()
- .Enrich.WithProperty("ThreadName", "BG")
- .ReadFrom.Configuration(config);
+ .Enrich.WithThreadId()
+ .Enrich.WithThreadName()
+ .Enrich.WithProperty("ThreadName",
+ "BG")
+ .ReadFrom.Configuration(config);
Logger logger = loggerConfiguration.CreateLogger();
@@ -161,7 +211,9 @@ private static bool IsAlreadyRunning()
{
try
{
- _mutex = new Mutex(true, "Local\\github.com/coenm/RepoM", out var createdNew);
+ _mutex = new Mutex(true,
+ "Local\\github.com/coenm/RepoM",
+ out var createdNew);
if (createdNew)
{
@@ -198,6 +250,5 @@ private static void ReleaseAndDisposeMutex()
// ignore
}
}
+}
- public static string? AvailableUpdate { get; private set; } = null;
-}
\ No newline at end of file
diff --git a/src/RepoM.App/Bootstrapper.cs b/src/RepoM.App/Bootstrapper.cs
index 5eb543ce..f691147b 100644
--- a/src/RepoM.App/Bootstrapper.cs
+++ b/src/RepoM.App/Bootstrapper.cs
@@ -1,22 +1,32 @@
namespace RepoM.App;
+using System;
+using System.IO.Abstractions;
+using System.Runtime.Caching;
+using System.Threading.Tasks;
+using System.Windows;
+using Microsoft.Extensions.Logging;
+using RepoM.Api;
using RepoM.Api.Common;
+using RepoM.Api.Git;
using RepoM.Api.Git.AutoFetch;
using RepoM.Api.Git.ProcessExecution;
-using RepoM.Api.Git;
-using RepoM.Api.IO.ModuleBasedRepositoryActionProvider;
using RepoM.Api.IO;
+using RepoM.Api.IO.ModuleBasedRepositoryActionProvider;
using RepoM.Api.Ordering.Az;
using RepoM.Api.Ordering.Composition;
using RepoM.Api.Ordering.IsPinned;
using RepoM.Api.Ordering.Label;
using RepoM.Api.Ordering.Score;
using RepoM.Api.Ordering.Sum;
+using RepoM.Api.Plugins;
using RepoM.Api.RepositoryActions.Decorators;
+using RepoM.App.ActionMenuCore;
using RepoM.App.i18n;
+using RepoM.App.Plugins;
using RepoM.App.RepositoryActions;
-using RepoM.App.RepositoryFiltering.QueryMatchers;
using RepoM.App.RepositoryFiltering;
+using RepoM.App.RepositoryFiltering.QueryMatchers;
using RepoM.App.RepositoryOrdering;
using RepoM.App.Services;
using RepoM.Core.Plugin.Common;
@@ -24,18 +34,7 @@ namespace RepoM.App;
using RepoM.Core.Plugin.RepositoryFiltering;
using RepoM.Core.Plugin.RepositoryFinder;
using RepoM.Core.Plugin.RepositoryOrdering;
-using System.IO.Abstractions;
-using System;
-using System.Threading.Tasks;
using SimpleInjector;
-using Microsoft.Extensions.Logging;
-using RepoM.Api.Plugins;
-using RepoM.App.Plugins;
-using RepoM.App.Services.HotKey;
-using RepoM.Api;
-using System.Runtime.Caching;
-using System.Windows;
-using RepoM.App.ActionMenuCore;
internal static class Bootstrapper
{
@@ -82,22 +81,22 @@ public static void RegisterServices(IFileSystem fileSystem)
Container.Collection.Append(Lifestyle.Singleton);
Container.Collection.Append(Lifestyle.Singleton);
Container.Collection.Append(Lifestyle.Singleton);
- Container.Collection.Append(() => new FreeTextMatcher(ignoreCase: true, ignoreCaseTag: true), Lifestyle.Singleton);
+ Container.Collection.Append(() => new FreeTextMatcher(true, true), Lifestyle.Singleton);
Container.Register(Lifestyle.Singleton);
-
+
Container.Register(Lifestyle.Singleton);
- Container.RegisterInstance(fileSystem);
+ Container.RegisterInstance(fileSystem);
ActionMenu.Core.Bootstrapper.RegisterServices(Container);
-
+
Container.RegisterSingleton();
Container.RegisterSingleton();
CoreBootstrapper.RegisterRepositoryComparerConfigurationsTypes(Container);
CoreBootstrapper.RegisterRepositoryScorerConfigurationsTypes(Container);
-
+
Container.Register, IsPinnedScorerFactory>(Lifestyle.Singleton);
Container.Register, TagScorerFactory>(Lifestyle.Singleton);
Container.Register, AzRepositoryComparerFactory>(Lifestyle.Singleton);
@@ -108,9 +107,9 @@ public static void RegisterServices(IFileSystem fileSystem)
Container.RegisterSingleton();
Container.Register(typeof(ICommandExecutor<>), new[] { typeof(CoreBootstrapper).Assembly, }, Lifestyle.Singleton);
Container.RegisterDecorator(
- typeof(ICommandExecutor<>),
- typeof(LoggerCommandExecutorDecorator<>),
- Lifestyle.Singleton);
+ typeof(ICommandExecutor<>),
+ typeof(LoggerCommandExecutorDecorator<>),
+ Lifestyle.Singleton);
Container.RegisterSingleton();
Container.RegisterSingleton();
@@ -118,16 +117,15 @@ public static void RegisterServices(IFileSystem fileSystem)
Container.RegisterSingleton();
}
- public static async Task RegisterPlugins(
- IPluginFinder pluginFinder,
- IFileSystem fileSystem,
- ILoggerFactory loggerFactory)
+ public static async Task RegisterPlugins(IPluginFinder pluginFinder,
+ IFileSystem fileSystem,
+ ILoggerFactory loggerFactory)
{
Container.Register(Lifestyle.Singleton);
Container.RegisterInstance(pluginFinder);
var coreBootstrapper = new CoreBootstrapper(pluginFinder, fileSystem, DefaultAppDataPathProvider.Instance, loggerFactory);
- var baseDirectory = fileSystem.Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
+ var baseDirectory = fileSystem.Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
await coreBootstrapper.LoadAndRegisterPluginsAsync(Container, baseDirectory).ConfigureAwait(false);
}
@@ -135,15 +133,15 @@ public static void RegisterLogging(ILoggerFactory loggerFactory)
{
// https://stackoverflow.com/questions/41243485/simple-injector-register-iloggert-by-using-iloggerfactory-createloggert
- Container.RegisterInstance(loggerFactory);
+ Container.RegisterInstance(loggerFactory);
Container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));
Container.RegisterConditional(
- typeof(ILogger),
- c => c.Consumer == null
- ? typeof(Logger