ZD-52550 (better startup diagnostic)
[idea/community.git] / platform / bootstrap / src / com / intellij / idea / Main.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.idea;
17
18 import com.intellij.ide.Bootstrap;
19 import com.intellij.openapi.application.PathManager;
20 import com.intellij.openapi.util.Comparing;
21 import com.intellij.openapi.util.SystemInfoRt;
22 import com.intellij.openapi.util.io.FileUtilRt;
23 import com.intellij.util.ArrayUtilRt;
24 import com.intellij.util.Restarter;
25 import com.intellij.util.ui.JBUI;
26 import com.intellij.util.ui.UIUtil;
27
28 import javax.swing.*;
29 import java.awt.*;
30 import java.io.*;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.Locale;
35
36 @SuppressWarnings({"UseOfSystemOutOrSystemErr", "MethodNamesDifferingOnlyByCase"})
37 public class Main {
38   public static final int NO_GRAPHICS = 1;
39   public static final int UPDATE_FAILED = 2;
40   public static final int STARTUP_EXCEPTION = 3;
41   public static final int JDK_CHECK_FAILED = 4;
42   public static final int DIR_CHECK_FAILED = 5;
43   public static final int INSTANCE_CHECK_FAILED = 6;
44   public static final int LICENSE_ERROR = 7;
45   public static final int PLUGIN_ERROR = 8;
46
47   private static final String AWT_HEADLESS = "java.awt.headless";
48   private static final String PLATFORM_PREFIX_PROPERTY = "idea.platform.prefix";
49   private static final String[] NO_ARGS = {};
50
51   private static boolean isHeadless;
52   private static boolean isCommandLine;
53
54   private Main() { }
55
56   public static void main(String[] args) {
57     if (args.length == 1 && "%f".equals(args[0])) {
58       args = NO_ARGS;
59     }
60
61     setFlags(args);
62
63     if (isHeadless()) {
64       System.setProperty(AWT_HEADLESS, Boolean.TRUE.toString());
65     }
66     else if (GraphicsEnvironment.isHeadless()) {
67       showMessage("Startup Error", "Unable to detect graphics environment", true);
68       System.exit(NO_GRAPHICS);
69     }
70     else if (args.length == 0) {
71       try {
72         installPatch();
73       }
74       catch (Throwable t) {
75         showMessage("Update Failed", t);
76         System.exit(UPDATE_FAILED);
77       }
78     }
79
80     try {
81       Bootstrap.main(args, Main.class.getName() + "Impl", "start");
82     }
83     catch (Throwable t) {
84       showMessage("Start Failed", t);
85       System.exit(STARTUP_EXCEPTION);
86     }
87   }
88
89   public static boolean isHeadless() {
90     return isHeadless;
91   }
92
93   public static boolean isCommandLine() {
94     return isCommandLine;
95   }
96
97   public static void setFlags(String[] args) {
98     isHeadless = isHeadless(args);
99     isCommandLine = isCommandLine(args);
100   }
101
102   private static boolean isHeadless(String[] args) {
103     if (Boolean.valueOf(System.getProperty(AWT_HEADLESS))) {
104       return true;
105     }
106
107     if (args.length == 0) {
108       return false;
109     }
110
111     String firstArg = args[0];
112     return Comparing.strEqual(firstArg, "ant") ||
113            Comparing.strEqual(firstArg, "duplocate") ||
114            Comparing.strEqual(firstArg, "traverseUI") ||
115            (firstArg.length() < 20 && firstArg.endsWith("inspect"));
116   }
117
118   private static boolean isCommandLine(String[] args) {
119     if (isHeadless()) return true;
120     return args.length > 0 && Comparing.strEqual(args[0], "diff");
121   }
122
123   public static boolean isUITraverser(final String[] args) {
124     return args.length > 0 && Comparing.strEqual(args[0], "traverseUI");
125   }
126
127   private static void installPatch() throws IOException {
128     String platform = System.getProperty(PLATFORM_PREFIX_PROPERTY, "idea");
129     String patchFileName = ("jetbrains.patch.jar." + platform).toLowerCase(Locale.US);
130     String tempDir = System.getProperty("java.io.tmpdir");
131
132     // always delete previous patch copy
133     File patchCopy = new File(tempDir, patchFileName + "_copy");
134     File log4jCopy = new File(tempDir, "log4j.jar." + platform + "_copy");
135     File jnaUtilsCopy = new File(tempDir, "jna-utils.jar." + platform + "_copy");
136     File jnaCopy = new File(tempDir, "jna.jar." + platform + "_copy");
137     if (!FileUtilRt.delete(patchCopy) || !FileUtilRt.delete(log4jCopy) || !FileUtilRt.delete(jnaUtilsCopy) || !FileUtilRt.delete(jnaCopy)) {
138       throw new IOException("Cannot delete temporary files in " + tempDir);
139     }
140
141     File patch = new File(tempDir, patchFileName);
142     if (!patch.exists()) return;
143
144     File log4j = new File(PathManager.getLibPath(), "log4j.jar");
145     if (!log4j.exists()) throw new IOException("Log4J is missing: " + log4j);
146
147     File jnaUtils = new File(PathManager.getLibPath(), "jna-utils.jar");
148     if (!jnaUtils.exists()) throw new IOException("jna-utils.jar is missing: " + jnaUtils);
149
150     File jna = new File(PathManager.getLibPath(), "jna.jar");
151     if (!jna.exists()) throw new IOException("jna is missing: " + jna);
152
153     copyFile(patch, patchCopy, true);
154     copyFile(log4j, log4jCopy, false);
155     copyFile(jna, jnaCopy, false);
156     copyFile(jnaUtils, jnaUtilsCopy, false);
157
158     int status = 0;
159     if (Restarter.isSupported()) {
160       List<String> args = new ArrayList<String>();
161
162       if (SystemInfoRt.isWindows) {
163         File launcher = new File(PathManager.getBinPath(), "VistaLauncher.exe");
164         args.add(Restarter.createTempExecutable(launcher).getPath());
165       }
166
167       //noinspection SpellCheckingInspection
168       Collections.addAll(args,
169                          System.getProperty("java.home") + "/bin/java",
170                          "-Xmx500m",
171                          "-Djna.nosys=true",
172                          "-Djna.boot.library.path=",
173                          "-Djna.debug_load=true",
174                          "-Djna.debug_load.jna=true",
175                          "-classpath",
176                          patchCopy.getPath() + File.pathSeparator + log4jCopy.getPath() + File.pathSeparator + jnaCopy.getPath() + File.pathSeparator + jnaUtilsCopy.getPath(),
177                          "-Djava.io.tmpdir=" + tempDir,
178                          "-Didea.updater.log=" + PathManager.getLogPath(),
179                          "-Dswing.defaultlaf=" + UIManager.getSystemLookAndFeelClassName(),
180                          "com.intellij.updater.Runner",
181                          "install",
182                          PathManager.getHomePath());
183
184       status = Restarter.scheduleRestart(ArrayUtilRt.toStringArray(args));
185     }
186     else {
187       String message = "Patch update is not supported - please do it manually";
188       showMessage("Update Error", message, true);
189     }
190
191     System.exit(status);
192   }
193
194   private static void copyFile(File original, File copy, boolean move) throws IOException {
195     if (move) {
196       if (!original.renameTo(copy) || !FileUtilRt.delete(original)) {
197         throw new IOException("Cannot create temporary file: " + copy);
198       }
199     }
200     else {
201       FileUtilRt.copy(original, copy);
202       if (!copy.exists()) {
203         throw new IOException("Cannot create temporary file: " + copy);
204       }
205     }
206   }
207
208   public static void showMessage(String title, Throwable t) {
209     StringWriter message = new StringWriter();
210     message.append("Internal error. Please report to http://");
211     boolean studio = "AndroidStudio".equalsIgnoreCase(System.getProperty(PLATFORM_PREFIX_PROPERTY));
212     message.append(studio ? "code.google.com/p/android/issues" : "youtrack.jetbrains.com");
213     message.append("\n\n");
214     t.printStackTrace(new PrintWriter(message));
215     showMessage(title, message.toString(), true);
216   }
217
218   @SuppressWarnings({"UseJBColor", "UndesirableClassUsage"})
219   public static void showMessage(String title, String message, boolean error) {
220     if (isCommandLine() || GraphicsEnvironment.isHeadless()) {
221       PrintStream stream = error ? System.err : System.out;
222       stream.println("\n" + title + ": " + message);
223     }
224     else {
225       try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
226       catch (Throwable ignore) { }
227
228       JTextPane textPane = new JTextPane();
229       textPane.setEditable(false);
230       textPane.setText(message.replaceAll("\t", "    "));
231       textPane.setBackground(UIUtil.getPanelBackground());
232       textPane.setCaretPosition(0);
233       JScrollPane scrollPane = new JScrollPane(
234         textPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
235       scrollPane.setBorder(null);
236
237       int maxHeight = Math.min(JBUI.scale(600), Toolkit.getDefaultToolkit().getScreenSize().height - 150);
238       Dimension component = scrollPane.getPreferredSize();
239       if (component.height >= maxHeight) {
240         Object setting = UIManager.get("ScrollBar.width");
241         int width = setting instanceof Integer ? ((Integer)setting).intValue() : 20;
242         scrollPane.setPreferredSize(new Dimension(component.width + width, maxHeight));
243       }
244
245       int type = error ? JOptionPane.ERROR_MESSAGE : JOptionPane.INFORMATION_MESSAGE;
246       JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), scrollPane, title, type);
247     }
248   }
249 }