mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-05-21 15:12:16 +00:00
Fixed the Pandoc installation
This commit is contained in:
parent
f72bbfe9c6
commit
06407ad111
@ -244,12 +244,7 @@ public static partial class Pandoc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await IsPandocExecutableValidAsync(stagedPandocExecutable))
|
LOG.LogInformation("Found Pandoc executable in downloaded archive: '{Executable}'.", stagedPandocExecutable);
|
||||||
{
|
|
||||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("Pandoc was not installed successfully, because the downloaded executable could not be validated.")));
|
|
||||||
LOG.LogError("Pandoc was not installed, the downloaded executable could not be validated: '{Executable}'.", stagedPandocExecutable);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReplaceInstallationDirectoryAsync(stagingDir, installDir);
|
await ReplaceInstallationDirectoryAsync(stagingDir, installDir);
|
||||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} was installed successfully."), latestVersion)));
|
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} was installed successfully."), latestVersion)));
|
||||||
@ -257,6 +252,7 @@ public static partial class Pandoc
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("Pandoc was not installed successfully.")));
|
||||||
LOG.LogError(ex, "An error occurred while installing Pandoc.");
|
LOG.LogError(ex, "An error occurred while installing Pandoc.");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -274,73 +270,44 @@ public static partial class Pandoc
|
|||||||
{
|
{
|
||||||
var backupDir = $"{installDir}.backup-{Guid.NewGuid():N}";
|
var backupDir = $"{installDir}.backup-{Guid.NewGuid():N}";
|
||||||
var hasBackup = false;
|
var hasBackup = false;
|
||||||
|
var stagingWasMoved = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Directory.Exists(installDir))
|
if (Directory.Exists(installDir))
|
||||||
{
|
{
|
||||||
Directory.Move(installDir, backupDir);
|
await MoveDirectoryWithRetriesAsync(installDir, backupDir, "moving the previous Pandoc installation to backup");
|
||||||
hasBackup = true;
|
hasBackup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Move(stagingDir, installDir);
|
await MoveDirectoryWithRetriesAsync(stagingDir, installDir, "moving the new Pandoc installation into place");
|
||||||
|
stagingWasMoved = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (hasBackup && !Directory.Exists(installDir) && Directory.Exists(backupDir))
|
if (hasBackup && !stagingWasMoved && !Directory.Exists(installDir) && Directory.Exists(backupDir))
|
||||||
Directory.Move(backupDir, installDir);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await MoveDirectoryWithRetriesAsync(backupDir, installDir, "restoring the previous Pandoc installation");
|
||||||
|
hasBackup = false;
|
||||||
|
}
|
||||||
|
catch (Exception rollbackEx)
|
||||||
|
{
|
||||||
|
LOG.LogError(rollbackEx, "Error restoring previous Pandoc installation directory. Keeping backup directory at: '{BackupDir}'.", backupDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG.LogError(ex, "Error replacing pandoc installation directory.");
|
LOG.LogError(ex, "Error replacing pandoc installation directory.");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (hasBackup && Directory.Exists(backupDir))
|
if (hasBackup && stagingWasMoved && Directory.Exists(backupDir))
|
||||||
await TryDeleteFolderAsync(backupDir);
|
await TryDeleteFolderAsync(backupDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<bool> IsPandocExecutableValidAsync(string executable)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var startInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = executable,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true
|
|
||||||
};
|
|
||||||
startInfo.ArgumentList.Add("--version");
|
|
||||||
|
|
||||||
using var process = Process.Start(startInfo);
|
|
||||||
if (process is null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var outputTask = process.StandardOutput.ReadToEndAsync();
|
|
||||||
var errorTask = process.StandardError.ReadToEndAsync();
|
|
||||||
|
|
||||||
await process.WaitForExitAsync();
|
|
||||||
var output = await outputTask;
|
|
||||||
var error = await errorTask;
|
|
||||||
|
|
||||||
if (process.ExitCode is not 0)
|
|
||||||
{
|
|
||||||
LOG.LogError("Downloaded Pandoc executable exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionMatch = PandocCmdRegex().Match(output);
|
|
||||||
return versionMatch.Success && Version.Parse(versionMatch.Groups[1].Value) >= MINIMUM_REQUIRED_VERSION;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LOG.LogError(ex, "Error validating downloaded Pandoc executable.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FindExecutableInDirectory(string rootDirectory, string executableName)
|
private static string FindExecutableInDirectory(string rootDirectory, string executableName)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(rootDirectory))
|
if (!Directory.Exists(rootDirectory))
|
||||||
@ -360,19 +327,30 @@ public static partial class Pandoc
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task RunWithRetriesAsync(Func<Task> operation, string operationName)
|
private static async Task MoveDirectoryWithRetriesAsync(string sourceDir, string destinationDir, string operationName)
|
||||||
{
|
{
|
||||||
const int MAX_ATTEMPTS = 4;
|
await RunWithRetriesAsync(
|
||||||
for (var attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)
|
() =>
|
||||||
|
{
|
||||||
|
Directory.Move(sourceDir, destinationDir);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
operationName,
|
||||||
|
maxAttempts: 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task RunWithRetriesAsync(Func<Task> operation, string operationName, int maxAttempts = 4)
|
||||||
|
{
|
||||||
|
for (var attempt = 1; attempt <= maxAttempts; attempt++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await operation();
|
await operation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (attempt < MAX_ATTEMPTS && ex is IOException or UnauthorizedAccessException)
|
catch (Exception ex) when (attempt < maxAttempts && ex is IOException or UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
LOG.LogWarning(ex, "Error while {OperationName}; retrying attempt {Attempt}/{MaxAttempts}.", operationName, attempt + 1, MAX_ATTEMPTS);
|
LOG.LogWarning(ex, "Error while {OperationName}; retrying attempt {Attempt}/{MaxAttempts}.", operationName, attempt + 1, maxAttempts);
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(250 * attempt));
|
await Task.Delay(TimeSpan.FromMilliseconds(250 * attempt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,7 +384,8 @@ public static partial class Pandoc
|
|||||||
Directory.Delete(path, true);
|
Directory.Delete(path, true);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
},
|
},
|
||||||
$"deleting temporary Pandoc directory '{path}'");
|
$"deleting temporary Pandoc directory '{path}'",
|
||||||
|
maxAttempts: 3);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user