4747import java .util .jar .JarFile ;
4848import java .util .stream .Stream ;
4949
50+ import static com .oracle .svm .driver .launcher .ContainerSupport .CONTAINER_GRAAL_VM_HOME ;
51+
5052
5153public class BundleLauncher {
5254
@@ -63,6 +65,9 @@ public class BundleLauncher {
6365 public static final String IMAGE_PATH_OUTPUT_DIR_NAME = "default" ;
6466 public static final String AUXILIARY_OUTPUT_DIR_NAME = "other" ;
6567
68+ private static Path rootDir ;
69+ private static Path inputDir ;
70+ private static Path outputDir ;
6671 private static Path stageDir ;
6772 private static Path classPathDir ;
6873 private static Path modulePathDir ;
@@ -76,6 +81,8 @@ public class BundleLauncher {
7681
7782 public static boolean verbose = false ;
7883
84+ public static ContainerSupport containerSupport ;
85+
7986
8087 public static void main (String [] args ) {
8188 bundleFilePath = Paths .get (BundleLauncher .class .getProtectionDomain ().getCodeSource ().getLocation ().getPath ());
@@ -93,16 +100,32 @@ public static void main(String[] args) {
93100 ProcessBuilder pb = new ProcessBuilder (command );
94101
95102 Path environmentFile = stageDir .resolve ("environment.json" );
103+ Map <String , String > launcherEnvironment = new HashMap <>();
96104 if (Files .isReadable (environmentFile )) {
97105 try (Reader reader = Files .newBufferedReader (environmentFile )) {
98- Map <String , String > launcherEnvironment = new HashMap <>();
99106 new BundleEnvironmentParser (launcherEnvironment ).parseAndRegister (reader );
100107 pb .environment ().putAll (launcherEnvironment );
101108 } catch (IOException e ) {
102109 throw new RuntimeException ("Failed to read bundle-file " + environmentFile , e );
103110 }
104111 }
105112
113+ if (useContainer ()) {
114+ Path javaHome = getJavaExecutable ().getParent ().getParent ();
115+ ContainerSupport .replaceContainerPaths (command , javaHome , rootDir );
116+
117+ // TODO also mount agentDir if necessary
118+
119+ Map <Path , ContainerSupport .TargetPath > mountMapping = new HashMap <>();
120+ Path containerRoot = Paths .get ("/" );
121+ mountMapping .put (javaHome , new ContainerSupport .TargetPath (containerRoot .resolve (CONTAINER_GRAAL_VM_HOME ),true ));
122+ mountMapping .put (inputDir , new ContainerSupport .TargetPath (containerRoot .resolve (INPUT_DIR_NAME ),true ));
123+ mountMapping .put (outputDir , new ContainerSupport .TargetPath (containerRoot .resolve (OUTPUT_DIR_NAME ),false ));
124+
125+ containerSupport .initializeContainerImage ();
126+ command .addAll (0 , containerSupport .createContainerCommand (launcherEnvironment , mountMapping ));
127+ }
128+
106129 if (verbose ) {
107130 List <String > environmentList = pb .environment ()
108131 .entrySet ()
@@ -136,6 +159,10 @@ public static void main(String[] args) {
136159 System .exit (exitCode );
137160 }
138161
162+ public static boolean useContainer () {
163+ return containerSupport != null ;
164+ }
165+
139166 private static List <String > createLaunchCommand (String [] args ) {
140167 List <String > command = new ArrayList <>();
141168
@@ -247,13 +274,43 @@ private static List<String> parseBundleLauncherArgs(String[] args, List<String>
247274 } catch (IOException e ) {
248275 System .out .println ("Failed to create native image agent output dir" );
249276 }
250- } else if (arg .equals ("--verbose" )) {
251- verbose = true ;
252- } else if (arg .equals ("--" )) {
253- applicationArgs .addAll (argQueue );
254- argQueue .clear ();
277+ } else if (arg .startsWith ("--container" )) {
278+ if (useContainer ()) {
279+ throw new RuntimeException ("native-image bundle allows option container to be specified only once." );
280+ }
281+ Path dockerfile ;
282+ if (arg .indexOf (',' ) != -1 ) {
283+ String option = arg .substring (arg .indexOf (',' ) + 1 );
284+ arg = arg .substring (0 , arg .indexOf (',' ));
285+
286+ if (option .startsWith ("dockerfile" )) {
287+ if (option .indexOf ('=' ) != -1 ) {
288+ dockerfile = Paths .get (option .substring (option .indexOf ('=' ) + 1 ));
289+ if (!Files .isReadable (dockerfile )) {
290+ throw new Error (String .format ("Dockerfile '%s' is not readable" , dockerfile .toAbsolutePath ()));
291+ }
292+ } else {
293+ throw new Error ("container option dockerfile requires a dockerfile argument. E.g. dockerfile=path/to/Dockerfile." );
294+ }
295+ } else {
296+ throw new Error (String .format ("Unknown option %s. Valid option is: dockerfile=path/to/Dockerfile." , option ));
297+ }
298+ } else {
299+ dockerfile = stageDir .resolve ("Dockerfile" );
300+ }
301+ containerSupport = new ContainerSupport (dockerfile , stageDir );
302+ if (arg .indexOf ('=' ) != -1 ) {
303+ containerSupport .containerTool = arg .substring (arg .indexOf ('=' ) + 1 );
304+ }
255305 } else {
256- applicationArgs .add (arg );
306+ switch (arg ) {
307+ case "--verbose" -> verbose = true ;
308+ case "--" -> {
309+ applicationArgs .addAll (argQueue );
310+ argQueue .clear ();
311+ }
312+ default -> applicationArgs .add (arg );
313+ }
257314 }
258315 }
259316
@@ -334,9 +391,8 @@ private static void deleteAllFiles(Path toDelete) {
334391 }
335392
336393 private static void unpackBundle (Path bundleFilePath ) {
337- Path inputDir ;
338394 try {
339- Path rootDir = createBundleRootDir ();
395+ rootDir = createBundleRootDir ();
340396 inputDir = rootDir .resolve (INPUT_DIR_NAME );
341397
342398 try (JarFile archive = new JarFile (bundleFilePath .toFile ())) {
@@ -369,6 +425,7 @@ private static void unpackBundle(Path bundleFilePath) {
369425 Path classesDir = inputDir .resolve (CLASSES_DIR_NAME );
370426 classPathDir = Files .createDirectories (classesDir .resolve (CLASSPATH_DIR_NAME ));
371427 modulePathDir = Files .createDirectories (classesDir .resolve (MODULE_PATH_DIR_NAME ));
428+ outputDir = Files .createDirectories (rootDir .resolve (OUTPUT_DIR_NAME ));
372429 } catch (IOException e ) {
373430 throw new RuntimeException ("Unable to create bundle directory layout" , e );
374431 }
0 commit comments