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
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected override async Task OnBeforeExecute(IModuleContext context)

foreach (var packagePath in packagePaths.Value!)
{
context.Logger.LogInformation("Uploading {File}", packagePath);
context.Logger.LogInformation("[Local Directory] Uploading {File}", packagePath);
}

await base.OnBeforeExecute(context);
Expand Down
16 changes: 16 additions & 0 deletions ModularPipelines.Examples/Modules/DependentOn2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using ModularPipelines.Attributes;
using ModularPipelines.Context;
using ModularPipelines.Models;
using ModularPipelines.Modules;

namespace ModularPipelines.Examples.Modules;

[DependsOn<DependentOnSuccessModule>]
public class DependentOn2 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}
16 changes: 16 additions & 0 deletions ModularPipelines.Examples/Modules/DependentOn3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using ModularPipelines.Attributes;
using ModularPipelines.Context;
using ModularPipelines.Models;
using ModularPipelines.Modules;

namespace ModularPipelines.Examples.Modules;

[DependsOn<DependentOn2>]
public class DependentOn3 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}
16 changes: 16 additions & 0 deletions ModularPipelines.Examples/Modules/DependentOn4.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using ModularPipelines.Attributes;
using ModularPipelines.Context;
using ModularPipelines.Models;
using ModularPipelines.Modules;

namespace ModularPipelines.Examples.Modules;

[DependsOn<DependentOn3>]
public class DependentOn4 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}
30 changes: 0 additions & 30 deletions ModularPipelines.Examples/Modules/DependentOnSuccessModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,6 @@ namespace ModularPipelines.Examples.Modules;

[DependsOn<SuccessModule>]
public class DependentOnSuccessModule : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}

[DependsOn<DependentOnSuccessModule>]
public class DependentOn2 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}

[DependsOn<DependentOn2>]
public class DependentOn3 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
return null;
}
}

[DependsOn<DependentOn3>]
public class DependentOn4 : Module
{
protected override async Task<ModuleResult<IDictionary<string, object>>?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
Expand Down
2 changes: 1 addition & 1 deletion ModularPipelines.UnitTests/DirectCollisionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void Modules_Dependent_On_Each_Other_Throws_Exception()
})
.ExecutePipelineAsync(),
Throws.Exception.TypeOf<DependencyCollisionException>()
.With.Message.EqualTo("Dependency collision detected: **ModularPipelines.UnitTests.DirectCollisionTests+DependencyConflictModule2** -> ModularPipelines.UnitTests.DirectCollisionTests+DependencyConflictModule1 -> **ModularPipelines.UnitTests.DirectCollisionTests+DependencyConflictModule2**"));
.With.Message.EqualTo("Dependency collision detected: **DependencyConflictModule1** -> DependencyConflictModule2 -> **DependencyConflictModule1**"));
}

[DependsOn<DependencyConflictModule2>]
Expand Down
2 changes: 1 addition & 1 deletion ModularPipelines.UnitTests/NestedCollisionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void Modules_Dependent_On_Each_Other_Throws_Exception()
})
.ExecutePipelineAsync(),
Throws.Exception.TypeOf<DependencyCollisionException>()
.With.Message.EqualTo("Dependency collision detected: **ModularPipelines.UnitTests.NestedCollisionTests+DependencyConflictModule5** -> ModularPipelines.UnitTests.NestedCollisionTests+DependencyConflictModule2 -> ModularPipelines.UnitTests.NestedCollisionTests+DependencyConflictModule3 -> ModularPipelines.UnitTests.NestedCollisionTests+DependencyConflictModule4 -> **ModularPipelines.UnitTests.NestedCollisionTests+DependencyConflictModule5**"));
.With.Message.EqualTo("Dependency collision detected: **DependencyConflictModule2** -> DependencyConflictModule3 -> DependencyConflictModule4 -> DependencyConflictModule5 -> **DependencyConflictModule2**"));
}

