~ruther/NosSmooth

fd54bcc9213d0d1e0426e9ecc0e9aec6d6d33628 — František Boháček 3 years ago 2d5e058
feat(data): add cli for database migration and extraction of nos files
A Data/NosSmooth.Data.CLI/Commands/ExtractNosFileCommand.cs => Data/NosSmooth.Data.CLI/Commands/ExtractNosFileCommand.cs +63 -0
@@ 0,0 1,63 @@
//
//  ExtractNosFileCommand.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Net;
using System.Text;
using NosSmooth.Data.NOSFiles.Files;
using NosSmooth.Data.NOSFiles.Readers;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
using Remora.Results;

namespace NosSmooth.Data.CLI.Commands;

/// <summary>
/// A command to extract files from a NosTale archive.
/// </summary>
public class ExtractNosFileCommand : CommandGroup
{
    private readonly FileReader _reader;

    /// <summary>
    /// Initializes a new instance of the <see cref="ExtractNosFileCommand"/> class.
    /// </summary>
    /// <param name="reader">The file reader.</param>
    public ExtractNosFileCommand(FileReader reader)
    {
        _reader = reader;
    }

    /// <summary>
    /// Handles extract command.
    /// </summary>
    /// <param name="inputFile">The input nos archive.</param>
    /// <param name="outputDirectory">The output directory to put the extracted files to.</param>
    /// <returns>A result that may or may not have succeeded..</returns>
    [Command("extract")]
    public async Task<Result> HandleExtract
    (
        string inputFile,
        [Option('o', "option")]
        string outputDirectory = "out"
    )
    {
        Directory.CreateDirectory(outputDirectory);

        var readResult = _reader.ReadFileSystemFile<FileArchive>(inputFile);
        if (!readResult.IsSuccess)
        {
            return Result.FromError(readResult);
        }

        foreach (var file in readResult.Entity.Content.Files)
        {
            var outputPath = Path.Combine(outputDirectory, file.Path);
            await File.WriteAllBytesAsync(outputPath, file.Content, CancellationToken);
        }

        return Result.FromSuccess();
    }
}
\ No newline at end of file

A Data/NosSmooth.Data.CLI/Commands/MigrateDatabaseCommand.cs => Data/NosSmooth.Data.CLI/Commands/MigrateDatabaseCommand.cs +63 -0
@@ 0,0 1,63 @@
//
//  MigrateDatabaseCommand.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Data.Abstractions.Language;
using NosSmooth.Data.Database;
using NosSmooth.Data.NOSFiles;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
using Remora.Results;

namespace NosSmooth.Data.CLI.Commands;

/// <summary>
/// Create a database from nos files.
/// </summary>
public class MigrateDatabaseCommand : CommandGroup
{
    private readonly DatabaseMigrator _migrator;
    private readonly NostaleDataParser _parser;

    /// <summary>
    /// Initializes a new instance of the <see cref="MigrateDatabaseCommand"/> class.
    /// </summary>
    /// <param name="migrator">The database migrator.</param>
    /// <param name="parser">The data parser.</param>
    public MigrateDatabaseCommand(DatabaseMigrator migrator, NostaleDataParser parser)
    {
        _migrator = migrator;
        _parser = parser;
    }

    /// <summary>
    /// Migrate the database using nos files.
    /// </summary>
    /// <param name="nostaleDataPath">The directory with nostale data files.</param>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    [Command("migrate")]
    public async Task<Result> HandleMigrate(string nostaleDataPath)
    {
        var parsingResult = _parser.ParseFiles
        (
            nostaleDataPath,
            Language.Cz,
            Language.De,
            Language.Uk,
            Language.Es,
            Language.Fr,
            Language.It,
            Language.Pl,
            Language.Ru,
            Language.Tr
        );
        if (!parsingResult.IsSuccess)
        {
            return Result.FromError(parsingResult);
        }

        return await _migrator.Migrate(parsingResult.Entity);
    }
}
\ No newline at end of file

M Data/NosSmooth.Data.CLI/NosSmooth.Data.CLI.csproj => Data/NosSmooth.Data.CLI/NosSmooth.Data.CLI.csproj +11 -0
@@ 7,4 7,15 @@
        <OutputType>Exe</OutputType>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
      <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
      <PackageReference Include="Remora.Commands" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
      <ProjectReference Include="..\NosSmooth.Data.Database\NosSmooth.Data.Database.csproj" />
      <ProjectReference Include="..\NosSmooth.Data.NOSFiles\NosSmooth.Data.NOSFiles.csproj" />
    </ItemGroup>

</Project>

A Data/NosSmooth.Data.CLI/Program.cs => Data/NosSmooth.Data.CLI/Program.cs +76 -0
@@ 0,0 1,76 @@
//
//  Program.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Extensions.DependencyInjection;
using NosSmooth.Data.CLI.Commands;
using NosSmooth.Data.Database.Extensions;
using NosSmooth.Data.NOSFiles.Extensions;
using NosSmooth.Data.NOSFiles.Files;
using NosSmooth.Data.NOSFiles.Readers;
using NosSmooth.Data.NOSFiles.Readers.Types;
using Remora.Commands.Extensions;
using Remora.Commands.Services;
using Remora.Results;

namespace NosSmooth.Data.CLI;

/// <summary>
/// Entrypoint class.
/// </summary>
public class Program
{
    /// <summary>
    /// Entrypoint method.
    /// </summary>
    /// <param name="arguments">The arguments.</param>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    public static async Task Main(string[] arguments)
    {
        var services = CreateServices();
        var commandService = services.GetRequiredService<CommandService>();
        var preparedCommandResult = await commandService.TryPrepareCommandAsync(string.Join(' ', arguments), services);
        if (!preparedCommandResult.IsSuccess)
        {
            Console.Error.WriteLine($"There was an error, {preparedCommandResult.Error.Message}");
            return;
        }

        if (preparedCommandResult.Entity is null)
        {
            Console.Error.WriteLine("You must enter a command such ast list or inject.");
            return;
        }

        var executionResult = await commandService.TryExecuteAsync(preparedCommandResult.Entity, services);
        if (!executionResult.Entity.IsSuccess)
        {
            switch (executionResult.Entity.Error)
            {
                case ExceptionError exc:
                    Console.Error.WriteLine($"There was an exception, {exc.Exception.Message}");
                    break;
                default:
                    Console.Error.WriteLine($"There was an error, {executionResult.Entity.Error!.Message}");
                    break;
            }
        }
    }

    private static IServiceProvider CreateServices()
    {
        var collection = new ServiceCollection();

        collection
            .AddNostaleDataParsing()
            .AddNostaleDatabaseMigrator()
            .AddCommands()
            .AddCommandTree()
            .WithCommandGroup<MigrateDatabaseCommand>()
            .WithCommandGroup<ExtractNosFileCommand>();

        return collection.BuildServiceProvider();
    }
}
\ No newline at end of file