/* * Copyright (c) 2013-2017 Cinchapi Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cinchapi.concourse.util; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import java.util.Map; import com.cinchapi.concourse.annotate.UtilityClass; import com.google.common.base.Throwables; import com.google.common.collect.Lists; /** * Utilities for dealing with {@link Process} objects. * * @author jnelson */ @UtilityClass public final class Processes { /** * Create a {@link ProcessBuilder} that, on the appropriate platforms, * sources the standard interactive profile for the user (i.e. * ~/.bash_profile). * * @param commands a string array containing the program and its arguments * @return a {@link ProcessBuilder} */ public static ProcessBuilder getBuilder(String... commands) { ProcessBuilder pb = new ProcessBuilder(commands); if(!Platform.isWindows()) { Map<String, String> env = pb.environment(); env.put("BASH_ENV", System.getProperty("user.home") + "/.bash_profile"); } return pb; } /** * Create a {@link ProcessBuilder} that, on the appropriate platforms, * sources the standard interactive profile for the user (i.e. * ~/.bash_profile) and supports the use of the pipe (|) redirection on * platforms that allow it. * * @param commands a string array containing the program and its arguments * @return a {@link ProcessBuilder} */ public static ProcessBuilder getBuilderWithPipeSupport(String... commands) { if(!Platform.isWindows()) { List<String> listCommands = Lists .newArrayListWithCapacity(commands.length + 2); // Need to invoke a shell in which the commands can be run. That // shell will properly interpret the pipe(|). listCommands.add("/bin/sh"); listCommands.add("-c"); for (String command : commands) { listCommands.add(command); } return getBuilder(listCommands.toArray(commands)); } else { return getBuilder(commands); } } /** * Get the stdout for {@code process}. * * @param process * @return a collection of output lines */ public static List<String> getStdOut(Process process) { return readStream(process.getInputStream()); } /** * Read an input stream. * * @param stream * @return the lines in the stream */ private static List<String> readStream(InputStream stream) { try { BufferedReader out = new BufferedReader(new InputStreamReader( stream)); String line; List<String> output = Lists.newArrayList(); while ((line = out.readLine()) != null) { output.add(line); } return output; } catch (Exception e) { throw Throwables.propagate(e); } } /** * Similar to {@link Process#waitFor()} but will throw a * {@link RuntimeException} if the process does not have an exit code of * {@code 0}. * * @param process */ public static void waitForSuccessfulCompletion(Process process) { try { int exitVal = process.waitFor(); if(exitVal != 0) { throw new RuntimeException(getStdErr(process).toString()); } } catch (Exception e) { throw Throwables.propagate(e); } } /** * Get the stderr for {@code process}. * * @param process * @return a collection of error lines */ public static List<String> getStdErr(Process process) { return readStream(process.getErrorStream()); } private Processes() {} /* noinit */ }