author | herrick |
Mon, 30 Sep 2019 19:11:19 -0400 | |
branch | JDK-8200758-branch |
changeset 58416 | f09bf58c1f17 |
parent 58301 | e0efb29609bd |
child 58648 | 3bf53ffa9ae7 |
permissions | -rw-r--r-- |
58113 | 1 |
/* |
2 |
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. |
|
8 |
* |
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
13 |
* accompanied this code). |
|
14 |
* |
|
15 |
* You should have received a copy of the GNU General Public License version |
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 |
* |
|
19 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 |
* or visit www.oracle.com if you need additional information or have any |
|
21 |
* questions. |
|
22 |
*/ |
|
23 |
package jdk.jpackage.test; |
|
24 |
||
25 |
import java.io.File; |
|
26 |
import java.io.IOException; |
|
27 |
import java.nio.file.Files; |
|
28 |
import java.nio.file.Path; |
|
58416 | 29 |
import java.util.ArrayList; |
58113 | 30 |
import java.util.List; |
58416 | 31 |
import java.util.concurrent.atomic.AtomicBoolean; |
32 |
import java.util.regex.Matcher; |
|
33 |
import java.util.regex.Pattern; |
|
34 |
import java.util.stream.Collectors; |
|
35 |
import jdk.jpackage.test.Functional.ThrowingFunction; |
|
36 |
import jdk.jpackage.test.Functional.ThrowingSupplier; |
|
58113 | 37 |
|
38 |
public class HelloApp { |
|
58301
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
39 |
|
58416 | 40 |
private HelloApp() { |
41 |
setClassName(CLASS_NAME).setJarFileName("hello.jar"); |
|
42 |
} |
|
43 |
||
44 |
/** |
|
45 |
* Set fully qualified class name. E.g: foo.bar.Buzz. |
|
46 |
*/ |
|
47 |
private HelloApp setClassName(String v) { |
|
48 |
qualifiedClassName = v; |
|
49 |
return this; |
|
50 |
} |
|
51 |
||
52 |
private HelloApp setModuleName(String v) { |
|
53 |
moduleName = v; |
|
54 |
return this; |
|
55 |
} |
|
56 |
||
57 |
private HelloApp setJarFileName(String v) { |
|
58 |
jarFileName = v; |
|
59 |
return this; |
|
60 |
} |
|
61 |
||
62 |
private HelloApp setModuleVersion(String v) { |
|
63 |
moduleVersion = v; |
|
64 |
return this; |
|
65 |
} |
|
66 |
||
67 |
private JarBuilder prepareSources(Path srcDir) throws IOException { |
|
68 |
final String className = qualifiedClassName.substring( |
|
69 |
qualifiedClassName.lastIndexOf('.') + 1); |
|
70 |
final String packageName = packageName(); |
|
71 |
||
72 |
final Path srcFile = srcDir.resolve(Path.of(String.join( |
|
73 |
File.separator, qualifiedClassName.split("\\.")) + ".java")); |
|
74 |
Files.createDirectories(srcFile.getParent()); |
|
75 |
||
76 |
JarBuilder jarBuilder = createJarBuilder().addSourceFile(srcFile); |
|
77 |
if (moduleName != null) { |
|
78 |
Path moduleInfoFile = srcDir.resolve("module-info.java"); |
|
79 |
TKit.createTextFile(moduleInfoFile, List.of( |
|
80 |
String.format("module %s {", moduleName), |
|
81 |
String.format(" exports %s;", packageName), |
|
82 |
"}" |
|
83 |
)); |
|
84 |
jarBuilder.addSourceFile(moduleInfoFile); |
|
85 |
if (moduleVersion != null) { |
|
86 |
jarBuilder.setModuleVersion(moduleVersion); |
|
87 |
} |
|
88 |
} |
|
89 |
||
90 |
// Add package directive and replace class name in java source file. |
|
91 |
// Works with simple test Hello.java. |
|
92 |
// Don't expect too much from these regexps! |
|
93 |
Pattern classDeclaration = Pattern.compile("(^.*\\bclass\\s+)Hello(.*$)"); |
|
94 |
Pattern importDirective = Pattern.compile( |
|
95 |
"(?<=import (?:static )?+)[^;]+"); |
|
96 |
AtomicBoolean classDeclared = new AtomicBoolean(); |
|
97 |
AtomicBoolean packageInserted = new AtomicBoolean(packageName == null); |
|
98 |
||
99 |
var packageInserter = Functional.identityFunction((line) -> { |
|
100 |
packageInserted.setPlain(true); |
|
101 |
return String.format("package %s;%s%s", packageName, |
|
102 |
System.lineSeparator(), line); |
|
103 |
}); |
|
58301
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
104 |
|
58416 | 105 |
Files.write(srcFile, Files.readAllLines(HELLO_JAVA).stream().map(line -> { |
106 |
if (classDeclared.getPlain()) { |
|
107 |
return line; |
|
108 |
} |
|
109 |
||
110 |
Matcher m; |
|
111 |
if (!packageInserted.getPlain() && importDirective.matcher(line).find()) { |
|
112 |
line = packageInserter.apply(line); |
|
113 |
} else if ((m = classDeclaration.matcher(line)).find()) { |
|
114 |
classDeclared.setPlain(true); |
|
115 |
line = m.group(1) + className + m.group(2); |
|
116 |
if (!packageInserted.getPlain()) { |
|
117 |
line = packageInserter.apply(line); |
|
118 |
} |
|
119 |
} |
|
120 |
return line; |
|
121 |
}).collect(Collectors.toList())); |
|
122 |
||
123 |
return jarBuilder; |
|
124 |
} |
|
125 |
||
126 |
private JarBuilder createJarBuilder() { |
|
127 |
return new JarBuilder().setMainClass(qualifiedClassName); |
|
128 |
} |
|
129 |
||
130 |
private void addTo(JPackageCommand cmd) { |
|
131 |
if (moduleName != null && packageName() == null) { |
|
132 |
throw new IllegalArgumentException(String.format( |
|
133 |
"Module [%s] with default package", moduleName)); |
|
134 |
} |
|
135 |
||
136 |
if (moduleName == null && CLASS_NAME.equals(qualifiedClassName)) { |
|
137 |
// Use Hello.java as is. |
|
138 |
cmd.addAction((self) -> { |
|
139 |
File jarFile = self.inputDir().resolve(jarFileName).toFile(); |
|
140 |
createJarBuilder().setOutputJar(jarFile).addSourceFile( |
|
141 |
HELLO_JAVA).create(); |
|
142 |
}); |
|
143 |
} else { |
|
144 |
cmd.addAction((self) -> { |
|
145 |
final Path jarFile; |
|
146 |
if (moduleName == null) { |
|
147 |
jarFile = self.inputDir().resolve(jarFileName); |
|
148 |
} else { |
|
149 |
// `--module-path` option should be set by the moment |
|
150 |
// when this action is being executed. |
|
151 |
jarFile = Path.of(self.getArgumentValue("--module-path", |
|
152 |
() -> self.inputDir().toString()), jarFileName); |
|
153 |
Files.createDirectories(jarFile.getParent()); |
|
154 |
} |
|
155 |
||
156 |
TKit.withTempDirectory("src", |
|
157 |
workDir -> prepareSources(workDir).setOutputJar( |
|
158 |
jarFile.toFile()).create()); |
|
159 |
}); |
|
160 |
} |
|
161 |
||
162 |
if (moduleName == null) { |
|
163 |
cmd.addArguments("--main-jar", jarFileName); |
|
164 |
cmd.addArguments("--main-class", qualifiedClassName); |
|
165 |
} else { |
|
166 |
cmd.addArguments("--module-path", TKit.workDir().resolve( |
|
167 |
"input-modules")); |
|
168 |
cmd.addArguments("--module", String.join("/", moduleName, |
|
169 |
qualifiedClassName)); |
|
170 |
// For modular app assume nothing will go in input directory and thus |
|
171 |
// nobody will create input directory, so remove corresponding option |
|
172 |
// from jpackage command line. |
|
173 |
cmd.removeArgumentWithValue("--input"); |
|
174 |
} |
|
175 |
if (TKit.isWindows()) { |
|
58113 | 176 |
cmd.addArguments("--win-console"); |
177 |
} |
|
178 |
} |
|
179 |
||
58416 | 180 |
private String packageName() { |
181 |
int lastDotIdx = qualifiedClassName.lastIndexOf('.'); |
|
182 |
if (lastDotIdx == -1) { |
|
183 |
return null; |
|
184 |
} |
|
185 |
return qualifiedClassName.substring(0, lastDotIdx); |
|
186 |
} |
|
187 |
||
188 |
/** |
|
189 |
* Configures Java application to be used with the given jpackage command. |
|
190 |
* Syntax of encoded Java application description is |
|
191 |
* [jar_file:][module_name/]qualified_class_name[@module_version]. |
|
192 |
* |
|
193 |
* E.g.: duke.jar:com.other/com.other.foo.bar.Buz@3.7 encodes modular |
|
194 |
* application. Module name is `com.other`. Main class is |
|
195 |
* `com.other.foo.bar.Buz`. Module version is `3.7`. Application will be |
|
196 |
* compiled and packed in `duke.jar` jar file. |
|
197 |
* |
|
198 |
* @param cmd jpackage command to configure |
|
199 |
* @param javaAppDesc encoded Java application description |
|
200 |
*/ |
|
201 |
static void addTo(JPackageCommand cmd, String javaAppDesc) { |
|
202 |
HelloApp helloApp = new HelloApp(); |
|
203 |
if (javaAppDesc != null) { |
|
204 |
String moduleNameAndOther = Functional.identity(() -> { |
|
205 |
String[] components = javaAppDesc.split(":", 2); |
|
206 |
if (components.length == 2) { |
|
207 |
helloApp.setJarFileName(components[0]); |
|
208 |
} |
|
209 |
return components[components.length - 1]; |
|
210 |
}).get(); |
|
211 |
||
212 |
String classNameAndOther = Functional.identity(() -> { |
|
213 |
String[] components = moduleNameAndOther.split("/", 2); |
|
214 |
if (components.length == 2) { |
|
215 |
helloApp.setModuleName(components[0]); |
|
216 |
} |
|
217 |
return components[components.length - 1]; |
|
218 |
}).get(); |
|
219 |
||
220 |
Functional.identity(() -> { |
|
221 |
String[] components = classNameAndOther.split("@", 2); |
|
222 |
helloApp.setClassName(components[0]); |
|
223 |
if (components.length == 2) { |
|
224 |
helloApp.setModuleVersion(components[1]); |
|
225 |
} |
|
226 |
}).run(); |
|
227 |
} |
|
228 |
helloApp.addTo(cmd); |
|
229 |
} |
|
230 |
||
231 |
static void verifyOutputFile(Path outputFile, List<String> args) { |
|
58301
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
232 |
if (!outputFile.isAbsolute()) { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
233 |
verifyOutputFile(outputFile.toAbsolutePath().normalize(), args); |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
234 |
return; |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
235 |
} |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
236 |
|
58416 | 237 |
TKit.assertFileExists(outputFile); |
58113 | 238 |
|
58416 | 239 |
List<String> contents = ThrowingSupplier.toSupplier( |
240 |
() -> Files.readAllLines(outputFile)).get(); |
|
58113 | 241 |
|
58416 | 242 |
List<String> expected = new ArrayList<>(List.of( |
243 |
"jpackage test application", |
|
244 |
String.format("args.length: %d", args.size()) |
|
245 |
)); |
|
246 |
expected.addAll(args); |
|
58113 | 247 |
|
58416 | 248 |
TKit.assertStringListEquals(expected, contents, String.format( |
249 |
"Check contents of [%s] file", outputFile)); |
|
58113 | 250 |
} |
251 |
||
58301
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
252 |
public static void executeLauncherAndVerifyOutput(JPackageCommand cmd) { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
253 |
final Path launcherPath; |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
254 |
if (cmd.packageType() == PackageType.IMAGE) { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
255 |
launcherPath = cmd.appImage().resolve(cmd.launcherPathInAppImage()); |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
256 |
if (cmd.isFakeRuntimeInAppImage(String.format( |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
257 |
"Not running [%s] launcher from application image", |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
258 |
launcherPath))) { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
259 |
return; |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
260 |
} |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
261 |
} else { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
262 |
launcherPath = cmd.launcherInstallationPath(); |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
263 |
if (cmd.isFakeRuntimeInstalled(String.format( |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
264 |
"Not running [%s] launcher", launcherPath))) { |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
265 |
return; |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
266 |
} |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
267 |
} |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
268 |
|
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
269 |
executeAndVerifyOutput(launcherPath, cmd.getAllArgumentValues( |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
270 |
"--arguments")); |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
271 |
} |
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
272 |
|
58113 | 273 |
public static void executeAndVerifyOutput(Path helloAppLauncher, |
274 |
String... defaultLauncherArgs) { |
|
58416 | 275 |
executeAndVerifyOutput(helloAppLauncher, List.of(defaultLauncherArgs)); |
276 |
} |
|
277 |
||
278 |
public static void executeAndVerifyOutput(Path helloAppLauncher, |
|
279 |
List<String> defaultLauncherArgs) { |
|
280 |
// Output file will be created in the current directory. |
|
281 |
Path outputFile = Path.of(OUTPUT_FILENAME); |
|
282 |
ThrowingFunction.toFunction(Files::deleteIfExists).apply(outputFile); |
|
58113 | 283 |
new Executor() |
58416 | 284 |
.setDirectory(outputFile.getParent()) |
285 |
.setExecutable(helloAppLauncher) |
|
58113 | 286 |
.execute() |
287 |
.assertExitCodeIsZero(); |
|
288 |
||
58416 | 289 |
verifyOutputFile(outputFile, defaultLauncherArgs); |
58113 | 290 |
} |
291 |
||
58301
e0efb29609bd
8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
herrick
parents:
58115
diff
changeset
|
292 |
final static String OUTPUT_FILENAME = "appOutput.txt"; |
58416 | 293 |
|
294 |
private String qualifiedClassName; |
|
295 |
private String moduleName; |
|
296 |
private String jarFileName; |
|
297 |
private String moduleVersion; |
|
298 |
||
299 |
private static final Path HELLO_JAVA = TKit.TEST_SRC_ROOT.resolve( |
|
300 |
"apps/image/Hello.java"); |
|
301 |
||
302 |
private final static String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( |
|
303 |
"\\.", 2)[0]; |
|
58113 | 304 |
} |