diff --git a/app/MindWork AI Studio/Tools/Pandoc.cs b/app/MindWork AI Studio/Tools/Pandoc.cs index 0d290a4c..c54aa21e 100644 --- a/app/MindWork AI Studio/Tools/Pandoc.cs +++ b/app/MindWork AI Studio/Tools/Pandoc.cs @@ -23,6 +23,29 @@ public static partial class Pandoc private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 7); private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2); + /// + /// Prepares a ProcessStartInfo for running pandoc with the given parameters. + /// + /// + /// Any local installation of pandoc will be preferred over the system-wide installation. + /// + /// The global rust service to access file system and data dir. + /// The input file to convert. + /// The output file to write the converted content to. + /// The format of the input file (e.g., markdown, html, etc.). + /// The format of the output file (e.g., pdf, docx, etc.). + /// Additional arguments to pass to the pandoc command (optional). + /// The ProcessStartInfo object configured to run pandoc with the specified parameters. + public static async Task PreparePandocProcess(RustService rustService, string inputFile, string outputFile, string inputFormat, string outputFormat, string? additionalArgs = null) => new() + { + FileName = await PandocExecutablePath(rustService), + Arguments = $"{inputFile} -f {inputFormat} -t {outputFormat} {additionalArgs ?? string.Empty} -o {outputFile}", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + /// /// Checks if pandoc is available on the system and can be started as a process or is present in AI Studio's data dir. /// @@ -31,20 +54,11 @@ public static partial class Pandoc /// True, if pandoc is available and the minimum required version is met, else false. public static async Task CheckAvailabilityAsync(RustService rustService, bool showMessages = true) { - var installDir = await GetPandocDataFolder(rustService); - if (HasPandoc(installDir)) - return true; - try { - var startInfo = new ProcessStartInfo - { - FileName = PandocExecutableName, - Arguments = "--version", - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true - }; + var startInfo = await PreparePandocProcess(rustService, string.Empty, string.Empty, string.Empty, string.Empty); + startInfo.Arguments = "--version"; + using var process = Process.Start(startInfo); if (process == null) { @@ -102,27 +116,6 @@ public static partial class Pandoc return false; } } - - private static bool HasPandoc(string pandocDirectory) - { - try - { - var subdirectories = Directory.GetDirectories(pandocDirectory); - foreach (var subdirectory in subdirectories) - { - var pandocPath = Path.Combine(subdirectory, PandocExecutableName); - if (File.Exists(pandocPath)) - return true; - } - - return false; - } - catch (Exception ex) - { - LOG.LogInformation("Pandoc is not installed in the data directory and might have thrown and error: {0}", ex.Message); - return false; - } - } /// /// Automatically decompresses the latest pandoc archive into AiStudio's data directory @@ -301,6 +294,45 @@ public static partial class Pandoc /// Reads the os platform to determine the used executable name. /// private static string PandocExecutableName => CPU_ARCHITECTURE is RID.WIN_ARM64 or RID.WIN_X64 ? "pandoc.exe" : "pandoc"; + + /// + /// Returns the path to the pandoc executable. + /// + /// + /// 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. + /// + /// Global rust service to access file system and data dir. + /// Path to the pandoc executable. + private static async Task 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 pandocPath; + } + } + catch + { + // ignored + } + + // + // When no local installation was found, we assume that the pandoc executable is in the system PATH. + // + return PandocExecutableName; + } private static async Task GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");