App
This commit is contained in:
10
src/Alma.Abstraction/Alma.Abstraction.csproj
Normal file
10
src/Alma.Abstraction/Alma.Abstraction.csproj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>Alma</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
7
src/Alma.Abstraction/Command/ICommand.cs
Normal file
7
src/Alma.Abstraction/Command/ICommand.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Alma.Command;
|
||||||
|
|
||||||
|
public interface ICommand
|
||||||
|
{
|
||||||
|
public string CommandString { get; }
|
||||||
|
public Task Run(List<string> parameters);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Alma.Configuration.Module;
|
||||||
|
|
||||||
|
public record ModuleConfiguration(string? Target, Dictionary<string, string>? Links)
|
||||||
|
{
|
||||||
|
public ModuleConfiguration Merge(ModuleConfiguration merge)
|
||||||
|
{
|
||||||
|
var mergedLinks = (Links ?? new Dictionary<string, string>())
|
||||||
|
.Concat(merge.Links ?? new Dictionary<string, string>());
|
||||||
|
return new ModuleConfiguration(
|
||||||
|
merge.Target ?? Target,
|
||||||
|
new Dictionary<string, string>(mergedLinks)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModuleConfiguration Empty() =>
|
||||||
|
new(null, new Dictionary<string, string>());
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Alma.Configuration.Module;
|
||||||
|
|
||||||
|
public class ModuleConfigurationRoot : Dictionary<string, ModuleConfiguration>
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Alma.Configuration.Repository;
|
||||||
|
|
||||||
|
public interface IRepositoryConfiguration
|
||||||
|
{
|
||||||
|
public Task LoadAsync();
|
||||||
|
RepositoryConfigurationRoot Configuration { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Alma.Configuration.Repository;
|
||||||
|
|
||||||
|
public record RepositoryConfigurationEntry(
|
||||||
|
string Name,
|
||||||
|
string? RepositoryPath,
|
||||||
|
string? LinkPath
|
||||||
|
);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Alma.Configuration.Repository;
|
||||||
|
|
||||||
|
public record RepositoryConfigurationRoot(List<RepositoryConfigurationEntry> Repositories);
|
||||||
6
src/Alma.Abstraction/Data/Constants.cs
Normal file
6
src/Alma.Abstraction/Data/Constants.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Alma.Data;
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public static readonly string ModuleConfigFileStub = ".alma-config";
|
||||||
|
}
|
||||||
3
src/Alma.Abstraction/Data/ItemToLink.cs
Normal file
3
src/Alma.Abstraction/Data/ItemToLink.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Alma.Data;
|
||||||
|
|
||||||
|
public record ItemToLink(string SourcePath, string TargetPath);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public interface IConfigurationFileReader
|
||||||
|
{
|
||||||
|
public Task<(T? Result, string? FileName)> DeserializeAsync<T>(string fileNameWithoutExtension, string? extension = null) where T : class;
|
||||||
|
}
|
||||||
7
src/Alma.Abstraction/Services/IFolderService.cs
Normal file
7
src/Alma.Abstraction/Services/IFolderService.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public interface IFolderService
|
||||||
|
{
|
||||||
|
string? ConfigRoot { get; }
|
||||||
|
string AppData { get; }
|
||||||
|
}
|
||||||
8
src/Alma.Abstraction/Services/IMetadataHandler.cs
Normal file
8
src/Alma.Abstraction/Services/IMetadataHandler.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Alma.Data;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public interface IMetadataHandler
|
||||||
|
{
|
||||||
|
Task SaveLinkedItemsAsync(List<ItemToLink> successfulLinks, DirectoryInfo sourceDirectory, DirectoryInfo targetDirectory);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Alma.Configuration.Module;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public interface IModuleConfigurationResolver
|
||||||
|
{
|
||||||
|
Task<(ModuleConfiguration? mergedModuleConfig, string? moduleConfigFileName)> ResolveModuleConfiguration(string moduleConfigStub);
|
||||||
|
}
|
||||||
7
src/Alma.Abstraction/Services/IOsInformation.cs
Normal file
7
src/Alma.Abstraction/Services/IOsInformation.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public interface IOsInformation
|
||||||
|
{
|
||||||
|
string GetOsIdentifier();
|
||||||
|
bool IsOnPlatform(string platform);
|
||||||
|
}
|
||||||
14
src/Alma.App/Alma.App.csproj
Normal file
14
src/Alma.App/Alma.App.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Alma.Abstraction\Alma.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>Alma</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
37
src/Alma.App/Application.cs
Normal file
37
src/Alma.App/Application.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using Alma.Command;
|
||||||
|
using Alma.Command.Help;
|
||||||
|
|
||||||
|
namespace Alma;
|
||||||
|
|
||||||
|
public class Application
|
||||||
|
{
|
||||||
|
private readonly IList<ICommand> _commands;
|
||||||
|
|
||||||
|
public Application(IEnumerable<ICommand> commands)
|
||||||
|
{
|
||||||
|
_commands = commands.Append(new HelpCommand(() => _commands!)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No command was given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandString = args[0];
|
||||||
|
|
||||||
|
var command = _commands.FirstOrDefault(c => c.CommandString == commandString);
|
||||||
|
|
||||||
|
if (command is null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Invalid command: {commandString}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await command.Run(args[1..].ToList());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/Alma.App/Command/Help/HelpCommand.cs
Normal file
24
src/Alma.App/Command/Help/HelpCommand.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Alma.Command.Help;
|
||||||
|
|
||||||
|
public class HelpCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Func<IEnumerable<ICommand>> _commandsProvider;
|
||||||
|
public string CommandString => "help";
|
||||||
|
|
||||||
|
public HelpCommand(Func<IEnumerable<ICommand>> commandsProvider)
|
||||||
|
{
|
||||||
|
_commandsProvider = commandsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Commands:" + Environment.NewLine);
|
||||||
|
|
||||||
|
foreach (var command in _commandsProvider().OrderBy(c => c.CommandString))
|
||||||
|
{
|
||||||
|
Console.WriteLine(command.CommandString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Alma.App/Command/Info/ModuleInfoCommand.cs
Normal file
10
src/Alma.App/Command/Info/ModuleInfoCommand.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Alma.Command.Info;
|
||||||
|
|
||||||
|
public class ModuleInfoCommand : ICommand
|
||||||
|
{
|
||||||
|
public string CommandString => "info";
|
||||||
|
public Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
193
src/Alma.App/Command/Link/LinkCommand.cs
Normal file
193
src/Alma.App/Command/Link/LinkCommand.cs
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
using Alma.Configuration.Module;
|
||||||
|
using Alma.Configuration.Repository;
|
||||||
|
using Alma.Data;
|
||||||
|
using Alma.Services;
|
||||||
|
|
||||||
|
namespace Alma.Command.Link;
|
||||||
|
|
||||||
|
public class LinkCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
||||||
|
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly IMetadataHandler _metadataHandler;
|
||||||
|
public string CommandString => "link";
|
||||||
|
|
||||||
|
public LinkCommand(
|
||||||
|
IRepositoryConfiguration repositoryConfiguration,
|
||||||
|
IModuleConfigurationResolver moduleConfigurationResolver,
|
||||||
|
IFolderService folderService,
|
||||||
|
IMetadataHandler metadataHandler)
|
||||||
|
{
|
||||||
|
_repositoryConfiguration = repositoryConfiguration;
|
||||||
|
_moduleConfigurationResolver = moduleConfigurationResolver;
|
||||||
|
_folderService = folderService;
|
||||||
|
_metadataHandler = metadataHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
if (parameters.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No module specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string moduleName = parameters[0];
|
||||||
|
|
||||||
|
string sourceDirectory = Path.Combine(Environment.CurrentDirectory);
|
||||||
|
string targetDirectory = Path.Combine(Environment.CurrentDirectory, "..");
|
||||||
|
|
||||||
|
var repoName = GetRepositoryName(parameters);
|
||||||
|
if (repoName is not null
|
||||||
|
&& _repositoryConfiguration.Configuration.Repositories.FirstOrDefault(r => r.Name == repoName) is { } repoConfig)
|
||||||
|
{
|
||||||
|
sourceDirectory = repoConfig.RepositoryPath ?? sourceDirectory;
|
||||||
|
targetDirectory = repoConfig.LinkPath ?? targetDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(sourceDirectory))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Source directory not exists: " + sourceDirectory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string moduleNameAsPath = moduleName.Replace('/', Path.DirectorySeparatorChar);
|
||||||
|
string moduleDirectory = Path.Combine(sourceDirectory, moduleNameAsPath);
|
||||||
|
|
||||||
|
if (!Directory.Exists(moduleDirectory))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Module directory not exists: " + moduleDirectory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleConfigFileStub = Path.Combine(moduleDirectory, Constants.ModuleConfigFileStub);
|
||||||
|
var (moduleConfiguration, moduleConfigurationFile) = await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub);
|
||||||
|
|
||||||
|
if (moduleConfiguration?.Target is string moduleTargetDir)
|
||||||
|
{
|
||||||
|
targetDirectory = ResolvePath(moduleTargetDir, targetDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(targetDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(targetDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleConfigurationFileFullPath = moduleConfigurationFile is null ? null : Path.Combine(moduleDirectory, moduleConfigurationFile);
|
||||||
|
|
||||||
|
var moduleDir = new DirectoryInfo(moduleDirectory);
|
||||||
|
var currentTargetDirectory = new DirectoryInfo(targetDirectory);
|
||||||
|
var itemsToLink = (await TraverseTree(
|
||||||
|
moduleDir,
|
||||||
|
currentTargetDirectory,
|
||||||
|
moduleDir,
|
||||||
|
currentTargetDirectory,
|
||||||
|
moduleConfiguration)).ToList();
|
||||||
|
if (moduleConfigurationFile is not null) itemsToLink.RemoveAll(i => i.SourcePath == moduleConfigurationFileFullPath);
|
||||||
|
|
||||||
|
foreach (var itemToLink in itemsToLink)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Link: '{itemToLink.SourcePath}' '{itemToLink.TargetPath}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
var successfulLinks = CreateLinks(itemsToLink);
|
||||||
|
|
||||||
|
await _metadataHandler.SaveLinkedItemsAsync(successfulLinks, moduleDir, currentTargetDirectory);
|
||||||
|
//await _metadataHandler.SaveLinkedItemsAsync(itemsToLink, moduleDir, currentTargetDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ItemToLink> CreateLinks(List<ItemToLink> itemsToLink)
|
||||||
|
{
|
||||||
|
var successfulLinks = new List<ItemToLink>();
|
||||||
|
|
||||||
|
foreach (var itemToLink in itemsToLink)
|
||||||
|
{
|
||||||
|
if (File.Exists(itemToLink.TargetPath) || Directory.Exists(itemToLink.TargetPath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Item already exists: " + itemToLink.TargetPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceFileExists = File.Exists(itemToLink.SourcePath);
|
||||||
|
var sourceDirectoryExists = Directory.Exists(itemToLink.SourcePath);
|
||||||
|
|
||||||
|
if (sourceFileExists)
|
||||||
|
{
|
||||||
|
File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath);
|
||||||
|
}
|
||||||
|
else if (sourceDirectoryExists)
|
||||||
|
{
|
||||||
|
File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Source not exists: " + itemToLink.SourcePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
successfulLinks.Add(itemToLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
return successfulLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<ItemToLink>> TraverseTree(
|
||||||
|
DirectoryInfo currentDirectory,
|
||||||
|
DirectoryInfo currentTargetDirectory,
|
||||||
|
DirectoryInfo moduleDirectory,
|
||||||
|
DirectoryInfo targetDirectory,
|
||||||
|
ModuleConfiguration? moduleConfiguration)
|
||||||
|
{
|
||||||
|
var filesToLink = new List<ItemToLink>();
|
||||||
|
foreach (var file in currentDirectory.GetFiles())
|
||||||
|
{
|
||||||
|
filesToLink.Add(new ItemToLink(Path.Combine(currentDirectory.FullName, file.Name), Path.Combine(currentTargetDirectory.FullName, file.Name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var subDirLinksToAdd = Enumerable.Empty<ItemToLink>();
|
||||||
|
|
||||||
|
foreach (var subDir in currentDirectory.GetDirectories())
|
||||||
|
{
|
||||||
|
var relativePath = GetRelativePath(subDir.FullName, moduleDirectory.FullName);
|
||||||
|
if (moduleConfiguration?.Links?.ContainsKey(relativePath) ?? false)
|
||||||
|
{
|
||||||
|
filesToLink.Add(new ItemToLink(subDir.FullName, ResolvePath(moduleConfiguration.Links[relativePath], targetDirectory.FullName)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var subDirLinks = await TraverseTree(
|
||||||
|
subDir,
|
||||||
|
new DirectoryInfo(Path.Combine(currentTargetDirectory.FullName, subDir.Name)),
|
||||||
|
moduleDirectory,
|
||||||
|
targetDirectory,
|
||||||
|
moduleConfiguration
|
||||||
|
);
|
||||||
|
subDirLinksToAdd = subDirLinksToAdd.Concat(subDirLinks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filesToLink.Concat(subDirLinksToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetRepositoryName(List<string> parameters)
|
||||||
|
{
|
||||||
|
//TODO: handle parameters
|
||||||
|
if (parameters.Count < 2) return null;
|
||||||
|
return parameters[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolvePath(string path, string currentDirectory)
|
||||||
|
{
|
||||||
|
if (path.StartsWith("~"))
|
||||||
|
{
|
||||||
|
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), path.Substring(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: more special character
|
||||||
|
|
||||||
|
return Path.Combine(currentDirectory, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRelativePath(string full, string parent) => full.Substring(parent.Length).TrimStart(Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
90
src/Alma.App/Command/List/ListCommand.cs
Normal file
90
src/Alma.App/Command/List/ListCommand.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Alma.Configuration.Repository;
|
||||||
|
using Alma.Data;
|
||||||
|
using Alma.Services;
|
||||||
|
|
||||||
|
namespace Alma.Command.List;
|
||||||
|
|
||||||
|
public class ListCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
||||||
|
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
|
||||||
|
public string CommandString => "ls";
|
||||||
|
|
||||||
|
public ListCommand(
|
||||||
|
IRepositoryConfiguration repositoryConfiguration,
|
||||||
|
IModuleConfigurationResolver moduleConfigurationResolver)
|
||||||
|
{
|
||||||
|
_repositoryConfiguration = repositoryConfiguration;
|
||||||
|
_moduleConfigurationResolver = moduleConfigurationResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
if (parameters.Count > 0)
|
||||||
|
{
|
||||||
|
await ListModulesByRepoName(parameters[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ListRepositories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ListRepositories()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Repositories:" + Environment.NewLine);
|
||||||
|
foreach (var repository in _repositoryConfiguration.Configuration.Repositories)
|
||||||
|
{
|
||||||
|
Console.WriteLine(repository.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ListModulesByRepoName(string repositoryName)
|
||||||
|
{
|
||||||
|
var repo = _repositoryConfiguration.Configuration.Repositories.FirstOrDefault(r => r.Name == repositoryName);
|
||||||
|
if (repo is null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No repository found with name '{repositoryName}'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repo.RepositoryPath is null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No repository path is specified in repository settings '{repositoryName}'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ListModules(repo.RepositoryPath, repositoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ListModules(string repositoryPath, string repositoryName)
|
||||||
|
{
|
||||||
|
var repositoryDirectory = new DirectoryInfo(repositoryPath);
|
||||||
|
var moduleDirectories = await TraverseRepositoryFolder(repositoryDirectory);
|
||||||
|
|
||||||
|
Console.WriteLine($"Modules in repository '{repositoryName}':" + Environment.NewLine);
|
||||||
|
foreach (var modulePath in moduleDirectories)
|
||||||
|
{
|
||||||
|
Console.WriteLine(modulePath.FullName.Substring(repositoryDirectory.FullName.Length).Replace(Path.DirectorySeparatorChar, '/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<DirectoryInfo>> TraverseRepositoryFolder(DirectoryInfo currentDirectory)
|
||||||
|
{
|
||||||
|
var moduleConfigFileStub = Path.Combine(currentDirectory.FullName, Constants.ModuleConfigFileStub);
|
||||||
|
var (moduleConfiguration, moduleConfigurationFile) = await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub);
|
||||||
|
|
||||||
|
var result = Enumerable.Empty<DirectoryInfo>();
|
||||||
|
if (moduleConfigurationFile is not null)
|
||||||
|
{
|
||||||
|
result = new List<DirectoryInfo> {currentDirectory};
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var subDir in currentDirectory.GetDirectories())
|
||||||
|
{
|
||||||
|
result = result.Concat(await TraverseRepositoryFolder(subDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Alma.App/Command/Unlink/UnlinkCommand.cs
Normal file
10
src/Alma.App/Command/Unlink/UnlinkCommand.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Alma.Command.Unlink;
|
||||||
|
|
||||||
|
public class UnlinkCommand : ICommand
|
||||||
|
{
|
||||||
|
public string CommandString => "unlink";
|
||||||
|
public Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Alma.Services;
|
||||||
|
|
||||||
|
namespace Alma.Configuration.Repository;
|
||||||
|
|
||||||
|
public class RepositoryConfiguration : IRepositoryConfiguration
|
||||||
|
{
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly ConfigurationFileReader _configurationFileReader;
|
||||||
|
|
||||||
|
public RepositoryConfigurationRoot Configuration { get; private set; } = new RepositoryConfigurationRoot(new List<RepositoryConfigurationEntry>());
|
||||||
|
|
||||||
|
public RepositoryConfiguration(IFolderService folderService, ConfigurationFileReader configurationFileReader)
|
||||||
|
{
|
||||||
|
_folderService = folderService;
|
||||||
|
_configurationFileReader = configurationFileReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadAsync()
|
||||||
|
{
|
||||||
|
if (_folderService.ConfigRoot is null)
|
||||||
|
{
|
||||||
|
Configuration = new RepositoryConfigurationRoot(new List<RepositoryConfigurationEntry>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var repoConfigFileNameStub = Path.Combine(_folderService.ConfigRoot, "repository");
|
||||||
|
var (configuration, repoConfigFileName) = await _configurationFileReader.DeserializeAsync<RepositoryConfigurationRoot>(repoConfigFileNameStub);
|
||||||
|
Configuration = configuration ?? new RepositoryConfigurationRoot(new List<RepositoryConfigurationEntry>());
|
||||||
|
|
||||||
|
foreach (var repositoryConfigurationEntry in Configuration.Repositories)
|
||||||
|
{
|
||||||
|
if (repositoryConfigurationEntry.Name is null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Entry name is null in {repoConfigFileName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/Alma.App/Data/Repository/RepositoryFolder.cs
Normal file
6
src/Alma.App/Data/Repository/RepositoryFolder.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Alma.Data.Repository;
|
||||||
|
|
||||||
|
public class RepositoryFolder
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
19
src/Alma.App/Helper/MD5Helper.cs
Normal file
19
src/Alma.App/Helper/MD5Helper.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Alma.Helper;
|
||||||
|
|
||||||
|
public static class MD5Helper
|
||||||
|
{
|
||||||
|
public static string GetMD5Hash(string source)
|
||||||
|
{
|
||||||
|
using var md5Hasher = MD5.Create();
|
||||||
|
var data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(source));
|
||||||
|
var sBuilder = new StringBuilder();
|
||||||
|
for (var i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
sBuilder.Append(data[i].ToString("x2"));
|
||||||
|
}
|
||||||
|
return sBuilder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/Alma.App/Services/ConfigurationFileReader.cs
Normal file
21
src/Alma.App/Services/ConfigurationFileReader.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class ConfigurationFileReader
|
||||||
|
{
|
||||||
|
private readonly List<IConfigurationFileReader> _configurationFileReaders;
|
||||||
|
|
||||||
|
public ConfigurationFileReader(IEnumerable<IConfigurationFileReader> configurationFileReaders)
|
||||||
|
{
|
||||||
|
_configurationFileReaders = configurationFileReaders.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(T? Result, string? FileName)> DeserializeAsync<T>(string fileNameWithoutExtension, string? extension = null) where T : class
|
||||||
|
{
|
||||||
|
foreach (var configurationFileReader in _configurationFileReaders)
|
||||||
|
{
|
||||||
|
if (await configurationFileReader.DeserializeAsync<T>(fileNameWithoutExtension, extension) is {Result: { }} result) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/Alma.App/Services/FolderService.cs
Normal file
51
src/Alma.App/Services/FolderService.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class FolderService : IFolderService
|
||||||
|
{
|
||||||
|
public string? ConfigRoot { get; }
|
||||||
|
public string AppData { get; }
|
||||||
|
|
||||||
|
public FolderService()
|
||||||
|
{
|
||||||
|
ConfigRoot = GetConfigHomePath();
|
||||||
|
AppData = GetAppDataPath();
|
||||||
|
|
||||||
|
if (!Directory.Exists(AppData)) Directory.CreateDirectory(AppData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetConfigHomePath()
|
||||||
|
{
|
||||||
|
var configHomeProviders = new List<Func<string?>>
|
||||||
|
{
|
||||||
|
() => Environment.GetEnvironmentVariable("XDG_CONFIG_HOME"),
|
||||||
|
() => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config")
|
||||||
|
};
|
||||||
|
|
||||||
|
var configHome = EnumerateProviders(configHomeProviders);
|
||||||
|
return configHome == null ? null : Path.Combine(configHome, "alma");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetAppDataPath()
|
||||||
|
{
|
||||||
|
var appDataProviders = new List<Func<string?>>
|
||||||
|
{
|
||||||
|
() => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
|
||||||
|
};
|
||||||
|
|
||||||
|
var appData = EnumerateProviders(appDataProviders) ?? Environment.CurrentDirectory;
|
||||||
|
return Path.Combine(appData, "alma");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? EnumerateProviders(List<Func<string?>> providers)
|
||||||
|
{
|
||||||
|
string? result = null;
|
||||||
|
|
||||||
|
foreach (var provider in providers)
|
||||||
|
{
|
||||||
|
result = provider();
|
||||||
|
if (result is not null && Directory.Exists(result)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Alma.App/Services/JsonConfigurationFileReader.cs
Normal file
18
src/Alma.App/Services/JsonConfigurationFileReader.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class JsonConfigurationFileReader : IConfigurationFileReader
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions DefaultOptions = new(JsonSerializerDefaults.Web);
|
||||||
|
|
||||||
|
public async Task<(T? Result, string? FileName)> DeserializeAsync<T>(string fileNameWithoutExtension, string? extension) where T : class
|
||||||
|
{
|
||||||
|
extension ??= "json";
|
||||||
|
var fileName = fileNameWithoutExtension + "." + extension;
|
||||||
|
if (!File.Exists(fileName)) return (null, null);
|
||||||
|
|
||||||
|
await using FileStream openStream = File.OpenRead(fileName);
|
||||||
|
return (await JsonSerializer.DeserializeAsync<T>(openStream, DefaultOptions), fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/Alma.App/Services/MetadataHandler.cs
Normal file
66
src/Alma.App/Services/MetadataHandler.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Alma.Data;
|
||||||
|
using Alma.Helper;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class MetadataHandler : IMetadataHandler
|
||||||
|
{
|
||||||
|
private const string MetadataFilename = "moduleHashes.txt";
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
|
||||||
|
public MetadataHandler(IFolderService folderService)
|
||||||
|
{
|
||||||
|
_folderService = folderService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveLinkedItemsAsync(List<ItemToLink> successfulLinks, DirectoryInfo sourceDirectory, DirectoryInfo targetDirectory)
|
||||||
|
{
|
||||||
|
var sourcePathHash = MD5Helper.GetMD5Hash(sourceDirectory.FullName);
|
||||||
|
var targetPathHash = MD5Helper.GetMD5Hash(targetDirectory.FullName);
|
||||||
|
var modulePathHash = MD5Helper.GetMD5Hash(sourcePathHash + targetPathHash);
|
||||||
|
var appDataDirectory = new DirectoryInfo(_folderService.AppData);
|
||||||
|
|
||||||
|
var moduleFolderMetadataPath = Path.Combine(appDataDirectory.FullName, modulePathHash + ".txt");
|
||||||
|
|
||||||
|
var previousData = new List<string>();
|
||||||
|
|
||||||
|
if (File.Exists(moduleFolderMetadataPath))
|
||||||
|
{
|
||||||
|
var content = await File.ReadAllLinesAsync(moduleFolderMetadataPath);
|
||||||
|
previousData.AddRange(content.Skip(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
var newContent = previousData.Concat(successfulLinks.Select(s => s.TargetPath)).Distinct();
|
||||||
|
await File.WriteAllLinesAsync(moduleFolderMetadataPath, newContent.Prepend("text"));
|
||||||
|
|
||||||
|
//TODO write md5 & path to a common file
|
||||||
|
var hashAlreadySaved = false;
|
||||||
|
|
||||||
|
var metadataFilePath = Path.Combine(_folderService.AppData, MetadataFilename);
|
||||||
|
if (File.Exists(metadataFilePath))
|
||||||
|
{
|
||||||
|
await using var metadataFileStream = File.OpenRead(metadataFilePath);
|
||||||
|
using var metadataFileStream2 = new StreamReader(metadataFileStream);
|
||||||
|
while (await metadataFileStream2.ReadLineAsync() is { } s)
|
||||||
|
{
|
||||||
|
if (!s.StartsWith(modulePathHash)) continue;
|
||||||
|
|
||||||
|
hashAlreadySaved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hashAlreadySaved)
|
||||||
|
{
|
||||||
|
var newLineContent = modulePathHash + " " + EncodePath(sourceDirectory.FullName) + " " + EncodePath(targetDirectory.FullName);
|
||||||
|
await File.AppendAllLinesAsync(metadataFilePath, new[] {newLineContent});
|
||||||
|
}
|
||||||
|
|
||||||
|
static string EncodePath(string path)
|
||||||
|
{
|
||||||
|
byte[] toEncodeAsBytes = Encoding.UTF8.GetBytes(path);
|
||||||
|
return Convert.ToBase64String(toEncodeAsBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/Alma.App/Services/ModuleConfigurationResolver.cs
Normal file
35
src/Alma.App/Services/ModuleConfigurationResolver.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Alma.Configuration.Module;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class ModuleConfigurationResolver : IModuleConfigurationResolver
|
||||||
|
{
|
||||||
|
private readonly IConfigurationFileReader _configurationFileReader;
|
||||||
|
private readonly IOsInformation _osInformation;
|
||||||
|
|
||||||
|
public ModuleConfigurationResolver(
|
||||||
|
IConfigurationFileReader configurationFileReader,
|
||||||
|
IOsInformation osInformation)
|
||||||
|
{
|
||||||
|
_configurationFileReader = configurationFileReader;
|
||||||
|
_osInformation = osInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(ModuleConfiguration? mergedModuleConfig, string? moduleConfigFileName)> ResolveModuleConfiguration(string moduleConfigStub)
|
||||||
|
{
|
||||||
|
var (moduleConfigRoot, moduleConfigFileName) = await _configurationFileReader.DeserializeAsync<ModuleConfigurationRoot>(moduleConfigStub);
|
||||||
|
|
||||||
|
if (moduleConfigRoot is null) return (null, null);
|
||||||
|
|
||||||
|
var validModuleConfigurations = moduleConfigRoot.Where(m => _osInformation.IsOnPlatform(m.Key));
|
||||||
|
|
||||||
|
//TODO: priority order
|
||||||
|
var orderedValidModuleConfigurations = new Dictionary<string, ModuleConfiguration>(validModuleConfigurations);
|
||||||
|
|
||||||
|
var mergedModuleConfig = orderedValidModuleConfigurations
|
||||||
|
.Select(m => m.Value)
|
||||||
|
.Aggregate((a, b) => a.Merge(b));
|
||||||
|
|
||||||
|
return (mergedModuleConfig, moduleConfigFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/Alma.App/Services/OsInformation.cs
Normal file
24
src/Alma.App/Services/OsInformation.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Alma.Services;
|
||||||
|
|
||||||
|
public class OsInformation : IOsInformation
|
||||||
|
{
|
||||||
|
private const string OsIdentifierDefault = "default";
|
||||||
|
private const string OsIdentifierWin = "windows";
|
||||||
|
private const string OsIdentifierLinux = "linux";
|
||||||
|
|
||||||
|
public string GetOsIdentifier()
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return OsIdentifierWin;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return OsIdentifierLinux;
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsOnPlatform(string platform)
|
||||||
|
{
|
||||||
|
if (platform == OsIdentifierDefault) return true;
|
||||||
|
return platform == GetOsIdentifier();
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/Alma.sln
Normal file
34
src/Alma.sln
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alma.Abstraction", "Alma.Abstraction\Alma.Abstraction.csproj", "{49A2563D-8D89-4B2A-A81E-39A50F5B0C25}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alma.App", "Alma.App\Alma.App.csproj", "{6FBB9920-A249-41AE-8CE2-5D2A4FF3B551}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alma", "Alma\Alma.csproj", "{23157A6F-C737-4ED4-B36B-BFE3EA31EAF1}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{49A2563D-8D89-4B2A-A81E-39A50F5B0C25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{49A2563D-8D89-4B2A-A81E-39A50F5B0C25}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{49A2563D-8D89-4B2A-A81E-39A50F5B0C25}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{49A2563D-8D89-4B2A-A81E-39A50F5B0C25}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6FBB9920-A249-41AE-8CE2-5D2A4FF3B551}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FBB9920-A249-41AE-8CE2-5D2A4FF3B551}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6FBB9920-A249-41AE-8CE2-5D2A4FF3B551}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6FBB9920-A249-41AE-8CE2-5D2A4FF3B551}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{23157A6F-C737-4ED4-B36B-BFE3EA31EAF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{23157A6F-C737-4ED4-B36B-BFE3EA31EAF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{23157A6F-C737-4ED4-B36B-BFE3EA31EAF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{23157A6F-C737-4ED4-B36B-BFE3EA31EAF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
18
src/Alma/Alma.csproj
Normal file
18
src/Alma/Alma.csproj
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Alma.App\Alma.App.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Jab" Version="0.8.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
81
src/Alma/Program.cs
Normal file
81
src/Alma/Program.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using Alma.Command;
|
||||||
|
using Alma.Command.Help;
|
||||||
|
using Alma.Command.Info;
|
||||||
|
using Alma.Command.Link;
|
||||||
|
using Alma.Command.List;
|
||||||
|
using Alma.Command.Unlink;
|
||||||
|
using Alma.Configuration.Repository;
|
||||||
|
using Alma.Services;
|
||||||
|
using Jab;
|
||||||
|
|
||||||
|
namespace Alma;
|
||||||
|
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
|
/*public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
var services = BuildServices();
|
||||||
|
|
||||||
|
var repositoryConfiguration = services.GetRequiredService<IRepositoryConfiguration>();
|
||||||
|
await repositoryConfiguration.LoadAsync();
|
||||||
|
var application = services.GetRequiredService<Application>();
|
||||||
|
|
||||||
|
await application.Run(args);
|
||||||
|
|
||||||
|
static IServiceProvider BuildServices()
|
||||||
|
{
|
||||||
|
var serviceCollection = new ServiceCollection();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<IRepositoryConfiguration, RepositoryConfiguration>();
|
||||||
|
serviceCollection.AddSingleton<IFolderService, FolderService>();
|
||||||
|
serviceCollection.AddSingleton<ConfigurationFileReader>();
|
||||||
|
serviceCollection.AddSingleton<IConfigurationFileReader, JsonConfigurationFileReader>();
|
||||||
|
serviceCollection.AddSingleton<IOsInformation, OsInformation>();
|
||||||
|
serviceCollection.AddSingleton<ICommand, LinkCommand>();
|
||||||
|
serviceCollection.AddSingleton<IModuleConfigurationResolver, ModuleConfigurationResolver>();
|
||||||
|
serviceCollection.AddSingleton<Application>();
|
||||||
|
|
||||||
|
typeof(IRepositoryConfiguration), typeof(RepositoryConfiguration)
|
||||||
|
typeof(IFolderService), typeof(FolderService)
|
||||||
|
typeof(ConfigurationFileReader)
|
||||||
|
typeof(IConfigurationFileReader), typeof(JsonConfigurationFileReader)
|
||||||
|
typeof(IOsInformation), typeof(OsInformation)
|
||||||
|
typeof(ICommand), typeof(LinkCommand)
|
||||||
|
typeof(IModuleConfigurationResolver), typeof(ModuleConfigurationResolver)
|
||||||
|
typeof(Application)
|
||||||
|
|
||||||
|
return serviceCollection.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
var services = new AlmaServiceProvider();
|
||||||
|
|
||||||
|
var repositoryConfiguration = services.GetService<IRepositoryConfiguration>();
|
||||||
|
await repositoryConfiguration.LoadAsync();
|
||||||
|
var application = services.GetService<Application>();
|
||||||
|
|
||||||
|
await application.Run(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ServiceProvider]
|
||||||
|
[Singleton(typeof(IRepositoryConfiguration), typeof(RepositoryConfiguration))]
|
||||||
|
[Singleton(typeof(IFolderService), typeof(FolderService))]
|
||||||
|
[Singleton(typeof(ConfigurationFileReader))]
|
||||||
|
[Singleton(typeof(IConfigurationFileReader), typeof(JsonConfigurationFileReader))]
|
||||||
|
[Singleton(typeof(IOsInformation), typeof(OsInformation))]
|
||||||
|
[Singleton(typeof(ICommand), typeof(LinkCommand))]
|
||||||
|
[Singleton(typeof(ICommand), typeof(UnlinkCommand))]
|
||||||
|
[Singleton(typeof(ICommand), typeof(ModuleInfoCommand))]
|
||||||
|
[Singleton(typeof(ICommand), typeof(ListCommand))]
|
||||||
|
//Dependency cycle
|
||||||
|
//[Singleton(typeof(ICommand), typeof(HelpCommand))]
|
||||||
|
[Singleton(typeof(IModuleConfigurationResolver), typeof(ModuleConfigurationResolver))]
|
||||||
|
[Singleton(typeof(IMetadataHandler), typeof(MetadataHandler))]
|
||||||
|
[Singleton(typeof(Application))]
|
||||||
|
internal partial class AlmaServiceProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user