[platform] better restarter for Linux (IDEA-161186)

This commit is contained in:
Roman Shevchenko
2016-09-24 17:21:11 +03:00
parent 8770a7c21c
commit e7571b78c0
11 changed files with 83 additions and 86 deletions
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
# Waits for the parent process to terminate, then executes specified commands.
import os
import sys
import time
if len(sys.argv) < 2:
raise Exception('At least one argument expected')
while os.getppid() != 1:
time.sleep(0.5)
if len(sys.argv) > 2:
os.spawnv(os.P_WAIT, sys.argv[2], sys.argv[2:])
to_launch = sys.argv[1]
if sys.platform == 'darwin':
os.execv('/usr/bin/open', ['/usr/bin/open', to_launch])
else:
os.execv(to_launch, [to_launch])
+2 -14
View File
@@ -184,23 +184,11 @@ LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JAVA_BIN" \
"-Xbootclasspath/a:$IDE_HOME/lib/boot.jar" \
-classpath "$CLASSPATH" \
${VM_OPTIONS} \
"-Djb.vmOptionsFile=$VM_OPTIONS_FILE" \
"-XX:ErrorFile=$HOME/java_error_in_@@product_uc@@_%p.log" \
"-XX:HeapDumpPath=$HOME/java_error_in_@@product_uc@@.hprof" \
-Djb.restart.code=88 -Didea.paths.selector=@@system_selector@@ \
-Didea.paths.selector=@@system_selector@@ \
"-Djb.vmOptionsFile=$VM_OPTIONS_FILE" \
${IDE_PROPERTIES_PROPERTY} \
@@ide_jvm_args@@ \
com.intellij.idea.Main \
"$@"
EC=$?
unset IFS
test ${EC} -ne 88 && exit ${EC}
RESTARTER="$HOME/.@@system_selector@@/system/restart/restarter.sh"
if [ -x "$RESTARTER" ]; then
"$RESTARTER"
"$RM" -f "$RESTARTER"
fi
exec "$0"
@@ -78,11 +78,13 @@ class CrossPlatformDistributionBuilder {
exclude(name: "bin/fsnotifier*")
exclude(name: "bin/*.vmoptions")
exclude(name: "bin/*.sh")
exclude(name: "bin/*.py")
exclude(name: "bin/idea.properties")
exclude(name: "help/**")
}
zipfileset(dir: "$linuxDistPath/bin", filemode: "775", prefix: "bin") {
zipfileset(dir: "$linuxDistPath/bin", prefix: "bin", filemode: "775") {
include(name: "*.sh")
include(name: "*.py")
}
zipfileset(dir: "$linuxDistPath/bin", prefix: "bin/linux", filemode: "775") {
include(name: "fsnotifier*")
@@ -97,7 +99,7 @@ class CrossPlatformDistributionBuilder {
exclude(name: "bin/idea.properties")
exclude(name: "bin/*.vmoptions")
}
zipfileset(dir: "$macDistPath/bin", filemode: "775", prefix: "bin") {
zipfileset(dir: "$macDistPath/bin", prefix: "bin", filemode: "775") {
include(name: "restarter*")
include(name: "*.py")
}
@@ -157,6 +157,7 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder {
paths.each {
tarfileset(dir: it, prefix: tarRoot) {
exclude(name: "bin/*.sh")
exclude(name: "bin/*.py")
exclude(name: "bin/fsnotifier*")
extraBins.each {
exclude(name: it)
@@ -166,8 +167,9 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder {
}
paths.each {
tarfileset(dir: it, filemode: "755", prefix: tarRoot) {
tarfileset(dir: it, prefix: tarRoot, filemode: "755") {
include(name: "bin/*.sh")
include(name: "bin/*.py")
include(name: "bin/fsnotifier*")
extraBins.each {
include(name: it)
+8 -4
View File
@@ -1006,10 +1006,12 @@ binding.setVariable("buildCrossPlatformZip", { String zipPath, String sandbox, L
exclude(name: "bin/fsnotifier*")
exclude(name: "bin/*.vmoptions")
exclude(name: "bin/*.sh")
exclude(name: "bin/*.py")
exclude(name: "help/**")
}
zipfileset(dir: "$distUnix/bin", filemode: "775", prefix: "bin") {
zipfileset(dir: "$distUnix/bin", prefix: "bin", filemode: "775") {
include(name: "*.sh")
include(name: "*.py")
}
zipfileset(dir: "$distUnix/bin", prefix: "bin/linux", filemode: "775") {
include(name: "fsnotifier*")
@@ -1024,7 +1026,7 @@ binding.setVariable("buildCrossPlatformZip", { String zipPath, String sandbox, L
exclude(name: "bin/idea.properties")
exclude(name: "bin/*.vmoptions")
}
zipfileset(dir: "$distMac/bin", filemode: "775", prefix: "bin") {
zipfileset(dir: "$distMac/bin", prefix: "bin", filemode: "775") {
include(name: "restarter*")
include(name: "*.py")
}
@@ -1058,7 +1060,7 @@ binding.setVariable("buildMacZip", { String zipRoot, String zipPath, List paths,
}
allPaths.each {
zipfileset(dir: it, filemode: "755", prefix: zipRoot) {
zipfileset(dir: it, prefix: zipRoot, filemode: "755") {
include(name: "bin/*.sh")
include(name: "bin/*.py")
include(name: "bin/fsnotifier")
@@ -1090,6 +1092,7 @@ binding.setVariable("buildTarGz", { String tarRoot, String tarPath, List paths,
paths.each {
tarfileset(dir: it, prefix: tarRoot) {
exclude(name: "bin/*.sh")
exclude(name: "bin/*.py")
exclude(name: "bin/fsnotifier*")
extraBins.each {
exclude(name: it)
@@ -1099,8 +1102,9 @@ binding.setVariable("buildTarGz", { String tarRoot, String tarPath, List paths,
}
paths.each {
tarfileset(dir: it, filemode: "755", prefix: tarRoot) {
tarfileset(dir: it, prefix: tarRoot, filemode: "755") {
include(name: "bin/*.sh")
include(name: "bin/*.py")
include(name: "bin/fsnotifier*")
extraBins.each {
include(name: it)
+1
View File
@@ -53,6 +53,7 @@ OS_TYPE=`uname -s`
if [ "$OS_TYPE" = "Linux" ]; then
cp -a "$DEV_IDEA_HOME/bin/linux/"*.so "$WORK_IDEA_HOME/bin"
cp -a "$DEV_IDEA_HOME/bin/linux/"fsnotifier* "$WORK_IDEA_HOME/bin"
cp -a "$DEV_IDEA_HOME/bin/linux/"*.py "$WORK_IDEA_HOME/bin"
elif [ "$OS_TYPE" = "Darwin" ]; then
cp -a "$DEV_IDEA_HOME/bin/mac/"*.jnilib "$WORK_IDEA_HOME/bin"
cp -a "$DEV_IDEA_HOME/bin/mac/fsnotifier" "$WORK_IDEA_HOME/bin"
@@ -30,7 +30,7 @@ import java.io.StringWriter;
public class Main {
public static final int NO_GRAPHICS = 1;
//public static final int UPDATE_FAILED = 2;
public static final int RESTART_FAILED = 2;
public static final int STARTUP_EXCEPTION = 3;
public static final int JDK_CHECK_FAILED = 4;
public static final int DIR_CHECK_FAILED = 5;
@@ -64,6 +64,7 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter {
public void initComponent() {
checkJvm();
checkIBus();
checkLauncherScript();
startDiskSpaceMonitoring();
}
@@ -91,6 +92,12 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter {
}
}
private void checkLauncherScript() {
if (SystemInfo.isXWindow && System.getProperty("jb.restart.code") != null) {
showNotification("ide.launcher.script.outdated");
}
}
private void showNotification(@PropertyKey(resourceBundle = "messages.IdeBundle") String key) {
final String ignoreKey = "ignore." + key;
boolean ignored = myProperties.isValueSet(ignoreKey);
@@ -780,10 +780,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
int exitCode = 0;
if (restart && Restarter.isSupported()) {
try {
exitCode = Restarter.scheduleRestart(beforeRestart);
Restarter.scheduleRestart(beforeRestart);
}
catch (IOException e) {
LOG.error("Cannot restart", e);
catch (Throwable t) {
LOG.error("Restart failed", t);
Main.showMessage("Restart failed", t);
exitCode = Main.RESTART_FAILED;
}
}
System.exit(exitCode);
@@ -16,6 +16,7 @@
package com.intellij.util;
import com.intellij.jna.JnaLoader;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtilRt;
@@ -28,9 +29,7 @@ import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -39,76 +38,40 @@ import java.util.List;
public class Restarter {
private Restarter() { }
private static int getRestartCode() {
return SystemProperties.getIntProperty("jb.restart.code", 0);
private static File getLauncherScript() {
return new File(PathManager.getBinPath(), ApplicationNamesInfo.getInstance().getLowercaseProductName() + ".sh");
}
public static boolean isSupported() {
if (getRestartCode() != 0) {
return true;
}
if (SystemInfo.isWindows) {
return JnaLoader.isLoaded() && new File(PathManager.getBinPath(), "restarter.exe").exists();
}
if (SystemInfo.isMac) {
return PathManager.getHomePath().contains(".app");
return PathManager.getHomePath().contains(".app") && new File(PathManager.getBinPath(), "restarter").canExecute();
}
if (SystemInfo.isUnix) {
return getLauncherScript().canExecute() && new File(PathManager.getBinPath(), "restart.py").canExecute();
}
return false;
}
public static int scheduleRestart(@NotNull String... beforeRestart) throws IOException {
try {
int restartCode = getRestartCode();
if (restartCode != 0) {
runCommand(beforeRestart);
return restartCode;
}
else if (SystemInfo.isWindows) {
restartOnWindows(beforeRestart);
return 0;
}
else if (SystemInfo.isMac) {
restartOnMac(beforeRestart);
return 0;
}
public static void scheduleRestart(@NotNull String... beforeRestart) throws IOException {
if (SystemInfo.isWindows) {
restartOnWindows(beforeRestart);
}
catch (Throwable t) {
throw new IOException("Cannot restart application: " + t.getMessage(), t);
else if (SystemInfo.isMac) {
restartOnMac(beforeRestart);
}
runCommand(beforeRestart);
throw new IOException("Cannot restart application: not supported.");
}
private static void runCommand(String... beforeRestart) throws IOException {
if (beforeRestart.length == 0) return;
File restartDir = new File(getRestarterDir());
String systemPath = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/system/restart").getPath();
if (! systemPath.equals(restartDir.getPath())){
throw new IOException("idea.system.path was changed. Restart is not supported.");
else if (SystemInfo.isUnix) {
restartOnUnix(beforeRestart);
}
if (!FileUtilRt.createDirectory(restartDir)) {
throw new IOException("Cannot create dir: " + restartDir);
}
File restarter = new File(restartDir, "restarter.sh");
try (BufferedWriter output = new BufferedWriter(new FileWriter(restarter))) {
output.write("#!/bin/sh\n");
for (int i = 0; i < beforeRestart.length; i++) {
output.write(beforeRestart[i]);
if (i <= beforeRestart.length - 2) output.write(' ');
if (i >= beforeRestart.length - 2) output.write('"');
}
output.write('\n');
}
if (!restarter.setExecutable(true, true)) {
throw new IOException("Cannot make file executable: " + restarter);
else {
throw new IOException("Cannot restart application: not supported.");
}
}
private static void restartOnWindows(@NotNull String... beforeRestart) throws IOException {
private static void restartOnWindows(String... beforeRestart) throws IOException {
Kernel32 kernel32 = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class);
Shell32 shell32 = (Shell32)Native.loadLibrary("shell32", Shell32.class);
@@ -144,14 +107,22 @@ public class Restarter {
TimeoutUtil.sleep(500);
}
private static void restartOnMac(@NotNull String... beforeRestart) throws IOException {
private static void restartOnMac(String... beforeRestart) throws IOException {
String homePath = PathManager.getHomePath();
int p = homePath.indexOf(".app");
if (p < 0) throw new IOException("Application bundle not found: " + homePath);
String bundlePath = homePath.substring(0, p + 4);
doScheduleRestart(new File(PathManager.getBinPath(), "restarter"), commands -> {
Collections.addAll(commands, bundlePath);
commands.add(bundlePath);
Collections.addAll(commands, beforeRestart);
});
}
private static void restartOnUnix(String... beforeRestart) throws IOException {
File launcherScript = getLauncherScript();
if (!launcherScript.exists()) throw new IOException("Launcher script not found: " + launcherScript);
doScheduleRestart(new File(PathManager.getBinPath(), "restart.py"), commands -> {
commands.add(launcherScript.getPath());
Collections.addAll(commands, beforeRestart);
});
}
@@ -1138,11 +1138,9 @@ FileChooser.refreshActionLabelText=Refresh
browsers.settings=Web Browsers
updates.check.period.on.exit=On every exit
unsupported.jvm.openjdk.message=OpenJDK 6 is not supported. Please use Oracle Java or newer OpenJDK.
unsupported.jvm.ea.message=Early Access Java versions may cause compatibility issues. Please use stable release.
ibus.blocking.warn.message=IBus prior to 1.5.11 may cause input problems. See <a href="https://youtrack.jetbrains.com/issue/IDEA-78860">IDEA-78860</a> for details.
ide.launcher.script.outdated=IDE launcher script (idea.sh) is outdated. Please upgrade, otherwise you won't be able to restart the IDE.
sys.health.acknowledge.link=<br/><a href="ack">Do not show again</a>.
low.disk.space.message=Low disk space on a {0} system directory partition