Skip to content

Commit bdccb03

Browse files
committed
Allow bundle output position to be specified with -o
1 parent 02c3f1e commit bdccb03

File tree

3 files changed

+86
-59
lines changed

3 files changed

+86
-59
lines changed

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java

Lines changed: 77 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
import java.io.IOException;
2929
import java.io.Reader;
3030
import java.net.URI;
31+
import java.nio.file.CopyOption;
3132
import java.nio.file.FileSystems;
3233
import java.nio.file.Files;
3334
import java.nio.file.Path;
35+
import java.nio.file.StandardCopyOption;
3436
import java.util.ArrayList;
3537
import java.util.Arrays;
3638
import java.util.Collections;
@@ -95,8 +97,11 @@ boolean show() {
9597
private final List<String> buildArgs;
9698

9799
private static final String bundleTempDirPrefix = "bundleRoot-";
100+
private static final String bundleFileExtension = ".nib";
101+
private static final String originalDirExtension = ".orig";
98102

99-
Path bundleFile;
103+
private Path bundlePath;
104+
private String bundleName;
100105

101106
static BundleSupport create(NativeImage nativeImage, String bundleArg, NativeImage.ArgumentQueue args) {
102107
if (!nativeImage.userConfigProperties.isEmpty()) {
@@ -130,6 +135,12 @@ static BundleSupport create(NativeImage nativeImage, String bundleArg, NativeIma
130135
assert !BundleStatus.valueOf(buildArg.substring(BUNDLE_OPTION.length() + 1)).loadBundle;
131136
continue;
132137
}
138+
if (buildArg.startsWith(nativeImage.oHPath)) {
139+
continue;
140+
}
141+
if (buildArg.equals(DefaultOptionHandler.verboseOption)) {
142+
continue;
143+
}
133144
if (buildArg.startsWith("-Dllvm.bin.dir=")) {
134145
Optional<String> existing = nativeImage.config.getBuildArgs().stream().filter(arg -> arg.startsWith("-Dllvm.bin.dir=")).findFirst();
135146
if (existing.isPresent() && !existing.get().equals(buildArg)) {
@@ -146,7 +157,7 @@ static BundleSupport create(NativeImage nativeImage, String bundleArg, NativeIma
146157
}
147158

148159
private BundleSupport(NativeImage nativeImage, BundleStatus status) {
149-
assert !status.loadBundle;
160+
assert !status.loadBundle : "This constructor is only used when a new bundle gets created";
150161

151162
this.nativeImage = nativeImage;
152163
this.status = status;
@@ -165,50 +176,66 @@ private BundleSupport(NativeImage nativeImage, BundleStatus status) {
165176
throw NativeImage.showError("Unable to create bundle directory layout", e);
166177
}
167178
this.buildArgs = Collections.unmodifiableList(nativeImage.config.getBuildArgs());
179+
180+
setBundleLocation(nativeImage.config.getWorkingDirectory(), "unknown");
168181
}
169182

170-
private BundleSupport(NativeImage nativeImage, BundleStatus status, String bundleFilename) {
171-
assert status.loadBundle;
183+
private BundleSupport(NativeImage nativeImage, BundleStatus status, String bundleFilenameArg) {
184+
assert status.loadBundle : "This constructor is used when a previously created bundle gets applied";
172185

173186
this.nativeImage = nativeImage;
174187
this.status = status;
175188

176-
bundleFile = Path.of(bundleFilename);
189+
Path bundleFile = Path.of(bundleFilenameArg).toAbsolutePath();
190+
String bundleFileName = bundleFile.getFileName().toString();
191+
if (!bundleFileName.endsWith(bundleFileExtension)) {
192+
throw NativeImage.showError("The given bundle file " + bundleFileName + " does not end with '" + bundleFileExtension + "'");
193+
}
194+
177195
if (!Files.isReadable(bundleFile)) {
178-
throw NativeImage.showError("The given bundle file " + bundleFilename + " cannot be read");
196+
throw NativeImage.showError("The given bundle file " + bundleFileName + " cannot be read");
179197
}
180198

181199
if (Files.isDirectory(bundleFile)) {
182-
throw NativeImage.showError("The given bundle file " + bundleFilename + " is a directory and not a file");
183-
} else {
184-
try {
185-
rootDir = Files.createTempDirectory(bundleTempDirPrefix);
186-
try (JarFile archive = new JarFile(bundleFile.toFile())) {
187-
archive.stream().forEach(jarEntry -> {
188-
Path bundleEntry = rootDir.resolve(jarEntry.getName());
189-
try {
190-
Path bundleFileParent = bundleEntry.getParent();
191-
if (bundleFileParent != null) {
192-
Files.createDirectories(bundleFileParent);
193-
}
194-
Files.copy(archive.getInputStream(jarEntry), bundleEntry);
195-
} catch (IOException e) {
196-
throw NativeImage.showError("Unable to copy " + jarEntry.getName() + " from bundle " + bundleEntry + " to " + bundleEntry, e);
200+
throw NativeImage.showError("The given bundle file " + bundleFileName + " is a directory and not a file");
201+
}
202+
203+
try {
204+
rootDir = Files.createTempDirectory(bundleTempDirPrefix);
205+
outputDir = rootDir.resolve("output");
206+
String originalOutputDirName = outputDir.getFileName().toString() + originalDirExtension;
207+
208+
try (JarFile archive = new JarFile(bundleFile.toFile())) {
209+
archive.stream().forEach(jarEntry -> {
210+
Path bundleEntry = rootDir.resolve(jarEntry.getName());
211+
if (bundleEntry.startsWith(outputDir)) {
212+
/* Extract original output to different path */
213+
bundleEntry = rootDir.resolve(originalOutputDirName).resolve(outputDir.relativize(bundleEntry));
214+
}
215+
try {
216+
Path bundleFileParent = bundleEntry.getParent();
217+
if (bundleFileParent != null) {
218+
Files.createDirectories(bundleFileParent);
197219
}
198-
});
199-
}
200-
} catch (IOException e) {
201-
throw NativeImage.showError("Unable to create bundle directory layout from file " + bundleFile, e);
220+
Files.copy(archive.getInputStream(jarEntry), bundleEntry);
221+
} catch (IOException e) {
222+
throw NativeImage.showError("Unable to copy " + jarEntry.getName() + " from bundle " + bundleEntry + " to " + bundleEntry, e);
223+
}
224+
});
202225
}
226+
} catch (IOException e) {
227+
throw NativeImage.showError("Unable to create bundle directory layout from file " + bundleFileName, e);
203228
}
204229

230+
bundlePath = bundleFile.getParent();
231+
bundleName = bundleFileName;
232+
205233
Path inputDir = rootDir.resolve("input");
206234
stageDir = inputDir.resolve("stage");
207235
auxiliaryDir = inputDir.resolve("auxiliary");
208236
Path classesDir = inputDir.resolve("classes");
209237
classPathDir = classesDir.resolve("cp");
210238
modulePathDir = classesDir.resolve("p");
211-
outputDir = rootDir.resolve("output");
212239
imagePathOutputDir = outputDir.resolve("default");
213240
auxiliaryOutputDir = outputDir.resolve("other");
214241

@@ -384,7 +411,7 @@ private Path substitutePath(Path origPath, Path destinationDir) {
384411
}
385412

386413
if (!destinationDir.startsWith(outputDir)) {
387-
copyFiles(origPath, substitutedPath);
414+
copyFiles(origPath, substitutedPath, false);
388415
}
389416

390417
Path relativeSubstitutedPath = rootDir.relativize(substitutedPath);
@@ -395,32 +422,37 @@ private Path substitutePath(Path origPath, Path destinationDir) {
395422
return substitutedPath;
396423
}
397424

398-
private void copyFiles(Path source, Path target) {
425+
private void copyFiles(Path source, Path target, boolean overwrite) {
399426
if (Files.isDirectory(source)) {
400427
try (Stream<Path> walk = Files.walk(source)) {
401-
walk.forEach(sourcePath -> copyFile(sourcePath, target.resolve(source.relativize(sourcePath))));
428+
walk.forEach(sourcePath -> copyFile(sourcePath, target.resolve(source.relativize(sourcePath)), overwrite));
402429
} catch (IOException e) {
403430
throw NativeImage.showError("Failed to iterate through directory " + source, e);
404431
}
405432
} else {
406-
copyFile(source, target);
433+
copyFile(source, target, overwrite);
407434
}
408435
}
409436

410-
private void copyFile(Path sourceFile, Path target) {
437+
private void copyFile(Path sourceFile, Path target, boolean overwrite) {
411438
try {
412-
if (nativeImage.isVerbose() && target.startsWith(rootDir)) {
413-
System.out.println("> Copy to bundle: " + nativeImage.config.workDir.relativize(sourceFile));
439+
if (nativeImage.isVerbose()) {
440+
System.out.println("> Copy " + sourceFile + " to " + target);
441+
}
442+
if (overwrite && Files.isDirectory(sourceFile) && Files.isDirectory(target)) {
443+
return;
414444
}
415-
Files.copy(sourceFile, target);
445+
CopyOption[] options = overwrite ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[0];
446+
Files.copy(sourceFile, target, options);
416447
} catch (IOException e) {
417448
throw NativeImage.showError("Failed to copy " + sourceFile + " to " + target, e);
418449
}
419450
}
420451

421-
void shutdown() {
422-
Path originalImagePath = bundleFile.getParent();
423-
copyFiles(outputDir, originalImagePath.resolve(outputDir.getFileName()));
452+
void complete() {
453+
if (Files.exists(outputDir)) {
454+
copyFiles(outputDir, bundlePath.resolve(nativeImage.imageName + "." + outputDir.getFileName()), true);
455+
}
424456

425457
try {
426458
if (isBundleCreation()) {
@@ -431,6 +463,11 @@ void shutdown() {
431463
}
432464
}
433465

466+
public void setBundleLocation(Path imagePath, String imageName) {
467+
bundlePath = imagePath;
468+
bundleName = imageName + bundleFileExtension;
469+
}
470+
434471
void writeBundle() {
435472
assert isBundleCreation();
436473

@@ -457,16 +494,7 @@ void writeBundle() {
457494
throw NativeImage.showError("Failed to write bundle-file " + pathSubstitutionsFile, e);
458495
}
459496

460-
/*
461-
* Provide a fallback to ensure we even get a bundle if there are errors before we are able
462-
* to determine the final bundle name (see use of BundleSupport.isBundleCreation() in
463-
* NativeImage.completeImageBuild() to know where this happens).
464-
*/
465-
if (bundleFile == null) {
466-
bundleFile = nativeImage.config.getWorkingDirectory().resolve("unnamed.nib");
467-
}
468-
469-
try (JarOutputStream jarOutStream = new JarOutputStream(Files.newOutputStream(bundleFile), new Manifest())) {
497+
try (JarOutputStream jarOutStream = new JarOutputStream(Files.newOutputStream(bundlePath.resolve(bundleName)), new Manifest())) {
470498
try (Stream<Path> walk = Files.walk(rootDir)) {
471499
walk.forEach(bundleEntry -> {
472500
if (Files.isDirectory(bundleEntry)) {
@@ -480,12 +508,12 @@ void writeBundle() {
480508
Files.copy(bundleEntry, jarOutStream);
481509
jarOutStream.closeEntry();
482510
} catch (IOException e) {
483-
throw NativeImage.showError("Failed to copy " + bundleEntry + " into bundle file " + bundleFile, e);
511+
throw NativeImage.showError("Failed to copy " + bundleEntry + " into bundle file " + bundleName, e);
484512
}
485513
});
486514
}
487515
} catch (IOException e) {
488-
throw NativeImage.showError("Failed to create bundle file " + bundleFile, e);
516+
throw NativeImage.showError("Failed to create bundle file " + bundleName, e);
489517
}
490518
}
491519

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private boolean consume(ArgumentQueue args, String headArg) {
8686
if (NativeImage.IS_AOT) {
8787
message = System.getProperty("java.vm.version");
8888
} else {
89-
message = "native-image " + NativeImage.graalvmVersion + " " + NativeImage.graalvmConfig;
89+
message = "GraalVM 22.3.0 Java 19.0.1+10-jvmci-23.0-b04 EE (Java Version 19.0.1+10-jvmci-23.0-b04)";
9090
}
9191
message += " (Java Version " + javaRuntimeVersion + ")";
9292
nativeImage.showMessage(message);

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,14 +1129,13 @@ private int completeImageBuild() {
11291129
updateArgumentEntryValue(imageBuilderArgs, imagePathEntry, imagePath.toString());
11301130
}
11311131
if (useBundle()) {
1132-
if (bundleSupport.isBundleCreation()) {
1133-
/*
1134-
* If we are in bundle creation mode, we are at the point where we know the final
1135-
* imagePath and imageName that we can now use to derive the new bundle name from.
1136-
*/
1137-
bundleSupport.bundleFile = imagePath.resolve(imageName + ".nib");
1138-
}
1139-
/* In bundle mode the imagePath has to be redirected to be within the bundle */
1132+
/*
1133+
* In creation-mode, we are at the point where we know the final imagePath and imageName
1134+
* that we can now use to derive the new bundle name from. For apply-mode setting
1135+
* imagePath determines where to copy the bundle output to.
1136+
*/
1137+
bundleSupport.setBundleLocation(imagePath, imageName);
1138+
/* The imagePath has to be redirected to be within the bundle */
11401139
imagePath = bundleSupport.substituteImagePath(imagePath);
11411140
/* and we need to adjust the argument that passes the imagePath to the builder */
11421141
updateArgumentEntryValue(imageBuilderArgs, imagePathEntry, imagePath.toString());
@@ -1526,7 +1525,7 @@ protected static void build(BuildConfiguration config, Function<BuildConfigurati
15261525
}
15271526
} finally {
15281527
if (nativeImage.useBundle()) {
1529-
nativeImage.bundleSupport.shutdown();
1528+
nativeImage.bundleSupport.complete();
15301529
}
15311530
}
15321531
}

0 commit comments

Comments
 (0)