mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: support restart (#299)
This commit is contained in:
@@ -134,6 +134,10 @@ kotlin-stdlib-jdk8 1.9.10
|
|||||||
Apache License 2.0
|
Apache License 2.0
|
||||||
https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt
|
https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt
|
||||||
|
|
||||||
|
restart4j 0.0.1
|
||||||
|
Apache License 2.0
|
||||||
|
https://github.com/hstyi/restart4j/blob/main/LICENSE
|
||||||
|
|
||||||
kotlinx-coroutines-core-jvm 1.10.1
|
kotlinx-coroutines-core-jvm 1.10.1
|
||||||
Apache License 2.0
|
Apache License 2.0
|
||||||
https://www.apache.org/licenses/LICENSE-2.0
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import org.gradle.kotlin.dsl.support.uppercaseFirstChar
|
|||||||
import org.gradle.nativeplatform.platform.internal.ArchitectureInternal
|
import org.gradle.nativeplatform.platform.internal.ArchitectureInternal
|
||||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||||
import org.jetbrains.kotlin.org.apache.commons.io.FileUtils
|
import org.jetbrains.kotlin.org.apache.commons.io.FileUtils
|
||||||
|
import org.jetbrains.kotlin.org.apache.commons.io.filefilter.FileFilterUtils
|
||||||
import org.jetbrains.kotlin.org.apache.commons.lang3.StringUtils
|
import org.jetbrains.kotlin.org.apache.commons.lang3.StringUtils
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|
||||||
@@ -109,6 +110,7 @@ dependencies {
|
|||||||
implementation(libs.mixpanel)
|
implementation(libs.mixpanel)
|
||||||
implementation(libs.jSerialComm)
|
implementation(libs.jSerialComm)
|
||||||
implementation(libs.ini4j)
|
implementation(libs.ini4j)
|
||||||
|
implementation(libs.restart4j)
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@@ -147,11 +149,13 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
val jna = libs.jna.asProvider().get()
|
val jna = libs.jna.asProvider().get()
|
||||||
val pty4j = libs.pty4j.get()
|
val pty4j = libs.pty4j.get()
|
||||||
val jSerialComm = libs.jSerialComm.get()
|
val jSerialComm = libs.jSerialComm.get()
|
||||||
|
val restart4j = libs.restart4j.get()
|
||||||
|
|
||||||
// 对 JNA 和 PTY4J 的本地库提取
|
// 对 JNA 和 PTY4J 的本地库提取
|
||||||
// 提取出来是为了单独签名,不然无法通过公证
|
// 提取出来是为了单独签名,不然无法通过公证
|
||||||
if (os.isMacOsX && macOSSign) {
|
if (os.isMacOsX && macOSSign) {
|
||||||
doLast {
|
doLast {
|
||||||
|
val archName = if (arch.isArm) "aarch64" else "x86_64"
|
||||||
val dylib = dir.get().dir("dylib").asFile
|
val dylib = dir.get().dir("dylib").asFile
|
||||||
for (file in dir.get().asFile.listFiles() ?: emptyArray()) {
|
for (file in dir.get().asFile.listFiles() ?: emptyArray()) {
|
||||||
if ("${jna.name}-${jna.version}" == file.nameWithoutExtension) {
|
if ("${jna.name}-${jna.version}" == file.nameWithoutExtension) {
|
||||||
@@ -178,7 +182,6 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
// 删除所有二进制类库
|
// 删除所有二进制类库
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "resources/*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*") }
|
||||||
} else if ("${jSerialComm.name}-${jSerialComm.version}" == file.nameWithoutExtension) {
|
} else if ("${jSerialComm.name}-${jSerialComm.version}" == file.nameWithoutExtension) {
|
||||||
val archName = if (arch.isArm) "aarch64" else "x86_64"
|
|
||||||
val targetDir = FileUtils.getFile(dylib, jSerialComm.name, "OSX", archName)
|
val targetDir = FileUtils.getFile(dylib, jSerialComm.name, "OSX", archName)
|
||||||
FileUtils.forceMkdir(targetDir)
|
FileUtils.forceMkdir(targetDir)
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@@ -192,6 +195,24 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
exec { commandLine("zip", "-d", file.absolutePath, "OSX/*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "OSX/*") }
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "Solaris/*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "Solaris/*") }
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "Windows/*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "Windows/*") }
|
||||||
|
} else if ("${restart4j.name}-${restart4j.version}" == file.nameWithoutExtension) {
|
||||||
|
val targetDir = FileUtils.getFile(dylib, restart4j.name)
|
||||||
|
FileUtils.forceMkdir(targetDir)
|
||||||
|
// @formatter:off
|
||||||
|
exec { commandLine("unzip", "-j" , "-o", file.absolutePath, "darwin/${archName}/*", "-d", targetDir.absolutePath) }
|
||||||
|
// @formatter:on
|
||||||
|
// 删除所有二进制类库
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "win32/*") }
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "darwin/*") }
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "linux/*") }
|
||||||
|
// 设置可执行权限
|
||||||
|
for (e in FileUtils.listFiles(
|
||||||
|
targetDir,
|
||||||
|
FileFilterUtils.trueFileFilter(),
|
||||||
|
FileFilterUtils.falseFileFilter()
|
||||||
|
)) {
|
||||||
|
e.setExecutable(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +237,12 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/aix-*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/aix-*") }
|
||||||
if (os.isWindows) {
|
if (os.isWindows) {
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/linux-*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/linux-*") }
|
||||||
|
if (arch.isArm) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/win32-x86*") }
|
||||||
|
} else {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/win32-aarch64/*") }
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/win32-x86/*") }
|
||||||
|
}
|
||||||
} else if (os.isLinux) {
|
} else if (os.isLinux) {
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/win32-*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "com/sun/jna/win32-*") }
|
||||||
}
|
}
|
||||||
@@ -224,6 +251,13 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
exec { commandLine("zip", "-d", file.absolutePath, "resources/*freebsd*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*freebsd*") }
|
||||||
if (os.isWindows) {
|
if (os.isWindows) {
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "resources/*linux*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*linux*") }
|
||||||
|
if (arch.isArm) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win/x86/*") }
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win/x86-64*") }
|
||||||
|
} else {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win/x86/*") }
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win/aarch64/*") }
|
||||||
|
}
|
||||||
} else if (os.isLinux) {
|
} else if (os.isLinux) {
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "resources/*win*") }
|
||||||
}
|
}
|
||||||
@@ -238,6 +272,23 @@ tasks.register<Copy>("copy-dependencies") {
|
|||||||
} else if (os.isLinux) {
|
} else if (os.isLinux) {
|
||||||
exec { commandLine("zip", "-d", file.absolutePath, "Windows/*") }
|
exec { commandLine("zip", "-d", file.absolutePath, "Windows/*") }
|
||||||
}
|
}
|
||||||
|
} else if ("${restart4j.name}-${restart4j.version}" == file.nameWithoutExtension) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "darwin/*") }
|
||||||
|
if (os.isWindows) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "linux/*") }
|
||||||
|
if (arch.isArm) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "win32/x86_64/*") }
|
||||||
|
} else {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "win32/aarch64/*") }
|
||||||
|
}
|
||||||
|
} else if (os.isLinux) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "win32/*") }
|
||||||
|
if (arch.isArm) {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "linux/x86_64/*") }
|
||||||
|
} else {
|
||||||
|
exec { commandLine("zip", "-d", file.absolutePath, "linux/aarch64/*") }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,6 +540,7 @@ Terminal=false
|
|||||||
sb.append("#!/bin/sh").appendLine()
|
sb.append("#!/bin/sh").appendLine()
|
||||||
sb.append("SELF=$(readlink -f \"$0\")").appendLine()
|
sb.append("SELF=$(readlink -f \"$0\")").appendLine()
|
||||||
sb.append("HERE=\${SELF%/*}").appendLine()
|
sb.append("HERE=\${SELF%/*}").appendLine()
|
||||||
|
sb.append("export LinuxAppImage=true").appendLine()
|
||||||
sb.append("exec \"\${HERE}/bin/${termoraName}\" \"$@\"")
|
sb.append("exec \"\${HERE}/bin/${termoraName}\" \"$@\"")
|
||||||
appRun.writeText(sb.toString())
|
appRun.writeText(sb.toString())
|
||||||
appRun.setExecutable(true)
|
appRun.setExecutable(true)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ testcontainers = "1.20.4"
|
|||||||
mixpanel = "1.5.3"
|
mixpanel = "1.5.3"
|
||||||
jSerialComm = "2.11.0"
|
jSerialComm = "2.11.0"
|
||||||
ini4j = "0.5.5-2"
|
ini4j = "0.5.5-2"
|
||||||
|
restart4j = "0.0.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
|
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
|
||||||
@@ -76,6 +77,7 @@ versioncompare = { module = "io.github.g00fy2:versioncompare", version.ref = "ve
|
|||||||
jfa = { module = "de.jangassen:jfa", version.ref = "jfa" }
|
jfa = { module = "de.jangassen:jfa", version.ref = "jfa" }
|
||||||
oshi-core = { module = "com.github.oshi:oshi-core", version.ref = "oshi" }
|
oshi-core = { module = "com.github.oshi:oshi-core", version.ref = "oshi" }
|
||||||
commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
|
commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
|
||||||
|
restart4j = { module = "com.github.hstyi:restart4j", version.ref = "restart4j" }
|
||||||
jbr-api = { module = "com.jetbrains:jbr-api", version.ref = "jbr-api" }
|
jbr-api = { module = "com.jetbrains:jbr-api", version.ref = "jbr-api" }
|
||||||
flatlaf-swingx = { module = "com.formdev:flatlaf-swingx", version.ref = "flatlaf" }
|
flatlaf-swingx = { module = "com.formdev:flatlaf-swingx", version.ref = "flatlaf" }
|
||||||
leveldb = { module = "org.iq80.leveldb:leveldb", version.ref = "leveldb" }
|
leveldb = { module = "org.iq80.leveldb:leveldb", version.ref = "leveldb" }
|
||||||
|
|||||||
@@ -104,16 +104,8 @@ class ApplicationRunner {
|
|||||||
@Suppress("OPT_IN_USAGE")
|
@Suppress("OPT_IN_USAGE")
|
||||||
private fun clearTemporary() {
|
private fun clearTemporary() {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
// 启动时清除
|
// 启动时清除
|
||||||
FileUtils.cleanDirectory(Application.getTemporaryDir())
|
FileUtils.cleanDirectory(Application.getTemporaryDir())
|
||||||
|
|
||||||
// 关闭时清除
|
|
||||||
Disposer.register(ApplicationScope.forApplicationScope(), object : Disposable {
|
|
||||||
override fun dispose() {
|
|
||||||
FileUtils.cleanDirectory(Application.getTemporaryDir())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -195,7 +187,7 @@ class ApplicationRunner {
|
|||||||
themeManager.change(theme, true)
|
themeManager.change(theme, true)
|
||||||
|
|
||||||
if (Application.isUnknownVersion())
|
if (Application.isUnknownVersion())
|
||||||
FlatInspector.install("ctrl shift alt X");
|
FlatInspector.install("ctrl shift alt X")
|
||||||
|
|
||||||
UIManager.put(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
UIManager.put(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
||||||
UIManager.put(FlatClientProperties.USE_WINDOW_DECORATIONS, false)
|
UIManager.put(FlatClientProperties.USE_WINDOW_DECORATIONS, false)
|
||||||
|
|||||||
@@ -50,4 +50,9 @@ private fun setupNativeLibraries() {
|
|||||||
if (jSerialComm.exists()) {
|
if (jSerialComm.exists()) {
|
||||||
System.setProperty("jSerialComm.library.path", jSerialComm.absolutePath)
|
System.setProperty("jSerialComm.library.path", jSerialComm.absolutePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val restart4j = FileUtils.getFile(dylib, "restart4j", "restarter")
|
||||||
|
if (restart4j.exists()) {
|
||||||
|
System.setProperty("restarter.path", restart4j.absolutePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,6 @@ import com.jthemedetecor.OsThemeDetector
|
|||||||
import com.sun.jna.LastErrorException
|
import com.sun.jna.LastErrorException
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.swing.Swing
|
import kotlinx.coroutines.swing.Swing
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
import org.apache.commons.codec.binary.Base64
|
import org.apache.commons.codec.binary.Base64
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
@@ -199,12 +198,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
if (it.stateChange == ItemEvent.SELECTED) {
|
if (it.stateChange == ItemEvent.SELECTED) {
|
||||||
appearance.language = languageComboBox.selectedItem as String
|
appearance.language = languageComboBox.selectedItem as String
|
||||||
SwingUtilities.invokeLater {
|
SwingUtilities.invokeLater {
|
||||||
OptionPane.showMessageDialog(
|
TermoraRestarter.getInstance().scheduleRestart(owner)
|
||||||
owner,
|
|
||||||
I18n.getString("termora.settings.restart.message"),
|
|
||||||
I18n.getString("termora.settings.restart.title"),
|
|
||||||
messageType = JOptionPane.INFORMATION_MESSAGE,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
142
src/main/kotlin/app/termora/TermoraRestarter.kt
Normal file
142
src/main/kotlin/app/termora/TermoraRestarter.kt
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package app.termora
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
|
import com.github.hstyi.restart4j.Restarter
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import org.apache.commons.lang3.StringUtils
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.awt.Component
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import javax.swing.JOptionPane
|
||||||
|
import javax.swing.SwingUtilities
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
|
||||||
|
class TermoraRestarter {
|
||||||
|
companion object {
|
||||||
|
private val log = LoggerFactory.getLogger(TermoraRestarter::class.java)
|
||||||
|
|
||||||
|
fun getInstance(): TermoraRestarter {
|
||||||
|
return ApplicationScope.forApplicationScope().getOrCreate(TermoraRestarter::class) { TermoraRestarter() }
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
Restarter.setProcessHandler { ProcessHandle.current().pid().toInt() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val restarting = AtomicBoolean(false)
|
||||||
|
private val isSupported get() = !restarting.get() && checkIsSupported()
|
||||||
|
private val isLinuxAppImage by lazy { System.getenv("LinuxAppImage")?.toBoolean() == true }
|
||||||
|
private val startupCommand by lazy { ProcessHandle.current().info().command().getOrNull() }
|
||||||
|
private val macOSApplicationPath by lazy {
|
||||||
|
StringUtils.removeEndIgnoreCase(
|
||||||
|
Application.getAppPath(),
|
||||||
|
"/Contents/MacOS/Termora"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restart() {
|
||||||
|
if (!isSupported) return
|
||||||
|
if (!restarting.compareAndSet(false, true)) return
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
try {
|
||||||
|
doRestart()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (log.isErrorEnabled) {
|
||||||
|
log.error(e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划重启,如果当前进程支持重启,那么会询问用户是否重启。如果不支持重启,那么弹窗提示需要手动重启。
|
||||||
|
*/
|
||||||
|
fun scheduleRestart(owner: Component) {
|
||||||
|
|
||||||
|
if (isSupported) {
|
||||||
|
if (OptionPane.showConfirmDialog(
|
||||||
|
owner,
|
||||||
|
I18n.getString("termora.settings.restart.message"),
|
||||||
|
I18n.getString("termora.settings.restart.title"),
|
||||||
|
messageType = JOptionPane.QUESTION_MESSAGE,
|
||||||
|
optionType = JOptionPane.YES_NO_OPTION,
|
||||||
|
options = arrayOf(
|
||||||
|
I18n.getString("termora.settings.restart.title"),
|
||||||
|
I18n.getString("termora.cancel")
|
||||||
|
),
|
||||||
|
initialValue = I18n.getString("termora.settings.restart.title")
|
||||||
|
) == JOptionPane.YES_OPTION
|
||||||
|
) {
|
||||||
|
restart()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OptionPane.showMessageDialog(
|
||||||
|
owner,
|
||||||
|
I18n.getString("termora.settings.restart.message"),
|
||||||
|
I18n.getString("termora.settings.restart.title"),
|
||||||
|
messageType = JOptionPane.INFORMATION_MESSAGE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doRestart() {
|
||||||
|
|
||||||
|
for (window in TermoraFrameManager.getInstance().getWindows()) {
|
||||||
|
window.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SystemInfo.isMacOS) {
|
||||||
|
Restarter.restart(arrayOf("open", "-n", macOSApplicationPath))
|
||||||
|
} else if (SystemInfo.isWindows && startupCommand != null) {
|
||||||
|
Restarter.restart(arrayOf(startupCommand))
|
||||||
|
} else if (SystemInfo.isLinux) {
|
||||||
|
if (isLinuxAppImage) {
|
||||||
|
Restarter.restart(arrayOf(System.getenv("APPIMAGE")))
|
||||||
|
} else if (startupCommand != null) {
|
||||||
|
Restarter.restart(arrayOf(startupCommand))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun checkIsSupported(): Boolean {
|
||||||
|
val appPath = Application.getAppPath()
|
||||||
|
if (appPath.isBlank() || Application.isUnknownVersion()) {
|
||||||
|
if (log.isWarnEnabled) {
|
||||||
|
log.warn("Restart not supported")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("startupCommand: ${startupCommand}")
|
||||||
|
log.info("apppath: ${Application.getAppPath()}")
|
||||||
|
|
||||||
|
if (SystemInfo.isWindows && startupCommand == null) {
|
||||||
|
if (log.isWarnEnabled) {
|
||||||
|
log.warn("Restart not supported , ProcessHandle#info#command is null.")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SystemInfo.isLinux) {
|
||||||
|
if (isLinuxAppImage) {
|
||||||
|
val appImage = System.getenv("APPIMAGE") ?: StringUtils.EMPTY
|
||||||
|
return appImage.isNotBlank() && FileUtils.getFile(appImage).exists()
|
||||||
|
}
|
||||||
|
return startupCommand != null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SystemInfo.isMacOS) {
|
||||||
|
return Application.getAppPath().isNotBlank()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user