Skip to content

Commit

Permalink
Remove more json stuff + cache RepositoryAction files and env files f…
Browse files Browse the repository at this point in the history
…or speeding up process.
  • Loading branch information
coenm committed Aug 17, 2023
1 parent 38e2c2e commit 16127de
Show file tree
Hide file tree
Showing 28 changed files with 232 additions and 292 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization;

using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data;

public interface IRepositoryActionDeserializer
{
RepositoryActionConfiguration Deserialize(string content);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionDeserializers;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data;

public class JsonDynamicRepositoryActionDeserializer
internal class JsonDynamicRepositoryActionDeserializer
{
private readonly ActionDeserializerComposition _deserializers;
private static readonly JsonSerializer _jsonSerializer = new()
Expand All @@ -29,7 +29,6 @@ public class JsonDynamicRepositoryActionDeserializer
CommentHandling = CommentHandling.Ignore,
};


public JsonDynamicRepositoryActionDeserializer(ActionDeserializerComposition deserializers)
{
_deserializers = deserializers ?? throw new ArgumentNullException(nameof(deserializers));
Expand Down Expand Up @@ -99,7 +98,7 @@ private void DeserializeRepositoryActions(JToken? repositoryActionsToken, Reposi
continue;
}

RepositoryAction? customAction = _deserializers.DeserializeSingleAction(typeValue!, variable, _jsonSerializer);
RepositoryAction? customAction = _deserializers.DeserializeSingleAction(typeValue, variable, _jsonSerializer);
if (customAction == null)
{
continue;
Expand Down Expand Up @@ -230,11 +229,9 @@ private static int DeserializeVersion(JToken? versionToken)
return DEFAULT_VERSION;
}

var version = DEFAULT_VERSION;

if (versionToken.Type == JTokenType.Integer)
{
version = versionToken.Value<int>();
var version = versionToken.Value<int>();
return version < 1 ? DEFAULT_VERSION : version;
}

Expand All @@ -246,7 +243,7 @@ private static int DeserializeVersion(JToken? versionToken)
return DEFAULT_VERSION;
}

if (int.TryParse(versionString, out version))
if (int.TryParse(versionString, out var version))
{
return version < 1 ? DEFAULT_VERSION : version;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization;

using System;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionDeserializers;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data;
using YamlDotNet.Serialization;

public class YamlDynamicRepositoryActionDeserializer
public class YamlDynamicRepositoryActionDeserializer : IRepositoryActionDeserializer
{
private readonly JsonDynamicRepositoryActionDeserializer _jsonDynamicRepositoryActionDeserializer;
private readonly IDeserializer _deserializer;
private readonly ISerializer _serializer;

public YamlDynamicRepositoryActionDeserializer(JsonDynamicRepositoryActionDeserializer jsonDynamicRepositoryActionDeserializer)
public YamlDynamicRepositoryActionDeserializer(ActionDeserializerComposition deserializers)
{
_jsonDynamicRepositoryActionDeserializer = jsonDynamicRepositoryActionDeserializer ?? throw new ArgumentNullException(nameof(jsonDynamicRepositoryActionDeserializer));
_jsonDynamicRepositoryActionDeserializer = new JsonDynamicRepositoryActionDeserializer(deserializers);
_deserializer = new DeserializerBuilder().Build();
_serializer = new SerializerBuilder().JsonCompatible().Build();
}

public RepositoryActionConfiguration Deserialize(string rawContent)
public RepositoryActionConfiguration Deserialize(string content)
{
var yamlObject = _deserializer.Deserialize(rawContent, typeof(object));
var yamlObject = _deserializer.Deserialize(content, typeof(object));
if (yamlObject == null)
{
// todo, log, throw?, ..
return _jsonDynamicRepositoryActionDeserializer.Deserialize(rawContent);
// maybe it is json, just give it a try
return _jsonDynamicRepositoryActionDeserializer.Deserialize(content);
}

var json = _serializer.Serialize(yamlObject);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider;

using System;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Runtime.Caching;
using DotNetEnv;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization;

internal class RepositoryActionsFileStore
{
private readonly IFileSystem _fileSystem;
private readonly IRepositoryActionDeserializer _repositoryActionsDeserializer;
private readonly ObjectCache _cache;

public RepositoryActionsFileStore(IFileSystem fileSystem, IRepositoryActionDeserializer repositoryActionsDeserializer, ObjectCache cache)
{
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
_repositoryActionsDeserializer = repositoryActionsDeserializer ?? throw new ArgumentNullException(nameof(repositoryActionsDeserializer));
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
}

public RepositoryActionConfiguration? TryGet(string filename)
{
if (_cache[filename] is RepositoryActionConfiguration fileContents)
{
return fileContents;
}

var policy = new CacheItemPolicy();
var filePaths = new List<string>(1) { filename, };
policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));

var payload = _fileSystem.File.ReadAllText(filename);
fileContents = _repositoryActionsDeserializer.Deserialize(payload);

if (fileContents == null)
{
return null;
}

var cacheResult = _cache.AddOrGetExisting(filename, fileContents, policy) as RepositoryActionConfiguration;
return cacheResult ?? fileContents;
}
}

internal class EnvFileStore
{
private readonly ObjectCache _cache;

public EnvFileStore(ObjectCache cache)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
}

public IDictionary<string, string> TryGet(string filename)
{
if (_cache[filename] is Dictionary<string, string> fileContents)
{
return fileContents;
}

var policy = new CacheItemPolicy();
var filePaths = new List<string>(1) { filename, };
policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));

IEnumerable<KeyValuePair<string, string>>? result = Env.Load(filename, new LoadOptions(setEnvVars: false));

fileContents = result == null ? new Dictionary<string, string>(0) : result.ToDictionary();

var cacheResult = _cache.AddOrGetExisting(filename, fileContents, policy) as Dictionary<string, string>;
return cacheResult ?? fileContents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text;
using System.Runtime.Caching;
using DotNetEnv;
using Microsoft.Extensions.Logging;
using RepoM.Api.Common;
Expand All @@ -27,23 +27,26 @@ public class RepositoryConfigurationReader
public const string FILENAME = "RepositoryActions.yaml";
private readonly IAppDataPathProvider _appDataPathProvider;
private readonly IFileSystem _fileSystem;
private readonly YamlDynamicRepositoryActionDeserializer _yamlAppSettingsDeserializer;
private readonly IRepositoryExpressionEvaluator _repoExpressionEvaluator;
private readonly ILogger _logger;

private readonly RepositoryActionsFileStore _repositoryActionsFileStore;
private readonly EnvFileStore _envFileStore;

public RepositoryConfigurationReader(
IAppDataPathProvider appDataPathProvider,
IFileSystem fileSystem,
YamlDynamicRepositoryActionDeserializer yamlAppSettingsDeserializer,
IRepositoryActionDeserializer repositoryActionsDeserializer,
IRepositoryExpressionEvaluator repoExpressionEvaluator,
ILogger logger)
ILogger logger,
ObjectCache cache)
{
_appDataPathProvider = appDataPathProvider ?? throw new ArgumentNullException(nameof(appDataPathProvider));
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
_yamlAppSettingsDeserializer = yamlAppSettingsDeserializer ?? throw new ArgumentNullException(nameof(yamlAppSettingsDeserializer));
_repoExpressionEvaluator = repoExpressionEvaluator ?? throw new ArgumentNullException(nameof(repoExpressionEvaluator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));

_repositoryActionsFileStore = new RepositoryActionsFileStore(_fileSystem, repositoryActionsDeserializer, cache);
_envFileStore = new EnvFileStore(cache);
}