[DependsOn<DependencyConflictModule2>]
Expand Down
2 changes: 1 addition & 1 deletion ModularPipelines/Context/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace ModularPipelines.Context;
internal class Command : ICommand
{
private readonly IModuleLoggerProvider _moduleLoggerProvider;
private ILogger Logger => _moduleLoggerProvider.Logger;
private ILogger Logger => _moduleLoggerProvider.GetLogger();

public Command(IModuleLoggerProvider moduleLoggerProvider)
{
Expand Down
2 changes: 1 addition & 1 deletion ModularPipelines/Context/Downloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public async Task<File> DownloadFileAsync(DownloadOptions options, CancellationT

await stream.CopyToAsync(newFile, cancellationToken);

_moduleLoggerProvider.Logger.LogInformation("File {Uri} downloaded to {SaveLocation}", options.DownloadUri, filePathToSave);
_moduleLoggerProvider.GetLogger().LogInformation("File {Uri} downloaded to {SaveLocation}", options.DownloadUri, filePathToSave);

return filePathToSave!;
}
Expand Down
1 change: 1 addition & 0 deletions ModularPipelines/Context/IModuleContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface IModuleContext
public IOptions<PipelineOptions> PipelineOptions { get; }
internal IDependencyCollisionDetector DependencyCollisionDetector { get; }
internal IModuleResultRepository ModuleResultRepository { get; }
internal void FetchLogger(Type getType);
public T? Get<T>();
public ILogger Logger { get; }

Expand Down
8 changes: 7 additions & 1 deletion ModularPipelines/Context/ModuleContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ namespace ModularPipelines.Context;
internal class ModuleContext : IModuleContext
{
private readonly IModuleLoggerProvider _moduleLoggerProvider;
private ILogger? _logger;

public ILogger Logger => _moduleLoggerProvider.Logger;
public ILogger Logger => _logger ?? _moduleLoggerProvider.GetLogger();

public IServiceProvider ServiceProvider { get; }

Expand All @@ -36,6 +37,11 @@ internal class ModuleContext : IModuleContext
public IHex Hex { get; }
public IBase64 Base64 { get; }

public void FetchLogger(Type getType)
{
_logger = _moduleLoggerProvider.GetLogger(getType);
}

public T Get<T>()
{
return (T) ServiceProvider.GetRequiredService(typeof(T));
Expand Down
48 changes: 48 additions & 0 deletions ModularPipelines/Engine/DependencyChainProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Reflection;
using ModularPipelines.Attributes;
using ModularPipelines.Models;
using ModularPipelines.Modules;

namespace ModularPipelines.Engine;

internal class DependencyChainProvider : IDependencyChainProvider
{
public IReadOnlyList<ModuleDependencyModel> ModuleDependencyModels { get; }

public DependencyChainProvider(IEnumerable<ModuleBase> modules)
{
ModuleDependencyModels = Detect(modules.Select(x => new ModuleDependencyModel(x)).ToList());
}

private List<ModuleDependencyModel> Detect(List<ModuleDependencyModel> allModules)
{
foreach (var moduleDependencyModel in allModules)
{
var dependencies = GetModuleDependencies(moduleDependencyModel, allModules).ToList();

moduleDependencyModel.IsDependentOn.AddRange(dependencies);

foreach (var dependencyModel in dependencies)
{
dependencyModel.IsDependencyFor.Add(moduleDependencyModel);
}
}

return allModules;
}

private IEnumerable<ModuleDependencyModel> GetModuleDependencies(ModuleDependencyModel moduleDependencyModel, IReadOnlyCollection<ModuleDependencyModel> allModules)
{
var customAttributes = moduleDependencyModel.Module.GetType().GetCustomAttributes<DependsOnAttribute>(true);

foreach (var dependsOnAttribute in customAttributes)
{
yield return GetModuleDependencyModel(dependsOnAttribute.Type, allModules);
}
}

private ModuleDependencyModel GetModuleDependencyModel(Type type, IEnumerable<ModuleDependencyModel> allModules)
{
return allModules.First(x => x.Module.GetType() == type);
}
}
84 changes: 12 additions & 72 deletions ModularPipelines/Engine/DependencyDetector.cs
Original file line number Diff line number Diff line change
@@ -1,82 +1,22 @@
using System.Reflection;
using System.Text;
using Microsoft.Extensions.Logging;
using ModularPipelines.Attributes;
using ModularPipelines.Modules;
using ModularPipelines.Helpers;

namespace ModularPipelines;
namespace ModularPipelines.Engine;

public class DependencyDetector : IDependencyDetector
internal class DependencyDetector : IDependencyDetector
{
private readonly ILogger<DependencyDetector> _logger;
public IReadOnlyList<ModuleDependencyModel> ModuleDependencyModels { get; }
private readonly IDependencyCollisionDetector _dependencyCollisionDetector;
private readonly IDependencyPrinter _dependencyPrinter;

public DependencyDetector(IEnumerable<ModuleBase> modules, ILogger<DependencyDetector> logger)
public DependencyDetector(IDependencyCollisionDetector dependencyCollisionDetector,
IDependencyPrinter dependencyPrinter)
{
_logger = logger;
ModuleDependencyModels = Detect(modules.Select(x => new ModuleDependencyModel(x)).ToList());
_dependencyCollisionDetector = dependencyCollisionDetector;
_dependencyPrinter = dependencyPrinter;
}

public void Print()
public void Check()
{
var stringBuilder = new StringBuilder();

foreach (var moduleDependencyModel in ModuleDependencyModels)
{
stringBuilder.AppendLine();
Print(stringBuilder, moduleDependencyModel, 1);
}

_logger.LogInformation("The following dependency chains have been detected:\r\n{Chain}", stringBuilder.ToString());
}

private void Print(StringBuilder stringBuilder, ModuleDependencyModel moduleDependencyModel, int i)
{
stringBuilder.Append(new string('-', i));
stringBuilder.Append(' ');
stringBuilder.AppendLine(moduleDependencyModel.Module.GetType().Name);

foreach (var dependencyModel in moduleDependencyModel.IsDependencyFor)
{
Print(stringBuilder, dependencyModel, i+2);
}
}

private List<ModuleDependencyModel> Detect(List<ModuleDependencyModel> allModules)
{
foreach (var moduleDependencyModel in allModules)
{
var dependencies = GetModuleDependencies(moduleDependencyModel, allModules).ToList();

moduleDependencyModel.IsDependentOn.AddRange(dependencies);

foreach (var dependencyModel in dependencies)
{
dependencyModel.IsDependencyFor.Add(moduleDependencyModel);
}
}

return allModules.Where(x => !x.IsDependentOn.Any()).ToList();
_dependencyCollisionDetector.CheckCollisions();
_dependencyPrinter.Print();
}

private IEnumerable<ModuleDependencyModel> GetModuleDependencies(ModuleDependencyModel moduleDependencyModel, IReadOnlyCollection<ModuleDependencyModel> allModules)
{
var customAttributes = moduleDependencyModel.Module.GetType().GetCustomAttributes<DependsOnAttribute>(true);

foreach (var dependsOnAttribute in customAttributes)
{
yield return GetModuleDependencyModel(dependsOnAttribute.Type, allModules);
}
}

private ModuleDependencyModel GetModuleDependencyModel(Type type, IEnumerable<ModuleDependencyModel> allModules)
{
return allModules.First(x => x.Module.GetType() == type);
}
}

public record ModuleDependencyModel(ModuleBase Module)
{
public List<ModuleDependencyModel> IsDependencyFor { get; } = new();
public List<ModuleDependencyModel> IsDependentOn { get; } = new();
}
42 changes: 42 additions & 0 deletions ModularPipelines/Engine/DependencyPrinter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Text;
using Microsoft.Extensions.Logging;
using ModularPipelines.Models;

namespace ModularPipelines.Engine;

internal class DependencyPrinter : IDependencyPrinter
{
private readonly IDependencyChainProvider _dependencyChainProvider;
private readonly ILogger<DependencyPrinter> _logger;

public DependencyPrinter(IDependencyChainProvider dependencyChainProvider, ILogger<DependencyPrinter> logger)
{
_dependencyChainProvider = dependencyChainProvider;
_logger = logger;
}

public void Print()
{
var stringBuilder = new StringBuilder();

foreach (var moduleDependencyModel in _dependencyChainProvider.ModuleDependencyModels)
{
stringBuilder.AppendLine();
Print(stringBuilder, moduleDependencyModel, 1);
}

_logger.LogInformation("The following dependency chains have been detected:\r\n{Chain}", stringBuilder.ToString());
}

private void Print(StringBuilder stringBuilder, ModuleDependencyModel moduleDependencyModel, int i)
{
stringBuilder.Append(new string('-', i));
stringBuilder.Append(' ');
stringBuilder.AppendLine(moduleDependencyModel.Module.GetType().Name);

foreach (var dependencyModel in moduleDependencyModel.IsDependencyFor)
{
Print(stringBuilder, dependencyModel, i+2);
}
}
}
8 changes: 8 additions & 0 deletions ModularPipelines/Engine/IDependencyChainProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ModularPipelines.Models;

namespace ModularPipelines.Engine;

internal interface IDependencyChainProvider
{
IReadOnlyList<ModuleDependencyModel> ModuleDependencyModels { get; }
}
9 changes: 4 additions & 5 deletions ModularPipelines/Engine/IDependencyDetector.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace ModularPipelines;
namespace ModularPipelines.Engine;

public interface IDependencyDetector
{
IReadOnlyList<ModuleDependencyModel> ModuleDependencyModels { get; }
void Print();
internal interface IDependencyDetector
{
void Check();
}
6 changes: 6 additions & 0 deletions ModularPipelines/Engine/IDependencyPrinter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace ModularPipelines.Engine;

internal interface IDependencyPrinter
{
void Print();
}
4 changes: 1 addition & 3 deletions ModularPipelines/Engine/IModuleResultPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using ModularPipelines.Enums;

namespace ModularPipelines.Engine;
namespace ModularPipelines.Engine;

public interface IModuleResultPrinter
{
Expand Down
Loading