< prev index next >

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java

Print this page




  22  */
  23 package jdk.jpackage.test;
  24 
  25 import java.io.BufferedReader;
  26 import java.io.ByteArrayOutputStream;
  27 import java.io.IOException;
  28 import java.io.InputStreamReader;
  29 import java.io.OutputStream;
  30 import java.io.PrintStream;
  31 import java.io.StringReader;
  32 import java.nio.file.Path;
  33 import java.util.*;
  34 import java.util.regex.Pattern;
  35 import java.util.spi.ToolProvider;
  36 import java.util.stream.Collectors;
  37 import java.util.stream.Stream;
  38 import jdk.jpackage.test.Functional.ThrowingSupplier;
  39 
  40 public final class Executor extends CommandArguments<Executor> {
  41 





  42     public Executor() {
  43         saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE));
  44     }
  45 
  46     public Executor setExecutable(String v) {
  47         return setExecutable(Path.of(v));
  48     }
  49 
  50     public Executor setExecutable(Path v) {
  51         executable = Objects.requireNonNull(v);
  52         toolProvider = null;
  53         return this;
  54     }
  55 
  56     public Executor setToolProvider(ToolProvider v) {
  57         toolProvider = Objects.requireNonNull(v);
  58         executable = null;
  59         return this;
  60     }
  61 


 153 
 154         public String getPrintableCommandLine() {
 155             return Executor.this.getPrintableCommandLine();
 156         }
 157 
 158         public Result assertExitCodeIs(int expectedExitCode) {
 159             TKit.assertEquals(expectedExitCode, exitCode, String.format(
 160                     "Check command %s exited with %d code",
 161                     getPrintableCommandLine(), expectedExitCode));
 162             return this;
 163         }
 164 
 165         public Result assertExitCodeIsZero() {
 166             return assertExitCodeIs(0);
 167         }
 168 
 169         final int exitCode;
 170         private List<String> output;
 171     }
 172 
 173     public Result execute() {
 174         if (toolProvider != null && directory != null) {
 175             throw new IllegalArgumentException(
 176                     "Can't change directory when using tool provider");
 177         }
 178 
 179         return ThrowingSupplier.toSupplier(() -> {
 180             if (toolProvider != null) {
 181                 return runToolProvider();
 182             }
 183 
 184             if (executable != null) {
 185                 return runExecutable();
 186             }
 187 
 188             throw new IllegalStateException("No command to execute");
 189         }).get();
 190     }
 191 








 192     public String executeAndGetFirstLineOfOutput() {
 193         return saveFirstLineOfOutput().execute().assertExitCodeIsZero().getFirstLineOfOutput();
 194     }
 195 
 196     public List<String> executeAndGetOutput() {
 197         return saveOutput().execute().assertExitCodeIsZero().getOutput();
 198     }
 199 
 200     private boolean withSavedOutput() {
 201         return saveOutputType.contains(SaveOutputType.FULL) || saveOutputType.contains(
 202                 SaveOutputType.FIRST_LINE);
 203     }
 204 
 205     private Path executablePath() {
 206         if (directory == null || executable.isAbsolute()) {


 207             return executable;
 208         }
 209 
 210         // If relative path to executable is used it seems to be broken when
 211         // ProcessBuilder changes the directory. On Windows it changes the
 212         // directory first and on Linux it looks up for executable before
 213         // changing the directory. So to stay of safe side, use absolute path
 214         // to executable.
 215         return executable.toAbsolutePath();
 216     }
 217 
 218     private Result runExecutable() throws IOException, InterruptedException {
 219         List<String> command = new ArrayList<>();
 220         command.add(executablePath().toString());
 221         command.addAll(args);
 222         ProcessBuilder builder = new ProcessBuilder(command);
 223         StringBuilder sb = new StringBuilder(getPrintableCommandLine());
 224         if (withSavedOutput()) {
 225             builder.redirectErrorStream(true);
 226             sb.append("; save output");
 227         } else if (saveOutputType.contains(SaveOutputType.DUMP)) {
 228             builder.inheritIO();
 229             sb.append("; inherit I/O");
 230         } else {
 231             builder.redirectError(ProcessBuilder.Redirect.DISCARD);
 232             builder.redirectOutput(ProcessBuilder.Redirect.DISCARD);
 233             sb.append("; discard I/O");
 234         }
 235         if (directory != null) {
 236             builder.directory(directory.toFile());
 237             sb.append(String.format("; in directory [%s]", directory));
 238         }
 239 
 240         TKit.trace("Execute " + sb.toString() + "...");
 241         Process process = builder.start();
 242 
 243         List<String> outputLines = null;
 244         if (withSavedOutput()) {
 245             try (BufferedReader outReader = new BufferedReader(
 246                     new InputStreamReader(process.getInputStream()))) {
 247                 if (saveOutputType.contains(SaveOutputType.DUMP)
 248                         || saveOutputType.contains(SaveOutputType.FULL)) {
 249                     outputLines = outReader.lines().collect(Collectors.toList());
 250                 } else {
 251                     outputLines = Arrays.asList(
 252                             outReader.lines().findFirst().orElse(null));
 253                 }
 254             } finally {
 255                 if (saveOutputType.contains(SaveOutputType.DUMP) && outputLines != null) {
 256                     outputLines.stream().forEach(System.out::println);
 257                     if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) {
 258                         // Pick the first line of saved output if there is one
 259                         for (String line: outputLines) {
 260                             outputLines = List.of(line);
 261                             break;
 262                         }
 263                     }
 264                 }
 265             }
 266         }
 267 
 268         Result reply = new Result(process.waitFor());
 269         TKit.trace("Done. Exit code: " + reply.exitCode);
 270 
 271         if (outputLines != null) {
 272             reply.output = Collections.unmodifiableList(outputLines);
 273         }
 274         return reply;
 275     }
 276 
 277     private Result runToolProvider(PrintStream out, PrintStream err) {
 278         TKit.trace("Execute " + getPrintableCommandLine() + "...");
 279         Result reply = new Result(toolProvider.run(out, err, args.toArray(
 280                 String[]::new)));
 281         TKit.trace("Done. Exit code: " + reply.exitCode);
 282         return reply;
 283     }
 284 
 285 
 286     private Result runToolProvider() throws IOException {
 287         if (!withSavedOutput()) {
 288             if (saveOutputType.contains(SaveOutputType.DUMP)) {
 289                 return runToolProvider(System.out, System.err);
 290             }
 291 
 292             PrintStream nullPrintStream = new PrintStream(new OutputStream() {
 293                 @Override
 294                 public void write(int b) {
 295                     // Nop
 296                 }
 297             });
 298             return runToolProvider(nullPrintStream, nullPrintStream);
 299         }
 300 
 301         try (ByteArrayOutputStream buf = new ByteArrayOutputStream();


 334         if (toolProvider == null && executable == null) {
 335             exec = "<null>";
 336         } else if (toolProvider != null) {
 337             format = "tool provider " + format;
 338             exec = toolProvider.name();
 339         } else {
 340             exec = executablePath().toString();
 341         }
 342 
 343         return String.format(format, printCommandLine(exec, args),
 344                 args.size() + 1);
 345     }
 346 
 347     private static String printCommandLine(String executable, List<String> args) {
 348         // Want command line printed in a way it can be easily copy/pasted
 349         // to be executed manally
 350         Pattern regex = Pattern.compile("\\s");
 351         return Stream.concat(Stream.of(executable), args.stream()).map(
 352                 v -> (v.isEmpty() || regex.matcher(v).find()) ? "\"" + v + "\"" : v).collect(
 353                         Collectors.joining(" "));




 354     }
 355 
 356     private ToolProvider toolProvider;
 357     private Path executable;
 358     private Set<SaveOutputType> saveOutputType;
 359     private Path directory;
 360 
 361     private static enum SaveOutputType {
 362         NONE, FULL, FIRST_LINE, DUMP
 363     };
 364 }


  22  */
  23 package jdk.jpackage.test;
  24 
  25 import java.io.BufferedReader;
  26 import java.io.ByteArrayOutputStream;
  27 import java.io.IOException;
  28 import java.io.InputStreamReader;
  29 import java.io.OutputStream;
  30 import java.io.PrintStream;
  31 import java.io.StringReader;
  32 import java.nio.file.Path;
  33 import java.util.*;
  34 import java.util.regex.Pattern;
  35 import java.util.spi.ToolProvider;
  36 import java.util.stream.Collectors;
  37 import java.util.stream.Stream;
  38 import jdk.jpackage.test.Functional.ThrowingSupplier;
  39 
  40 public final class Executor extends CommandArguments<Executor> {
  41 
  42     public static Executor of(String... cmdline) {
  43         return new Executor().setExecutable(cmdline[0]).addArguments(
  44                 Arrays.copyOfRange(cmdline, 1, cmdline.length));
  45     }
  46 
  47     public Executor() {
  48         saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE));
  49     }
  50 
  51     public Executor setExecutable(String v) {
  52         return setExecutable(Path.of(v));
  53     }
  54 
  55     public Executor setExecutable(Path v) {
  56         executable = Objects.requireNonNull(v);
  57         toolProvider = null;
  58         return this;
  59     }
  60 
  61     public Executor setToolProvider(ToolProvider v) {
  62         toolProvider = Objects.requireNonNull(v);
  63         executable = null;
  64         return this;
  65     }
  66 


 158 
 159         public String getPrintableCommandLine() {
 160             return Executor.this.getPrintableCommandLine();
 161         }
 162 
 163         public Result assertExitCodeIs(int expectedExitCode) {
 164             TKit.assertEquals(expectedExitCode, exitCode, String.format(
 165                     "Check command %s exited with %d code",
 166                     getPrintableCommandLine(), expectedExitCode));
 167             return this;
 168         }
 169 
 170         public Result assertExitCodeIsZero() {
 171             return assertExitCodeIs(0);
 172         }
 173 
 174         final int exitCode;
 175         private List<String> output;
 176     }
 177 
 178     public Result executeWithoutExitCodeCheck() {
 179         if (toolProvider != null && directory != null) {
 180             throw new IllegalArgumentException(
 181                     "Can't change directory when using tool provider");
 182         }
 183 
 184         return ThrowingSupplier.toSupplier(() -> {
 185             if (toolProvider != null) {
 186                 return runToolProvider();
 187             }
 188 
 189             if (executable != null) {
 190                 return runExecutable();
 191             }
 192 
 193             throw new IllegalStateException("No command to execute");
 194         }).get();
 195     }
 196 
 197     public Result execute(int expectedCode) {
 198         return executeWithoutExitCodeCheck().assertExitCodeIs(expectedCode);
 199     }
 200 
 201     public Result execute() {
 202         return execute(0);
 203     }
 204 
 205     public String executeAndGetFirstLineOfOutput() {
 206         return saveFirstLineOfOutput().execute().getFirstLineOfOutput();
 207     }
 208 
 209     public List<String> executeAndGetOutput() {
 210         return saveOutput().execute().getOutput();
 211     }
 212 
 213     private boolean withSavedOutput() {
 214         return saveOutputType.contains(SaveOutputType.FULL) || saveOutputType.contains(
 215                 SaveOutputType.FIRST_LINE);
 216     }
 217 
 218     private Path executablePath() {
 219         if (directory == null
 220                 || executable.isAbsolute()
 221                 || !Set.of(".", "..").contains(executable.getName(0).toString())) {
 222             return executable;
 223         }
 224 
 225         // If relative path to executable is used it seems to be broken when
 226         // ProcessBuilder changes the directory. On Windows it changes the
 227         // directory first and on Linux it looks up for executable before
 228         // changing the directory. So to stay of safe side, use absolute path
 229         // to executable.
 230         return executable.toAbsolutePath();
 231     }
 232 
 233     private Result runExecutable() throws IOException, InterruptedException {
 234         List<String> command = new ArrayList<>();
 235         command.add(executablePath().toString());
 236         command.addAll(args);
 237         ProcessBuilder builder = new ProcessBuilder(command);
 238         StringBuilder sb = new StringBuilder(getPrintableCommandLine());
 239         if (withSavedOutput()) {
 240             builder.redirectErrorStream(true);
 241             sb.append("; save output");
 242         } else if (saveOutputType.contains(SaveOutputType.DUMP)) {
 243             builder.inheritIO();
 244             sb.append("; inherit I/O");
 245         } else {
 246             builder.redirectError(ProcessBuilder.Redirect.DISCARD);
 247             builder.redirectOutput(ProcessBuilder.Redirect.DISCARD);
 248             sb.append("; discard I/O");
 249         }
 250         if (directory != null) {
 251             builder.directory(directory.toFile());
 252             sb.append(String.format("; in directory [%s]", directory));
 253         }
 254 
 255         trace("Execute " + sb.toString() + "...");
 256         Process process = builder.start();
 257 
 258         List<String> outputLines = null;
 259         if (withSavedOutput()) {
 260             try (BufferedReader outReader = new BufferedReader(
 261                     new InputStreamReader(process.getInputStream()))) {
 262                 if (saveOutputType.contains(SaveOutputType.DUMP)
 263                         || saveOutputType.contains(SaveOutputType.FULL)) {
 264                     outputLines = outReader.lines().collect(Collectors.toList());
 265                 } else {
 266                     outputLines = Arrays.asList(
 267                             outReader.lines().findFirst().orElse(null));
 268                 }
 269             } finally {
 270                 if (saveOutputType.contains(SaveOutputType.DUMP) && outputLines != null) {
 271                     outputLines.stream().forEach(System.out::println);
 272                     if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) {
 273                         // Pick the first line of saved output if there is one
 274                         for (String line: outputLines) {
 275                             outputLines = List.of(line);
 276                             break;
 277                         }
 278                     }
 279                 }
 280             }
 281         }
 282 
 283         Result reply = new Result(process.waitFor());
 284         trace("Done. Exit code: " + reply.exitCode);
 285 
 286         if (outputLines != null) {
 287             reply.output = Collections.unmodifiableList(outputLines);
 288         }
 289         return reply;
 290     }
 291 
 292     private Result runToolProvider(PrintStream out, PrintStream err) {
 293         trace("Execute " + getPrintableCommandLine() + "...");
 294         Result reply = new Result(toolProvider.run(out, err, args.toArray(
 295                 String[]::new)));
 296         trace("Done. Exit code: " + reply.exitCode);
 297         return reply;
 298     }
 299 
 300 
 301     private Result runToolProvider() throws IOException {
 302         if (!withSavedOutput()) {
 303             if (saveOutputType.contains(SaveOutputType.DUMP)) {
 304                 return runToolProvider(System.out, System.err);
 305             }
 306 
 307             PrintStream nullPrintStream = new PrintStream(new OutputStream() {
 308                 @Override
 309                 public void write(int b) {
 310                     // Nop
 311                 }
 312             });
 313             return runToolProvider(nullPrintStream, nullPrintStream);
 314         }
 315 
 316         try (ByteArrayOutputStream buf = new ByteArrayOutputStream();


 349         if (toolProvider == null && executable == null) {
 350             exec = "<null>";
 351         } else if (toolProvider != null) {
 352             format = "tool provider " + format;
 353             exec = toolProvider.name();
 354         } else {
 355             exec = executablePath().toString();
 356         }
 357 
 358         return String.format(format, printCommandLine(exec, args),
 359                 args.size() + 1);
 360     }
 361 
 362     private static String printCommandLine(String executable, List<String> args) {
 363         // Want command line printed in a way it can be easily copy/pasted
 364         // to be executed manally
 365         Pattern regex = Pattern.compile("\\s");
 366         return Stream.concat(Stream.of(executable), args.stream()).map(
 367                 v -> (v.isEmpty() || regex.matcher(v).find()) ? "\"" + v + "\"" : v).collect(
 368                         Collectors.joining(" "));
 369     }
 370 
 371     private static void trace(String msg) {
 372         TKit.trace(String.format("exec: %s", msg));
 373     }
 374 
 375     private ToolProvider toolProvider;
 376     private Path executable;
 377     private Set<SaveOutputType> saveOutputType;
 378     private Path directory;
 379 
 380     private static enum SaveOutputType {
 381         NONE, FULL, FIRST_LINE, DUMP
 382     };
 383 }
< prev index next >