private string GetRepositoryActionsFilename(string basePath)
Expand Down Expand Up @@ -107,32 +110,37 @@ private string GetRepositoryActionsFilename(string basePath)

try
{
var content = _fileSystem.File.ReadAllText(filename, Encoding.UTF8);
rootFile = Deserialize(_fileSystem.Path.GetExtension(filename), content);
rootFile = _repositoryActionsFileStore.TryGet(filename);
}
catch (Exception e)
{
throw new InvalidConfigurationException(filename, e.Message, e);
}


if (rootFile == null)
{
throw new InvalidConfigurationException(filename, "Could not read and deserialize file");
}

Redirect? redirect = rootFile.Redirect;
if (!string.IsNullOrWhiteSpace(redirect?.Filename))
if (!string.IsNullOrWhiteSpace(redirect?.Filename) && IsEnabled(redirect.Enabled, true, null))
{
if (IsEnabled(redirect.Enabled, true, null))
filename = EvaluateString(redirect.Filename, null);
if (_fileSystem.File.Exists(filename))
{
filename = EvaluateString(redirect.Filename, null);
if (_fileSystem.File.Exists(filename))
try
{
try
{
var content = _fileSystem.File.ReadAllText(filename, Encoding.UTF8);
rootFile = Deserialize(_fileSystem.Path.GetExtension(filename), content);
}
catch (Exception e)
{
_logger.LogWarning(e, "Could not read and deserialize file '{file}'", filename);
throw new InvalidConfigurationException(filename, e.Message, e);
}
rootFile = _repositoryActionsFileStore.TryGet(filename);
}
catch (Exception e)
{
_logger.LogWarning(e, "Could not read and deserialize file '{file}'", filename);
throw new InvalidConfigurationException(filename, e.Message, e);
}

if (rootFile == null)
{
throw new InvalidConfigurationException(filename, "Could not read and deserialize file");
}
}
}
Expand Down Expand Up @@ -177,7 +185,7 @@ List<EvaluatedVariable> EvaluateVariables(IEnumerable<Variable>? vars)

