diff --git a/bin/linux/restart.py b/bin/linux/restart.py
new file mode 100755
index 000000000000..9055b0308259
--- /dev/null
+++ b/bin/linux/restart.py
@@ -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])
diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh
index 786a99486585..38487a589aa4 100755
--- a/bin/scripts/unix/idea.sh
+++ b/bin/scripts/unix/idea.sh
@@ -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"
diff --git a/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy
index 1f2b603a71ee..6d2cbd5861cb 100644
--- a/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy
+++ b/build/groovy/org/jetbrains/intellij/build/impl/CrossPlatformDistributionBuilder.groovy
@@ -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")
}
diff --git a/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy
index a80bd98e956b..df30239efe13 100644
--- a/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy
+++ b/build/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy
@@ -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)
diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant
index e6b010a1cb93..5bc2b23fb9ce 100644
--- a/build/scripts/utils.gant
+++ b/build/scripts/utils.gant
@@ -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)
diff --git a/build/update.sh b/build/update.sh
index ba75073ff0c2..099b6332f180 100755
--- a/build/update.sh
+++ b/build/update.sh
@@ -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"
diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java
index 2988d812edd7..8adafa0c9b7f 100644
--- a/platform/bootstrap/src/com/intellij/idea/Main.java
+++ b/platform/bootstrap/src/com/intellij/idea/Main.java
@@ -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;
diff --git a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java
index 00a7e0094a96..d80290d4a19b 100644
--- a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java
+++ b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java
@@ -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);
diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
index 10cdb97b8285..8485b9d9fe66 100644
--- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
@@ -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);
diff --git a/platform/platform-impl/src/com/intellij/util/Restarter.java b/platform/platform-impl/src/com/intellij/util/Restarter.java
index c9d8862e6839..4787908047dc 100644
--- a/platform/platform-impl/src/com/intellij/util/Restarter.java
+++ b/platform/platform-impl/src/com/intellij/util/Restarter.java
@@ -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);
});
}
diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties
index b91af5868706..83c64e9d3955 100644
--- a/platform/platform-resources-en/src/messages/IdeBundle.properties
+++ b/platform/platform-resources-en/src/messages/IdeBundle.properties
@@ -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 IDEA-78860 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=
Do not show again.
low.disk.space.message=Low disk space on a {0} system directory partition