Skip to content

Commit 4f44fd6

Browse files
author
Doug Simon
committed
8237467: jlink plugin to save the argument files as input to jlink in the output image
Reviewed-by: mchung
1 parent edfb18a commit 4f44fd6

File tree

6 files changed

+414
-1
lines changed

6 files changed

+414
-1
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2022, 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. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package jdk.tools.jlink.internal;
27+
28+
import java.io.IOException;
29+
import java.io.InputStream;
30+
import java.io.InputStreamReader;
31+
import java.io.Reader;
32+
import java.util.List;
33+
34+
/**
35+
* This file was originally a copy of CommandLine.java in
36+
* com.sun.tools.javac.main.
37+
* It should track changes made to that file.
38+
*/
39+
40+
/**
41+
* Various utility methods for processing Java tool command line arguments.
42+
*/
43+
public class CommandLine {
44+
45+
static void loadCmdFile(InputStream in, List<String> args)
46+
throws IOException {
47+
try (Reader r = new InputStreamReader(in)) {
48+
Tokenizer t = new Tokenizer(r);
49+
String s;
50+
while ((s = t.nextToken()) != null) {
51+
args.add(s);
52+
}
53+
}
54+
}
55+
public static class Tokenizer {
56+
private final Reader in;
57+
private int ch;
58+
59+
public Tokenizer(Reader in) throws IOException {
60+
this.in = in;
61+
ch = in.read();
62+
}
63+
64+
public String nextToken() throws IOException {
65+
skipWhite();
66+
if (ch == -1) {
67+
return null;
68+
}
69+
70+
StringBuilder sb = new StringBuilder();
71+
char quoteChar = 0;
72+
73+
while (ch != -1) {
74+
switch (ch) {
75+
case ' ':
76+
case '\t':
77+
case '\f':
78+
if (quoteChar == 0) {
79+
return sb.toString();
80+
}
81+
sb.append((char) ch);
82+
break;
83+
84+
case '\n':
85+
case '\r':
86+
return sb.toString();
87+
88+
case '\'':
89+
case '"':
90+
if (quoteChar == 0) {
91+
quoteChar = (char) ch;
92+
} else if (quoteChar == ch) {
93+
quoteChar = 0;
94+
} else {
95+
sb.append((char) ch);
96+
}
97+
break;
98+
99+
case '\\':
100+
if (quoteChar != 0) {
101+
ch = in.read();
102+
switch (ch) {
103+
case '\n':
104+
case '\r':
105+
while (ch == ' ' || ch == '\n'
106+
|| ch == '\r' || ch == '\t'
107+
|| ch == '\f') {
108+
ch = in.read();
109+
}
110+
continue;
111+
112+
case 'n':
113+
ch = '\n';
114+
break;
115+
case 'r':
116+
ch = '\r';
117+
break;
118+
case 't':
119+
ch = '\t';
120+
break;
121+
case 'f':
122+
ch = '\f';
123+
break;
124+
default:
125+
break;
126+
}
127+
}
128+
sb.append((char) ch);
129+
break;
130+
131+
default:
132+
sb.append((char) ch);
133+
}
134+
135+
ch = in.read();
136+
}
137+
138+
return sb.toString();
139+
}
140+
141+
void skipWhite() throws IOException {
142+
while (ch != -1) {
143+
switch (ch) {
144+
case ' ':
145+
case '\t':
146+
case '\n':
147+
case '\r':
148+
case '\f':
149+
break;
150+
151+
case '#':
152+
ch = in.read();
153+
while (ch != '\n' && ch != '\r' && ch != -1) {
154+
ch = in.read();
155+
}
156+
break;
157+
158+
default:
159+
return;
160+
}
161+
162+
ch = in.read();
163+
}
164+
}
165+
}
166+
}

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.io.BufferedInputStream;
2828
import java.io.File;
2929
import java.io.IOException;
30+
import java.io.InputStream;
3031
import java.io.PrintWriter;
3132
import java.io.UncheckedIOException;
3233
import java.lang.module.Configuration;
@@ -223,13 +224,27 @@ static class OptionsValues {
223224
boolean suggestProviders = false;
224225
}
225226

