1 /*
  2  * Copyright (c) 2024, 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.code.tools.renderer;
 27 
 28 import java.io.*;
 29 import java.util.ArrayList;
 30 import java.util.List;
 31 import java.util.regex.Matcher;
 32 import java.util.regex.Pattern;
 33 
 34 /**
 35  * Created by gfrost
 36  */
 37 public class ProcessRunner {
 38 
 39     static public ProcessRunner run(String prog) {
 40         return new ProcessRunner(prog);
 41     }
 42 
 43     static public ProcessRunner run(File file) {
 44         return new ProcessRunner(file);
 45     }
 46 
 47     List<String> args = new ArrayList<>();
 48 
 49     @SuppressWarnings("this-escape")
 50     public ProcessRunner(String prog) {
 51         opt(prog);
 52     }
 53 
 54     @SuppressWarnings("this-escape")
 55     public ProcessRunner(File prog) {
 56         file(prog);
 57     }
 58 
 59     public ProcessRunner opt(String... argsToAdd) {
 60         for (String s : argsToAdd) {
 61             args.add(s);
 62         }
 63         return this;
 64     }
 65 
 66     public ProcessRunner fileOpt(String opt, File file) {
 67         return opt(opt).file(file);
 68     }
 69 
 70     public ProcessRunner dirOpt(String opt, File dir) {
 71         dir.mkdir();
 72         return fileOpt(opt, dir);
 73     }
 74 
 75     public ProcessRunner file(File file) {
 76         opt(file.getAbsolutePath());
 77         return this;
 78     }
 79 
 80     public ProcessRunner files(File[] files) {
 81         for (File f : files) {
 82             file(f);
 83         }
 84         return this;
 85     }
 86 
 87     public void files(List<File> rsFiles) {
 88         files(rsFiles.toArray(new File[0]));
 89     }
 90 
 91     public static class Result {
 92         public Result() {
 93         }
 94 
 95         public void scan(Pattern pattern, Scanner scanner) {
 96             for (List<String> list : streams) { //stdout then stderr
 97                 for (String text : list) {
 98                     Matcher matcher;
 99                     if ((matcher = pattern.matcher(text)).matches()) {
100                         scanner.process(matcher);
101                     }
102                 }
103             }
104         }
105 
106         public interface Scanner {
107             void process(Matcher m);
108         }
109 
110         public int status = -1;
111         public boolean ok = false;
112         public String commandLine = "";
113 
114         public List<String> stdout = new ArrayList<>();
115         public List<String> stderr = new ArrayList<>();
116         public List<List<String>> streams = List.of(stdout, stderr);
117     }
118 
119 
120     public Result go(boolean verbose) {
121         Result result = new Result();
122 
123         StringBuilder commandBuilder = new StringBuilder();
124 
125         for (String arg : args) {
126             commandBuilder.append(arg + " ");
127             if (verbose) {
128                 System.out.print(arg + " ");
129             }
130         }
131 
132         result.commandLine = commandBuilder.toString();
133         ProcessBuilder processBuilder = new ProcessBuilder(args);
134         try {
135             Process process = processBuilder.start();
136             Thread stdout = new StreamReader("OUT", process.getErrorStream(), result.stdout, verbose).thread;
137             Thread stderr = new StreamReader("ERR", process.getInputStream(), result.stderr, verbose).thread;
138             result.status = process.waitFor();
139             stdout.join();
140             stderr.join();
141             result.ok = result.status == 0;
142         } catch (IOException | InterruptedException e) {
143             e.printStackTrace();
144         }
145         return result;
146     }
147 
148     public ProcessRunner temp(String prefix, String suffix, String text) {
149         try {
150             File tempFile = File.createTempFile(prefix, suffix);
151             FileWriter tempDotFileWriter = new FileWriter(tempFile);
152             tempDotFileWriter.append(text);
153             tempDotFileWriter.close();
154             file(tempFile);
155         } catch (IOException e) {
156             e.printStackTrace();
157         }
158         return this;
159     }
160 
161 
162     static class StreamReader {
163         Thread thread;
164 
165         StreamReader(final String prefix, InputStream is, final List<String> out, final boolean verbose) {
166             final BufferedReader br = new BufferedReader(new InputStreamReader(is));
167             thread = new Thread(() -> {
168                 try {
169                     for (String string = br.readLine(); string != null; string = br.readLine()) {
170                         if (verbose) {
171                             System.out.println(prefix + ":" + string);
172                         }
173                         out.add(string);
174                     }
175                     br.close();
176                 } catch (Exception e) {
177                     e.printStackTrace();
178                 }
179             });
180             thread.start();
181 
182         }
183 
184     }
185 
186 }