Removed JavaService, and moved Java handling to CmlLib.
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AlayaCore.Installation;
|
||||
using AlayaCore.Models.Manifests;
|
||||
|
||||
namespace AlayaCore.Abstractions.Interfaces.Services
|
||||
{
|
||||
public interface IJavaService
|
||||
{
|
||||
Task EnsureValidJavaInstalledAsync(
|
||||
ManifestModel manifest,
|
||||
InstallEnvironment environment,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AlayaCore.Abstractions.Interfaces;
|
||||
using AlayaCore.Abstractions.Interfaces.Services;
|
||||
using AlayaCore.Installation;
|
||||
using AlayaCore.Models.Manifests;
|
||||
using AlayaCore.Utilities.Enums;
|
||||
|
||||
namespace AlayaCore.Services
|
||||
{
|
||||
public sealed class JavaService : IJavaService
|
||||
{
|
||||
private const string JavaArchiveHashPlaceholder = "REPLACE_WITH_MANIFEST_HASH_SUPPORT";
|
||||
private const string BaseUrl = "https://aka.ms/download-jdk/";
|
||||
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly IFileStore _fileStore;
|
||||
|
||||
public JavaService(IDownloadService downloadService, IFileStore fileStore)
|
||||
{
|
||||
_downloadService = downloadService ?? throw new ArgumentNullException(nameof(downloadService));
|
||||
_fileStore = fileStore ?? throw new ArgumentNullException(nameof(fileStore));
|
||||
}
|
||||
|
||||
public async Task EnsureValidJavaInstalledAsync(
|
||||
ManifestModel manifest,
|
||||
InstallEnvironment environment,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (manifest == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manifest));
|
||||
}
|
||||
|
||||
if (environment == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(environment));
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
string installDirectory = GetJavaInstallDirectory();
|
||||
|
||||
if (environment.JavaInstalled &&
|
||||
Directory.Exists(installDirectory) &&
|
||||
string.Equals(environment.JavaVersion, manifest.RequiredJavaVersion, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Directory.Exists(installDirectory))
|
||||
{
|
||||
await RemoveDirectoryAsync(installDirectory, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Uri downloadUri = GetPlatformSpecificJavaUri(manifest.RequiredJavaVersion);
|
||||
string downloadPath = GetJavaDownloadPath(downloadUri);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(downloadPath) ?? AppContext.BaseDirectory);
|
||||
Directory.CreateDirectory(installDirectory);
|
||||
|
||||
await DownloadJavaAsync(
|
||||
downloadUri,
|
||||
downloadPath,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await InstallJavaAsync(
|
||||
downloadPath,
|
||||
installDirectory,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Uri GetPlatformSpecificJavaUri(string javaVersion)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(javaVersion))
|
||||
{
|
||||
throw new ArgumentException("Java version must be provided.", nameof(javaVersion));
|
||||
}
|
||||
|
||||
string os = GetOsSegment();
|
||||
string arch = GetArchitectureSegment();
|
||||
string extension = GetFileExtension(os);
|
||||
|
||||
string fileName = $"microsoft-jdk-{javaVersion}-{os}-{arch}.{extension}";
|
||||
return new Uri($"{BaseUrl}{fileName}");
|
||||
}
|
||||
|
||||
private string GetJavaInstallDirectory()
|
||||
{
|
||||
return _fileStore.GetOrCreate(FolderLocation.Java);
|
||||
}
|
||||
|
||||
private string GetJavaDownloadPath(Uri downloadUri)
|
||||
{
|
||||
if (downloadUri == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(downloadUri));
|
||||
}
|
||||
|
||||
string fileName = Path.GetFileName(downloadUri.AbsolutePath);
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
throw new InvalidOperationException("Could not determine Java archive file name from download URI.");
|
||||
}
|
||||
|
||||
return Path.Combine(_fileStore.GetOrCreate(FolderLocation.Downloads), fileName);
|
||||
}
|
||||
|
||||
private static string GetOsSegment()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return "windows";
|
||||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return "linux";
|
||||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return "macos";
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException("Unsupported operating system.");
|
||||
}
|
||||
|
||||
private static string GetArchitectureSegment()
|
||||
{
|
||||
return RuntimeInformation.OSArchitecture switch
|
||||
{
|
||||
Architecture.X64 => "x64",
|
||||
Architecture.Arm64 => "aarch64",
|
||||
Architecture.X86 => throw new NotSupportedException("X86 is not supported."),
|
||||
Architecture.Arm => throw new NotSupportedException("Arm32 is not supported."),
|
||||
_ => throw new PlatformNotSupportedException(
|
||||
$"Unsupported architecture: {RuntimeInformation.OSArchitecture}")
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetFileExtension(string os)
|
||||
{
|
||||
return os switch
|
||||
{
|
||||
"windows" => "zip",
|
||||
"linux" => "tar.gz",
|
||||
"macos" => "tar.gz",
|
||||
_ => throw new PlatformNotSupportedException($"Unsupported OS: {os}")
|
||||
};
|
||||
}
|
||||
|
||||
private static Task RemoveDirectoryAsync(
|
||||
string directoryPath,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(directoryPath))
|
||||
{
|
||||
throw new ArgumentException("Directory path cannot be null, empty, or whitespace.", nameof(directoryPath));
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (Directory.Exists(directoryPath))
|
||||
{
|
||||
Directory.Delete(directoryPath, recursive: true);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task DownloadJavaAsync(
|
||||
Uri javaUri,
|
||||
string destinationPath,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (javaUri == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(javaUri));
|
||||
}
|
||||
|
||||
if (!javaUri.IsAbsoluteUri)
|
||||
{
|
||||
throw new ArgumentException("Java download URI must be absolute.", nameof(javaUri));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(destinationPath))
|
||||
{
|
||||
throw new ArgumentException("Destination path cannot be null, empty, or whitespace.", nameof(destinationPath));
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
string directory = Path.GetDirectoryName(destinationPath);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
if (File.Exists(destinationPath))
|
||||
{
|
||||
File.Delete(destinationPath);
|
||||
}
|
||||
|
||||
await _downloadService.DownloadFileAsync(
|
||||
javaUri,
|
||||
destinationPath,
|
||||
JavaArchiveHashPlaceholder,
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task InstallJavaAsync(
|
||||
string archivePath,
|
||||
string installDirectory,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(archivePath))
|
||||
{
|
||||
throw new ArgumentException("Archive path cannot be null, empty, or whitespace.", nameof(archivePath));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(installDirectory))
|
||||
{
|
||||
throw new ArgumentException("Install directory cannot be null, empty, or whitespace.", nameof(installDirectory));
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!File.Exists(archivePath))
|
||||
{
|
||||
throw new FileNotFoundException("Java archive was not found.", archivePath);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(installDirectory);
|
||||
|
||||
if (archivePath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ZipFile.ExtractToDirectory(archivePath, installDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
if (archivePath.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await ExtractTarGzAsync(archivePath, installDirectory, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new NotSupportedException(
|
||||
$"Unsupported Java archive format: {Path.GetFileName(archivePath)}");
|
||||
}
|
||||
|
||||
private static async Task ExtractTarGzAsync(
|
||||
string archivePath,
|
||||
string destinationDirectory,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(archivePath))
|
||||
{
|
||||
throw new ArgumentException("Archive path cannot be null, empty, or whitespace.", nameof(archivePath));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(destinationDirectory))
|
||||
{
|
||||
throw new ArgumentException("Destination directory cannot be null, empty, or whitespace.", nameof(destinationDirectory));
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "tar",
|
||||
Arguments = $"-xzf \"{archivePath}\" -C \"{destinationDirectory}\"",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using var process = new Process { StartInfo = startInfo };
|
||||
await using (cancellationToken.Register(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore race conditions if the process exits while cancellation is being handled.
|
||||
}
|
||||
}))
|
||||
{
|
||||
process.Start();
|
||||
|
||||
string standardOutput = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
|
||||
string standardError = await process.StandardError.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.Run(() => process.WaitForExit(), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"tar extraction failed with exit code {process.ExitCode}. Error: {standardError}. Output: {standardOutput}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user