InfoCommand repo & module info

This commit is contained in:
2022-12-23 13:59:07 +01:00
parent a47f9b0826
commit 332188444a
10 changed files with 205 additions and 54 deletions

View File

@@ -7,7 +7,7 @@ public class ModuleConfiguration
public string? Install { get; set; } public string? Install { get; set; }
public string? Configure { get; set; } public string? Configure { get; set; }
public ModuleConfiguration(string? target, Dictionary<string, string>? links, string? install, string? configure) public ModuleConfiguration(string? target, Dictionary<string, string>? links, string? install, string? configure)
{ {
Target = target; Target = target;

View File

@@ -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";
}

View File

@@ -0,0 +1,5 @@
using Alma.Configuration.Module;
namespace Alma.Data;
public record ModuleConfigurationWithName(string Name, ModuleConfiguration Configuration);

View File

@@ -9,7 +9,6 @@ namespace Alma.Command.Configure;
public class ConfigureCommand : RepositoryModuleCommandBase public class ConfigureCommand : RepositoryModuleCommandBase
{ {
private readonly ILogger<InstallCommand> _logger; private readonly ILogger<InstallCommand> _logger;
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
private readonly IShellService _shellService; private readonly IShellService _shellService;
public override string CommandString => "configure"; public override string CommandString => "configure";
@@ -19,10 +18,9 @@ public class ConfigureCommand : RepositoryModuleCommandBase
IModuleConfigurationResolver moduleConfigurationResolver, IModuleConfigurationResolver moduleConfigurationResolver,
IShellService shellService, IShellService shellService,
IPathHelperService pathHelperService) IPathHelperService pathHelperService)
: base(repositoryConfiguration, pathHelperService) : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
{ {
_logger = logger; _logger = logger;
_moduleConfigurationResolver = moduleConfigurationResolver;
_shellService = shellService; _shellService = shellService;
} }
@@ -34,17 +32,7 @@ public class ConfigureCommand : RepositoryModuleCommandBase
_logger.LogInformation("No module specified"); _logger.LogInformation("No module specified");
return; return;
} }
var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName);
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);
if (moduleConfiguration is null) if (moduleConfiguration is null)
{ {

View File

@@ -1,42 +1,73 @@
using Alma.Configuration.Module;
using Alma.Configuration.Repository; using Alma.Configuration.Repository;
using Alma.Data;
using Alma.Helper; using Alma.Helper;
using Alma.Logging; using Alma.Logging;
using Alma.Services; using Alma.Services;
namespace Alma.Command.Info; 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 IFolderService _folderService;
private readonly IRepositoryConfiguration _repositoryConfiguration; private readonly IRepositoryConfiguration _repositoryConfiguration;
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
private readonly ILogger<InfoCommand> _logger; private readonly ILogger<InfoCommand> _logger;
private readonly IOsInformation _osInformation; private readonly IOsInformation _osInformation;
private readonly IVersionService _versionService; private readonly IVersionService _versionService;
private readonly IPathHelperService _pathHelperService; private readonly IPathHelperService _pathHelperService;
private static readonly List<Func<ModuleConfiguration, string?>> _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( public InfoCommand(
IFolderService folderService, IFolderService folderService,
IRepositoryConfiguration repositoryConfiguration, IRepositoryConfiguration repositoryConfiguration,
IModuleConfigurationResolver moduleConfigurationResolver,
ILogger<InfoCommand> logger, ILogger<InfoCommand> logger,
IOsInformation osInformation, IOsInformation osInformation,
IVersionService versionService, IVersionService versionService,
IPathHelperService pathHelperService IPathHelperService pathHelperService
) ) : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
{ {
_folderService = folderService; _folderService = folderService;
_repositoryConfiguration = repositoryConfiguration; _repositoryConfiguration = repositoryConfiguration;
_moduleConfigurationResolver = moduleConfigurationResolver;
_logger = logger; _logger = logger;
_osInformation = osInformation; _osInformation = osInformation;
_versionService = versionService; _versionService = versionService;
_pathHelperService = pathHelperService; _pathHelperService = pathHelperService;
} }
public async Task Run(List<string> parameters) public override async Task Run(List<string> 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("Alma " + _versionService.GetVersion());
_logger.LogInformation(""); _logger.LogInformation("");
@@ -66,6 +97,7 @@ public class InfoCommand : ICommand
{ {
Console.Write($" (containing folder not exists {repository.RepositoryPath})"); Console.Write($" (containing folder not exists {repository.RepositoryPath})");
} }
_logger.LogInformation(""); _logger.LogInformation("");
} }
} }
@@ -74,4 +106,111 @@ public class InfoCommand : ICommand
_logger.LogInformation("No repositories found"); _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<IEnumerable<ModuleConfigurationWithName>> TraverseRepoFolder(DirectoryInfo repoRoot, DirectoryInfo currentDirectory)
{
var modulesFound = Enumerable.Empty<ModuleConfigurationWithName>();
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.");
}
}
} }

View File

