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
69
70 ForkedTool(final AbstractCompilerMojo mojo) {
71 basedir = mojo.basedir;
72 executable = Objects.requireNonNull(mojo.executable);
73 debugFilePath = mojo.getDebugFilePath();
74 }
75
76
77
78
79 @Override
80 public String name() {
81 return executable;
82 }
83
84
85
86
87
88
89
90
91
92 @Override
93 public int isSupportedOption(String option) {
94 return -1;
95 }
96
97
98
99
100
101
102 @Override
103 public Set<SourceVersion> getSourceVersions() {
104 return Set.of(SourceVersion.latestSupported());
105 }
106
107
108
109
110 public StandardJavaFileManager getStandardFileManager(
111 DiagnosticListener<? super JavaFileObject> diagnosticListener, Locale locale, Charset encoding) {
112 return new ForkedToolSources(encoding);
113 }
114
115
116
117
118
119 private ProcessBuilder builder() {
120 var builder = new ProcessBuilder(executable);
121 if (basedir != null) {
122 builder.directory(basedir.toFile());
123 }
124 return builder;
125 }
126
127
128
129
130
131
132
133
134
135
136
137 final boolean run(
138 Writer out,
139 ForkedToolSources fileManager,
140 Iterable<String> options,
141 Iterable<? extends JavaFileObject> compilationUnits)
142 throws IOException {
143 ProcessBuilder builder = builder();
144 List<String> command = builder.command();
145 for (String option : options) {
146 command.add(option);
147 }
148 fileManager.addAllLocations(command);
149 for (JavaFileObject source : compilationUnits) {
150 Path path = fileManager.asPath(source);
151 if (basedir != null) {
152 try {
153 path = basedir.relativize(path);
154 } catch (IllegalArgumentException e) {
155
156 }
157 }
158 command.add(path.toString());
159 }
160 File output = File.createTempFile("javac", null);
161 try {
162 var dest = ProcessBuilder.Redirect.appendTo(output);
163 builder.redirectError(dest);
164 builder.redirectOutput(dest);
165 return start(builder, out) == 0;
166 } finally {
167 out.append(Files.readString(output.toPath()));
168 output.delete();
169 }
170 }
171
172
173
174
175
176 @Override
177 public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
178 ProcessBuilder builder = builder();
179 builder.command().addAll(Arrays.asList(arguments));
180 try {
181 return start(builder, System.err);
182 } catch (IOException e) {
183 throw new UncheckedIOException(e);
184 }
185 }
186
187
188
189
190
191
192
193
194 private int start(ProcessBuilder builder, Appendable out) throws IOException {
195 if (debugFilePath != null) {
196
197 final boolean windows = File.separatorChar == '\\';
198 String filename = debugFilePath.getFileName().toString();
199 filename = filename.substring(0, filename.lastIndexOf('.') + 1);
200 filename += windows ? "bat" : "sh";
201 boolean more = false;
202 try (BufferedWriter debugFile = Files.newBufferedWriter(debugFilePath.resolveSibling(filename))) {
203 if (basedir != null) {
204 debugFile.write(windows ? "chdir " : "cd ");
205 debugFile.write(basedir.toString());
206 debugFile.newLine();
207 }
208 for (String cmd : builder.command()) {
209 if (more) {
210 debugFile.append(' ');
211 }
212 debugFile.append(cmd);
213 more = true;
214 }
215 debugFile.newLine();
216 }
217 }
218 Process process = builder.start();
219 try {
220 return process.waitFor();
221 } catch (InterruptedException e) {
222 out.append("Compilation has been interrupted by " + e).append(System.lineSeparator());
223 process.destroy();
224 return 1;
225 }
226 }
227 }