4444import java .util .stream .Collectors ;
4545import java .util .stream .Stream ;
4646
47- import static java .util .Collections .singletonList ;
4847import static java .util .Objects .requireNonNull ;
4948
5049@ SuppressWarnings ("unused" )
5150@ RequiredArgsConstructor (access = AccessLevel .PRIVATE )
5251public class PythonParser implements Parser {
52+
5353 private final Collection <NamedStyles > styles ;
5454 private final boolean logCompilationWarningsAndErrors ;
5555 private final JavaTypeCache typeCache ;
5656 private final List <Path > pythonPath ;
57+
5758 private final @ Nullable Path logFile ;
59+
5860 private final int parseTimeoutMs ;
5961
6062 private @ Nullable Process pythonProcess ;
@@ -248,14 +250,10 @@ public static Builder builder() {
248250 }
249251
250252 public static Builder usingRemotingInstallation (Path dir ) {
251- try {
252- return verifyRemotingInstallation (dir );
253- } catch (IOException | InterruptedException ignore ) {
254- }
255- return builder ();
253+ return new Builder (dir );
256254 }
257255
258- private static Builder verifyRemotingInstallation (Path dir ) throws IOException , InterruptedException {
256+ private static boolean verifyRemotingInstallation (Path dir , @ Nullable Path logFile ) throws IOException , InterruptedException {
259257 if (!Files .isDirectory (dir )) {
260258 Files .createDirectories (dir );
261259 }
@@ -267,26 +265,39 @@ private static Builder verifyRemotingInstallation(Path dir) throws IOException,
267265 command .addAll (packages );
268266
269267 ProcessBuilder processBuilder = new ProcessBuilder (command );
270- Process process = processBuilder .start ();
268+ File redirectTo = logFile != null ? logFile .toFile () : new File (System .getProperty ("os.name" ).startsWith ("Windows" ) ? "NULL" : "/dev/null" );
269+ processBuilder .redirectOutput (redirectTo );
270+ processBuilder .redirectError (redirectTo );
271271
272- int exitCode = process . waitFor ();
273- return new Builder (). pythonPath ( singletonList ( dir )) ;
272+ Process process = processBuilder . start ();
273+ return process . waitFor () == 0 ;
274274 }
275275 }
276276
277277 @ SuppressWarnings ("unused" )
278278 public static class Builder extends Parser .Builder {
279279 private JavaTypeCache typeCache = new JavaTypeCache ();
280+
281+ @ Nullable
282+ private Path installationDir ;
283+
280284 private boolean logCompilationWarningsAndErrors ;
281285 private final Collection <NamedStyles > styles = new ArrayList <>();
282286 private List <Path > pythonPath = new ArrayList <>();
287+
283288 private @ Nullable Path logFile ;
289+
284290 private long parseTimeoutMs = -1 ;
285291
286292 private Builder () {
287293 super (Py .CompilationUnit .class );
288294 }
289295
296+ private Builder (Path installationDir ) {
297+ super (Py .CompilationUnit .class );
298+ this .installationDir = installationDir ;
299+ }
300+
290301 public Builder logCompilationWarningsAndErrors (boolean logCompilationWarningsAndErrors ) {
291302 this .logCompilationWarningsAndErrors = logCompilationWarningsAndErrors ;
292303 return this ;
@@ -321,6 +332,14 @@ public Builder pythonPath(List<Path> path) {
321332
322333 @ Override
323334 public PythonParser build () {
335+ if (installationDir != null ) {
336+ try {
337+ if (verifyRemotingInstallation (installationDir , logFile ) && !pythonPath .contains (installationDir )) {
338+ pythonPath .add (installationDir );
339+ }
340+ } catch (IOException | InterruptedException ignore ) {
341+ }
342+ }
324343 return new PythonParser (styles , logCompilationWarningsAndErrors , typeCache , pythonPath , logFile , (int ) parseTimeoutMs );
325344 }
326345
0 commit comments