From f5f01dd100d521327f404cfb58ae2f41e9ef5b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20Kov=C3=A1cs?= Date: Fri, 23 Dec 2022 13:59:07 +0100 Subject: [PATCH] InfoCommand repo & module info --- .../Module/ModuleConfiguration.cs | 2 +- src/Alma.Abstraction/Data/ColorCodes.cs | 8 + .../Data/ModuleConfigurationWithName.cs | 5 + .../Command/Configure/ConfigureCommand.cs | 16 +- src/Alma.App/Command/Info/InfoCommand.cs | 151 +++++++++++++++++- .../Command/Install/InstallCommand.cs | 16 +- src/Alma.App/Command/Link/LinkCommand.cs | 7 +- .../Command/RepositoryModuleCommandBase.cs | 39 ++++- .../Services/ModuleConfigurationResolver.cs | 5 + src/Alma.App/Services/PathHelperService.cs | 10 +- 10 files changed, 205 insertions(+), 54 deletions(-) create mode 100644 src/Alma.Abstraction/Data/ColorCodes.cs create mode 100644 src/Alma.Abstraction/Data/ModuleConfigurationWithName.cs diff --git a/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs b/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs index ace6c92..e07cfa2 100644 --- a/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs +++ b/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs @@ -7,7 +7,7 @@ public class ModuleConfiguration public string? Install { get; set; } public string? Configure { get; set; } - + public ModuleConfiguration(string? target, Dictionary? links, string? install, string? configure) { Target = target; diff --git a/src/Alma.Abstraction/Data/ColorCodes.cs b/src/Alma.Abstraction/Data/ColorCodes.cs new file mode 100644 index 0000000..ab3264b --- /dev/null +++ b/src/Alma.Abstraction/Data/ColorCodes.cs @@ -0,0 +1,8 @@ +namespace Alma.Data; + +public static class ColorCodes +{ + public const string Reset = "\u001b[0m"; + public const string RedForeground = "\u001b[38;5;1m"; + public const string GreenForeground = "\u001b[38;5;2m"; +} \ No newline at end of file diff --git a/src/Alma.Abstraction/Data/ModuleConfigurationWithName.cs b/src/Alma.Abstraction/Data/ModuleConfigurationWithName.cs new file mode 100644 index 0000000..26cc53a --- /dev/null +++ b/src/Alma.Abstraction/Data/ModuleConfigurationWithName.cs @@ -0,0 +1,5 @@ +using Alma.Configuration.Module; + +namespace Alma.Data; + +public record ModuleConfigurationWithName(string Name, ModuleConfiguration Configuration); \ No newline at end of file diff --git a/src/Alma.App/Command/Configure/ConfigureCommand.cs b/src/Alma.App/Command/Configure/ConfigureCommand.cs index 3e80554..3e2df8f 100644 --- a/src/Alma.App/Command/Configure/ConfigureCommand.cs +++ b/src/Alma.App/Command/Configure/ConfigureCommand.cs @@ -9,7 +9,6 @@ namespace Alma.Command.Configure; public class ConfigureCommand : RepositoryModuleCommandBase { private readonly ILogger _logger; - private readonly IModuleConfigurationResolver _moduleConfigurationResolver; private readonly IShellService _shellService; public override string CommandString => "configure"; @@ -19,10 +18,9 @@ public class ConfigureCommand : RepositoryModuleCommandBase IModuleConfigurationResolver moduleConfigurationResolver, IShellService shellService, IPathHelperService pathHelperService) - : base(repositoryConfiguration, pathHelperService) + : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver) { _logger = logger; - _moduleConfigurationResolver = moduleConfigurationResolver; _shellService = shellService; } @@ -34,17 +32,7 @@ public class ConfigureCommand : RepositoryModuleCommandBase _logger.LogInformation("No module specified"); return; } - - string sourceDirectory = Path.Combine(Environment.CurrentDirectory); - string targetDirectory = Path.Combine(Environment.CurrentDirectory, ".."); - - string moduleNameAsPath = moduleName.Replace('/', Path.DirectorySeparatorChar); - (sourceDirectory, _) = GetModuleSourceAndTargetDirectory(repoName, sourceDirectory, targetDirectory); - - string moduleDirectory = Path.Combine(sourceDirectory, moduleNameAsPath); - - var moduleConfigFileStub = Path.Combine(moduleDirectory, Constants.ModuleConfigFileStub); - var (moduleConfiguration, moduleConfigurationFile) = await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub); + var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName); if (moduleConfiguration is null) { diff --git a/src/Alma.App/Command/Info/InfoCommand.cs b/src/Alma.App/Command/Info/InfoCommand.cs index 922f918..2aebd81 100644 --- a/src/Alma.App/Command/Info/InfoCommand.cs +++ b/src/Alma.App/Command/Info/InfoCommand.cs @@ -1,42 +1,73 @@ +using Alma.Configuration.Module; using Alma.Configuration.Repository; +using Alma.Data; using Alma.Helper; using Alma.Logging; using Alma.Services; namespace Alma.Command.Info; -public class InfoCommand : ICommand +public class InfoCommand : RepositoryModuleCommandBase { - public string CommandString => "info"; + public override string CommandString => "info"; private readonly IFolderService _folderService; private readonly IRepositoryConfiguration _repositoryConfiguration; + private readonly IModuleConfigurationResolver _moduleConfigurationResolver; private readonly ILogger _logger; private readonly IOsInformation _osInformation; private readonly IVersionService _versionService; private readonly IPathHelperService _pathHelperService; + private static readonly List> _moduleInfoDetailResolvers = new() + { + (m) => + { + var linkCount = m.Links?.Count ?? 0; + return linkCount.ToString().PadLeft(3) + $" link{(linkCount > 1 ? "s" : "")}".PadRight(6); + }, + (m) => m.Install is not null ? "[Install]" : null, + (m) => m.Configure is not null ? "[Configure]" : null, + }; + public InfoCommand( IFolderService folderService, IRepositoryConfiguration repositoryConfiguration, + IModuleConfigurationResolver moduleConfigurationResolver, ILogger logger, IOsInformation osInformation, IVersionService versionService, IPathHelperService pathHelperService - ) + ) : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver) { _folderService = folderService; _repositoryConfiguration = repositoryConfiguration; + _moduleConfigurationResolver = moduleConfigurationResolver; _logger = logger; _osInformation = osInformation; _versionService = versionService; _pathHelperService = pathHelperService; } - public async Task Run(List parameters) + public override async Task Run(List parameters) + { + var (repoName, moduleName) = GetRepositoryAndModuleName(parameters, true); + if (repoName is not null && moduleName is null) + { + await ProcessRepoInfoAsync(repoName); + } + else if (repoName is not null && moduleName is not null) + { + await ProcessModuleInfoAsync(repoName, moduleName); + } + else + { + await ProcessGeneralInfoAsync(); + } + } + + async Task ProcessGeneralInfoAsync() { - //Add info REPO - //Add info REPO MODULE _logger.LogInformation("Alma " + _versionService.GetVersion()); _logger.LogInformation(""); @@ -66,6 +97,7 @@ public class InfoCommand : ICommand { Console.Write($" (containing folder not exists {repository.RepositoryPath})"); } + _logger.LogInformation(""); } } @@ -74,4 +106,111 @@ public class InfoCommand : ICommand _logger.LogInformation("No repositories found"); } } + + async Task ProcessRepoInfoAsync(string repoName) + { + var (repoSourceDirectory, _) = GetRepositorySourceAndTargetDirectory(repoName); + + var repoRoot = new DirectoryInfo(repoSourceDirectory); + var modules = (await TraverseRepoFolder(repoRoot, repoRoot)).OrderBy(e => e.Name).ToList(); + + var maxNameLength = modules.Max(m => m.Name.Length); + + _logger.LogInformation($"Repository '{repoName}' contains {modules.Count} modules:"); + _logger.LogInformation(""); + + foreach (var module in modules) + { + var moduleDetails = _moduleInfoDetailResolvers + .Select(m => m(module.Configuration)) + .Where(m => m is not null) + .ToList(); + _logger.LogInformation($"{module.Name.PadRight(maxNameLength + 3)} {string.Join(" ", moduleDetails)}"); + } + } + + async Task> TraverseRepoFolder(DirectoryInfo repoRoot, DirectoryInfo currentDirectory) + { + var modulesFound = Enumerable.Empty(); + + var moduleConfigFileStub = Path.Combine(currentDirectory.FullName, Constants.ModuleConfigFileStub); + var (moduleConfig, _) = await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub); + + if (moduleConfig is not null) + { + var moduleName = currentDirectory.FullName[(repoRoot.FullName.Length + 1)..].Replace(Path.DirectorySeparatorChar, '/'); + modulesFound = modulesFound.Append(new(moduleName, moduleConfig)); + } + + foreach (var subDir in currentDirectory.GetDirectories()) + { + modulesFound = modulesFound.Concat(await TraverseRepoFolder(repoRoot, subDir)); + } + + return modulesFound; + } + + async Task ProcessModuleInfoAsync(string repoName, string moduleName) + { + var (moduleConfiguration, moduleConfigFileName) = await GetModuleConfiguration(repoName, moduleName); + + if (moduleConfiguration is null) + { + _logger.LogInformation($"No configuration is found for module '{moduleName}' in repository '{repoName}':"); + return; + } + + _logger.LogInformation($"Information about module '{moduleName}' in repository '{repoName}':"); + _logger.LogInformation(""); + + var moduleTargetPath = moduleConfiguration.Target is not null + ? _pathHelperService.ResolvePath(moduleConfiguration.Target) + : null; + + if (moduleTargetPath is not null) + { + _logger.LogInformation($"Target directory is: {moduleTargetPath}"); + _logger.LogInformation(""); + } + + if (moduleConfiguration.Install is not null) + { + _logger.LogInformation("Can be installed."); + } + + if (moduleConfiguration.Configure is not null) + { + _logger.LogInformation("Can be configured."); + } + + if (moduleConfiguration.Links is { } links && links.Count != 0) + { + var linkCount = links.Count; + _logger.LogInformation(""); + _logger.LogInformation($"Has {linkCount} link{(linkCount > 1 ? "s" : "")}:"); + _logger.LogInformation(""); + + foreach (var link in links) + { + var sourcePath = Path.Combine(new FileInfo(moduleConfigFileName!).Directory!.FullName, link.Key); + var sourceExists = File.Exists(sourcePath) || Directory.Exists(sourcePath); + var sourceColor = sourceExists ? ColorCodes.GreenForeground : ColorCodes.RedForeground; + + var targetColor = ColorCodes.RedForeground; + if (moduleTargetPath is not null) + { + var targetPath = Path.Combine(moduleTargetPath, link.Key); + var targetExists = File.Exists(targetPath) || Directory.Exists(targetPath); + + targetColor = targetExists ? ColorCodes.GreenForeground : ColorCodes.RedForeground; + } + + _logger.LogInformation($"{sourceColor}{link.Key}{ColorCodes.Reset} -> {targetColor}{link.Value}"); + } + } + else + { + _logger.LogInformation("Has no links."); + } + } } \ No newline at end of file diff --git a/src/Alma.App/Command/Install/InstallCommand.cs b/src/Alma.App/Command/Install/InstallCommand.cs index 6bbffdb..45ca05e 100644 --- a/src/Alma.App/Command/Install/InstallCommand.cs +++ b/src/Alma.App/Command/Install/InstallCommand.cs @@ -9,7 +9,6 @@ namespace Alma.Command.Install; public class InstallCommand : RepositoryModuleCommandBase { private readonly ILogger _logger; - private readonly IModuleConfigurationResolver _moduleConfigurationResolver; private readonly IShellService _shellService; public override string CommandString => "install"; @@ -19,10 +18,9 @@ public class InstallCommand : RepositoryModuleCommandBase IModuleConfigurationResolver moduleConfigurationResolver, IShellService shellService, IPathHelperService pathHelperService) - : base(repositoryConfiguration, pathHelperService) + : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver) { _logger = logger; - _moduleConfigurationResolver = moduleConfigurationResolver; _shellService = shellService; } @@ -34,17 +32,7 @@ public class InstallCommand : RepositoryModuleCommandBase _logger.LogInformation("No module specified"); return; } - - string sourceDirectory = Path.Combine(Environment.CurrentDirectory); - string targetDirectory = Path.Combine(Environment.CurrentDirectory, ".."); - - string moduleNameAsPath = moduleName.Replace('/', Path.DirectorySeparatorChar); - (sourceDirectory, _) = GetModuleSourceAndTargetDirectory(repoName, sourceDirectory, targetDirectory); - - string moduleDirectory = Path.Combine(sourceDirectory, moduleNameAsPath); - - var moduleConfigFileStub = Path.Combine(moduleDirectory, Constants.ModuleConfigFileStub); - var (moduleConfiguration, moduleConfigurationFile) = await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub); + var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName); if (moduleConfiguration is null) { diff --git a/src/Alma.App/Command/Link/LinkCommand.cs b/src/Alma.App/Command/Link/LinkCommand.cs index 1d5431f..3d6d063 100644 --- a/src/Alma.App/Command/Link/LinkCommand.cs +++ b/src/Alma.App/Command/Link/LinkCommand.cs @@ -24,7 +24,7 @@ public class LinkCommand : RepositoryModuleCommandBase IMetadataHandler metadataHandler, IPathHelperService pathHelperService, ILogger logger) - : base(repositoryConfiguration, pathHelperService) + : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver) { _repositoryConfiguration = repositoryConfiguration; _moduleConfigurationResolver = moduleConfigurationResolver; @@ -42,10 +42,7 @@ public class LinkCommand : RepositoryModuleCommandBase return; } - string sourceDirectory = Path.Combine(Environment.CurrentDirectory); - string targetDirectory = Path.Combine(Environment.CurrentDirectory, ".."); - - (sourceDirectory, targetDirectory) = GetModuleSourceAndTargetDirectory(repoName, sourceDirectory, targetDirectory); + var (sourceDirectory, targetDirectory) = GetRepositorySourceAndTargetDirectory(repoName); if (!Directory.Exists(sourceDirectory)) { diff --git a/src/Alma.App/Command/RepositoryModuleCommandBase.cs b/src/Alma.App/Command/RepositoryModuleCommandBase.cs index d7c4ac7..efb5511 100644 --- a/src/Alma.App/Command/RepositoryModuleCommandBase.cs +++ b/src/Alma.App/Command/RepositoryModuleCommandBase.cs @@ -1,5 +1,5 @@ using Alma.Configuration.Repository; -using Alma.Helper; +using Alma.Data; using Alma.Services; namespace Alma.Command; @@ -7,19 +7,33 @@ namespace Alma.Command; public abstract class RepositoryModuleCommandBase : ICommand { private readonly IRepositoryConfiguration _repositoryConfiguration; + private readonly IModuleConfigurationResolver _moduleConfigurationResolver; private readonly IPathHelperService _pathHelperService; public abstract string CommandString { get; } public abstract Task Run(List parameters); protected RepositoryModuleCommandBase( IRepositoryConfiguration repositoryConfiguration, - IPathHelperService pathHelperService) + IPathHelperService pathHelperService, + IModuleConfigurationResolver moduleConfigurationResolver) { _repositoryConfiguration = repositoryConfiguration; _pathHelperService = pathHelperService; + _moduleConfigurationResolver = moduleConfigurationResolver; } - protected (string?, string?) GetRepositoryAndModuleName(List parameters) + protected async Task<(Configuration.Module.ModuleConfiguration? mergedModuleConfig, string? moduleConfigFileName)> GetModuleConfiguration(string? repoName, string moduleName) + { + var (repoSourceDirectory, _) = GetRepositorySourceAndTargetDirectory(repoName); + + var moduleNameAsPath = moduleName.Replace('/', Path.DirectorySeparatorChar); + var moduleDirectory = Path.Combine(repoSourceDirectory, moduleNameAsPath); + + var moduleConfigFileStub = Path.Combine(moduleDirectory, Constants.ModuleConfigFileStub); + return await _moduleConfigurationResolver.ResolveModuleConfiguration(moduleConfigFileStub); + } + + protected (string? repoName, string? moduleName) GetRepositoryAndModuleName(List parameters, bool singleParamIsRepo = false) { //TODO: handle parameters string? repositoryName = null; @@ -27,7 +41,14 @@ public abstract class RepositoryModuleCommandBase : ICommand if (parameters.Count == 1) { - moduleName = parameters[0]; + if (singleParamIsRepo) + { + repositoryName = parameters[0]; + } + else + { + moduleName = parameters[0]; + } } else if (parameters.Count >= 1) { @@ -38,10 +59,16 @@ public abstract class RepositoryModuleCommandBase : ICommand return (repositoryName, moduleName); } - protected (string sourceDirectory, string targetDirectory) GetModuleSourceAndTargetDirectory(string? repoName, string fallbackSourceDirectory, string fallbackTargetDirectory) + protected (string repoSourceDirectory, string repoTargetDirectory) GetRepositorySourceAndTargetDirectory(string? repoName) + { + string repoSourceDirectory = Path.Combine(Environment.CurrentDirectory); + string repoTargetDirectory = Path.Combine(Environment.CurrentDirectory, ".."); + return GetRepositorySourceAndTargetDirectory(repoName, repoSourceDirectory, repoTargetDirectory); + } + protected (string repoSourceDirectory, string repoTargetDirectory) GetRepositorySourceAndTargetDirectory(string? repoName, string fallbackSourceDirectory, string fallbackTargetDirectory) { if (repoName is not null - && _repositoryConfiguration.Configuration.Repositories.FirstOrDefault(r => r.Name == repoName) is { } repoConfig) + && _repositoryConfiguration.Configuration.Repositories.Find(r => r.Name == repoName) is { } repoConfig) { fallbackSourceDirectory = repoConfig.RepositoryPath is { } repoPath diff --git a/src/Alma.App/Services/ModuleConfigurationResolver.cs b/src/Alma.App/Services/ModuleConfigurationResolver.cs index a08b561..604b9ec 100644 --- a/src/Alma.App/Services/ModuleConfigurationResolver.cs +++ b/src/Alma.App/Services/ModuleConfigurationResolver.cs @@ -29,6 +29,11 @@ public class ModuleConfigurationResolver : IModuleConfigurationResolver //TODO: priority order var orderedValidModuleConfigurations = new Dictionary(validModuleConfigurations); + if (orderedValidModuleConfigurations.Count == 0) + { + return (ModuleConfiguration.Empty(), moduleConfigFileName); + } + var mergedModuleConfig = orderedValidModuleConfigurations .Select(m => m.Value) .Aggregate((a, b) => a.Merge(b)); diff --git a/src/Alma.App/Services/PathHelperService.cs b/src/Alma.App/Services/PathHelperService.cs index f5a5119..f2d3617 100644 --- a/src/Alma.App/Services/PathHelperService.cs +++ b/src/Alma.App/Services/PathHelperService.cs @@ -4,7 +4,7 @@ namespace Alma.Services; public class PathHelperService : IPathHelperService { - private static List _specialPathResolvers = new() + private static readonly List _specialPathResolvers = new() { new("~", () => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), true), new("%DOCUMENTS%", () => Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)), @@ -13,12 +13,6 @@ public class PathHelperService : IPathHelperService public string ResolvePath(string path, string? currentDirectory = null) { var skipCombiningCurrentDirectory = false; - /*if (path.StartsWith("~")) - { - var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - path = path.Length > 1 ? Path.Combine(userProfile, path[2..]) : userProfile; - skipCombiningCurrentDirectory = true; - }*/ foreach (var specialPathResolver in _specialPathResolvers) { @@ -30,7 +24,7 @@ public class PathHelperService : IPathHelperService } } - //TODO: more special character + path = path.Replace('/', Path.DirectorySeparatorChar); return currentDirectory is null || skipCombiningCurrentDirectory ? path