big changes
This commit is contained in:
@@ -5,37 +5,99 @@ using ZA.CoreService.ESBCertificateManager.Models;
|
||||
namespace ZA.CoreService.ESBCertificateManager.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Startet nur den Container-Restart über SonicMfContainerTool (Java + MF-Client-JARs).
|
||||
/// Startet den Container-Restart über SonicMfContainerTool
|
||||
/// mit Java und den Sonic-MfApi-Clientbibliotheken.
|
||||
/// </summary>
|
||||
public sealed class SonicMfApiExecutor
|
||||
{
|
||||
private readonly SonicConnection _connection;
|
||||
|
||||
public SonicMfApiExecutor(SonicConnection connection)
|
||||
public SonicMfApiExecutor(
|
||||
SonicConnection connection)
|
||||
{
|
||||
_connection = connection;
|
||||
_connection =
|
||||
connection
|
||||
?? throw new ArgumentNullException(
|
||||
nameof(connection));
|
||||
}
|
||||
|
||||
public (string SonicHome, string? JavaExe) ResolveRuntimePaths()
|
||||
public (string SonicHome, string? JavaExe)
|
||||
ResolveRuntimePaths()
|
||||
{
|
||||
string sonicHome = string.IsNullOrWhiteSpace(_connection.SonicHome)
|
||||
? "(leer)"
|
||||
: _connection.SonicHome.Trim();
|
||||
return (sonicHome, ResolveJavaExe());
|
||||
string sonicHome =
|
||||
string.IsNullOrWhiteSpace(
|
||||
_connection.SonicHome)
|
||||
? "(leer)"
|
||||
: _connection.SonicHome.Trim();
|
||||
|
||||
return (
|
||||
sonicHome,
|
||||
ResolveJavaExe());
|
||||
}
|
||||
|
||||
public async Task<(bool Success, string? Output, string? Error)> RestartAsync(
|
||||
string containerName,
|
||||
CancellationToken cancellationToken = default)
|
||||
public async Task<(
|
||||
bool Success,
|
||||
string? Output,
|
||||
string? Error)> RestartAsync(
|
||||
string containerName,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
(bool prepared, string? javaExe, string? classDir, string? classpath, string? prepareError) =
|
||||
PrepareTool();
|
||||
if (!prepared)
|
||||
if (string.IsNullOrWhiteSpace(containerName))
|
||||
{
|
||||
return (false, null, prepareError);
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
"Der Sonic-Containername fehlt.");
|
||||
}
|
||||
|
||||
ProcessStartInfo psi = new()
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
_connection.Username)
|
||||
|| string.IsNullOrEmpty(
|
||||
_connection.Password))
|
||||
{
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
"Für die Sonic-Verbindung sind keine " +
|
||||
"vollständigen Zugangsdaten eingerichtet. " +
|
||||
"Bitte das Setup ausführen.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
_connection.DomainName))
|
||||
{
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
"Für die Sonic-Verbindung fehlt DomainName.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
_connection.ConnectionUrl))
|
||||
{
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
"Für die Sonic-Verbindung fehlt ConnectionUrl.");
|
||||
}
|
||||
|
||||
(
|
||||
bool prepared,
|
||||
string? javaExe,
|
||||
string? classDir,
|
||||
string? classpath,
|
||||
string? prepareError
|
||||
) = PrepareTool();
|
||||
|
||||
if (!prepared)
|
||||
{
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
prepareError);
|
||||
}
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
FileName = javaExe!,
|
||||
UseShellExecute = false,
|
||||
@@ -47,173 +109,393 @@ public sealed class SonicMfApiExecutor
|
||||
WorkingDirectory = classDir!
|
||||
};
|
||||
|
||||
psi.ArgumentList.Add("-cp");
|
||||
psi.ArgumentList.Add(classpath!);
|
||||
psi.ArgumentList.Add("SonicMfContainerTool");
|
||||
psi.ArgumentList.Add("restart");
|
||||
psi.ArgumentList.Add("--domain");
|
||||
psi.ArgumentList.Add(_connection.DomainName);
|
||||
psi.ArgumentList.Add("--url");
|
||||
psi.ArgumentList.Add(_connection.ConnectionUrl);
|
||||
psi.ArgumentList.Add("--user");
|
||||
psi.ArgumentList.Add(_connection.Username);
|
||||
psi.ArgumentList.Add("--container");
|
||||
psi.ArgumentList.Add(containerName);
|
||||
psi.ArgumentList.Add("--timeout");
|
||||
psi.ArgumentList.Add(Math.Clamp(_connection.TimeoutSeconds, 5, 600).ToString());
|
||||
startInfo.ArgumentList.Add("-cp");
|
||||
startInfo.ArgumentList.Add(classpath!);
|
||||
startInfo.ArgumentList.Add(
|
||||
"SonicMfContainerTool");
|
||||
|
||||
psi.Environment["ESB_SONIC_PASSWORD"] = _connection.Password ?? string.Empty;
|
||||
startInfo.ArgumentList.Add("restart");
|
||||
|
||||
using Process process = new() { StartInfo = psi };
|
||||
if (!process.Start())
|
||||
startInfo.ArgumentList.Add("--domain");
|
||||
startInfo.ArgumentList.Add(
|
||||
_connection.DomainName);
|
||||
|
||||
startInfo.ArgumentList.Add("--url");
|
||||
startInfo.ArgumentList.Add(
|
||||
_connection.ConnectionUrl);
|
||||
|
||||
startInfo.ArgumentList.Add("--user");
|
||||
startInfo.ArgumentList.Add(
|
||||
_connection.Username);
|
||||
|
||||
startInfo.ArgumentList.Add("--container");
|
||||
startInfo.ArgumentList.Add(
|
||||
containerName);
|
||||
|
||||
startInfo.ArgumentList.Add("--timeout");
|
||||
startInfo.ArgumentList.Add(
|
||||
Math.Clamp(
|
||||
_connection.TimeoutSeconds,
|
||||
5,
|
||||
600)
|
||||
.ToString());
|
||||
|
||||
/*
|
||||
* Das Kennwort wird nicht als Kommandozeilenargument
|
||||
* übergeben. Dadurch erscheint das Kennwort nicht in
|
||||
* der Prozessargumentliste.
|
||||
*
|
||||
* CredentialSecret wurde zuvor durch Microsoft.Data.SqlClient
|
||||
* clientseitig entschlüsselt und als Laufzeitwert in
|
||||
* SonicConnection.Password übernommen.
|
||||
*/
|
||||
startInfo.Environment[
|
||||
"ESB_SONIC_PASSWORD"] =
|
||||
_connection.Password;
|
||||
|
||||
using Process process = new()
|
||||
{
|
||||
return (false, null, "Java-Prozess konnte nicht gestartet werden.");
|
||||
}
|
||||
|
||||
using CancellationTokenSource timeoutCts =
|
||||
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
timeoutCts.CancelAfter(TimeSpan.FromSeconds(Math.Clamp(_connection.TimeoutSeconds, 10, 600)));
|
||||
|
||||
Task<string> stdoutTask = process.StandardOutput.ReadToEndAsync(cancellationToken);
|
||||
Task<string> stderrTask = process.StandardError.ReadToEndAsync(cancellationToken);
|
||||
StartInfo = startInfo
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await process.WaitForExitAsync(timeoutCts.Token);
|
||||
if (!process.Start())
|
||||
{
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
"Der Java-Prozess konnte nicht gestartet werden.");
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try { process.Kill(entireProcessTree: true); } catch { /* ignore */ }
|
||||
return (false, null, $"MfApi Timeout nach {_connection.TimeoutSeconds}s.");
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
$"Der Java-Prozess konnte nicht gestartet werden: " +
|
||||
$"{ex.Message}");
|
||||
}
|
||||
|
||||
string stdout = (await stdoutTask).Trim();
|
||||
string stderr = (await stderrTask).Trim();
|
||||
string combined = string.Join("\n", new[] { stdout, stderr }.Where(s => s.Length > 0));
|
||||
using CancellationTokenSource timeoutCts =
|
||||
CancellationTokenSource
|
||||
.CreateLinkedTokenSource(
|
||||
cancellationToken);
|
||||
|
||||
bool ok = process.ExitCode == 0
|
||||
&& combined.Contains("OK:RestartInvoked", StringComparison.OrdinalIgnoreCase)
|
||||
&& !combined.Contains("ERROR:", StringComparison.OrdinalIgnoreCase);
|
||||
int timeoutSeconds =
|
||||
Math.Clamp(
|
||||
_connection.TimeoutSeconds,
|
||||
10,
|
||||
600);
|
||||
|
||||
if (ok)
|
||||
timeoutCts.CancelAfter(
|
||||
TimeSpan.FromSeconds(
|
||||
timeoutSeconds));
|
||||
|
||||
Task<string> stdoutTask =
|
||||
process.StandardOutput
|
||||
.ReadToEndAsync();
|
||||
|
||||
Task<string> stderrTask =
|
||||
process.StandardError
|
||||
.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
return (true, combined, null);
|
||||
await process.WaitForExitAsync(
|
||||
timeoutCts.Token);
|
||||
}
|
||||
|
||||
string err = ExtractError(combined)
|
||||
?? $"SonicMfContainerTool ExitCode={process.ExitCode}";
|
||||
|
||||
if (err.Contains("ClassNotFoundException", StringComparison.OrdinalIgnoreCase)
|
||||
|| combined.Contains("JMSConnectorAddress", StringComparison.OrdinalIgnoreCase))
|
||||
catch (OperationCanceledException)
|
||||
when (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
err +=
|
||||
"\n\nClasspath unvollständig. MfClientLibPath auf Ordner mit mgmt_client.jar / mfcontext.jar setzen.";
|
||||
TryKillProcess(process);
|
||||
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
$"MfApi-Timeout nach {timeoutSeconds} Sekunden.");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
TryKillProcess(process);
|
||||
throw;
|
||||
}
|
||||
|
||||
string detail = string.IsNullOrWhiteSpace(combined) ? err : err + "\n\n--- Tool-Output ---\n" + combined;
|
||||
return (false, combined.Length > 0 ? combined : null, detail);
|
||||
string stdout =
|
||||
(await stdoutTask).Trim();
|
||||
|
||||
string stderr =
|
||||
(await stderrTask).Trim();
|
||||
|
||||
string combined = string.Join(
|
||||
Environment.NewLine,
|
||||
new[] { stdout, stderr }
|
||||
.Where(output =>
|
||||
!string.IsNullOrWhiteSpace(output)));
|
||||
|
||||
bool succeeded =
|
||||
process.ExitCode == 0
|
||||
&& combined.Contains(
|
||||
"OK:RestartInvoked",
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
&& !combined.Contains(
|
||||
"ERROR:",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
return (
|
||||
true,
|
||||
string.IsNullOrWhiteSpace(combined)
|
||||
? null
|
||||
: combined,
|
||||
null);
|
||||
}
|
||||
|
||||
string error =
|
||||
ExtractError(combined)
|
||||
?? $"SonicMfContainerTool ExitCode=" +
|
||||
$"{process.ExitCode}";
|
||||
|
||||
if (error.Contains(
|
||||
"ClassNotFoundException",
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
|| combined.Contains(
|
||||
"JMSConnectorAddress",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
error +=
|
||||
Environment.NewLine +
|
||||
Environment.NewLine +
|
||||
"Der Classpath ist vermutlich unvollständig. " +
|
||||
"Runtime:SonicClientLibraryPath muss auf den " +
|
||||
"Ordner mit den benötigten Sonic-JARs zeigen.";
|
||||
}
|
||||
|
||||
string detail =
|
||||
string.IsNullOrWhiteSpace(combined)
|
||||
? error
|
||||
: error
|
||||
+ Environment.NewLine
|
||||
+ Environment.NewLine
|
||||
+ "--- Tool-Output ---"
|
||||
+ Environment.NewLine
|
||||
+ combined;
|
||||
|
||||
return (
|
||||
false,
|
||||
string.IsNullOrWhiteSpace(combined)
|
||||
? null
|
||||
: combined,
|
||||
detail);
|
||||
}
|
||||
|
||||
private (bool Ok, string? JavaExe, string? ClassDir, string? Classpath, string? Error) PrepareTool()
|
||||
private (
|
||||
bool Ok,
|
||||
string? JavaExe,
|
||||
string? ClassDir,
|
||||
string? Classpath,
|
||||
string? Error) PrepareTool()
|
||||
{
|
||||
string? javaExe = ResolveJavaExe();
|
||||
string? javaExe =
|
||||
ResolveJavaExe();
|
||||
|
||||
if (javaExe is null)
|
||||
{
|
||||
return (false, null, null, null,
|
||||
"Java nicht gefunden. In appsettings JavaPath auf java.exe (Java 8+) setzen.");
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"Java wurde nicht gefunden. " +
|
||||
"Runtime:JavaExecutablePath prüfen.");
|
||||
}
|
||||
|
||||
(string? libClasspath, string? libError) = ResolveSonicClasspath();
|
||||
if (libClasspath is null)
|
||||
(
|
||||
string? libraryClasspath,
|
||||
string? libraryError
|
||||
) = ResolveSonicClasspath();
|
||||
|
||||
if (libraryClasspath is null)
|
||||
{
|
||||
return (false, null, null, null, libError);
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
libraryError);
|
||||
}
|
||||
|
||||
string? toolsDir = ResolveToolsDir();
|
||||
if (toolsDir is null)
|
||||
string? toolsDirectory =
|
||||
ResolveToolsDir();
|
||||
|
||||
if (toolsDirectory is null)
|
||||
{
|
||||
return (false, null, null, null,
|
||||
"Tools\\SonicMfContainerTool.class nicht gefunden. Projekt neu bauen.");
|
||||
return (
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"Tools\\SonicMfContainerTool.class " +
|
||||
"wurde nicht gefunden. " +
|
||||
"Projekt vollständig neu bauen.");
|
||||
}
|
||||
|
||||
string classpath = toolsDir + Path.PathSeparator + libClasspath;
|
||||
return (true, javaExe, toolsDir, classpath, null);
|
||||
string classpath =
|
||||
toolsDirectory
|
||||
+ Path.PathSeparator
|
||||
+ libraryClasspath;
|
||||
|
||||
return (
|
||||
true,
|
||||
javaExe,
|
||||
toolsDirectory,
|
||||
classpath,
|
||||
null);
|
||||
}
|
||||
|
||||
private string? ResolveJavaExe()
|
||||
{
|
||||
foreach (string? candidate in EnumerateJavaCandidates())
|
||||
foreach (string? candidate
|
||||
in EnumerateJavaCandidates())
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(candidate) && File.Exists(candidate))
|
||||
if (string.IsNullOrWhiteSpace(candidate))
|
||||
{
|
||||
return Path.GetFullPath(candidate);
|
||||
continue;
|
||||
}
|
||||
|
||||
string resolvedCandidate;
|
||||
|
||||
try
|
||||
{
|
||||
resolvedCandidate =
|
||||
Path.IsPathRooted(candidate)
|
||||
? Path.GetFullPath(candidate)
|
||||
: Path.GetFullPath(
|
||||
Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
candidate));
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (File.Exists(resolvedCandidate))
|
||||
{
|
||||
return resolvedCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerable<string?> EnumerateJavaCandidates()
|
||||
private IEnumerable<string?>
|
||||
EnumerateJavaCandidates()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_connection.JavaPath))
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
_connection.JavaPath))
|
||||
{
|
||||
yield return _connection.JavaPath.Trim();
|
||||
yield return
|
||||
_connection.JavaPath.Trim();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_connection.JavaHome))
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
_connection.JavaHome))
|
||||
{
|
||||
yield return Path.Combine(_connection.JavaHome.Trim(), "bin", "java.exe");
|
||||
yield return Path.Combine(
|
||||
_connection.JavaHome.Trim(),
|
||||
"bin",
|
||||
"java.exe");
|
||||
}
|
||||
|
||||
string? javaHome = Environment.GetEnvironmentVariable("JAVA_HOME");
|
||||
string? javaHome =
|
||||
Environment.GetEnvironmentVariable(
|
||||
"JAVA_HOME");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(javaHome))
|
||||
{
|
||||
yield return Path.Combine(javaHome.Trim(), "bin", "java.exe");
|
||||
yield return Path.Combine(
|
||||
javaHome.Trim(),
|
||||
"bin",
|
||||
"java.exe");
|
||||
}
|
||||
|
||||
string? jreHome = Environment.GetEnvironmentVariable("JRE_HOME");
|
||||
string? jreHome =
|
||||
Environment.GetEnvironmentVariable(
|
||||
"JRE_HOME");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(jreHome))
|
||||
{
|
||||
yield return Path.Combine(jreHome.Trim(), "bin", "java.exe");
|
||||
yield return Path.Combine(
|
||||
jreHome.Trim(),
|
||||
"bin",
|
||||
"java.exe");
|
||||
}
|
||||
|
||||
yield return "java.exe"; // PATH
|
||||
yield return "java.exe";
|
||||
}
|
||||
|
||||
private (string? Classpath, string? Error) ResolveSonicClasspath()
|
||||
private (
|
||||
string? Classpath,
|
||||
string? Error) ResolveSonicClasspath()
|
||||
{
|
||||
List<string> libDirs = [];
|
||||
List<string> libraryDirectories = [];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_connection.MfClientLibPath))
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
_connection.MfClientLibPath))
|
||||
{
|
||||
libDirs.Add(_connection.MfClientLibPath.Trim());
|
||||
libraryDirectories.Add(
|
||||
ResolveDirectoryPath(
|
||||
_connection.MfClientLibPath));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_connection.SonicHome))
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
_connection.SonicHome))
|
||||
{
|
||||
string home = _connection.SonicHome.Trim();
|
||||
libDirs.Add(Path.Combine(home, "lib"));
|
||||
libDirs.Add(home);
|
||||
string sonicHome =
|
||||
ResolveDirectoryPath(
|
||||
_connection.SonicHome);
|
||||
|
||||
libraryDirectories.Add(
|
||||
Path.Combine(
|
||||
sonicHome,
|
||||
"lib"));
|
||||
|
||||
libraryDirectories.Add(
|
||||
sonicHome);
|
||||
}
|
||||
|
||||
HashSet<string> jars = new(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (string dir in libDirs.Where(Directory.Exists))
|
||||
HashSet<string> jars =
|
||||
new(
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (string directory
|
||||
in libraryDirectories
|
||||
.Where(Directory.Exists)
|
||||
.Distinct(
|
||||
StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (string jar in Directory.EnumerateFiles(dir, "*.jar", SearchOption.TopDirectoryOnly))
|
||||
foreach (string jar
|
||||
in Directory.EnumerateFiles(
|
||||
directory,
|
||||
"*.jar",
|
||||
SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
jars.Add(jar);
|
||||
jars.Add(
|
||||
Path.GetFullPath(jar));
|
||||
}
|
||||
}
|
||||
|
||||
if (jars.Count == 0)
|
||||
{
|
||||
return (null,
|
||||
"Keine Sonic-Client-JARs gefunden. MfClientLibPath oder SonicHome\\lib setzen "
|
||||
+ "(mgmt_client.jar, mfcontext.jar, …).");
|
||||
return (
|
||||
null,
|
||||
"Keine Sonic-Client-JARs gefunden. " +
|
||||
"Runtime:SonicClientLibraryPath prüfen.");
|
||||
}
|
||||
|
||||
// Explizite Kern-JARs zuerst, falls vorhanden
|
||||
string[] preferred =
|
||||
string[] preferredJarNames =
|
||||
[
|
||||
"mgmt_client.jar",
|
||||
"mfcontext.jar",
|
||||
@@ -222,58 +504,125 @@ public sealed class SonicMfApiExecutor
|
||||
"mf_common.jar"
|
||||
];
|
||||
|
||||
List<string> ordered = [];
|
||||
foreach (string name in preferred)
|
||||
List<string> orderedJars = [];
|
||||
|
||||
foreach (string preferredJarName
|
||||
in preferredJarNames)
|
||||
{
|
||||
string? hit = jars.FirstOrDefault(j =>
|
||||
string.Equals(Path.GetFileName(j), name, StringComparison.OrdinalIgnoreCase));
|
||||
if (hit is not null)
|
||||
string? matchingJar =
|
||||
jars.FirstOrDefault(
|
||||
jar => string.Equals(
|
||||
Path.GetFileName(jar),
|
||||
preferredJarName,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (matchingJar is not null)
|
||||
{
|
||||
ordered.Add(hit);
|
||||
orderedJars.Add(
|
||||
matchingJar);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string jar in jars.OrderBy(Path.GetFileName, StringComparer.OrdinalIgnoreCase))
|
||||
foreach (string jar
|
||||
in jars.OrderBy(
|
||||
Path.GetFileName,
|
||||
StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!ordered.Contains(jar, StringComparer.OrdinalIgnoreCase))
|
||||
if (!orderedJars.Contains(
|
||||
jar,
|
||||
StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
ordered.Add(jar);
|
||||
orderedJars.Add(jar);
|
||||
}
|
||||
}
|
||||
|
||||
return (string.Join(Path.PathSeparator, ordered), null);
|
||||
return (
|
||||
string.Join(
|
||||
Path.PathSeparator,
|
||||
orderedJars),
|
||||
null);
|
||||
}
|
||||
|
||||
private static string ResolveDirectoryPath(
|
||||
string configuredPath)
|
||||
{
|
||||
return Path.IsPathRooted(configuredPath)
|
||||
? Path.GetFullPath(configuredPath)
|
||||
: Path.GetFullPath(
|
||||
Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
configuredPath));
|
||||
}
|
||||
|
||||
private static string? ResolveToolsDir()
|
||||
{
|
||||
string[] dirs =
|
||||
string[] directories =
|
||||
[
|
||||
Path.Combine(AppContext.BaseDirectory, "Tools"),
|
||||
Path.Combine(Directory.GetCurrentDirectory(), "Tools"),
|
||||
Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
"Tools"),
|
||||
|
||||
Path.Combine(
|
||||
Directory.GetCurrentDirectory(),
|
||||
"Tools"),
|
||||
|
||||
AppContext.BaseDirectory
|
||||
];
|
||||
|
||||
foreach (string dir in dirs.Where(Directory.Exists))
|
||||
foreach (string directory
|
||||
in directories
|
||||
.Where(Directory.Exists))
|
||||
{
|
||||
if (File.Exists(Path.Combine(dir, "SonicMfContainerTool.class")))
|
||||
string toolPath =
|
||||
Path.Combine(
|
||||
directory,
|
||||
"SonicMfContainerTool.class");
|
||||
|
||||
if (File.Exists(toolPath))
|
||||
{
|
||||
return dir;
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? ExtractError(string combined)
|
||||
private static string? ExtractError(
|
||||
string combinedOutput)
|
||||
{
|
||||
foreach (string line in combined.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (string line
|
||||
in combinedOutput.Split(
|
||||
['\r', '\n'],
|
||||
StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (line.StartsWith("ERROR:", StringComparison.OrdinalIgnoreCase))
|
||||
if (line.StartsWith(
|
||||
"ERROR:",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return line["ERROR:".Length..].Trim();
|
||||
return line[
|
||||
"ERROR:".Length..]
|
||||
.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryKillProcess(
|
||||
Process process)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill(
|
||||
entireProcessTree: true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Der ursprüngliche Fehler oder Timeout
|
||||
// darf nicht verdeckt werden.
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user