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