try
{
IEnumerable<KeyValuePair<string, string>>? currentEnvVars = Env.Load(f, new LoadOptions(setEnvVars: false));
IDictionary<string, string> currentEnvVars = _envFileStore.TryGet(f);
if (envVars == null || !envVars.Any())
{
envVars = currentEnvVars.ToDictionary();
Expand Down Expand Up @@ -231,8 +239,7 @@ List<EvaluatedVariable> EvaluateVariables(IEnumerable<Variable>? vars)

try
{
var content = _fileSystem.File.ReadAllText(f, Encoding.UTF8);
repoSpecificConfig = Deserialize(_fileSystem.Path.GetExtension(f), content);
repoSpecificConfig = _repositoryActionsFileStore.TryGet(filename);
}
catch (Exception)
{
Expand Down Expand Up @@ -284,21 +291,6 @@ private bool IsEnabled(string? booleanExpression, bool defaultWhenNullOrEmpty, I
? defaultWhenNullOrEmpty
: _repoExpressionEvaluator.EvaluateBooleanExpression(booleanExpression!, repository);
}

private RepositoryActionConfiguration Deserialize(string extension, string rawContent)
{
if (extension.StartsWith('.'))
{
extension = extension[1..];
}

if ("yaml".Equals(extension, StringComparison.CurrentCultureIgnoreCase) || "yml".Equals(extension, StringComparison.CurrentCultureIgnoreCase))
{
return _yamlAppSettingsDeserializer.Deserialize(rawContent);
}

throw new NotImplementedException("Unknown extension");
}
}

public class RepositoryTagsConfigurationFactory : IRepositoryTagsFactory
Expand Down
1 change: 1 addition & 0 deletions src/RepoM.Api/RepoM.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="System.IO.Abstractions" Version="19.2.29" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Runtime.Caching" Version="7.0.0" />
<PackageReference Include="YamlDotNet" Version="13.1.0" />
</ItemGroup>

Expand Down
5 changes: 3 additions & 2 deletions src/RepoM.App/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ namespace RepoM.App;
using System.Linq;
using Microsoft.VisualStudio.Services.Common;
using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data;
using System.Runtime.Caching;

internal static class Bootstrapper
{
public static readonly Container Container = new();

public static void RegisterServices(IFileSystem fileSystem)
{
Container.RegisterInstance<ObjectCache>(MemoryCache.Default);
Container.Register<MainWindow>(Lifestyle.Singleton);
Container.RegisterInstance(StatusCharacterMap.Instance);
Container.Register<StatusCompressor>(Lifestyle.Singleton);
Expand Down Expand Up @@ -162,8 +164,7 @@ static IEnumerable<Type> GetExportedTypesFrom(Assembly assembly)
new[] { typeof(IActionToRepositoryActionMapper).Assembly, },
Lifestyle.Singleton);

Container.Register<JsonDynamicRepositoryActionDeserializer>(Lifestyle.Singleton);
Container.Register<YamlDynamicRepositoryActionDeserializer>(Lifestyle.Singleton);
Container.Register<IRepositoryActionDeserializer, YamlDynamicRepositoryActionDeserializer>(Lifestyle.Singleton);
Container.Register<RepositorySpecificConfiguration>(Lifestyle.Singleton);


Expand Down
Loading

0 comments on commit 16127de

Please sign in to comment.