Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 46c1a78e3f | |||
| fb381e56c5 |
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"image": "mcr.microsoft.com/dotnet/sdk:8.0-alpine"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"image": "mcr.microsoft.com/dotnet/sdk:8.0"
|
|
||||||
}
|
|
||||||
3
.devcontainer/devcontainer.json
Normal file
3
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"image": "mcr.microsoft.com/dotnet/sdk:7.0-alpine"
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
|
|
||||||
87
.github/workflows/github-actions.yml
vendored
87
.github/workflows/github-actions.yml
vendored
@@ -1,87 +0,0 @@
|
|||||||
name: Alma build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.target.runner }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- runtime: win-x64
|
|
||||||
runner: windows-latest
|
|
||||||
name: windows
|
|
||||||
outputname: Alma.exe
|
|
||||||
version_script: .scripts/versioning.ps1
|
|
||||||
- runtime: linux-x64
|
|
||||||
runner: ubuntu-latest
|
|
||||||
name: linux
|
|
||||||
outputname: Alma
|
|
||||||
version_script: .scripts/versioning.sh
|
|
||||||
- runtime: linux-musl-x64
|
|
||||||
runner: ubuntu-latest
|
|
||||||
name: linux-musl
|
|
||||||
outputname: Alma
|
|
||||||
version_script: .scripts/versioning.sh
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Setup dotnet
|
|
||||||
uses: actions/setup-dotnet@v3
|
|
||||||
with:
|
|
||||||
dotnet-version: '8.0.x'
|
|
||||||
- name: Patch version
|
|
||||||
run: ${{ matrix.target.version_script }}
|
|
||||||
continue-on-error: true
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore src/Alma
|
|
||||||
- name: Build
|
|
||||||
run: dotnet publish -c Release -p:PublishAot=true -r ${{ matrix.target.runtime }} -o app/ src/Alma
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: alma-${{ matrix.target.name }}
|
|
||||||
path: app/${{ matrix.target.outputname }}
|
|
||||||
|
|
||||||
release:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
name: Download Windows artifacts
|
|
||||||
with:
|
|
||||||
name: alma-windows
|
|
||||||
path: app/windows/
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
name: Download Linux artifacts
|
|
||||||
with:
|
|
||||||
name: alma-linux
|
|
||||||
path: app/linux/
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
name: Download Linux musl artifacts
|
|
||||||
with:
|
|
||||||
name: alma-linux
|
|
||||||
path: app/linux-musl/
|
|
||||||
|
|
||||||
- name: Create release directory
|
|
||||||
run: mkdir release
|
|
||||||
|
|
||||||
- name: Copy windows executable
|
|
||||||
run: cp app/windows/Alma.exe release/alma.exe
|
|
||||||
|
|
||||||
- name: Copy linux executable
|
|
||||||
run: cp app/linux/Alma release/alma-linux
|
|
||||||
|
|
||||||
- name: Copy linux-musl executable
|
|
||||||
run: cp app/linux-musl/Alma release/alma-linux-musl
|
|
||||||
|
|
||||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
|
||||||
name: Create release
|
|
||||||
with:
|
|
||||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
automatic_release_tag: latest
|
|
||||||
prerelease: false
|
|
||||||
draft: true
|
|
||||||
files: |
|
|
||||||
release/alma*
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
if((Get-Content env:\GITHUB_REF_TYPE) -ne "tag")
|
|
||||||
{
|
|
||||||
Return
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = (Get-Content env:\GITHUB_REF).Replace("refs/tags/v", "")
|
|
||||||
$git_sha = (Get-Content env:\GITHUB_SHA).Substring(0, 8)
|
|
||||||
|
|
||||||
Write-Host $version
|
|
||||||
Write-Host $git_sha
|
|
||||||
|
|
||||||
(Get-Content src\Alma\Alma.csproj).Replace("0.0.0", $version).Replace("development", $git_sha) | Set-Content src\Alma\Alma.csproj
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
if [ ${GITHUB_REF_TYPE} != "tag" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
version="${GITHUB_REF:11}"
|
|
||||||
git_hash="${GITHUB_SHA}"
|
|
||||||
echo $git_hash
|
|
||||||
git_hash=`expr substr $git_hash 1 8`
|
|
||||||
|
|
||||||
echo $version
|
|
||||||
echo $git_hash
|
|
||||||
|
|
||||||
sed -i "s/0.0.0/$version/g;s/development/$git_hash/g" src/Alma/Alma.csproj
|
|
||||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,8 +10,8 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/src/Alma/bin/Debug/net8.0/Alma.dll",
|
"program": "${workspaceFolder}/src/Alma/bin/Debug/net7.0/Alma.dll",
|
||||||
"args": ["link", "dotconfig", "git", "-d"],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}/src/Alma",
|
"cwd": "${workspaceFolder}/src/Alma",
|
||||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
|
|||||||
25
Dockerfile
25
Dockerfile
@@ -1,25 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine as BUILD
|
|
||||||
|
|
||||||
RUN apk add -U clang zlib-dev
|
|
||||||
WORKDIR /build
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN dotnet publish src/Alma/Alma.csproj -c Release -r linux-musl-x64 -p:PublishAot=true -o /app
|
|
||||||
|
|
||||||
FROM alpine:edge as FINAL
|
|
||||||
|
|
||||||
RUN mkdir /data
|
|
||||||
WORKDIR /data
|
|
||||||
|
|
||||||
ENV ALMA_APP_DATA_FALLBACK=/appdata
|
|
||||||
ENV ALMA_CONFIG_FALLBACK=/appconfig
|
|
||||||
|
|
||||||
RUN mkdir /appdata
|
|
||||||
RUN mkdir /appconfig
|
|
||||||
|
|
||||||
RUN apk add -U icu-libs libstdc++
|
|
||||||
|
|
||||||
COPY --from=BUILD /app/Alma /alma
|
|
||||||
|
|
||||||
ENTRYPOINT ["/alma"]
|
|
||||||
CMD ["help"]
|
|
||||||
32
README.md
32
README.md
@@ -1,32 +0,0 @@
|
|||||||
# Alma
|
|
||||||
|
|
||||||
Alma (aka Advanced Link Manager Application) is another dotfiles management tool.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
**Linux**
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo wget https://github.com/ADIX7/Alma/releases/download/latest/alma-linux -O /usr/local/bin/alma
|
|
||||||
sudo chmod +x /usr/local/bin/alma
|
|
||||||
```
|
|
||||||
|
|
||||||
**Windows**
|
|
||||||
|
|
||||||
This PowerShell command will download the alma.exe to the current folder. Move it to a folder that is in PATH.
|
|
||||||
```
|
|
||||||
Invoke-WebRequest https://github.com/ADIX7/Alma/releases/download/latest/Alma.exe -OutFile alma.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
**As a Docker tool**
|
|
||||||
|
|
||||||
You can run it with Docker/Podman. You should mount every directory (source and target too) to the same path as they are on the host.
|
|
||||||
For example, if you have your dotfiles cloned to your home folder and you have your repository.json in ~/.config/alma/repository.json, then you can run this command and the links will be correct on the host.
|
|
||||||
```
|
|
||||||
docker run --rm -it -v /home/myuser:/home/myuser -e "HOME=/home/myuser" adix7/alma:latest ...
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't have repository.json, you can set the WORKDIR (or ALMA_WORKDIR) env var to your repository. For example, if you cloned your dotfiles to ~/dotfiles, you can use this command.
|
|
||||||
```
|
|
||||||
docker run --rm -it -v /home/myuser:/home/myuser -e "WORKDIR=/home/myuser/dotfiles" adix7/alma:latest ...
|
|
||||||
```
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<RootNamespace>Alma</RootNamespace>
|
<RootNamespace>Alma</RootNamespace>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace Alma.Command;
|
|||||||
|
|
||||||
public interface ICommand
|
public interface ICommand
|
||||||
{
|
{
|
||||||
string CommandString { get; }
|
public string CommandString { get; }
|
||||||
string[] CommandAliases { get; }
|
public Task Run(List<string> parameters);
|
||||||
Task Run(List<string> parameters);
|
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,11 @@ public class ModuleConfiguration
|
|||||||
{
|
{
|
||||||
public string? Target { get; set; }
|
public string? Target { get; set; }
|
||||||
public Dictionary<string, string>? Links { get; set; }
|
public Dictionary<string, string>? Links { get; set; }
|
||||||
public List<string>? Exclude { get; set; }
|
|
||||||
public bool ExcludeReadme { get; set; } = true;
|
|
||||||
|
|
||||||
public string? Install { get; set; }
|
public ModuleConfiguration(string? target, Dictionary<string, string>? links)
|
||||||
public string? Configure { get; set; }
|
|
||||||
|
|
||||||
public ModuleConfiguration(string? target, Dictionary<string, string>? links, string? install, string? configure)
|
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
Links = links;
|
Links = links;
|
||||||
Install = install;
|
|
||||||
Configure = configure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleConfiguration Merge(ModuleConfiguration merge)
|
public ModuleConfiguration Merge(ModuleConfiguration merge)
|
||||||
@@ -24,12 +17,10 @@ public class ModuleConfiguration
|
|||||||
.Concat(merge.Links ?? new Dictionary<string, string>());
|
.Concat(merge.Links ?? new Dictionary<string, string>());
|
||||||
return new ModuleConfiguration(
|
return new ModuleConfiguration(
|
||||||
merge.Target ?? Target,
|
merge.Target ?? Target,
|
||||||
new Dictionary<string, string>(mergedLinks),
|
new Dictionary<string, string>(mergedLinks)
|
||||||
merge.Install ?? Install,
|
|
||||||
merge.Configure ?? Configure
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModuleConfiguration Empty() =>
|
public static ModuleConfiguration Empty() =>
|
||||||
new(null, new Dictionary<string, string>(), null, null);
|
new(null, new Dictionary<string, string>());
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
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";
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
using Alma.Configuration.Module;
|
|
||||||
|
|
||||||
namespace Alma.Data;
|
|
||||||
|
|
||||||
public record ModuleConfigurationWithName(string Name, ModuleConfiguration Configuration);
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace Alma.Data;
|
|
||||||
|
|
||||||
public record SpecialPathResolver(string PathName, Func<string> Resolver, bool? SkipCombiningCurrentDirectory = null);
|
|
||||||
@@ -2,6 +2,6 @@ namespace Alma.Services;
|
|||||||
|
|
||||||
public interface IOsInformation
|
public interface IOsInformation
|
||||||
{
|
{
|
||||||
Task<string> GetOsIdentifierAsync();
|
string GetOsIdentifier();
|
||||||
Task<bool> IsOnPlatformAsync(string platform);
|
bool IsOnPlatform(string platform);
|
||||||
}
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Alma.Services;
|
|
||||||
|
|
||||||
public interface IPathHelperService
|
|
||||||
{
|
|
||||||
string ResolvePath(string path, string? currentDirectory = null);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Alma.Services;
|
|
||||||
|
|
||||||
public interface IShellService
|
|
||||||
{
|
|
||||||
Task RunCommandAsync(string command);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Alma.Services;
|
|
||||||
|
|
||||||
public interface IVersionService
|
|
||||||
{
|
|
||||||
public string GetVersion();
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,8 @@
|
|||||||
<ProjectReference Include="..\Alma.Logging\Alma.Logging.csproj" />
|
<ProjectReference Include="..\Alma.Logging\Alma.Logging.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="LiteDB" Version="5.0.19" />
|
|
||||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<RootNamespace>Alma</RootNamespace>
|
<RootNamespace>Alma</RootNamespace>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Alma.Command;
|
using Alma.Command;
|
||||||
|
using Alma.Command.Help;
|
||||||
using Alma.Logging;
|
using Alma.Logging;
|
||||||
|
|
||||||
namespace Alma;
|
namespace Alma;
|
||||||
@@ -8,9 +9,9 @@ public class Application
|
|||||||
private readonly IList<ICommand> _commands;
|
private readonly IList<ICommand> _commands;
|
||||||
private readonly ILogger<Application> _logger;
|
private readonly ILogger<Application> _logger;
|
||||||
|
|
||||||
public Application(IEnumerable<ICommand> commands, ILogger<Application> logger)
|
public Application(IEnumerable<ICommand> commands, ILogger<Application> logger, ILogger<HelpCommand> helpCommandLogger)
|
||||||
{
|
{
|
||||||
_commands = commands.ToList();
|
_commands = commands.Append(new HelpCommand(() => _commands!, helpCommandLogger)).ToList();
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ public class Application
|
|||||||
|
|
||||||
var commandString = args[0];
|
var commandString = args[0];
|
||||||
|
|
||||||
var command = _commands.FirstOrDefault(c => c.CommandString == commandString || c.CommandAliases.Contains(commandString));
|
var command = _commands.FirstOrDefault(c => c.CommandString == commandString);
|
||||||
|
|
||||||
if (command is null)
|
if (command is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
using Alma.Command.Install;
|
|
||||||
using Alma.Configuration.Repository;
|
|
||||||
using Alma.Logging;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
namespace Alma.Command.Configure;
|
|
||||||
|
|
||||||
public class ConfigureCommand : RepositoryModuleCommandBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<InstallCommand> _logger;
|
|
||||||
private readonly IShellService _shellService;
|
|
||||||
public override string CommandString => "configure";
|
|
||||||
public override string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
public ConfigureCommand(
|
|
||||||
ILogger<InstallCommand> logger,
|
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver,
|
|
||||||
IShellService shellService,
|
|
||||||
IPathHelperService pathHelperService)
|
|
||||||
: base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_shellService = shellService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task Run(List<string> parameters)
|
|
||||||
{
|
|
||||||
var (repoName, moduleName) = GetRepositoryAndModuleName(parameters);
|
|
||||||
if (moduleName is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No module specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName);
|
|
||||||
|
|
||||||
if (moduleConfiguration is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"No module configuration found for module '{moduleName}'{(repoName is null ? "" : $" in repository '{repoName}'")}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var configureLines = moduleConfiguration.Configure?.Split(Environment.NewLine);
|
|
||||||
|
|
||||||
if (configureLines is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No configure command is found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Configure command: {string.Join("\n", configureLines)}");
|
|
||||||
|
|
||||||
if (configureLines.Length == 1)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Running configure command '" + configureLines[0] + "'");
|
|
||||||
await _shellService.RunCommandAsync(configureLines[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError("Multi line scripts are not currently supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using Alma.Logging;
|
|
||||||
|
|
||||||
namespace Alma.Command.Diag;
|
|
||||||
|
|
||||||
public class DiagCommand : ICommand
|
|
||||||
{
|
|
||||||
private readonly ILogger<DiagCommand> _logger;
|
|
||||||
public string CommandString => "diag";
|
|
||||||
public string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
private readonly Lazy<IReadOnlyList<MethodInfo>> _diagnosticHelpersLazy;
|
|
||||||
|
|
||||||
public DiagCommand(ILogger<DiagCommand> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_diagnosticHelpersLazy = new Lazy<IReadOnlyList<MethodInfo>>(FindDiagnosticHelpers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task Run(List<string> parameters)
|
|
||||||
{
|
|
||||||
if (parameters.Count < 1)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No diagnostic helper specified.");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var command = parameters[0];
|
|
||||||
|
|
||||||
if(command == "--help")
|
|
||||||
{
|
|
||||||
_logger.LogInformation(
|
|
||||||
"""
|
|
||||||
Usage:
|
|
||||||
diag list
|
|
||||||
diag <diag-helper>
|
|
||||||
"""
|
|
||||||
);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "list")
|
|
||||||
{
|
|
||||||
ListDiagnosticHelpers();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var diagnosticHelpers = _diagnosticHelpersLazy.Value;
|
|
||||||
|
|
||||||
var helper = diagnosticHelpers.FirstOrDefault(
|
|
||||||
h => GetDiagnosticHelper(h) is { } attr && attr.Command == command
|
|
||||||
);
|
|
||||||
|
|
||||||
if (helper is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Diagnostic helper {command} is not found.");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!helper.IsStatic)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Diagnostic helper {helper.Name} is not static.");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleHelper(helper, parameters.Skip(1));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ListDiagnosticHelpers()
|
|
||||||
{
|
|
||||||
var diagnosticHelpers = _diagnosticHelpersLazy.Value;
|
|
||||||
var commands = diagnosticHelpers
|
|
||||||
.Select(h => GetDiagnosticHelper(h)?.Command)
|
|
||||||
.OfType<string>()
|
|
||||||
.Order()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
_logger.LogInformation("Available diagnostic helpers:");
|
|
||||||
foreach (var command in commands)
|
|
||||||
{
|
|
||||||
_logger.LogInformation(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleHelper(MethodInfo helper, IEnumerable<string> parameters)
|
|
||||||
{
|
|
||||||
var helperParameters = helper.GetParameters();
|
|
||||||
var helperArguments = new object[helperParameters.Length];
|
|
||||||
for (var i = 0; i < helperParameters.Length; i++)
|
|
||||||
{
|
|
||||||
var parameterType = helperParameters[i].ParameterType;
|
|
||||||
if (parameterType == typeof(IEnumerable<string>))
|
|
||||||
{
|
|
||||||
helperArguments[i] = parameters;
|
|
||||||
}
|
|
||||||
else if (parameterType == typeof(ILogger))
|
|
||||||
{
|
|
||||||
helperArguments[i] = _logger;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Diagnostic helper {helper.Name} has wrong parameter type, could not resolve '{parameterType}'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
helper.Invoke(null, helperArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IReadOnlyList<MethodInfo> FindDiagnosticHelpers()
|
|
||||||
{
|
|
||||||
var assemblies = new[]
|
|
||||||
{
|
|
||||||
Assembly.GetExecutingAssembly(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return assemblies.SelectMany(
|
|
||||||
a =>
|
|
||||||
a
|
|
||||||
.GetTypes()
|
|
||||||
.SelectMany(t => t.GetMethods())
|
|
||||||
.Where(t => t.GetCustomAttributes(typeof(DiagnosticHelper)).Any()))
|
|
||||||
.ToList()
|
|
||||||
.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private DiagnosticHelper? GetDiagnosticHelper(MethodInfo o)
|
|
||||||
=> o.GetCustomAttributes(typeof(DiagnosticHelper)).FirstOrDefault() as DiagnosticHelper;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Alma.Command.Diag;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
|
||||||
public class DiagnosticHelper : Attribute
|
|
||||||
{
|
|
||||||
public string Command { get; }
|
|
||||||
|
|
||||||
public DiagnosticHelper(string command)
|
|
||||||
{
|
|
||||||
Command = command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,14 +9,12 @@ public class HelpCommand : ICommand
|
|||||||
|
|
||||||
public string CommandString => "help";
|
public string CommandString => "help";
|
||||||
|
|
||||||
public string[] CommandAliases { get; } = ["--help", "-h"];
|
|
||||||
|
|
||||||
public HelpCommand(
|
public HelpCommand(
|
||||||
IServiceProvider serviceProvider,
|
Func<IEnumerable<ICommand>> commandsProvider,
|
||||||
ILogger<HelpCommand> logger
|
ILogger<HelpCommand> logger
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_commandsProvider = () => (IEnumerable<ICommand>?)serviceProvider.GetService(typeof(IEnumerable<ICommand>)) ?? throw new ApplicationException();
|
_commandsProvider = commandsProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,216 +0,0 @@
|
|||||||
using Alma.Configuration.Module;
|
|
||||||
using Alma.Configuration.Repository;
|
|
||||||
using Alma.Data;
|
|
||||||
using Alma.Logging;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
namespace Alma.Command.Info;
|
|
||||||
|
|
||||||
public class InfoCommand : RepositoryModuleCommandBase
|
|
||||||
{
|
|
||||||
public override string CommandString => "info";
|
|
||||||
public override string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
private readonly IFolderService _folderService;
|
|
||||||
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
|
||||||
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
|
|
||||||
private readonly ILogger<InfoCommand> _logger;
|
|
||||||
private readonly IOsInformation _osInformation;
|
|
||||||
private readonly IVersionService _versionService;
|
|
||||||
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(
|
|
||||||
IFolderService folderService,
|
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver,
|
|
||||||
ILogger<InfoCommand> 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 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessGeneralInfoAsync()
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Alma " + _versionService.GetVersion());
|
|
||||||
_logger.LogInformation("");
|
|
||||||
|
|
||||||
_logger.LogInformation("AppData folder: " + _folderService.AppData);
|
|
||||||
|
|
||||||
if (_folderService.ConfigRoot is { } configRoot)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Configuration folder: " + configRoot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Configuration folder not exists.");
|
|
||||||
_logger.LogInformation("Preferred configuration folder is: " + Path.Combine(_folderService.GetPreferredConfigurationFolder(), _folderService.ApplicationSubfolderName));
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("");
|
|
||||||
_logger.LogInformation($"Platform is '{await _osInformation.GetOsIdentifierAsync()}'");
|
|
||||||
_logger.LogInformation("");
|
|
||||||
|
|
||||||
if (_repositoryConfiguration.Configuration.Repositories is { Count: > 0 } repositories)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Repositories:");
|
|
||||||
foreach (var repository in repositories)
|
|
||||||
{
|
|
||||||
Console.Write(repository.Name);
|
|
||||||
if (repository.RepositoryPath is not null && !Directory.Exists(_pathHelperService.ResolvePath(repository.RepositoryPath)))
|
|
||||||
{
|
|
||||||
Console.Write($" (containing folder not exists {repository.RepositoryPath})");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No repositories found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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.TrimEnd(Path.DirectorySeparatorChar).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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
64
src/Alma.App/Command/Info/ModuleInfoCommand.cs
Normal file
64
src/Alma.App/Command/Info/ModuleInfoCommand.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using Alma.Configuration.Repository;
|
||||||
|
using Alma.Logging;
|
||||||
|
using Alma.Services;
|
||||||
|
|
||||||
|
namespace Alma.Command.Info;
|
||||||
|
|
||||||
|
public class ModuleInfoCommand : ICommand
|
||||||
|
{
|
||||||
|
public string CommandString => "info";
|
||||||
|
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
||||||
|
private readonly ILogger<ModuleInfoCommand> _logger;
|
||||||
|
|
||||||
|
public ModuleInfoCommand(
|
||||||
|
IFolderService folderService,
|
||||||
|
IRepositoryConfiguration repositoryConfiguration,
|
||||||
|
ILogger<ModuleInfoCommand> logger
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_folderService = folderService;
|
||||||
|
_repositoryConfiguration = repositoryConfiguration;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Run(List<string> parameters)
|
||||||
|
{
|
||||||
|
//Add info REPO
|
||||||
|
//Add info REPO MODULE
|
||||||
|
_logger.LogInformation("AppData folder: " + _folderService.AppData);
|
||||||
|
|
||||||
|
if (_folderService.ConfigRoot is string configRoot)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Configuration folder: " + configRoot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Configuration folder not exists.");
|
||||||
|
_logger.LogInformation("Preffered configuration folder is: " + Path.Combine(_folderService.GetPreferredConfigurationFolder(), _folderService.ApplicationSubfolderName));
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("");
|
||||||
|
|
||||||
|
if (_repositoryConfiguration.Configuration.Repositories is var repositores && repositores?.Count > 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Repositories:");
|
||||||
|
foreach (var repository in repositores)
|
||||||
|
{
|
||||||
|
Console.Write(repository.Name);
|
||||||
|
if (repository.RepositoryPath is not null && !Directory.Exists(repository.RepositoryPath))
|
||||||
|
{
|
||||||
|
Console.Write($" (containing folder not exists {repository.RepositoryPath})");
|
||||||
|
}
|
||||||
|
_logger.LogInformation("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("No repositories found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
using Alma.Configuration.Repository;
|
|
||||||
using Alma.Logging;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
namespace Alma.Command.Install;
|
|
||||||
|
|
||||||
public class InstallCommand : RepositoryModuleCommandBase
|
|
||||||
{
|
|
||||||
private readonly ILogger<InstallCommand> _logger;
|
|
||||||
private readonly IShellService _shellService;
|
|
||||||
public override string CommandString => "install";
|
|
||||||
public override string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
public InstallCommand(
|
|
||||||
ILogger<InstallCommand> logger,
|
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver,
|
|
||||||
IShellService shellService,
|
|
||||||
IPathHelperService pathHelperService)
|
|
||||||
: base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_shellService = shellService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task Run(List<string> parameters)
|
|
||||||
{
|
|
||||||
var (repoName, moduleName) = GetRepositoryAndModuleName(parameters);
|
|
||||||
if (moduleName is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No module specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var (moduleConfiguration, _) = await GetModuleConfiguration(repoName, moduleName);
|
|
||||||
|
|
||||||
if (moduleConfiguration is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"No module configuration found for module '{moduleName}'{(repoName is null ? "" : $" in repository '{repoName}'")}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var installLines = moduleConfiguration.Install?.Split(Environment.NewLine);
|
|
||||||
|
|
||||||
if (installLines is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No install command is found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Install command: {string.Join("\n", installLines)}");
|
|
||||||
|
|
||||||
if (installLines.Length == 1)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Running install command '" + installLines[0] + "'");
|
|
||||||
await _shellService.RunCommandAsync(installLines[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError("Multi line scripts are not currently supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,65 +3,51 @@ using Alma.Configuration.Module;
|
|||||||
using Alma.Configuration.Repository;
|
using Alma.Configuration.Repository;
|
||||||
using Alma.Data;
|
using Alma.Data;
|
||||||
using Alma.Logging;
|
using Alma.Logging;
|
||||||
using Alma.Models;
|
|
||||||
using Alma.Services;
|
using Alma.Services;
|
||||||
|
|
||||||
namespace Alma.Command.Link;
|
namespace Alma.Command.Link;
|
||||||
|
|
||||||
public class LinkCommand : RepositoryModuleCommandBase
|
public class LinkCommand : ICommand
|
||||||
{
|
{
|
||||||
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
private readonly IRepositoryConfiguration _repositoryConfiguration;
|
||||||
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
|
private readonly IModuleConfigurationResolver _moduleConfigurationResolver;
|
||||||
private readonly IMetadataHandler _metadataHandler;
|
private readonly IMetadataHandler _metadataHandler;
|
||||||
private readonly IPathHelperService _pathHelperService;
|
|
||||||
private readonly ILogger<LinkCommand> _logger;
|
private readonly ILogger<LinkCommand> _logger;
|
||||||
|
|
||||||
public override string CommandString => "link";
|
public string CommandString => "link";
|
||||||
public override string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
public LinkCommand(
|
public LinkCommand(
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
IRepositoryConfiguration repositoryConfiguration,
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver,
|
IModuleConfigurationResolver moduleConfigurationResolver,
|
||||||
IMetadataHandler metadataHandler,
|
IMetadataHandler metadataHandler,
|
||||||
IPathHelperService pathHelperService,
|
|
||||||
ILogger<LinkCommand> logger)
|
ILogger<LinkCommand> logger)
|
||||||
: base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
|
|
||||||
{
|
{
|
||||||
_repositoryConfiguration = repositoryConfiguration;
|
_repositoryConfiguration = repositoryConfiguration;
|
||||||
_moduleConfigurationResolver = moduleConfigurationResolver;
|
_moduleConfigurationResolver = moduleConfigurationResolver;
|
||||||
_metadataHandler = metadataHandler;
|
_metadataHandler = metadataHandler;
|
||||||
_pathHelperService = pathHelperService;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Run(List<string> parameters)
|
public async Task Run(List<string> parameters)
|
||||||
{
|
{
|
||||||
if (parameters.Contains("--help"))
|
if (parameters.Count == 0)
|
||||||
{
|
|
||||||
_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)
|
|
||||||
{
|
{
|
||||||
_logger.LogInformation("No module specified");
|
_logger.LogInformation("No module specified");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (sourceDirectory, targetDirectory) = GetRepositorySourceAndTargetDirectory(repoName);
|
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))
|
if (!Directory.Exists(sourceDirectory))
|
||||||
{
|
{
|
||||||
@@ -83,7 +69,7 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
|
|
||||||
if (moduleConfiguration?.Target is string moduleTargetDir)
|
if (moduleConfiguration?.Target is string moduleTargetDir)
|
||||||
{
|
{
|
||||||
targetDirectory = _pathHelperService.ResolvePath(moduleTargetDir, targetDirectory);
|
targetDirectory = ResolvePath(moduleTargetDir, targetDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Directory.Exists(targetDirectory))
|
if (!Directory.Exists(targetDirectory))
|
||||||
@@ -101,46 +87,14 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
moduleDir,
|
moduleDir,
|
||||||
currentTargetDirectory,
|
currentTargetDirectory,
|
||||||
moduleConfiguration)).ToList();
|
moduleConfiguration)).ToList();
|
||||||
|
|
||||||
// Exclude
|
|
||||||
if (moduleConfigurationFile is not null) itemsToLink.RemoveAll(i => i.SourcePath == moduleConfigurationFileFullPath);
|
if (moduleConfigurationFile is not null) itemsToLink.RemoveAll(i => i.SourcePath == moduleConfigurationFileFullPath);
|
||||||
|
|
||||||
if (moduleConfiguration?.Exclude is { } excludeList)
|
var successfulLinks = CreateLinks(itemsToLink);
|
||||||
{
|
|
||||||
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<ReadmeFiles>())
|
|
||||||
{
|
|
||||||
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);
|
await _metadataHandler.SaveLinkedItemsAsync(successfulLinks, moduleDir, currentTargetDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ItemToLink> CreateLinks(List<ItemToLink> itemsToLink, bool dryRun)
|
private List<ItemToLink> CreateLinks(List<ItemToLink> itemsToLink)
|
||||||
{
|
{
|
||||||
var successfulLinks = new List<ItemToLink>();
|
var successfulLinks = new List<ItemToLink>();
|
||||||
|
|
||||||
@@ -159,8 +113,6 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
|
|
||||||
_logger.LogInformation($"Linking: '{itemToLink.SourcePath}' '{itemToLink.TargetPath}'");
|
_logger.LogInformation($"Linking: '{itemToLink.SourcePath}' '{itemToLink.TargetPath}'");
|
||||||
|
|
||||||
if (!dryRun)
|
|
||||||
{
|
|
||||||
if (sourceFileExists)
|
if (sourceFileExists)
|
||||||
{
|
{
|
||||||
File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath);
|
File.CreateSymbolicLink(itemToLink.TargetPath, itemToLink.SourcePath);
|
||||||
@@ -174,7 +126,6 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
_logger.LogInformation("Source not exists: " + itemToLink.SourcePath);
|
_logger.LogInformation("Source not exists: " + itemToLink.SourcePath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
successfulLinks.Add(itemToLink);
|
successfulLinks.Add(itemToLink);
|
||||||
}
|
}
|
||||||
@@ -184,7 +135,7 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
_logger.LogInformation("An error occured while creating links: " + e.Message);
|
_logger.LogInformation("An error occured while creating links: " + e.Message);
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("On Windows symlinks can be created only with Administrator privileges.");
|
_logger.LogInformation("On Windows symlinks can be greated only with Administrator privileges.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,14 +152,7 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
var filesToLink = new List<ItemToLink>();
|
var filesToLink = new List<ItemToLink>();
|
||||||
foreach (var file in currentDirectory.GetFiles())
|
foreach (var file in currentDirectory.GetFiles())
|
||||||
{
|
{
|
||||||
if (moduleConfiguration?.Links?.ContainsKey(file.Name) ?? false)
|
filesToLink.Add(new ItemToLink(Path.Combine(currentDirectory.FullName, file.Name), Path.Combine(currentTargetDirectory.FullName, file.Name)));
|
||||||
{
|
|
||||||
filesToLink.Add(new ItemToLink(file.FullName, _pathHelperService.ResolvePath(moduleConfiguration.Links[file.Name], targetDirectory.FullName)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filesToLink.Add(new ItemToLink(file.FullName, Path.Combine(currentTargetDirectory.FullName, file.Name)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var subDirLinksToAdd = Enumerable.Empty<ItemToLink>();
|
var subDirLinksToAdd = Enumerable.Empty<ItemToLink>();
|
||||||
@@ -218,7 +162,7 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
var relativePath = GetRelativePath(subDir.FullName, moduleDirectory.FullName);
|
var relativePath = GetRelativePath(subDir.FullName, moduleDirectory.FullName);
|
||||||
if (moduleConfiguration?.Links?.ContainsKey(relativePath) ?? false)
|
if (moduleConfiguration?.Links?.ContainsKey(relativePath) ?? false)
|
||||||
{
|
{
|
||||||
filesToLink.Add(new ItemToLink(subDir.FullName, _pathHelperService.ResolvePath(moduleConfiguration.Links[relativePath], targetDirectory.FullName)));
|
filesToLink.Add(new ItemToLink(subDir.FullName, ResolvePath(moduleConfiguration.Links[relativePath], targetDirectory.FullName)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -236,5 +180,24 @@ public class LinkCommand : RepositoryModuleCommandBase
|
|||||||
return filesToLink.Concat(subDirLinksToAdd);
|
return filesToLink.Concat(subDirLinksToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetRelativePath(string full, string parent) => full[parent.Length..].TrimStart(Path.DirectorySeparatorChar);
|
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);
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,6 @@ public class ListCommand : ICommand
|
|||||||
private readonly ILogger<ListCommand> _logger;
|
private readonly ILogger<ListCommand> _logger;
|
||||||
|
|
||||||
public string CommandString => "ls";
|
public string CommandString => "ls";
|
||||||
public string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
public ListCommand(
|
public ListCommand(
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
IRepositoryConfiguration repositoryConfiguration,
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
using Alma.Command.Install;
|
|
||||||
using Alma.Configuration.Repository;
|
|
||||||
using Alma.Logging;
|
|
||||||
using Alma.Models;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
namespace Alma.Command.List;
|
|
||||||
|
|
||||||
public class ReadMeCommand : RepositoryModuleCommandBase
|
|
||||||
{
|
|
||||||
private ILogger<InstallCommand> _logger;
|
|
||||||
|
|
||||||
public override string CommandString => "readme";
|
|
||||||
|
|
||||||
public override string[] CommandAliases => Array.Empty<string>();
|
|
||||||
|
|
||||||
private readonly Dictionary<ReadmeFiles, Func<string, Task>> _readmeFilePrinters;
|
|
||||||
|
|
||||||
public ReadMeCommand(
|
|
||||||
ILogger<InstallCommand> logger,
|
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver,
|
|
||||||
IPathHelperService pathHelperService)
|
|
||||||
: base(repositoryConfiguration, pathHelperService, moduleConfigurationResolver)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
|
|
||||||
_readmeFilePrinters = new Dictionary<ReadmeFiles, Func<string, Task>>
|
|
||||||
{
|
|
||||||
{ ReadmeFiles.Markdown, PrintReadMeMd },
|
|
||||||
{ ReadmeFiles.Text, PrintReadMeText },
|
|
||||||
{ ReadmeFiles.NoExtension, PrintReadMeText },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task Run(List<string> parameters)
|
|
||||||
{
|
|
||||||
var (repoName, moduleName) = GetRepositoryAndModuleName(parameters);
|
|
||||||
if (moduleName is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No module specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var (repoSource, _) = GetRepositorySourceAndTargetDirectory(repoName);
|
|
||||||
if (repoSource is null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No repository source found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileFound = false;
|
|
||||||
|
|
||||||
foreach (var readmeFile in _readmeFilePrinters.Keys)
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No README file found. Supported formats: README.md, README.txt, README");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PrintReadMeMd(string filePath)
|
|
||||||
{
|
|
||||||
var content = await File.ReadAllLinesAsync(filePath);
|
|
||||||
foreach (var line in content)
|
|
||||||
{
|
|
||||||
//TODO: Add support for markdown
|
|
||||||
_logger.LogInformation(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PrintReadMeText(string filePath)
|
|
||||||
{
|
|
||||||
var content = await File.ReadAllLinesAsync(filePath);
|
|
||||||
foreach (var line in content)
|
|
||||||
{
|
|
||||||
_logger.LogInformation(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
using Alma.Configuration.Repository;
|
|
||||||
using Alma.Data;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
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 string[] CommandAliases { get; }
|
|
||||||
|
|
||||||
public abstract Task Run(List<string> parameters);
|
|
||||||
|
|
||||||
protected RepositoryModuleCommandBase(
|
|
||||||
IRepositoryConfiguration repositoryConfiguration,
|
|
||||||
IPathHelperService pathHelperService,
|
|
||||||
IModuleConfigurationResolver moduleConfigurationResolver)
|
|
||||||
{
|
|
||||||
_repositoryConfiguration = repositoryConfiguration;
|
|
||||||
_pathHelperService = pathHelperService;
|
|
||||||
_moduleConfigurationResolver = moduleConfigurationResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
string? repositoryName = null;
|
|
||||||
string? moduleName = null;
|
|
||||||
|
|
||||||
parameters = parameters.Where(p => !p.StartsWith("-")).ToList();
|
|
||||||
|
|
||||||
if (parameters.Count == 1)
|
|
||||||
{
|
|
||||||
if (singleParamIsRepo)
|
|
||||||
{
|
|
||||||
repositoryName = parameters[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
moduleName = parameters[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parameters.Count >= 1)
|
|
||||||
{
|
|
||||||
repositoryName = parameters[0];
|
|
||||||
moduleName = parameters[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (repositoryName, moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Find(r => r.Name == repoName) is { } repoConfig)
|
|
||||||
{
|
|
||||||
fallbackSourceDirectory =
|
|
||||||
repoConfig.RepositoryPath is { } repoPath
|
|
||||||
? _pathHelperService.ResolvePath(repoPath)
|
|
||||||
: fallbackSourceDirectory;
|
|
||||||
fallbackTargetDirectory =
|
|
||||||
repoConfig.LinkPath is { } linkPath
|
|
||||||
? _pathHelperService.ResolvePath(linkPath)
|
|
||||||
: fallbackTargetDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fallbackSourceDirectory, fallbackTargetDirectory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ namespace Alma.Command.Unlink;
|
|||||||
public class UnlinkCommand : ICommand
|
public class UnlinkCommand : ICommand
|
||||||
{
|
{
|
||||||
public string CommandString => "unlink";
|
public string CommandString => "unlink";
|
||||||
public string[] CommandAliases => Array.Empty<string>();
|
|
||||||
public Task Run(List<string> parameters)
|
public Task Run(List<string> parameters)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
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)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -19,14 +19,7 @@ public class ConfigurationFileReader
|
|||||||
{
|
{
|
||||||
foreach (var configurationFileReader in _configurationFileReaders)
|
foreach (var configurationFileReader in _configurationFileReaders)
|
||||||
{
|
{
|
||||||
if (await configurationFileReader.DeserializeAsync<T>(
|
if (await configurationFileReader.DeserializeAsync<T>(fileNameWithoutExtension, contextGenerator, extension) is { Result: { } } result) return result;
|
||||||
fileNameWithoutExtension,
|
|
||||||
contextGenerator,
|
|
||||||
extension) is { Result: { } } result
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (null, null);
|
return (null, null);
|
||||||
|
|||||||
@@ -1,70 +1,47 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Alma.Command.Diag;
|
|
||||||
using Alma.Logging;
|
|
||||||
|
|
||||||
namespace Alma.Services;
|
namespace Alma.Services;
|
||||||
|
|
||||||
public class FolderService : IFolderService
|
public class FolderService : IFolderService
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, Func<string?>> _configHomeProviders;
|
|
||||||
private readonly Dictionary<string, Func<string?>> _appDataProviders;
|
|
||||||
public string? ConfigRoot { get; }
|
public string? ConfigRoot { get; }
|
||||||
public string AppData { get; }
|
public string AppData { get; }
|
||||||
|
|
||||||
public string ApplicationSubfolderName => "alma";
|
public string ApplicationSubfolderName => "alma";
|
||||||
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(FolderService))]
|
|
||||||
public FolderService()
|
public FolderService()
|
||||||
{
|
{
|
||||||
_configHomeProviders = ConfigHomeProviders();
|
|
||||||
_appDataProviders = AppDataProviders();
|
|
||||||
|
|
||||||
ConfigRoot = GetConfigHomePath();
|
ConfigRoot = GetConfigHomePath();
|
||||||
AppData = GetAppDataPath();
|
AppData = GetAppDataPath();
|
||||||
|
|
||||||
if (!Directory.Exists(AppData)) Directory.CreateDirectory(AppData);
|
if (!Directory.Exists(AppData)) Directory.CreateDirectory(AppData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, Func<string?>> ConfigHomeProviders()
|
public string GetPreferredConfigurationFolder()
|
||||||
{
|
|
||||||
return new Dictionary<string, Func<string?>>
|
|
||||||
{
|
|
||||||
{"ALMA_CONFIG", () => Environment.GetEnvironmentVariable("ALMA_CONFIG")},
|
|
||||||
{"XDG_CONFIG_HOME", () => Environment.GetEnvironmentVariable("XDG_CONFIG_HOME")},
|
|
||||||
{"UserProfile", GetPreferredConfigurationFolder},
|
|
||||||
{"ALMA_CONFIG_FALLBACK", () => Environment.GetEnvironmentVariable("ALMA_CONFIG_FALLBACK")},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, Func<string?>> AppDataProviders()
|
|
||||||
{
|
|
||||||
return new Dictionary<string, Func<string?>>
|
|
||||||
{
|
|
||||||
{"ALMA_APP_DATA", () => Environment.GetEnvironmentVariable("ALMA_APP_DATA")},
|
|
||||||
{"LocalApplicationData", () => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)},
|
|
||||||
{"ALMA_APP_DATA_FALLBACK", () => Environment.GetEnvironmentVariable("ALMA_APP_DATA_FALLBACK")},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
string IFolderService.GetPreferredConfigurationFolder()
|
|
||||||
=> GetPreferredConfigurationFolder();
|
|
||||||
|
|
||||||
public static string GetPreferredConfigurationFolder()
|
|
||||||
=> Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config");
|
=> Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config");
|
||||||
|
|
||||||
private string? GetConfigHomePath()
|
private string? GetConfigHomePath()
|
||||||
{
|
{
|
||||||
var configHome = EnumerateProviders(_configHomeProviders.Values);
|
var configHomeProviders = new List<Func<string?>>
|
||||||
|
{
|
||||||
|
() => Environment.GetEnvironmentVariable("XDG_CONFIG_HOME"),
|
||||||
|
() => GetPreferredConfigurationFolder()
|
||||||
|
};
|
||||||
|
|
||||||
|
var configHome = EnumerateProviders(configHomeProviders);
|
||||||
return configHome == null ? null : Path.Combine(configHome, ApplicationSubfolderName);
|
return configHome == null ? null : Path.Combine(configHome, ApplicationSubfolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAppDataPath()
|
private string GetAppDataPath()
|
||||||
{
|
{
|
||||||
var appData = EnumerateProviders(_appDataProviders.Values) ?? Environment.CurrentDirectory;
|
var appDataProviders = new List<Func<string?>>
|
||||||
|
{
|
||||||
|
() => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
|
||||||
|
};
|
||||||
|
|
||||||
|
var appData = EnumerateProviders(appDataProviders) ?? Environment.CurrentDirectory;
|
||||||
return Path.Combine(appData, ApplicationSubfolderName);
|
return Path.Combine(appData, ApplicationSubfolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? EnumerateProviders(IEnumerable<Func<string?>> providers)
|
private static string? EnumerateProviders(List<Func<string?>> providers)
|
||||||
{
|
{
|
||||||
string? result = null;
|
string? result = null;
|
||||||
|
|
||||||
@@ -76,26 +53,4 @@ public class FolderService : IFolderService
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DiagnosticHelper("config-home-providers")]
|
|
||||||
public static void ConfigHomeProviderDiag(ILogger logger)
|
|
||||||
{
|
|
||||||
var configHomeProviders = ConfigHomeProviders();
|
|
||||||
logger.LogInformation($"There are {configHomeProviders.Count} config home providers:");
|
|
||||||
foreach (var configHome in configHomeProviders)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"{configHome.Key} => {configHome.Value() ?? "<null>"}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DiagnosticHelper("app-data-providers")]
|
|
||||||
public static void AppDataProviderDiag(ILogger logger)
|
|
||||||
{
|
|
||||||
var appDataProviders = AppDataProviders();
|
|
||||||
logger.LogInformation($"There are {appDataProviders.Count} app data providers:");
|
|
||||||
foreach (var appData in appDataProviders)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"{appData.Key} => {appData.Value() ?? "<null>"}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -17,12 +17,6 @@ public class JsonConfigurationFileReader : IConfigurationFileReader
|
|||||||
if (!File.Exists(fileName)) return (null, null);
|
if (!File.Exists(fileName)) return (null, null);
|
||||||
|
|
||||||
await using FileStream openStream = File.OpenRead(fileName);
|
await using FileStream openStream = File.OpenRead(fileName);
|
||||||
var result =
|
return ((T?)await JsonSerializer.DeserializeAsync(openStream, typeof(T), contextGenerator(new JsonSerializerOptions(DefaultOptions))), fileName);
|
||||||
(T?)await JsonSerializer.DeserializeAsync(
|
|
||||||
openStream,
|
|
||||||
typeof(T),
|
|
||||||
contextGenerator(new JsonSerializerOptions(DefaultOptions))
|
|
||||||
);
|
|
||||||
return (result, fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,19 +21,11 @@ public class ModuleConfigurationResolver : IModuleConfigurationResolver
|
|||||||
|
|
||||||
if (moduleConfigRoot is null) return (null, null);
|
if (moduleConfigRoot is null) return (null, null);
|
||||||
|
|
||||||
var validModuleConfigurations = await moduleConfigRoot
|
var validModuleConfigurations = moduleConfigRoot.Where(m => _osInformation.IsOnPlatform(m.Key));
|
||||||
.ToAsyncEnumerable()
|
|
||||||
.WhereAwait(async m => await _osInformation.IsOnPlatformAsync(m.Key))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
//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));
|
||||||
|
|||||||
@@ -6,52 +6,19 @@ public class OsInformation : IOsInformation
|
|||||||
{
|
{
|
||||||
private const string OsIdentifierDefault = "default";
|
private const string OsIdentifierDefault = "default";
|
||||||
private const string OsIdentifierWin = "windows";
|
private const string OsIdentifierWin = "windows";
|
||||||
private const string OsIdentifierMac = "macos";
|
|
||||||
private const string OsIdentifierFreeBsd = "freebsd";
|
|
||||||
private const string OsIdentifierLinux = "linux";
|
private const string OsIdentifierLinux = "linux";
|
||||||
|
|
||||||
private const string LinuxOsRelease = "/etc/os-release";
|
public string GetOsIdentifier()
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return OsIdentifierWin;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return OsIdentifierLinux;
|
||||||
|
|
||||||
public async Task<string> GetOsIdentifierAsync()
|
|
||||||
{
|
|
||||||
string? baseOsIdentifier = null;
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) baseOsIdentifier = OsIdentifierWin;
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) baseOsIdentifier = OsIdentifierMac;
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) baseOsIdentifier = OsIdentifierFreeBsd;
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
||||||
{
|
|
||||||
baseOsIdentifier = OsIdentifierLinux;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(LinuxOsRelease))
|
|
||||||
{
|
|
||||||
var lines = await File.ReadAllLinesAsync(LinuxOsRelease);
|
|
||||||
var distroName = lines.FirstOrDefault(l => l.StartsWith("id=", StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
if (distroName is not null)
|
|
||||||
{
|
|
||||||
distroName = distroName.ToLower().Substring(distroName.IndexOf("=", StringComparison.Ordinal) + 1);
|
|
||||||
|
|
||||||
baseOsIdentifier += "-" + distroName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseOsIdentifier is null)
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
|
|
||||||
var architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLower();
|
|
||||||
|
|
||||||
return baseOsIdentifier + "-" + architecture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> IsOnPlatformAsync(string platform)
|
public bool IsOnPlatform(string platform)
|
||||||
{
|
{
|
||||||
return platform == OsIdentifierDefault
|
if (platform == OsIdentifierDefault) return true;
|
||||||
|| (await GetOsIdentifierAsync()).StartsWith(platform, StringComparison.InvariantCultureIgnoreCase);
|
return platform == GetOsIdentifier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Alma.Command.Diag;
|
|
||||||
using Alma.Data;
|
|
||||||
using Alma.Logging;
|
|
||||||
|
|
||||||
namespace Alma.Services;
|
|
||||||
|
|
||||||
public class PathHelperService : IPathHelperService
|
|
||||||
{
|
|
||||||
private static readonly List<SpecialPathResolver> _specialPathResolvers = new()
|
|
||||||
{
|
|
||||||
new("~", () => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), true),
|
|
||||||
new("%DOCUMENTS%", () => Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)),
|
|
||||||
};
|
|
||||||
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PathHelperService))]
|
|
||||||
public string ResolvePath(string path, string? currentDirectory = null)
|
|
||||||
{
|
|
||||||
var skipCombiningCurrentDirectory = false;
|
|
||||||
|
|
||||||
foreach (var specialPathResolver in _specialPathResolvers)
|
|
||||||
{
|
|
||||||
if (path.Contains(specialPathResolver.PathName))
|
|
||||||
{
|
|
||||||
var parts = path.Split(specialPathResolver.PathName);
|
|
||||||
path = string.Join(specialPathResolver.Resolver(), parts);
|
|
||||||
skipCombiningCurrentDirectory = (specialPathResolver.SkipCombiningCurrentDirectory ?? false) || skipCombiningCurrentDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path = path.Replace('/', Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
return currentDirectory is null || skipCombiningCurrentDirectory
|
|
||||||
? path
|
|
||||||
: Path.Combine(currentDirectory, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DiagnosticHelper("special-path-resolver")]
|
|
||||||
public static void SpecialPathResolverDiag(ILogger logger)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"There are {_specialPathResolvers.Count} special path resolvers:");
|
|
||||||
foreach (var specialPathResolver in _specialPathResolvers)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"{specialPathResolver.PathName} => {specialPathResolver.Resolver()}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Alma.Logging;
|
|
||||||
|
|
||||||
namespace Alma.Services;
|
|
||||||
|
|
||||||
public class ShellService : IShellService
|
|
||||||
{
|
|
||||||
private readonly ILogger<ShellService> _logger;
|
|
||||||
|
|
||||||
public ShellService(ILogger<ShellService> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RunCommandAsync(string command)
|
|
||||||
{
|
|
||||||
Process? process;
|
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
||||||
{
|
|
||||||
process = CreateLinuxShell(command);
|
|
||||||
}
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
process = CreateWindowsShell(command);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError("Platform not supported");
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.Start()) return;
|
|
||||||
|
|
||||||
var reader = process.StandardOutput;
|
|
||||||
while (!reader.EndOfStream)
|
|
||||||
{
|
|
||||||
var content = await reader.ReadLineAsync();
|
|
||||||
|
|
||||||
if (content is not null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await process.WaitForExitAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Process CreateLinuxShell(string command)
|
|
||||||
{
|
|
||||||
var processStartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "sh",
|
|
||||||
ArgumentList = {"-c", command},
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardInput = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
UseShellExecute = false
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Process {StartInfo = processStartInfo};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Process CreateWindowsShell(string command)
|
|
||||||
{
|
|
||||||
var processStartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
//TODO: customizable shell
|
|
||||||
FileName = "pwsh",
|
|
||||||
ArgumentList = {"-c", command},
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardInput = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
UseShellExecute = false
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Process {StartInfo = processStartInfo};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
namespace Alma.Logging;
|
namespace Alma.Logging;
|
||||||
|
|
||||||
public interface ILogger
|
public interface ILogger<T>
|
||||||
{
|
{
|
||||||
LogLevel DefaultLogLevel { get; }
|
LogLevel DefaultLogLevel { get; }
|
||||||
void LogInformation(string logMessage);
|
void LogInformation(string logMessage);
|
||||||
void LogDebug(string logMessage);
|
void LogDebug(string logMessage);
|
||||||
void LogTrace(string logMessage);
|
void LogTrace(string logMessage);
|
||||||
void Log(string logMessage, LogLevel logLevel);
|
void Log(string logMessage, LogLevel logLevel);
|
||||||
void LogError(string logMessage);
|
|
||||||
void LogCritical(string logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ILogger<T> : ILogger
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,5 @@
|
|||||||
public interface ILoggerFactory
|
public interface ILoggerFactory
|
||||||
{
|
{
|
||||||
ILogger<T> CreateLogger<T>();
|
ILogger<T> CreateLogger<T>();
|
||||||
ILogger CreateLogger(Type t);
|
|
||||||
LogLevel DefaultLogLevel { get; }
|
LogLevel DefaultLogLevel { get; }
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
Critical,
|
|
||||||
Error,
|
|
||||||
Information,
|
Information,
|
||||||
Debug,
|
Debug,
|
||||||
Trace
|
Trace
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
namespace Alma.Logging;
|
namespace Alma.Logging;
|
||||||
|
|
||||||
|
public class Logger<T> : ILogger<T>
|
||||||
public class Logger : ILogger
|
|
||||||
{
|
{
|
||||||
public LogLevel DefaultLogLevel { get; }
|
public LogLevel DefaultLogLevel { get; }
|
||||||
|
|
||||||
public Logger(LogLevel defaultLogLevel, string topicName)
|
public Logger(LogLevel defaultLogLevel)
|
||||||
{
|
{
|
||||||
DefaultLogLevel = defaultLogLevel;
|
DefaultLogLevel = defaultLogLevel;
|
||||||
}
|
}
|
||||||
@@ -23,22 +22,4 @@ public class Logger : ILogger
|
|||||||
Console.WriteLine(s);
|
Console.WriteLine(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogError(string logMessage)
|
|
||||||
{
|
|
||||||
Log(logMessage, LogLevel.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogCritical(string logMessage)
|
|
||||||
{
|
|
||||||
Log(logMessage, LogLevel.Critical);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Logger<T> : Logger, ILogger<T>
|
|
||||||
{
|
|
||||||
public Logger(LogLevel defaultLogLevel) : base(defaultLogLevel, typeof(T).Name)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -13,9 +13,4 @@ public class LoggerFactory : ILoggerFactory
|
|||||||
{
|
{
|
||||||
return new Logger<T>(DefaultLogLevel);
|
return new Logger<T>(DefaultLogLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILogger CreateLogger(Type t)
|
|
||||||
{
|
|
||||||
return new Logger(DefaultLogLevel, t.Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,16 +6,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Jab" Version="0.10.2" />
|
<PackageReference Include="Jab" Version="0.8.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<VersionPrefix>0.0.5</VersionPrefix>
|
|
||||||
<VersionSuffix>development</VersionSuffix>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using Alma.Command;
|
using Alma.Command;
|
||||||
using Alma.Command.Configure;
|
|
||||||
using Alma.Command.Diag;
|
|
||||||
using Alma.Command.Help;
|
|
||||||
using Alma.Command.Info;
|
using Alma.Command.Info;
|
||||||
using Alma.Command.Install;
|
|
||||||
using Alma.Command.Link;
|
using Alma.Command.Link;
|
||||||
using Alma.Command.List;
|
using Alma.Command.List;
|
||||||
using Alma.Command.Unlink;
|
using Alma.Command.Unlink;
|
||||||
@@ -16,18 +12,46 @@ namespace Alma;
|
|||||||
|
|
||||||
public static class Program
|
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)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
InitLogging();
|
InitLogging();
|
||||||
|
|
||||||
var logger = AlmaLoggerFactory.CreateLogger(typeof(Program));
|
|
||||||
|
|
||||||
var workdir = GetWorkdir(logger);
|
|
||||||
if (workdir != null)
|
|
||||||
{
|
|
||||||
Environment.CurrentDirectory = workdir;
|
|
||||||
}
|
|
||||||
|
|
||||||
var services = new AlmaServiceProvider();
|
var services = new AlmaServiceProvider();
|
||||||
|
|
||||||
var repositoryConfiguration = services.GetService<IRepositoryConfiguration>();
|
var repositoryConfiguration = services.GetService<IRepositoryConfiguration>();
|
||||||
@@ -37,39 +61,14 @@ public static class Program
|
|||||||
await application.Run(args);
|
await application.Run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? GetWorkdir(ILogger logger)
|
private static ILoggerFactory InitLogging()
|
||||||
{
|
{
|
||||||
var workdirProviders = new Dictionary<string, Func<string?>>
|
var loggerFactory = new LoggerFactory();
|
||||||
{
|
|
||||||
{"ALMA_WORKDIR", () => Environment.GetEnvironmentVariable("ALMA_WORKDIR")},
|
|
||||||
{"WORKDIR", () => Environment.GetEnvironmentVariable("WORKDIR")},
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var workdirProvider in workdirProviders)
|
return AlmaLoggerFactory = loggerFactory;
|
||||||
{
|
|
||||||
var workdir = workdirProvider.Value();
|
|
||||||
if (workdir != null)
|
|
||||||
{
|
|
||||||
if (Directory.Exists(workdir))
|
|
||||||
{
|
|
||||||
return workdir;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.LogInformation($"{workdirProvider.Key} is set to {workdir} but this directory does not exist.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public static ILoggerFactory AlmaLoggerFactory { get; private set; }
|
||||||
}
|
|
||||||
|
|
||||||
private static void InitLogging()
|
|
||||||
{
|
|
||||||
AlmaLoggerFactory = new LoggerFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ILoggerFactory AlmaLoggerFactory { get; private set; } = null!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ServiceProvider]
|
[ServiceProvider]
|
||||||
@@ -80,18 +79,12 @@ public static class Program
|
|||||||
[Singleton(typeof(IOsInformation), typeof(OsInformation))]
|
[Singleton(typeof(IOsInformation), typeof(OsInformation))]
|
||||||
[Singleton(typeof(ICommand), typeof(LinkCommand))]
|
[Singleton(typeof(ICommand), typeof(LinkCommand))]
|
||||||
[Singleton(typeof(ICommand), typeof(UnlinkCommand))]
|
[Singleton(typeof(ICommand), typeof(UnlinkCommand))]
|
||||||
[Singleton(typeof(ICommand), typeof(InfoCommand))]
|
[Singleton(typeof(ICommand), typeof(ModuleInfoCommand))]
|
||||||
[Singleton(typeof(ICommand), typeof(ListCommand))]
|
[Singleton(typeof(ICommand), typeof(ListCommand))]
|
||||||
[Singleton(typeof(ICommand), typeof(InstallCommand))]
|
//Dependency cycle
|
||||||
[Singleton(typeof(ICommand), typeof(HelpCommand))]
|
//[Singleton(typeof(ICommand), typeof(HelpCommand))]
|
||||||
[Singleton(typeof(ICommand), typeof(ConfigureCommand))]
|
|
||||||
[Singleton(typeof(ICommand), typeof(DiagCommand))]
|
|
||||||
[Singleton(typeof(ICommand), typeof(ReadMeCommand))]
|
|
||||||
[Singleton(typeof(IModuleConfigurationResolver), typeof(ModuleConfigurationResolver))]
|
[Singleton(typeof(IModuleConfigurationResolver), typeof(ModuleConfigurationResolver))]
|
||||||
[Singleton(typeof(IMetadataHandler), typeof(MetadataHandler))]
|
[Singleton(typeof(IMetadataHandler), typeof(MetadataHandler))]
|
||||||
[Singleton(typeof(IShellService), typeof(ShellService))]
|
|
||||||
[Singleton(typeof(IVersionService), typeof(VersionService))]
|
|
||||||
[Singleton(typeof(IPathHelperService), typeof(PathHelperService))]
|
|
||||||
[Singleton(typeof(Application))]
|
[Singleton(typeof(Application))]
|
||||||
[Transient(typeof(ILogger<>), Factory = nameof(CustomLoggerFactory))]
|
[Transient(typeof(ILogger<>), Factory = nameof(CustomLoggerFactory))]
|
||||||
internal partial class AlmaServiceProvider
|
internal partial class AlmaServiceProvider
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using Alma.Services;
|
|
||||||
|
|
||||||
namespace Alma;
|
|
||||||
|
|
||||||
public class VersionService : IVersionService
|
|
||||||
{
|
|
||||||
public string GetVersion()
|
|
||||||
{
|
|
||||||
return
|
|
||||||
typeof(Program).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
|
||||||
?? typeof(Program).Assembly.GetName().Version?.ToString()
|
|
||||||
?? "unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user