1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.compiler;
20
21 import javax.lang.model.SourceVersion;
22 import javax.tools.DiagnosticListener;
23 import javax.tools.JavaFileObject;
24 import javax.tools.OptionChecker;
25 import javax.tools.StandardJavaFileManager;
26 import javax.tools.Tool;
27
28 import java.io.BufferedWriter;
29 import java.io.File;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.io.UncheckedIOException;
34 import java.io.Writer;
35 import java.nio.charset.Charset;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Objects;
42 import java.util.Set;
43
44
45
46
47
48
49 class ForkedTool implements Tool, OptionChecker {
50
51
52
53 private final Path basedir;
54
55
56
57
58 private final String executable;
59
60
61
62
63 private final Path debugFilePath;
64
65
66
67
68 private final boolean verbose;
69
70
71
72
73
74
75 ForkedTool(final AbstractCompilerMojo mojo) {
76 basedir = mojo.basedir;
77 executable = Objects.requireNonNull(mojo.executable);
78 debugFilePath = mojo.getDebugFilePath();
79 verbose = mojo.shouldWriteDebugFile();
80 }
81
82
83
84
85 @Override
86 public String name() {
87 return executable;
88 }
89
90
91
92
93
94
95
96
97
98 @Override
99 public int isSupportedOption(String option) {
100 return -1;
101 }
102
103
104
105
106
107
108 @Override
109 public Set<SourceVersion> getSourceVersions() {
110 return Set.of(SourceVersion.latestSupported());
111 }
112
113
114
115
116 public StandardJavaFileManager getStandardFileManager(
117 DiagnosticListener<? super JavaFileObject> diagnosticListener, Locale locale, Charset encoding) {
118 return new ForkedToolSources(encoding);
119 }
120
121
122
123
124
125 private ProcessBuilder builder() {
126 var builder = new ProcessBuilder(executable);
127 if (basedir != null) {
128 builder.directory(basedir.toFile());
129 }
130 return builder;
131 }
132
133
134
135
136
137
138
139
140
141
142
143 final boolean run(
144 Writer out,
145 ForkedToolSources fileManager,
146 Iterable<String> options,
147 Iterable<? extends JavaFileObject> compilationUnits)
148 throws IOException {
149 ProcessBuilder builder = builder();
150 List<String> command = builder.command();
151 for (String option : options) {
152 command.add(option);
153 }
154 fileManager.addAllLocations(command);
155 for (JavaFileObject source : compilationUnits) {
156 Path path = fileManager.asPath(source);
157 if (basedir != null) {
158 try {
159 path = basedir.relativize(path);
160 } catch (IllegalArgumentException e) {
161
162 }
163 }
164 command.add(path.toString());
165 }
166 File output = File.createTempFile("javac", null);
167 try {
168 var dest = ProcessBuilder.Redirect.appendTo(output);
169 builder.redirectError(dest);
170 builder.redirectOutput(dest);
171 return start(builder, out) == 0;
172 } finally {
173
174
175
176
177
178 String cs = System.getProperty("native.encoding");
179 out.append(Files.readString(output.toPath(), Charset.forName(cs)));
180 output.delete();
181 }
182 }
183
184
185
186
187
188 @Override
189 public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
190 ProcessBuilder builder = builder();
191 builder.command().addAll(Arrays.asList(arguments));
192 try {
193 return start(builder, System.err);
194 } catch (IOException e) {
195 throw new UncheckedIOException(e);
196 }
197 }
198
199
200
201
202
203
204
205
206
207 private int start(ProcessBuilder builder, Appendable out) throws IOException {
208 Process process = builder.start();
209 int status;
210 try {
211 status = process.waitFor();
212 } catch (InterruptedException e) {
213 out.append("Compilation has been interrupted by " + e).append(System.lineSeparator());
214 process.destroy();
215 status = 1;
216 }
217 if ((status != 0 || verbose) && debugFilePath != null) {
218
219 final boolean windows = File.separatorChar == '\\';
220 String filename = debugFilePath.getFileName().toString();
221 filename = filename.substring(0, filename.lastIndexOf('.') + 1);
222 filename += windows ? "bat" : "sh";
223 boolean more = false;
224 try (BufferedWriter debugFile = Files.newBufferedWriter(debugFilePath.resolveSibling(filename))) {
225 if (basedir != null) {
226 debugFile.write(windows ? "chdir " : "cd ");
227 debugFile.write(basedir.toString());
228 debugFile.newLine();
229 }
230 for (String cmd : builder.command()) {
231 if (more) {
232 debugFile.append(' ');
233 }
234 debugFile.append(cmd);
235 more = true;
236 }
237 debugFile.newLine();
238 }
239 }
240 return status;
241 }
242 }