mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-08-21 04:12:56 +00:00
Refactor Pandoc process setup using a dedicated builder class
This commit is contained in:
parent
f4cac637c6
commit
bb1ce9febd
@ -24,31 +24,10 @@ public static partial class Pandoc
|
|||||||
private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2);
|
private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares a ProcessStartInfo for running pandoc with the given parameters.
|
/// Prepares a Pandoc process by using the Pandoc process builder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <returns>The Pandoc process builder with default settings.</returns>
|
||||||
/// Any local installation of pandoc will be preferred over the system-wide installation.
|
public static PandocProcessBuilder PreparePandocProcess() => PandocProcessBuilder.Create();
|
||||||
/// </remarks>
|
|
||||||
/// <param name="rustService">The global rust service to access file system and data dir.</param>
|
|
||||||
/// <param name="inputFile">The input file to convert.</param>
|
|
||||||
/// <param name="outputFile">The output file to write the converted content to.</param>
|
|
||||||
/// <param name="inputFormat">The format of the input file (e.g., markdown, html, 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>
|
|
||||||
/// <returns>The ProcessStartInfo object configured to run pandoc with the specified parameters.</returns>
|
|
||||||
public static async Task<PandocPreparedProcess> PreparePandocProcess(RustService rustService, string inputFile, string outputFile, string inputFormat, string outputFormat, string? additionalArgs = null)
|
|
||||||
{
|
|
||||||
var pandocExecutable = await PandocExecutablePath(rustService);
|
|
||||||
return new (new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = pandocExecutable.Executable,
|
|
||||||
Arguments = $"{inputFile} -f {inputFormat} -t {outputFormat} {additionalArgs ?? string.Empty} -o {outputFile}",
|
|
||||||
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.
|
||||||
@ -60,11 +39,8 @@ public static partial class Pandoc
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var preparedProcess = await PreparePandocProcess(rustService, string.Empty, string.Empty, string.Empty, string.Empty);
|
var preparedProcess = await PreparePandocProcess().AddArgument("--version").BuildAsync(rustService);
|
||||||
var startInfo = preparedProcess.StartInfo;
|
using var process = Process.Start(preparedProcess.StartInfo);
|
||||||
startInfo.Arguments = "--version";
|
|
||||||
|
|
||||||
using var process = Process.Start(startInfo);
|
|
||||||
if (process == null)
|
if (process == null)
|
||||||
{
|
{
|
||||||
if (showMessages)
|
if (showMessages)
|
||||||
@ -295,51 +271,7 @@ public static partial class Pandoc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static async Task<string> GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");
|
||||||
/// Reads the os platform to determine the used executable name.
|
|
||||||
/// </summary>
|
|
||||||
private static string PandocExecutableName => CPU_ARCHITECTURE is RID.WIN_ARM64 or RID.WIN_X64 ? "pandoc.exe" : "pandoc";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the path to the pandoc executable.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Any local installation of pandoc will be preferred over the system-wide installation.
|
|
||||||
/// When a local installation is found, its absolute path will be returned. In case no local
|
|
||||||
/// installation is found, the name of the pandoc executable will be returned.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
|
||||||
/// <returns>Path to the pandoc executable.</returns>
|
|
||||||
private static async Task<PandocExecutable> PandocExecutablePath(RustService rustService)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// First, we try to find the pandoc executable in the data directory.
|
|
||||||
// Any local installation should be preferred over the system-wide installation.
|
|
||||||
//
|
|
||||||
var localInstallationRootDirectory = await GetPandocDataFolder(rustService);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var executableName = PandocExecutableName;
|
|
||||||
var subdirectories = Directory.GetDirectories(localInstallationRootDirectory);
|
|
||||||
foreach (var subdirectory in subdirectories)
|
|
||||||
{
|
|
||||||
var pandocPath = Path.Combine(subdirectory, executableName);
|
|
||||||
if (File.Exists(pandocPath))
|
|
||||||
return new(pandocPath, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// When no local installation was found, we assume that the pandoc executable is in the system PATH.
|
|
||||||
//
|
|
||||||
return new(PandocExecutableName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<string> GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");
|
|
||||||
|
|
||||||
[GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?)")]
|
[GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?)")]
|
||||||
private static partial Regex PandocCmdRegex();
|
private static partial Regex PandocCmdRegex();
|
||||||
|
135
app/MindWork AI Studio/Tools/PandocProcessBuilder.cs
Normal file
135
app/MindWork AI Studio/Tools/PandocProcessBuilder.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using AIStudio.Tools.Metadata;
|
||||||
|
using AIStudio.Tools.Services;
|
||||||
|
|
||||||
|
using SharedTools;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
public sealed class PandocProcessBuilder
|
||||||
|
{
|
||||||
|
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
||||||
|
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
||||||
|
private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
||||||
|
|
||||||
|
private string? providedInputFile;
|
||||||
|
private string? providedOutputFile;
|
||||||
|
private string? providedInputFormat;
|
||||||
|
private string? providedOutputFormat;
|
||||||
|
|
||||||
|
private readonly List<string> additionalArguments = new();
|
||||||
|
|
||||||
|
private PandocProcessBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PandocProcessBuilder Create() => new();
|
||||||
|
|
||||||
|
public PandocProcessBuilder WithInputFile(string inputFile)
|
||||||
|
{
|
||||||
|
this.providedInputFile = inputFile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PandocProcessBuilder WithOutputFile(string outputFile)
|
||||||
|
{
|
||||||
|
this.providedOutputFile = outputFile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PandocProcessBuilder WithInputFormat(string inputFormat)
|
||||||
|
{
|
||||||
|
this.providedInputFormat = inputFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PandocProcessBuilder WithOutputFormat(string outputFormat)
|
||||||
|
{
|
||||||
|
this.providedOutputFormat = outputFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PandocProcessBuilder AddArgument(string argument)
|
||||||
|
{
|
||||||
|
this.additionalArguments.Add(argument);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PandocPreparedProcess> BuildAsync(RustService rustService)
|
||||||
|
{
|
||||||
|
var sbArguments = new StringBuilder();
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(this.providedInputFile))
|
||||||
|
sbArguments.Append(this.providedInputFile);
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(this.providedInputFormat))
|
||||||
|
sbArguments.Append($" -f {this.providedInputFormat}");
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(this.providedOutputFormat))
|
||||||
|
sbArguments.Append($" -t {this.providedOutputFormat}");
|
||||||
|
|
||||||
|
foreach (var additionalArgument in this.additionalArguments)
|
||||||
|
sbArguments.Append($" {additionalArgument}");
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(this.providedOutputFile))
|
||||||
|
sbArguments.Append($" -o {this.providedOutputFile}");
|
||||||
|
|
||||||
|
var pandocExecutable = await PandocExecutablePath(rustService);
|
||||||
|
return new (new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = pandocExecutable.Executable,
|
||||||
|
Arguments = sbArguments.ToString(),
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
}, pandocExecutable.IsLocalInstallation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the path to the pandoc executable.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Any local installation of pandoc will be preferred over the system-wide installation.
|
||||||
|
/// When a local installation is found, its absolute path will be returned. In case no local
|
||||||
|
/// installation is found, the name of the pandoc executable will be returned.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="rustService">Global rust service to access file system and data dir.</param>
|
||||||
|
/// <returns>Path to the pandoc executable.</returns>
|
||||||
|
private static async Task<PandocExecutable> PandocExecutablePath(RustService rustService)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// First, we try to find the pandoc executable in the data directory.
|
||||||
|
// Any local installation should be preferred over the system-wide installation.
|
||||||
|
//
|
||||||
|
var localInstallationRootDirectory = await Pandoc.GetPandocDataFolder(rustService);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var executableName = PandocExecutableName;
|
||||||
|
var subdirectories = Directory.GetDirectories(localInstallationRootDirectory);
|
||||||
|
foreach (var subdirectory in subdirectories)
|
||||||
|
{
|
||||||
|
var pandocPath = Path.Combine(subdirectory, executableName);
|
||||||
|
if (File.Exists(pandocPath))
|
||||||
|
return new(pandocPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// When no local installation was found, we assume that the pandoc executable is in the system PATH.
|
||||||
|
//
|
||||||
|
return new(PandocExecutableName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the os platform to determine the used executable name.
|
||||||
|
/// </summary>
|
||||||
|
private static string PandocExecutableName => CPU_ARCHITECTURE is RID.WIN_ARM64 or RID.WIN_X64 ? "pandoc.exe" : "pandoc";
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user