1 /*
   2  * Copyright (c) 2019, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.jpackage.test;
  24 
  25 import java.io.File;
  26 import java.nio.file.Files;
  27 import java.nio.file.Path;
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.Collections;
  31 import java.util.List;
  32 
  33 public final class Executor extends CommandArguments<Executor> {
  34 
  35     public Executor() {
  36         saveOutputType = SaveOutputType.NONE;
  37     }
  38 
  39     public Executor setExecutable(String v) {
  40         executable = v;
  41         return this;
  42     }
  43 
  44     public Executor setDirectory(Path v) {
  45         directory = v;
  46         return this;
  47     }
  48 
  49     public Executor setExecutable(JavaTool v) {
  50         return setExecutable(v.getPath().getAbsolutePath());
  51     }
  52 
  53     public Executor saveOutput() {
  54         saveOutputType = SaveOutputType.FULL;
  55         return this;
  56     }
  57 
  58     public Executor saveFirstLineOfOutput() {
  59         saveOutputType = SaveOutputType.FIRST_LINE;
  60         return this;
  61     }
  62 
  63     public class Result {
  64 
  65         Result(int exitCode) {
  66             this.exitCode = exitCode;
  67         }
  68 
  69         public String getFirstLineOfOutput() {
  70             return output.get(0).trim();
  71         }
  72 
  73         public List<String> getOutput() {
  74             return output;
  75         }
  76 
  77         public String getPrintableCommandLine() {
  78             return Executor.this.getPrintableCommandLine();
  79         }
  80 
  81         public Result assertExitCodeIs(int expectedExitCode) {
  82             Test.assertEquals(expectedExitCode, exitCode, String.format(
  83                     "Check command %s exited with %d code",
  84                     getPrintableCommandLine(), expectedExitCode));
  85             return this;
  86         }
  87 
  88         public Result assertExitCodeIsZero() {
  89             return assertExitCodeIs(0);
  90         }
  91 
  92         int exitCode;
  93         List<String> output;
  94     }
  95 
  96     public Result execute() {
  97         try {
  98             return executeImpl();
  99         } catch (RuntimeException e) {
 100             throw e;
 101         } catch (Exception e) {
 102             throw new RuntimeException(e);
 103         }
 104     }
 105 
 106     private Result executeImpl() throws Exception {
 107         List<String> command = new ArrayList<>();
 108         command.add(executable);
 109         command.addAll(args);
 110         Path outputFile = null;
 111         ProcessBuilder builder = new ProcessBuilder(command);
 112         StringBuilder sb = new StringBuilder(getPrintableCommandLine());
 113         if (saveOutputType != SaveOutputType.NONE) {
 114             outputFile = Test.createTempFile(".out");
 115             builder.redirectErrorStream(true);
 116             builder.redirectOutput(outputFile.toFile());
 117             sb.append(String.format("; redirect output to [%s]", outputFile));
 118         }
 119         if (directory != null) {
 120             builder.directory(directory.toFile());
 121             sb.append(String.format("; in directory [%s]", directory));
 122         }
 123 
 124         try {
 125             Test.trace("Execute " + sb.toString() + "...");
 126             Process process = builder.start();
 127             Result reply = new Result(process.waitFor());
 128             Test.trace("Done. Exit code: " + reply.exitCode);
 129             if (saveOutputType == SaveOutputType.FIRST_LINE) {
 130                 reply.output = Arrays.asList(
 131                         Files.readAllLines(outputFile).stream().findFirst().get());
 132             } else if (saveOutputType == SaveOutputType.FULL) {
 133                 reply.output = Collections.unmodifiableList(Files.readAllLines(
 134                         outputFile));
 135             }
 136             return reply;
 137         } finally {
 138             if (outputFile != null) {
 139                 Files.deleteIfExists(outputFile);
 140             }
 141         }
 142     }
 143 
 144     public String getPrintableCommandLine() {
 145         return "[" + executable + "]; args(" + args.size() + ")=" + Arrays.toString(
 146                 args.toArray());
 147     }
 148 
 149     private String executable;
 150     private SaveOutputType saveOutputType;
 151     private Path directory;
 152 
 153     private static enum SaveOutputType {
 154         NONE, FULL, FIRST_LINE
 155     };
 156 }