From 3a30e5b048d66112960c48a33ec32c0770427314 Mon Sep 17 00:00:00 2001 From: Burning_TNT Date: Sun, 2 Nov 2025 20:29:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Terracotta=20=E5=9C=A8=20m?= =?UTF-8?q?acOS=20=E4=B8=8A=E7=9A=84=E5=85=BC=E5=AE=B9=E6=80=A7=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20(#4723)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Glavo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../hmcl/terracotta/TerracottaManager.java | 11 ++--- .../terracotta/provider/MacOSProvider.java | 42 +++++++++++++++---- .../src/main/resources/assets/terracotta.json | 27 ++++++------ 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaManager.java index fa8accacd..ea7060860 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/TerracottaManager.java @@ -45,6 +45,7 @@ import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.util.concurrent.CancellationException; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; @@ -141,12 +142,7 @@ public final class TerracottaManager { return null; } - TerracottaState.Preparing preparing; - if (state instanceof TerracottaState.Preparing it) { - preparing = it; - } else { - preparing = new TerracottaState.Preparing(new ReadOnlyDoubleWrapper(-1)); - } + TerracottaState.Preparing preparing = new TerracottaState.Preparing(new ReadOnlyDoubleWrapper(-1)); Task.supplyAsync(Schedulers.io(), () -> { return file != null ? TarFileTree.open(file) : null; @@ -171,6 +167,7 @@ public final class TerracottaManager { if (compareAndSet(preparing, launching)) { launch(launching); } + } else if (exception instanceof CancellationException) { } else if (exception instanceof ITerracottaProvider.ArchiveFileMissingException) { LOG.warning("Cannot install terracotta from local package.", exception); compareAndSet(preparing, new TerracottaState.Fatal(TerracottaState.Fatal.Type.INSTALL)); @@ -181,7 +178,7 @@ public final class TerracottaManager { } }).start(); - return setState(preparing); + return compareAndSet(state, preparing) ? preparing : null; } private static ITerracottaProvider getProvider() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java index 00626f8b6..abb6195b4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/terracotta/provider/MacOSProvider.java @@ -17,8 +17,10 @@ */ package org.jackhuang.hmcl.terracotta.provider; +import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.terracotta.TerracottaNative; +import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.ManagedProcess; import org.jackhuang.hmcl.util.platform.SystemUtils; import org.jackhuang.hmcl.util.tree.TarFileTree; @@ -27,11 +29,13 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.PosixFilePermission; import java.util.List; import java.util.Set; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; public final class MacOSProvider implements ITerracottaProvider { public final TerracottaNative installer, binary; @@ -62,19 +66,39 @@ public final class MacOSProvider implements ITerracottaProvider { return Task.allOf( installerTask.thenComposeAsync(() -> { + Path osascript = SystemUtils.which("osascript"); + if (osascript == null) { + throw new IllegalStateException("Cannot locate 'osascript' system executable on MacOS for installing Terracotta."); + } + + Path pkg = Files.createTempDirectory(Metadata.HMCL_GLOBAL_DIRECTORY, "terracotta-pkg") + .toRealPath() + .resolve(FileUtils.getName(installer.getPath())); + Files.copy(installer.getPath(), pkg, StandardCopyOption.REPLACE_EXISTING); + ManagedProcess process = new ManagedProcess(new ProcessBuilder( - "osascript", - "-e", - String.format( - "do shell script \"installer -pkg %s -target /\" with prompt \"%s\" with administrator privileges", - installer.getPath(), - i18n("terracotta.sudo_installing") - ) - )); + osascript.toString(), "-e", String.format( + "do shell script \"installer -pkg '%s' -target /\" with prompt \"%s\" with administrator privileges", + pkg, i18n("terracotta.sudo_installing") + ))); process.pumpInputStream(SystemUtils::onLogLine); process.pumpErrorStream(SystemUtils::onLogLine); - return Task.fromCompletableFuture(process.getProcess().onExit()); + return Task.fromCompletableFuture(process.getProcess().onExit()).thenRunAsync(() -> { + try { + FileUtils.cleanDirectory(pkg.getParent()); + } catch (IOException e) { + LOG.warning("Cannot remove temporary Terracotta package file.", e); + } + + if (process.getExitCode() != 0) { + throw new IllegalStateException(String.format( + "Cannot install Terracotta %s: system installer exited with code %d", + pkg, + process.getExitCode() + )); + } + }); }), binaryTask.thenRunAsync(() -> Files.setPosixFilePermissions(binary.getPath(), Set.of( PosixFilePermission.OWNER_READ, diff --git a/HMCL/src/main/resources/assets/terracotta.json b/HMCL/src/main/resources/assets/terracotta.json index b9a7937e9..dd23c1b54 100644 --- a/HMCL/src/main/resources/assets/terracotta.json +++ b/HMCL/src/main/resources/assets/terracotta.json @@ -1,20 +1,21 @@ { - "version_legacy": "0\\.3\\.([89]-rc\\.([0-9]|10)|10|11)", + "version_legacy": "0\\.3\\.([89]-rc\\.([0-9]|10)|10|11|12)", "version_recent": [ - "0.3.11" + "0.3.12" ], - "version_latest": "0.3.12", + "version_latest": "0.3.13", "classifiers": { - "linux-arm64": "sha256:cb88933f539d287419b9a83960bfdd8252dd2a850cbb39008491916c8a8ee25b", - "linux-x86_64": "sha256:b329fed4157999f1be504a63ea2f5c95985d440435fba2f3b4604dced340572a", - "linux-loongarch64": "sha256:9e6b1beb90817339ca8b40b3e26bd064505cc789d1c5f7df80659d91971042b6", - "linux-riscv64": "sha256:58dde78047e3e0317cc935bfa6db0c2c3f6608fea15f545aa83d78a921805fc4", - "macos-arm64": "sha256:282f47dd0e2667da44b0bef74a87d41d9e568c224515d2f230d2ef25edb1f628", - "macos-arm64.pkg": "sha256:295974ec16d5a69006126d574efe16e7622ab67e85d35cd03020f38670cf3313", - "macos-x86_64": "sha256:8cf097ae87b6f8fdb4a3543176ecc526922201446c18170e779ffff0cc62ec01", - "macos-x86_64.pkg": "sha256:bfc1f4c121c107b3371b56e83cad80924be9016db3c3b39a9db7ae579dbaf1e2", - "windows-arm64.exe": "sha256:cfa93fbc426002dbd25e376457db2a27be101907f568d91e1f92adfcf1b69cb8", - "windows-x86_64.exe": "sha256:2153b676295cf059ca2ac08178e1d3754eb0007c947378cd1ae2ef2b9f7a2a4f" + "freebsd-x86_64": "sha256:0713e54ee552496416bda9d9e814e33a8950ca8f321f5b3c6dd2e07e79b0e3af", + "linux-arm64": "sha256:61affc46035337c182adeca3671b4cf4cc59c7b4e73039899f35416f7d00ad94", + "linux-x86_64": "sha256:9399e1627b77d518950e66d944c9a4b70c20d2e13ca2c0e2fed0ded637e7ae06", + "linux-loongarch64": "sha256:f3eb4c40dfccc25b5b355298c776abe3d399afb57a2af38803dd78089f0c182e", + "linux-riscv64": "sha256:26f95f8b5f83746c9cf9a8362ce0ef793ede8515897a1ba15e5e6f93c3d39533", + "macos-arm64": "sha256:35ba271c7dc924e91c2fdd8c1cabeff2ce3d060836748a7a07162b0a5900e8d5", + "macos-arm64.pkg": "sha256:90a613ec69f28713fe06188247c57b7cc91743c95112de5aed85ea252103beaa", + "macos-x86_64": "sha256:45b420b15a32d5450794a9776cf45a217871cf4333b29b65a35d7358c806b5b1", + "macos-x86_64.pkg": "sha256:587623becb3593ccb5fe542a201a67ab3a4029dfa847fcef758faff7ba6d38d5", + "windows-arm64.exe": "sha256:bd4e1acf2f304761cdabddd9ade94d046534f4c024bc3026ac98e6be58c2bc22", + "windows-x86_64.exe": "sha256:b89599bbcc92b00222cfc6f2e5ef636b7daf192c96efba1049a892e6cb59ee70" }, "downloads": [ "https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}"