@@ -9,7 +9,6 @@ namespace Alma.Command.Install;
public class InstallCommand : RepositoryModuleCommandBase public class InstallCommand : RepositoryModuleCommandBase
{ {
private readonly ILogger<InstallCommand> _logger; private readonly ILogger<InstallCommand> _logger;
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
private readonly IShellService _shellService; private readonly IShellService _shellService;
public override string CommandString => "install"; public override string CommandString => "install";
@@ -19,10 +18,9 @@ public class InstallCommand : RepositoryModuleCommandBase
IModuleConfigurationResolver moduleConfigurationResolver, IModuleConfigurationResolver moduleConfigurationResolver,
IShellService shellService, IShellService shellService,
IPathHelperService pathHelperService) IPathHelperService pathHelperService)
: base(repositoryConfiguration, pathHelperService) : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
{ {
_logger = logger; _logger = logger;
_moduleConfigurationResolver = moduleConfigurationResolver;
_shellService = shellService; _shellService = shellService;
} }
@@ -34,17 +32,7 @@ public class InstallCommand : RepositoryModuleCommandBase
_logger.LogInformation("No module specified"); _logger.LogInformation("No module specified");
return; return;
} }
var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName);
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);
if (moduleConfiguration is null) if (moduleConfiguration is null)
{ {

View File

@@ -24,7 +24,7 @@ public class LinkCommand : RepositoryModuleCommandBase
IMetadataHandler metadataHandler, IMetadataHandler metadataHandler,
IPathHelperService pathHelperService, IPathHelperService pathHelperService,
ILogger<LinkCommand> logger) ILogger<LinkCommand> logger)
: base(repositoryConfiguration, pathHelperService) : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
{ {
_repositoryConfiguration = repositoryConfiguration; _repositoryConfiguration = repositoryConfiguration;
_moduleConfigurationResolver = moduleConfigurationResolver; _moduleConfigurationResolver = moduleConfigurationResolver;
@@ -42,10 +42,7 @@ public class LinkCommand : RepositoryModuleCommandBase
return; return;
} }
string sourceDirectory = Path.Combine(Environment.CurrentDirectory); var (sourceDirectory, targetDirectory) = GetRepositorySourceAndTargetDirectory(repoName);
string targetDirectory = Path.Combine(Environment.CurrentDirectory, "..");
(sourceDirectory, targetDirectory) = GetModuleSourceAndTargetDirectory(repoName, sourceDirectory, targetDirectory);
if (!Directory.Exists(sourceDirectory)) if (!Directory.Exists(sourceDirectory))
{ {

View File

@@ -1,5 +1,5 @@
using Alma.Configuration.Repository; using Alma.Configuration.Repository;
using Alma.Helper; using Alma.Data;
using Alma.Services; using Alma.Services;
namespace Alma.Command; namespace Alma.Command;
@@ -7,19 +7,33 @@ namespace Alma.Command;
public abstract class RepositoryModuleCommandBase : ICommand public abstract class RepositoryModuleCommandBase : ICommand
{ {
private readonly IRepositoryConfiguration _repositoryConfiguration; private readonly IRepositoryConfiguration _repositoryConfiguration;
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
private readonly IPathHelperService _pathHelperService; private readonly IPathHelperService _pathHelperService;
public abstract string CommandString { get; } public abstract string CommandString { get; }
public abstract Task Run(List<string> parameters); public abstract Task Run(List<string> parameters);
protected RepositoryModuleCommandBase( protected RepositoryModuleCommandBase(
IRepositoryConfiguration repositoryConfiguration, IRepositoryConfiguration repositoryConfiguration,
IPathHelperService pathHelperService) IPathHelperService pathHelperService,
IModuleConfigurationResolver moduleConfigurationResolver)
{ {
_repositoryConfiguration = repositoryConfiguration; _repositoryConfiguration = repositoryConfiguration;
_pathHelperService = pathHelperService; _pathHelperService = pathHelperService;
_moduleConfigurationResolver = moduleConfigurationResolver;
} }
protected (string?, string?) GetRepositoryAndModuleName(List<string> 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<string> parameters, bool singleParamIsRepo = false)
{ {
//TODO: handle parameters //TODO: handle parameters
string? repositoryName = null; string? repositoryName = null;
@@ -27,7 +41,14 @@ public abstract class RepositoryModuleCommandBase : ICommand
if (parameters.Count == 1) if (parameters.Count == 1)
{ {
moduleName = parameters[0]; if (singleParamIsRepo)
{
repositoryName = parameters[0];
}
else
{
moduleName = parameters[0];
}
} }
else if (parameters.Count >= 1) else if (parameters.Count >= 1)
{ {
@@ -38,10 +59,16 @@ public abstract class RepositoryModuleCommandBase : ICommand
return (repositoryName, moduleName); 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 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 = fallbackSourceDirectory =
repoConfig.RepositoryPath is { } repoPath repoConfig.RepositoryPath is { } repoPath

View File

@@ -29,6 +29,11 @@ public class ModuleConfigurationResolver : IModuleConfigurationResolver
//TODO: priority order //TODO: priority order
var orderedValidModuleConfigurations = new Dictionary<string, ModuleConfiguration>(validModuleConfigurations); var orderedValidModuleConfigurations = new Dictionary<string, ModuleConfiguration>(validModuleConfigurations);
if (orderedValidModuleConfigurations.Count == 0)
{
return (ModuleConfiguration.Empty(), moduleConfigFileName);
}
var mergedModuleConfig = orderedValidModuleConfigurations var mergedModuleConfig = orderedValidModuleConfigurations
.Select(m => m.Value) .Select(m => m.Value)
.Aggregate((a, b) => a.Merge(b)); .Aggregate((a, b) => a.Merge(b));

View File

@@ -4,7 +4,7 @@ namespace Alma.Services;
public class PathHelperService : IPathHelperService public class PathHelperService : IPathHelperService
{ {
private static List<SpecialPathResolver> _specialPathResolvers = new() private static readonly List<SpecialPathResolver> _specialPathResolvers = new()
{ {
new("~", () => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), true), new("~", () => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), true),
new("%DOCUMENTS%", () => Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)), new("%DOCUMENTS%", () => Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)),
@@ -13,12 +13,6 @@ public class PathHelperService : IPathHelperService
public string ResolvePath(string path, string? currentDirectory = null) public string ResolvePath(string path, string? currentDirectory = null)
{ {
var skipCombiningCurrentDirectory = false; 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) 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 return currentDirectory is null || skipCombiningCurrentDirectory
? path ? path