From f2ce5df79fce2ec4e35ffa0b56cd7c7eefd22b7b Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Sat, 26 Nov 2011 14:53:33 +0100 Subject: [PATCH] Updater: automatically restart if possible --- bin/mac/relaunch | Bin 42636 -> 38388 bytes native/macrestarter/relaunch.m | 65 +----- .../relaunch.xcodeproj/project.pbxproj | 209 ++++++++++++++++++ .../bootstrap/src/com/intellij/idea/Main.java | 45 +++- .../application/impl/ApplicationImpl.java | 29 +-- .../application/impl/MacRestarter.java | 71 ------ .../application/impl/Win32Restarter.java | 70 ------ .../execution/process/UnixProcessManager.java | 57 +++-- .../util/src/com/intellij/util/Restarter.java | 119 ++++++++++ 9 files changed, 412 insertions(+), 253 deletions(-) create mode 100644 native/macrestarter/relaunch.xcodeproj/project.pbxproj delete mode 100644 platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java delete mode 100644 platform/platform-impl/src/com/intellij/openapi/application/impl/Win32Restarter.java rename platform/{platform-impl => util}/src/com/intellij/execution/process/UnixProcessManager.java (89%) create mode 100644 platform/util/src/com/intellij/util/Restarter.java diff --git a/bin/mac/relaunch b/bin/mac/relaunch index f66c7b8b54f3438f09861b7f903bdf415083532c..a28ad266c7563617869192574714cf796953582d 100755 GIT binary patch literal 38388 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 diff --git a/native/macrestarter/relaunch.m b/native/macrestarter/relaunch.m index 4b596895a9fa..766d70bff8e7 100644 --- a/native/macrestarter/relaunch.m +++ b/native/macrestarter/relaunch.m @@ -2,65 +2,20 @@ #import -@interface TerminationListener : NSObject -{ - const char *executablePath; - pid_t parentProcessId; -} +int main(int argc, const char *argv[]) { + if (argc != 2) return EXIT_FAILURE; -- (void) relaunch; + unsigned int interval = 500; // check every 0.5 second + unsigned int slept = 0; + while (getppid() != 1) { + usleep(interval * 1000); -@end - -@implementation TerminationListener - -- (id) initWithExecutablePath:(const char *)execPath parentProcessId:(pid_t)ppid -{ - self = [super init]; - if (self != nil) { - executablePath = execPath; - parentProcessId = ppid; - - // This adds the input source required by the run loop - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; - if (getppid() == 1) { - // ppid is launchd (1) => parent terminated already - [self relaunch]; - } + slept += interval; + if (slept > 10 * 1000 /* wait for maximum 10 seconds */) return EXIT_FAILURE; } - return self; -} -- (void) applicationDidTerminate:(NSNotification *)notification -{ - if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { - // parent just terminated - [self relaunch]; - } -} - -- (void) relaunch -{ - // [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(actualLaunch) userInfo:nil repeats:NO]; - // NSDate *future = [NSDate dateWithTimeIntervalSinceNow: 5.0 ]; - // [NSThread sleepUntilDate:future]; - - [[NSWorkspace sharedWorkspace] launchApplication:[NSString stringWithUTF8String:executablePath]]; - exit(0); -} - -@end - -int main (int argc, const char * argv[]) -{ - if (argc != 3) return EXIT_FAILURE; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - [[[TerminationListener alloc] initWithExecutablePath:argv[1] parentProcessId:atoi(argv[2])] autorelease]; - [[NSApplication sharedApplication] run]; - - [pool release]; + char const *pathToRelaunch = argv[1]; + [[NSWorkspace sharedWorkspace] launchApplication:[NSString stringWithUTF8String:pathToRelaunch]]; return EXIT_SUCCESS; } \ No newline at end of file diff --git a/native/macrestarter/relaunch.xcodeproj/project.pbxproj b/native/macrestarter/relaunch.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..8cc758f70181 --- /dev/null +++ b/native/macrestarter/relaunch.xcodeproj/project.pbxproj @@ -0,0 +1,209 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3A6C10B4148122790074811C /* relaunch.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A6C10B3148122790074811C /* relaunch.m */; }; + 3A6C10B7148122940074811C /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6C10B6148122940074811C /* AppKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + CF2F99674C3F98D5739C1B44 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3A6C10AE148122660074811C /* relaunch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = relaunch; sourceTree = BUILT_PRODUCTS_DIR; }; + 3A6C10B3148122790074811C /* relaunch.m */ = {isa = PBXFileReference; fileEncoding = 11; lastKnownFileType = sourcecode.c.objc; path = relaunch.m; sourceTree = ""; }; + 3A6C10B6148122940074811C /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + CF2F99674C3F98D5739C1B43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A6C10B7148122940074811C /* AppKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + CF2F99674C3F98D5739C1B39 = { + isa = PBXGroup; + children = ( + 3A6C10B3148122790074811C /* relaunch.m */, + CF2F99674C3F98D5739C1B3A /* Products */, + CF2F99674C3F98D5739C1B45 /* Frameworks */, + 3A6C10B6148122940074811C /* AppKit.framework */, + ); + sourceTree = ""; + }; + CF2F99674C3F98D5739C1B3A /* Products */ = { + isa = PBXGroup; + children = ( + 3A6C10AE148122660074811C /* relaunch */, + ); + name = Products; + sourceTree = ""; + }; + CF2F99674C3F98D5739C1B45 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CF2F99674C3F98D5739C1B3E /* relaunch */ = { + isa = PBXNativeTarget; + buildConfigurationList = CF2F99674C3F98D5739C1B3F /* Build configuration list for PBXNativeTarget "relaunch" */; + buildPhases = ( + CF2F99674C3F98D5739C1B42 /* Sources */, + CF2F99674C3F98D5739C1B43 /* Frameworks */, + CF2F99674C3F98D5739C1B44 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = relaunch; + productName = relaunch; + productReference = 3A6C10AE148122660074811C /* relaunch */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CF2F99674C3F98D5739C1B37 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = CF2F99674C3F98D5739C1B38 /* Build configuration list for PBXProject "relaunch" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = CF2F99674C3F98D5739C1B39; + productRefGroup = CF2F99674C3F98D5739C1B3A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CF2F99674C3F98D5739C1B3E /* relaunch */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + CF2F99674C3F98D5739C1B42 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A6C10B4148122790074811C /* relaunch.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + CF2F99674C3F98D5739C1B3B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = 4.0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.4; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = macosx10.4; + }; + name = Release; + }; + CF2F99674C3F98D5739C1B3C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = 4.0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.4; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = macosx10.4; + }; + name = Debug; + }; + CF2F99674C3F98D5739C1B40 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + CF2F99674C3F98D5739C1B41 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CF2F99674C3F98D5739C1B38 /* Build configuration list for PBXProject "relaunch" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CF2F99674C3F98D5739C1B3B /* Release */, + CF2F99674C3F98D5739C1B3C /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CF2F99674C3F98D5739C1B3F /* Build configuration list for PBXNativeTarget "relaunch" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CF2F99674C3F98D5739C1B40 /* Release */, + CF2F99674C3F98D5739C1B41 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = CF2F99674C3F98D5739C1B37 /* Project object */; +} diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 3cd1ab049f45..aade22a072d8 100644 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.java @@ -19,6 +19,7 @@ package com.intellij.idea; import com.intellij.ide.Bootstrap; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.Restarter; import org.jetbrains.annotations.NonNls; import javax.swing.*; @@ -39,12 +40,38 @@ public class Main { public static void main(final String[] args) { if (installPatch()) { + + boolean restarted = false; try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + restarted = Restarter.restart(); } - catch (Exception ignore) { } - JOptionPane.showMessageDialog(null, "The application cannot start right away since some critical files have been changed, " + - "please restart it manually."); + catch (Restarter.CannotRestartException e) { + // noinspection CallToPrintStackTrace + e.printStackTrace(); + } + + final int restartCode = Restarter.getRestartCode(); + + if (!restarted && restartCode == 0) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception ignore) { + } + JOptionPane.showMessageDialog(null, + "The application cannot start right away since some critical files have been changed.\n" + + "Please restart it manually.", + "Update", + JOptionPane.INFORMATION_MESSAGE); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + System.exit(restartCode); + } + }); + return; } @@ -69,11 +96,11 @@ public class Main { return false; } final String firstArg = args[0]; - return forceEnabledHeadlessMode || - Comparing.strEqual(firstArg, antAppCode) || - Comparing.strEqual(firstArg, duplocateCode) || - Comparing.strEqual(firstArg, traverseUI) || - (firstArg.length() < 20 && firstArg.endsWith("inspect")); + return forceEnabledHeadlessMode || + Comparing.strEqual(firstArg, antAppCode) || + Comparing.strEqual(firstArg, duplocateCode) || + Comparing.strEqual(firstArg, traverseUI) || + (firstArg.length() < 20 && firstArg.endsWith("inspect")); } public static boolean isUITraverser(final String[] args) { 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 8b3ab3ec0eaa..8408e01bdaf6 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 @@ -59,6 +59,7 @@ import com.intellij.ui.Splash; import com.intellij.util.Consumer; import com.intellij.util.EventDispatcher; import com.intellij.util.ReflectionCache; +import com.intellij.util.Restarter; import com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock; import com.intellij.util.containers.Stack; import com.intellij.util.io.storage.HeavyProcessLatch; @@ -246,13 +247,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application }); } - final String s = System.getProperty("jb.restart.code"); - if (s != null) { - try { - myRestartCode = Integer.parseInt(s); - } catch (NumberFormatException ignore) { - } - } + myRestartCode = Restarter.getRestartCode(); registerFont("/fonts/Inconsolata.ttf"); } @@ -1297,23 +1292,23 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } public boolean isRestartCapable() { - return SystemInfo.isWindows || SystemInfo.isMacOSSnowLeopard || myRestartCode > 0; + return Restarter.isSupported() || myRestartCode > 0; } public void restart() { - if (SystemInfo.isWindows) { - Win32Restarter.restart(); + boolean restarted = false; + try { + restarted = Restarter.restart(); } - else if (SystemInfo.isMacOSSnowLeopard) { - MacRestarter.restart(); + catch (Restarter.CannotRestartException e) { + LOG.warn(e); } - else if (myRestartCode > 0) { + + if (!restarted) { myExitCode = myRestartCode; - exit(true); - } - else { - exit(true); } + + exit(true); } public boolean isSaving() { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java deleted file mode 100644 index 73b76980be65..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/MacRestarter.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.openapi.application.impl; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ex.ApplicationEx; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.ui.mac.foundation.Foundation; -import com.intellij.ui.mac.foundation.ID; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; - -/** - * User: spLeaner - */ -public class MacRestarter { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.MacRestarter"); - - private MacRestarter() { - } - - @SuppressWarnings({"RedundantArrayCreation"}) - public static void restart() { - final ID autoReleasePool = Foundation.invoke("NSAutoreleasePool", "new"); - final ID app = Foundation.invoke("NSRunningApplication", "currentApplication"); - final ID executableURL = Foundation.invoke(app, Foundation.createSelector("executableURL")); - final ID stringURL = Foundation.invoke(executableURL, Foundation.createSelector("absoluteString")); - - try { - final String executablePath = Foundation.toStringViaUTF8(stringURL); - final URL url = new URL(executablePath); - final String path = url.getPath().replace("%20", " "); - if (path.contains(".app")) { - final int appIndex = path.indexOf(".app"); - final String appPath = path.substring(0, appIndex + 4); - final String relaunchPath = path.substring(0, path.lastIndexOf('/')) + "/../../bin/relaunch"; - if (new File(relaunchPath).exists()) { - final long processId = Foundation.invoke(app, Foundation.createSelector("processIdentifier")).longValue(); - - final ID args = Foundation.invoke(Foundation.getClass("NSArray"), Foundation.createSelector("arrayWithObjects:"), - new Object[]{Foundation.nsString(appPath), Foundation.nsString(String.valueOf(processId))}); - - Foundation.invoke(Foundation.getClass("NSTask"), Foundation.createSelector("launchedTaskWithLaunchPath:arguments:"), - Foundation.nsString(relaunchPath), args); - } - } - } - catch (MalformedURLException e) { - LOG.error(e); - } - finally { - Foundation.invoke(autoReleasePool, Foundation.createSelector("release")); - ((ApplicationEx)ApplicationManager.getApplication()).exit(true); - } - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/Win32Restarter.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/Win32Restarter.java deleted file mode 100644 index 74cd447b3a0e..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/Win32Restarter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.openapi.application.impl; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.ex.ApplicationEx; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.ui.Messages; -import com.sun.jna.Native; -import com.sun.jna.WString; -import com.sun.jna.win32.StdCallLibrary; - -import java.io.File; -import java.io.IOException; - -/** - * @author yole - */ -public class Win32Restarter { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.Win32Restarter"); - - private Win32Restarter() { - } - - public static void restart() { - Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); - WString cline = kernel32.GetCommandLineW(); - int pid = kernel32.GetCurrentProcessId(); - - try { - String command = "restarter " + Integer.toString(pid) + " " + cline; - LOG.info("Restarter command: " + command); - Runtime.getRuntime().exec(command, null, new File(PathManager.getBinPath())); - } - catch (IOException ex) { - Messages.showMessageDialog("Restart failed: " + ex.getMessage(), "Restart", Messages.getErrorIcon()); - return; - } - - // Since the process ID is passed through the command line, we want to make sure that we don't exit before the "restarter" - // process has a chance to open the handle to our process, and that it doesn't wait for the termination of an unrelated - // process which happened to have the same process ID. - try { - Thread.sleep(500); - } - catch (InterruptedException e1) { - // ignore - } - ((ApplicationEx)ApplicationManager.getApplication()).exit(true); - } - - private interface Kernel32 extends StdCallLibrary { - WString GetCommandLineW(); - int GetCurrentProcessId(); - } -} diff --git a/platform/platform-impl/src/com/intellij/execution/process/UnixProcessManager.java b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java similarity index 89% rename from platform/platform-impl/src/com/intellij/execution/process/UnixProcessManager.java rename to platform/util/src/com/intellij/execution/process/UnixProcessManager.java index 2a799ae83ffd..4a85fe333337 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/UnixProcessManager.java +++ b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,6 @@ */ package com.intellij.execution.process; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.intellij.openapi.util.SystemInfo; import com.sun.jna.Library; import com.sun.jna.Native; @@ -25,16 +23,8 @@ import org.jetbrains.annotations.NotNull; import java.io.*; import java.lang.reflect.Field; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.StringTokenizer; +import java.util.*; -/** - * Utility class to terminate unix processes. - * - * @author traff - */ public class UnixProcessManager { public static final int SIGINT = 2; public static final int SIGKILL = 9; @@ -56,6 +46,25 @@ public class UnixProcessManager { private UnixProcessManager() { } + public static int getProcessPid() { + checkCLib(); + return C_LIB.getpid(); + } + + public static int getProcessPid(Process process) { + try { + Field f = process.getClass().getDeclaredField("pid"); + f.setAccessible(true); + return ((Number)f.get(process)).intValue(); + } + catch (NoSuchFieldException e) { + throw new IllegalStateException("system is not unix", e); + } + catch (IllegalAccessException e) { + throw new IllegalStateException("system is not unix", e); + } + } + public static void sendSignal(Process process, int signal) { int process_pid = getProcessPid(process); sendSignal(process_pid, signal); @@ -99,11 +108,11 @@ public class UnixProcessManager { @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"}) BufferedReader stdInput = new BufferedReader(new - InputStreamReader(p.getInputStream())); + InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new - InputStreamReader(p.getErrorStream())); + InputStreamReader(p.getErrorStream())); - List childrenPids = Lists.newArrayList(); + List childrenPids = new ArrayList(); boolean result; try { @@ -162,20 +171,6 @@ public class UnixProcessManager { } } - public static int getProcessPid(Process process) { - try { - Field f = process.getClass().getDeclaredField("pid"); - f.setAccessible(true); - return ((Number)f.get(process)).intValue(); - } - catch (NoSuchFieldException e) { - throw new IllegalStateException("system is not unix", e); - } - catch (IllegalAccessException e) { - throw new IllegalStateException("system is not unix", e); - } - } - public static String[] getPSCmd(boolean commandLineOnly) { if (SystemInfo.isLinux) { return new String[]{"ps", "-e", "e", "--format", commandLineOnly ? "%a" : "%P%p%a"}; @@ -210,11 +205,11 @@ public class UnixProcessManager { } private static class ProcessInfo { - private Map> BY_PARENT = Maps.newTreeMap(); // pid -> list of children pids + private Map> BY_PARENT = new TreeMap>(); // pid -> list of children pids public void register(Integer pid, Integer parentPid) { List children = BY_PARENT.get(parentPid); - if (children == null) children = Lists.newLinkedList(); + if (children == null) children = new LinkedList(); children.add(pid); BY_PARENT.put(parentPid, children); } diff --git a/platform/util/src/com/intellij/util/Restarter.java b/platform/util/src/com/intellij/util/Restarter.java new file mode 100644 index 000000000000..423d1eb7c872 --- /dev/null +++ b/platform/util/src/com/intellij/util/Restarter.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.util.SystemInfo; +import com.sun.jna.Native; +import com.sun.jna.WString; +import com.sun.jna.win32.StdCallLibrary; + +import java.io.File; +import java.io.IOException; + +public class Restarter { + private Restarter() { + } + + public static int getRestartCode() { + String s = System.getProperty("jb.restart.code"); + if (s != null) { + try { + return Integer.parseInt(s); + } + catch (NumberFormatException ignore) { + } + } + return 0; + } + + public static boolean isSupported() { + return SystemInfo.isWindows || SystemInfo.isMac; + } + + public static boolean restart() throws CannotRestartException { + try { + if (SystemInfo.isWindows) { + return restartOnWindows(); + } + else if (SystemInfo.isMac) { + return restartOnMac(); + } + } + catch (CannotRestartException e) { + throw e; + } + catch (Throwable e) { + throw new CannotRestartException(e); + } + return false; + } + + private static boolean restartOnWindows() throws CannotRestartException { + Kernel32 kernel32 = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class); + WString cline = kernel32.GetCommandLineW(); + int pid = kernel32.GetCurrentProcessId(); + + try { + String command = "restarter " + Integer.toString(pid) + " " + cline; + Runtime.getRuntime().exec(command, null, new File(PathManager.getBinPath())); + } + catch (IOException ex) { + throw new CannotRestartException(ex); + } + + // Since the process ID is passed through the command line, we want to make sure that we don't exit before the "restarter" + // process has a chance to open the handle to our process, and that it doesn't wait for the termination of an unrelated + // process which happened to have the same process ID. + try { + Thread.sleep(500); + } + catch (InterruptedException e1) { + // ignore + } + return true; + } + + private interface Kernel32 extends StdCallLibrary { + WString GetCommandLineW(); + + int GetCurrentProcessId(); + } + + private static boolean restartOnMac() throws CannotRestartException { + String binPath = PathManager.getBinPath(); + + if (!binPath.contains(".app")) return false; + + int appIndex = binPath.indexOf(".app"); + String appPath = binPath.substring(0, appIndex + 4); + + try { + Runtime.getRuntime().exec(new String[]{new File(PathManager.getBinPath(), "relaunch").getPath(), appPath}); + } + catch (IOException e) { + throw new CannotRestartException(e); + } + + return true; + } + + public static class CannotRestartException extends Exception { + public CannotRestartException(Throwable cause) { + super(cause); + } + } +}