227+
public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options";
228+
226229
int run(String[] args) {
227230
if (log == null) {
228231
setLog(new PrintWriter(System.out, true),
229232
new PrintWriter(System.err, true));
230233
}
231234
Path outputPath = null;
232235
try {
236+
Module m = JlinkTask.class.getModule();
237+
try (InputStream savedOptions = m.getResourceAsStream(OPTIONS_RESOURCE)) {
238+
if (savedOptions != null) {
239+
List<String> prependArgs = new ArrayList<>();
240+
CommandLine.loadCmdFile(savedOptions, prependArgs);
241+
if (!prependArgs.isEmpty()) {
242+
prependArgs.addAll(Arrays.asList(args));
243+
args = prependArgs.toArray(new String[prependArgs.size()]);
244+
}
245+
}
246+
}
247+
233248
List<String> remaining = optionsHelper.handleOptions(this, args);
234249
if (remaining.size() > 0 && !options.suggestProviders) {
235250
throw taskHelper.newBadArgs("err.orphan.arguments",
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) 2022, 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. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package jdk.tools.jlink.internal.plugins;
27+
28+
import static jdk.tools.jlink.internal.JlinkTask.OPTIONS_RESOURCE;
29+
30+
import java.io.File;
31+
import java.io.IOException;
32+
import java.nio.charset.StandardCharsets;
33+
import java.nio.file.Files;
34+
import java.nio.file.Path;
35+
import java.util.ArrayList;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.function.Function;
39+
import java.util.stream.Collectors;
40+
41+
import jdk.tools.jlink.plugin.PluginException;
42+
import jdk.tools.jlink.plugin.ResourcePool;
43+
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
44+
import jdk.tools.jlink.plugin.ResourcePoolEntry;
45+
46+
/**
47+
* Saves the arguments in the specified argument files to a resource that's read
48+
* by jlink in the output image. The saved arguments are prepended to the arguments
49+
* specified on the jlink command line.
50+
*/
51+
public final class SaveJlinkArgfilesPlugin extends AbstractPlugin {
52+
53+
public SaveJlinkArgfilesPlugin() {
54+
super("save-jlink-argfiles");
55+
}
56+
57+
private List<String> argfiles = new ArrayList<>();
58+
59+
@Override
60+
public Category getType() {
61+
return Category.ADDER;
62+
}
63+
64+
@Override
65+
public boolean hasArguments() {
66+
return true;
67+
}
68+
69+
@Override
70+
public boolean hasRawArgument() {
71+
return true;
72+
}
73+
74+
@Override
75+
public void configure(Map<String, String> config) {
76+
var v = config.get(getName());
77+
78+
if (v == null)
79+
throw new AssertionError();
80+
81+
for (String argfile : v.split(File.pathSeparator)) {
82+
argfiles.add(readArgfile(argfile));
83+
}
84+
}
85+
86+
private static String readArgfile(String argfile) {
87+
try {
88+
return Files.readString(Path.of(argfile));
89+
} catch (IOException e) {
90+
throw new PluginException("Argfile " + argfile + " is not readable");
91+
}
92+
}
93+
94+
@Override
95+
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
96+
in.transformAndCopy(Function.identity(), out);
97+
if (!in.moduleView().findModule("jdk.jlink").isPresent()) {
98+
throw new PluginException("--save-jlink-argfiles requires jdk.jlink to be in the output image");
99+
}
100+
byte[] savedOptions = argfiles.stream()
101+
.collect(Collectors.joining("\n"))
102+
.getBytes(StandardCharsets.UTF_8);
103+
out.add(ResourcePoolEntry.create("/jdk.jlink/" + OPTIONS_RESOURCE,
104+
savedOptions));
105+
return out.build();
106+
}
107+
}

src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,20 @@ order-resources.usage=\
187187
\ e.g.: **/module-info.class,@classlist,\n\
188188
\ /java.base/java/lang/**
189189

190+
save-jlink-argfiles.argument=<filenames>
191+
192+
save-jlink-argfiles.description=\
193+
Save the specified argument files that contain the arguments \n\
194+
to be prepended to the execution of jlink in the output image. \n\
195+
<filenames> is a ':' (';' on Windows) separated list of command-line argument files.
196+
197+
save-jlink-argfiles.usage=\
198+
\ --save-jlink-argfiles <filenames>\n\
199+
\ Save the specified argument files that contain \n\
200+
\ the arguments to be prepended to the execution of \n\
201+
\ jlink in the output image. <filenames> is a \n\
202+
\ ':' (';' on Windows) separated list of command-line argument files.
203+
190204
strip-debug.description=\
191205
Strip debug information from the output image
192206

src/jdk.jlink/share/classes/module-info.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
jdk.tools.jlink.internal.plugins.VendorBugURLPlugin,
8181
jdk.tools.jlink.internal.plugins.VendorVMBugURLPlugin,
8282
jdk.tools.jlink.internal.plugins.VendorVersionPlugin,
83-
jdk.tools.jlink.internal.plugins.CDSPlugin;
83+
jdk.tools.jlink.internal.plugins.CDSPlugin,
84+
jdk.tools.jlink.internal.plugins.SaveJlinkArgfilesPlugin;
8485

8586
}

0 commit comments

Comments
 (0)