diff --git a/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs b/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs index e07cfa2..6ef678d 100644 --- a/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs +++ b/src/Alma.Abstraction/Configuration/Module/ModuleConfiguration.cs @@ -4,6 +4,8 @@ public class ModuleConfiguration { public string? Target { get; set; } public Dictionary? Links { get; set; } + public List? Exclude { get; set; } + public bool ExcludeReadme { get; set; } = true; public string? Install { get; set; } public string? Configure { get; set; } diff --git a/src/Alma.App/Command/Link/LinkCommand.cs b/src/Alma.App/Command/Link/LinkCommand.cs index b67462f..ae9145a 100644 --- a/src/Alma.App/Command/Link/LinkCommand.cs +++ b/src/Alma.App/Command/Link/LinkCommand.cs @@ -3,6 +3,7 @@ using Alma.Configuration.Module; using Alma.Configuration.Repository; using Alma.Data; using Alma.Logging; +using Alma.Models; using Alma.Services; namespace Alma.Command.Link; @@ -35,6 +36,24 @@ public class LinkCommand : RepositoryModuleCommandBase public override async Task Run(List parameters) { + if (parameters.Contains("--help")) + { + _logger.LogInformation( + """ + Usage: + alma link [module] + alma link [repository] [module] + + Options: + --help Show this message + -d, --dry-run Show what would be linked without actually linking + """ + ); + return; + } + + var dryRun = parameters.Contains("-d") || parameters.Contains("--dry-run"); + var (repoName, moduleName) = GetRepositoryAndModuleName(parameters); if (moduleName is null) { @@ -82,14 +101,46 @@ public class LinkCommand : RepositoryModuleCommandBase moduleDir, currentTargetDirectory, moduleConfiguration)).ToList(); + + // Exclude if (moduleConfigurationFile is not null) itemsToLink.RemoveAll(i => i.SourcePath == moduleConfigurationFileFullPath); - var successfulLinks = CreateLinks(itemsToLink); + if (moduleConfiguration?.Exclude is { } excludeList) + { + foreach (var itemToExclude in excludeList) + { + var excludePath = Path.Combine(moduleDirectory, Path.Combine(itemToExclude.Split('/'))); + itemsToLink.RemoveAll( + i => i.SourcePath == excludePath + || i.SourcePath.StartsWith(excludePath + Path.DirectorySeparatorChar) + ); + } + } + + if(moduleConfiguration?.ExcludeReadme ?? false) + { + foreach (var readmeFile in Enum.GetValues()) + { + var readmeFilePath = Path.Combine(moduleDirectory, readmeFile.GetFileName()); + itemsToLink.RemoveAll(i => i.SourcePath == readmeFilePath); + } + } + + // Linking + + if (dryRun) + { + _logger.LogInformation("Dry run. No links will be created. The following links would be created:"); + } + + var successfulLinks = CreateLinks(itemsToLink, dryRun); + + if (dryRun) return; await _metadataHandler.SaveLinkedItemsAsync(successfulLinks, moduleDir, currentTargetDirectory); } - private List CreateLinks(List itemsToLink) + private List CreateLinks(List itemsToLink, bool dryRun) { var successfulLinks = new List(); @@ -108,18 +159,21 @@ public class LinkCommand : RepositoryModuleCommandBase _logger.LogInformation($"Linking: '{itemToLink.SourcePath}' '{itemToLink.TargetPath}'"); - if (sourceFileExists) + if (!dryRun) { - File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath); - } - else if (sourceDirectoryExists) - { - Directory.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath); - } - else - { - _logger.LogInformation("Source not exists: " + itemToLink.SourcePath); - continue; + if (sourceFileExists) + { + File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath); + } + else if (sourceDirectoryExists) + { + Directory.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath); + } + else + { + _logger.LogInformation("Source not exists: " + itemToLink.SourcePath); + continue; + } } successfulLinks.Add(itemToLink); diff --git a/src/Alma.App/Command/ReadMe/ReadMeCommand.cs b/src/Alma.App/Command/ReadMe/ReadMeCommand.cs index 8a7ad23..4cbf4ac 100644 --- a/src/Alma.App/Command/ReadMe/ReadMeCommand.cs +++ b/src/Alma.App/Command/ReadMe/ReadMeCommand.cs @@ -3,6 +3,7 @@ using Alma.Command.Install; using Alma.Configuration.Repository; using Alma.Logging; +using Alma.Models; using Alma.Services; namespace Alma.Command.List; @@ -15,6 +16,8 @@ public class ReadMeCommand : RepositoryModuleCommandBase public override string[] CommandAliases => Array.Empty(); + private readonly Dictionary> _readmeFilePrinters; + public ReadMeCommand( ILogger logger, IRepositoryConfiguration repositoryConfiguration, @@ -23,6 +26,13 @@ public class ReadMeCommand : RepositoryModuleCommandBase : base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver) { _logger = logger; + + _readmeFilePrinters = new Dictionary> + { + { ReadmeFiles.Markdown, PrintReadMeMd }, + { ReadmeFiles.Text, PrintReadMeText }, + { ReadmeFiles.NoExtension, PrintReadMeText }, + }; } public override async Task Run(List parameters) @@ -42,26 +52,20 @@ public class ReadMeCommand : RepositoryModuleCommandBase } var fileFound = false; - var readmeMdPath = Path.Combine(repoSource, moduleName, "README.md"); - var readmeTxtPath = Path.Combine(repoSource, moduleName, "README.md"); - var readmePath = Path.Combine(repoSource, moduleName, "README.md"); - if(File.Exists(readmeMdPath)) + + foreach (var readmeFile in _readmeFilePrinters.Keys) { - fileFound = true; - await PrintReadMeMd(readmeMdPath); - } - else if(File.Exists(readmeTxtPath)) - { - fileFound = true; - await PrintReadMeText(readmeMdPath); - } - else if(File.Exists(readmePath)) - { - fileFound = true; - await PrintReadMeText(readmePath); + // TODO: make this case insensitive + var readmeFilePath = Path.Combine(repoSource, moduleName, readmeFile.ToString()); + if (File.Exists(readmeFilePath)) + { + fileFound = true; + await _readmeFilePrinters[readmeFile](readmeFilePath); + break; + } } - if(!fileFound) + if (!fileFound) { _logger.LogInformation("No README file found. Supported formats: README.md, README.txt, README"); } @@ -70,7 +74,7 @@ public class ReadMeCommand : RepositoryModuleCommandBase private async Task PrintReadMeMd(string filePath) { var content = await File.ReadAllLinesAsync(filePath); - foreach(var line in content) + foreach (var line in content) { //TODO: Add support for markdown _logger.LogInformation(line); @@ -80,7 +84,7 @@ public class ReadMeCommand : RepositoryModuleCommandBase private async Task PrintReadMeText(string filePath) { var content = await File.ReadAllLinesAsync(filePath); - foreach(var line in content) + foreach (var line in content) { _logger.LogInformation(line); } diff --git a/src/Alma.App/Command/RepositoryModuleCommandBase.cs b/src/Alma.App/Command/RepositoryModuleCommandBase.cs index cc00ea4..96bcfb7 100644 --- a/src/Alma.App/Command/RepositoryModuleCommandBase.cs +++ b/src/Alma.App/Command/RepositoryModuleCommandBase.cs @@ -41,6 +41,8 @@ public abstract class RepositoryModuleCommandBase : ICommand string? repositoryName = null; string? moduleName = null; + parameters = parameters.Where(p => !p.StartsWith("-")).ToList(); + if (parameters.Count == 1) { if (singleParamIsRepo) diff --git a/src/Alma.App/Models/ReadmeFiles.cs b/src/Alma.App/Models/ReadmeFiles.cs new file mode 100644 index 0000000..c012a80 --- /dev/null +++ b/src/Alma.App/Models/ReadmeFiles.cs @@ -0,0 +1,20 @@ +namespace Alma.Models; + +public enum ReadmeFiles +{ + Markdown, + Text, + NoExtension +} + +public static class ReadmeFileTypeExtensions +{ + public static string GetFileName(this ReadmeFiles type) + => type switch + { + ReadmeFiles.Markdown => "README.md", + ReadmeFiles.Text => "README.txt", + ReadmeFiles.NoExtension => "README", + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; +} \ No newline at end of file