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