cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / incremental / ExternalProcessUtil.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.jps.incremental;
3
4 import com.intellij.execution.CommandLineWrapperUtil;
5 import com.intellij.openapi.diagnostic.Logger;
6 import com.intellij.openapi.util.text.StringUtil;
7 import org.jetbrains.jps.cmdline.ClasspathBootstrap;
8
9 import java.io.File;
10 import java.io.IOException;
11 import java.nio.charset.Charset;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.jar.Manifest;
17
18 /**
19  * @author Eugene Zhuravlev
20  */
21 public final class ExternalProcessUtil {
22   private static final Logger LOG = Logger.getInstance(ExternalProcessUtil.class);
23
24   private static final class CommandLineWrapperClassHolder {
25     static final Class<?> ourWrapperClass;
26     static {
27       Class<?> aClass = null;
28       try {
29         aClass = Class.forName("com.intellij.rt.execution.CommandLineWrapper");
30       }
31       catch (Throwable ignored) { }
32       ourWrapperClass = aClass;
33     }
34   }
35
36   public static List<String> buildJavaCommandLine(String javaExecutable,
37                                                   String mainClass,
38                                                   List<String> bootClasspath,
39                                                   List<String> classpath,
40                                                   List<String> vmParams,
41                                                   List<String> programParams) {
42     return buildJavaCommandLine(javaExecutable, mainClass, bootClasspath, classpath, vmParams, programParams, true);
43   }
44
45   public static List<String> buildJavaCommandLine(String javaExecutable,
46                                                   String mainClass,
47                                                   List<String> bootClasspath,
48                                                   List<String> classpath,
49                                                   List<String> vmParams,
50                                                   List<String> programParams,
51                                                   boolean shortenClasspath) {
52     return buildJavaCommandLine(javaExecutable, mainClass, bootClasspath, classpath, vmParams, programParams, shortenClasspath, true);
53   }
54
55   public static List<String> buildJavaCommandLine(String javaExecutable,
56                                                   String mainClass,
57                                                   List<String> bootClasspath,
58                                                   List<String> classpath,
59                                                   List<String> vmParams,
60                                                   List<String> programParams,
61                                                   boolean shortenClasspath,
62                                                   boolean preferClasspathJar) {
63     List<String> cmdLine = new ArrayList<>();
64
65     cmdLine.add(javaExecutable);
66
67     cmdLine.addAll(vmParams);
68
69     if (!bootClasspath.isEmpty()) {
70       cmdLine.add("-bootclasspath");
71       cmdLine.add(StringUtil.join(bootClasspath, File.pathSeparator));
72     }
73
74     if (!classpath.isEmpty()) {
75       List<String> shortenedCp = null;
76
77       if (shortenClasspath) {
78         try {
79           Charset cs = Charset.defaultCharset();  // todo detect JNU charset from VM options?
80           if (isModularRuntime(javaExecutable)) {
81             List<String> args = Arrays.asList("-classpath", StringUtil.join(classpath, File.pathSeparator));
82             File argFile = CommandLineWrapperUtil.createArgumentFile(args, cs);
83             shortenedCp = Collections.singletonList('@' + argFile.getAbsolutePath());
84           }
85           else if (preferClasspathJar) {
86             File classpathJar = CommandLineWrapperUtil.createClasspathJarFile(new Manifest(), classpath);
87             shortenedCp = Arrays.asList("-classpath", classpathJar.getAbsolutePath());
88           }
89           else {
90             Class<?> wrapperClass = CommandLineWrapperClassHolder.ourWrapperClass;
91             if (wrapperClass != null) {
92               File classpathFile = CommandLineWrapperUtil.createWrapperFile(classpath, cs);
93               shortenedCp = Arrays.asList(
94                 "-classpath", ClasspathBootstrap.getResourcePath(wrapperClass), wrapperClass.getName(), classpathFile.getAbsolutePath());
95             }
96             else {
97               LOG.info("CommandLineWrapper class not found; classpath shortening won't be used");
98             }
99           }
100         }
101         catch (IOException e) {
102           LOG.warn("can't create temp file; classpath shortening won't be used", e);
103         }
104       }
105
106       // classpath
107       if (shortenedCp != null) {
108         cmdLine.addAll(shortenedCp);
109       }
110       else {
111         cmdLine.add("-classpath");
112         cmdLine.add(StringUtil.join(classpath, File.pathSeparator));
113       }
114     }
115
116     // main class and params
117     cmdLine.add(mainClass);
118
119     cmdLine.addAll(programParams);
120
121     return cmdLine;
122   }
123
124   private static boolean isModularRuntime(String javaExec) {
125     File jreHome = new File(javaExec).getParentFile().getParentFile();
126     return jreHome != null && (new File(jreHome, "lib/jrt-fs.jar").isFile() || new File(jreHome, "modules/java.base").isDirectory());
127   }
128 }