1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.surefire.booterclient;
20
21 import javax.annotation.Nonnegative;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24
25 import java.io.File;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.util.Collection;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Properties;
33
34 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.Commandline;
35 import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
36 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
37 import org.apache.maven.surefire.api.util.TempFileManager;
38 import org.apache.maven.surefire.booter.AbstractPathConfiguration;
39 import org.apache.maven.surefire.booter.Classpath;
40 import org.apache.maven.surefire.booter.ModularClasspath;
41 import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
42 import org.apache.maven.surefire.booter.StartupConfiguration;
43 import org.apache.maven.surefire.booter.SurefireBooterForkException;
44 import org.apache.maven.surefire.extensions.ForkNodeFactory;
45
46 import static java.io.File.pathSeparatorChar;
47 import static org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
48 import static org.apache.maven.surefire.api.util.internal.StringUtils.NL;
49 import static org.apache.maven.surefire.shared.utils.StringUtils.replace;
50
51
52
53
54
55 public class ModularClasspathForkConfiguration extends DefaultForkConfiguration {
56 @SuppressWarnings("checkstyle:parameternumber")
57 public ModularClasspathForkConfiguration(
58 @Nonnull Classpath bootClasspath,
59 @Nonnull File tempDirectory,
60 @Nullable String debugLine,
61 @Nonnull File workingDirectory,
62 @Nonnull Properties modelProperties,
63 @Nullable String argLine,
64 @Nonnull Map<String, String> environmentVariables,
65 @Nonnull String[] excludedEnvironmentVariables,
66 boolean debug,
67 @Nonnegative int forkCount,
68 boolean reuseForks,
69 @Nonnull Platform pluginPlatform,
70 @Nonnull ConsoleLogger log,
71 @Nonnull ForkNodeFactory forkNodeFactory) {
72 super(
73 bootClasspath,
74 tempDirectory,
75 debugLine,
76 workingDirectory,
77 modelProperties,
78 argLine,
79 environmentVariables,
80 excludedEnvironmentVariables,
81 debug,
82 forkCount,
83 reuseForks,
84 pluginPlatform,
85 log,
86 forkNodeFactory);
87 }
88
89 @Override
90 protected void resolveClasspath(
91 @Nonnull Commandline cli,
92 @Nonnull String startClass,
93 @Nonnull StartupConfiguration config,
94 @Nonnull File dumpLogDirectory)
95 throws SurefireBooterForkException {
96 try {
97 AbstractPathConfiguration pathConfig = config.getClasspathConfiguration();
98
99 ModularClasspathConfiguration modularClasspathConfiguration =
100 pathConfig.toRealPath(ModularClasspathConfiguration.class);
101
102 ModularClasspath modularClasspath = modularClasspathConfiguration.getModularClasspath();
103
104 boolean isMainDescriptor = modularClasspath.isMainDescriptor();
105 String moduleName = modularClasspath.getModuleNameFromDescriptor();
106 List<String> modulePath = modularClasspath.getModulePath();
107 Collection<String> packages = modularClasspath.getPackages();
108 File patchFile = modularClasspath.getPatchFile();
109 List<String> classpath = toCompleteClasspath(config);
110
111 File argsFile = createArgsFile(
112 moduleName,
113 modulePath,
114 classpath,
115 packages,
116 patchFile,
117 startClass,
118 isMainDescriptor,
119 config.getJpmsArguments());
120
121 cli.createArg().setValue("@" + escapeToPlatformPath(argsFile.getAbsolutePath()));
122 } catch (IOException e) {
123 String error = "Error creating args file";
124 InPluginProcessDumpSingleton.getSingleton().dumpException(e, error, dumpLogDirectory);
125 throw new SurefireBooterForkException(error, e);
126 }
127 }
128
129 @Nonnull
130 File createArgsFile(
131 @Nonnull String moduleName,
132 @Nonnull List<String> modulePath,
133 @Nonnull List<String> classPath,
134 @Nonnull Collection<String> packages,
135 File patchFile,
136 @Nonnull String startClassName,
137 boolean isMainDescriptor,
138 @Nonnull List<String[]> providerJpmsArguments)
139 throws IOException {
140 File surefireArgs = TempFileManager.instance(getTempDirectory()).createTempFile("surefireargs", "");
141 if (isDebug()) {
142 getLogger().debug("Path to args file: " + surefireArgs.getCanonicalPath());
143 } else {
144 surefireArgs.deleteOnExit();
145 }
146
147 try (FileWriter io = new FileWriter(surefireArgs)) {
148 StringBuilder args = new StringBuilder(64 * 1024);
149 if (!modulePath.isEmpty()) {
150
151 args.append("--module-path").append(NL).append('"');
152
153 for (Iterator<String> it = modulePath.iterator(); it.hasNext(); ) {
154 args.append(replace(it.next(), "\\", "\\\\"));
155 if (it.hasNext()) {
156 args.append(pathSeparatorChar);
157 }
158 }
159
160 args.append('"').append(NL);
161 }
162
163 if (!classPath.isEmpty()) {
164 args.append("--class-path").append(NL).append('"');
165
166 for (Iterator<String> it = classPath.iterator(); it.hasNext(); ) {
167 args.append(replace(it.next(), "\\", "\\\\"));
168 if (it.hasNext()) {
169 args.append(pathSeparatorChar);
170 }
171 }
172
173 args.append('"').append(NL);
174 }
175
176 if (isMainDescriptor) {
177 args.append("--patch-module")
178 .append(NL)
179 .append(moduleName)
180 .append('=')
181 .append('"')
182 .append(replace(patchFile.getPath(), "\\", "\\\\"))
183 .append('"')
184 .append(NL);
185
186 for (String pkg : packages) {
187 args.append("--add-opens")
188 .append(NL)
189 .append(moduleName)
190 .append('/')
191 .append(pkg)
192 .append('=')
193 .append("ALL-UNNAMED")
194 .append(NL);
195 }
196
197 args.append("--add-reads")
198 .append(NL)
199 .append(moduleName)
200 .append('=')
201 .append("ALL-UNNAMED")
202 .append(NL);
203 }
204
205 args.append("--add-modules").append(NL).append("ALL-MODULE-PATH").append(NL);
206
207 for (String[] entries : providerJpmsArguments) {
208 for (String entry : entries) {
209 args.append(entry).append(NL);
210 }
211 }
212
213 args.append(startClassName);
214
215 String argsFileContent = args.toString();
216
217 if (isDebug()) {
218 getLogger().debug("args file content:" + NL + argsFileContent);
219 }
220
221 io.write(argsFileContent);
222
223 return surefireArgs;
224 }
225 }
226 }