mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-08-21 03:52:57 +00:00
Refactored Pandoc handling with improved process abstractions
This commit is contained in:
parent
1de9e19c49
commit
4c09c434e2
@ -46,7 +46,8 @@ public partial class PandocDialog : ComponentBase
|
|||||||
|
|
||||||
private async Task CheckPandocAvailabilityAsync()
|
private async Task CheckPandocAvailabilityAsync()
|
||||||
{
|
{
|
||||||
this.isPandocAvailable = await Pandoc.CheckAvailabilityAsync(this.RustService);
|
var pandocInstallation = await Pandoc.CheckAvailabilityAsync(this.RustService);
|
||||||
|
this.isPandocAvailable = pandocInstallation.IsAvailable;
|
||||||
this.showSkeleton = false;
|
this.showSkeleton = false;
|
||||||
await this.InvokeAsync(this.StateHasChanged);
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
}
|
}
|
||||||
|
@ -36,15 +36,19 @@ public static partial class Pandoc
|
|||||||
/// <param name="outputFormat">The format of the output file (e.g., pdf, docx, etc.).</param>
|
/// <param name="outputFormat">The format of the output file (e.g., pdf, docx, etc.).</param>
|
||||||
/// <param name="additionalArgs">Additional arguments to pass to the pandoc command (optional).</param>
|
/// <param name="additionalArgs">Additional arguments to pass to the pandoc command (optional).</param>
|
||||||
/// <returns>The ProcessStartInfo object configured to run pandoc with the specified parameters.</returns>
|
/// <returns>The ProcessStartInfo object configured to run pandoc with the specified parameters.</returns>
|
||||||
public static async Task<ProcessStartInfo> PreparePandocProcess(RustService rustService, string inputFile, string outputFile, string inputFormat, string outputFormat, string? additionalArgs = null) => new()
|
public static async Task<PandocPreparedProcess> PreparePandocProcess(RustService rustService, string inputFile, string outputFile, string inputFormat, string outputFormat, string? additionalArgs = null)
|
||||||
{
|
{
|
||||||
FileName = await PandocExecutablePath(rustService),
|
var pandocExecutable = await PandocExecutablePath(rustService);
|
||||||
Arguments = $"{inputFile} -f {inputFormat} -t {outputFormat} {additionalArgs ?? string.Empty} -o {outputFile}",
|
return new (new ProcessStartInfo
|
||||||
RedirectStandardOutput = true,
|
{
|
||||||
RedirectStandardError = true,
|
FileName = pandocExecutable.Executable,
|
||||||
UseShellExecute = false,
|
Arguments = $"{inputFile} -f {inputFormat} -t {outputFormat} {additionalArgs ?? string.Empty} -o {outputFile}",
|
||||||
CreateNoWindow = true
|
RedirectStandardOutput = true,
|
||||||
};
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
}, pandocExecutable.IsLocalInstallation);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if pandoc is available on the system and can be started as a process or is present in AI Studio's data dir.
|
/// Checks if pandoc is available on the system and can be started as a process or is present in AI Studio's data dir.
|
||||||
@ -52,11 +56,12 @@ public static partial class Pandoc
|
|||||||
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
||||||
/// <param name="showMessages">Controls if snackbars are shown to the user.</param>
|
/// <param name="showMessages">Controls if snackbars are shown to the user.</param>
|
||||||
/// <returns>True, if pandoc is available and the minimum required version is met, else false.</returns>
|
/// <returns>True, if pandoc is available and the minimum required version is met, else false.</returns>
|
||||||
public static async Task<bool> CheckAvailabilityAsync(RustService rustService, bool showMessages = true)
|
public static async Task<PandocInstallation> CheckAvailabilityAsync(RustService rustService, bool showMessages = true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var startInfo = await PreparePandocProcess(rustService, string.Empty, string.Empty, string.Empty, string.Empty);
|
var preparedProcess = await PreparePandocProcess(rustService, string.Empty, string.Empty, string.Empty, string.Empty);
|
||||||
|
var startInfo = preparedProcess.StartInfo;
|
||||||
startInfo.Arguments = "--version";
|
startInfo.Arguments = "--version";
|
||||||
|
|
||||||
using var process = Process.Start(startInfo);
|
using var process = Process.Start(startInfo);
|
||||||
@ -66,7 +71,7 @@ public static partial class Pandoc
|
|||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, "The pandoc process could not be started."));
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, "The pandoc process could not be started."));
|
||||||
|
|
||||||
LOG.LogInformation("The pandoc process was not started, it was null");
|
LOG.LogInformation("The pandoc process was not started, it was null");
|
||||||
return false;
|
return new(false, "Was not able to start the pandoc process.", false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = await process.StandardOutput.ReadToEndAsync();
|
var output = await process.StandardOutput.ReadToEndAsync();
|
||||||
@ -77,7 +82,7 @@ public static partial class Pandoc
|
|||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, "The pandoc process exited unexpectedly."));
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, "The pandoc process exited unexpectedly."));
|
||||||
|
|
||||||
LOG.LogError("The pandoc process was exited with code {ProcessExitCode}", process.ExitCode);
|
LOG.LogError("The pandoc process was exited with code {ProcessExitCode}", process.ExitCode);
|
||||||
return false;
|
return new(false, "Pandoc is not available on the system or the process exited unexpectedly.", false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionMatch = PandocCmdRegex().Match(output);
|
var versionMatch = PandocCmdRegex().Match(output);
|
||||||
@ -87,25 +92,25 @@ public static partial class Pandoc
|
|||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, "pandoc --version returned an invalid format."));
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, "pandoc --version returned an invalid format."));
|
||||||
|
|
||||||
LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output);
|
LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output);
|
||||||
return false;
|
return new(false, "Pandoc is not available on the system or the version could not be parsed.", false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
var versions = versionMatch.Groups[1].Value;
|
var versions = versionMatch.Groups[1].Value;
|
||||||
var installedVersion = Version.Parse(versions);
|
var installedVersion = Version.Parse(versions);
|
||||||
|
var installedVersionString = installedVersion.ToString();
|
||||||
|
|
||||||
if (installedVersion >= MINIMUM_REQUIRED_VERSION)
|
if (installedVersion >= MINIMUM_REQUIRED_VERSION)
|
||||||
{
|
{
|
||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {installedVersion.ToString()} is installed."));
|
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {installedVersionString} is installed."));
|
||||||
|
|
||||||
return true;
|
return new(true, string.Empty, true, installedVersionString, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, $"Pandoc {installedVersion.ToString()} is installed, but it doesn't match the required version ({MINIMUM_REQUIRED_VERSION.ToString()})."));
|
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, $"Pandoc {installedVersionString} is installed, but it doesn't match the required version ({MINIMUM_REQUIRED_VERSION.ToString()})."));
|
||||||
|
|
||||||
LOG.LogInformation("Pandoc {Installed} is installed, but it does not match the required version ({Requirement})", installedVersion.ToString(), MINIMUM_REQUIRED_VERSION.ToString());
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
LOG.LogInformation("Pandoc {Installed} is installed, but it does not match the required version ({Requirement})", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
||||||
|
return new(true, $"Pandoc {installedVersionString} is installed, but it does not match the required version ({MINIMUM_REQUIRED_VERSION.ToString()}).", false, installedVersionString, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -113,7 +118,7 @@ public static partial class Pandoc
|
|||||||
await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, "Pandoc is not installed."));
|
await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, "Pandoc is not installed."));
|
||||||
|
|
||||||
LOG.LogError("Pandoc is not installed and threw an exception: {Message}", e.Message);
|
LOG.LogError("Pandoc is not installed and threw an exception: {Message}", e.Message);
|
||||||
return false;
|
return new(false, "Pandoc is not installed or could not be started.", false, string.Empty, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +310,7 @@ public static partial class Pandoc
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
||||||
/// <returns>Path to the pandoc executable.</returns>
|
/// <returns>Path to the pandoc executable.</returns>
|
||||||
private static async Task<string> PandocExecutablePath(RustService rustService)
|
private static async Task<PandocExecutable> PandocExecutablePath(RustService rustService)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// First, we try to find the pandoc executable in the data directory.
|
// First, we try to find the pandoc executable in the data directory.
|
||||||
@ -320,7 +325,7 @@ public static partial class Pandoc
|
|||||||
{
|
{
|
||||||
var pandocPath = Path.Combine(subdirectory, executableName);
|
var pandocPath = Path.Combine(subdirectory, executableName);
|
||||||
if (File.Exists(pandocPath))
|
if (File.Exists(pandocPath))
|
||||||
return pandocPath;
|
return new(pandocPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -331,7 +336,7 @@ public static partial class Pandoc
|
|||||||
//
|
//
|
||||||
// When no local installation was found, we assume that the pandoc executable is in the system PATH.
|
// When no local installation was found, we assume that the pandoc executable is in the system PATH.
|
||||||
//
|
//
|
||||||
return PandocExecutableName;
|
return new(PandocExecutableName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");
|
private static async Task<string> GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");
|
||||||
|
3
app/MindWork AI Studio/Tools/PandocExecutable.cs
Normal file
3
app/MindWork AI Studio/Tools/PandocExecutable.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
public readonly record struct PandocExecutable(string Executable, bool IsLocalInstallation);
|
3
app/MindWork AI Studio/Tools/PandocInstallation.cs
Normal file
3
app/MindWork AI Studio/Tools/PandocInstallation.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
public readonly record struct PandocInstallation(bool CheckWasSuccessful, string ErrorMessage, bool IsAvailable, string Version, bool IsLocalInstallation);
|
10
app/MindWork AI Studio/Tools/PandocPreparedProcess.cs
Normal file
10
app/MindWork AI Studio/Tools/PandocPreparedProcess.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
public class PandocPreparedProcess(ProcessStartInfo startInfo, bool isLocal)
|
||||||
|
{
|
||||||
|
public ProcessStartInfo StartInfo => startInfo;
|
||||||
|
|
||||||
|
public bool IsLocal => isLocal;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user