8132541: (process) ProcessBuilder support for redirection to discard output
Add redirect to NUL or /dev/null depending on the OS Reviewed-by: chegar, martin
This commit is contained in:
parent
f1f609ddaa
commit
4e7617c040
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -33,7 +33,8 @@ import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
/**
|
||||
* This class is used to create operating system processes.
|
||||
*
|
||||
@ -445,6 +446,7 @@ public final class ProcessBuilder
|
||||
* <ul>
|
||||
* <li>the special value {@link #PIPE Redirect.PIPE}
|
||||
* <li>the special value {@link #INHERIT Redirect.INHERIT}
|
||||
* <li>the special value {@link #DISCARD Redirect.DISCARD}
|
||||
* <li>a redirection to read from a file, created by an invocation of
|
||||
* {@link Redirect#from Redirect.from(File)}
|
||||
* <li>a redirection to write to a file, created by an invocation of
|
||||
@ -459,6 +461,13 @@ public final class ProcessBuilder
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract static class Redirect {
|
||||
private static final File NULL_FILE = AccessController.doPrivileged(
|
||||
(PrivilegedAction<File>) () -> {
|
||||
return new File((System.getProperty("os.name")
|
||||
.startsWith("Windows") ? "NUL" : "/dev/null"));
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* The type of a {@link Redirect}.
|
||||
*/
|
||||
@ -529,6 +538,28 @@ public final class ProcessBuilder
|
||||
public Type type() { return Type.INHERIT; }
|
||||
public String toString() { return type().toString(); }};
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that subprocess output will be discarded.
|
||||
* A typical implementation discards the output by writing to
|
||||
* an operating system specific "null file".
|
||||
*
|
||||
* <p>It will always be true that
|
||||
* <pre> {@code
|
||||
* Redirect.DISCARD.file() the filename appropriate for the operating system
|
||||
* and may be null &&
|
||||
* Redirect.DISCARD.type() == Redirect.Type.WRITE &&
|
||||
* Redirect.DISCARD.append() == false
|
||||
* }</pre>
|
||||
* @since 9
|
||||
*/
|
||||
public static final Redirect DISCARD = new Redirect() {
|
||||
public Type type() { return Type.WRITE; }
|
||||
public String toString() { return type().toString(); }
|
||||
public File file() { return NULL_FILE; }
|
||||
boolean append() { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the {@link File} source or destination associated
|
||||
* with this redirect, or {@code null} if there is no such file.
|
||||
|
@ -738,7 +738,7 @@ public class Basic {
|
||||
* Remove it from the list of env variables
|
||||
*/
|
||||
private static String removeAixExpectedVars(String vars) {
|
||||
return vars.replace("AIXTHREAD_GUARDPAGES=0,","");
|
||||
return vars.replace("AIXTHREAD_GUARDPAGES=0,", "");
|
||||
}
|
||||
|
||||
private static String sortByLinesWindowsly(String text) {
|
||||
@ -785,8 +785,8 @@ public class Basic {
|
||||
equal(entry.getKey(), key);
|
||||
equal(entry.getValue(), value);
|
||||
}
|
||||
check(! kIter.hasNext() &&
|
||||
! vIter.hasNext());
|
||||
check(!kIter.hasNext() &&
|
||||
!vIter.hasNext());
|
||||
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
}
|
||||
@ -815,9 +815,9 @@ public class Basic {
|
||||
|
||||
static void checkRedirects(ProcessBuilder pb,
|
||||
Redirect in, Redirect out, Redirect err) {
|
||||
equal(pb.redirectInput(), in);
|
||||
equal(pb.redirectInput(), in);
|
||||
equal(pb.redirectOutput(), out);
|
||||
equal(pb.redirectError(), err);
|
||||
equal(pb.redirectError(), err);
|
||||
}
|
||||
|
||||
static void redirectIO(ProcessBuilder pb,
|
||||
@ -862,6 +862,7 @@ public class Basic {
|
||||
Redirect[] redirects =
|
||||
{ PIPE,
|
||||
INHERIT,
|
||||
DISCARD,
|
||||
Redirect.from(ifile),
|
||||
Redirect.to(ifile),
|
||||
Redirect.appendTo(ifile),
|
||||
@ -884,6 +885,10 @@ public class Basic {
|
||||
equal(INHERIT.toString(), "INHERIT");
|
||||
equal(INHERIT.file(), null);
|
||||
|
||||
equal(DISCARD.type(), Redirect.Type.WRITE);
|
||||
equal(DISCARD.toString(), "WRITE");
|
||||
equal(DISCARD.file(), new File((Windows.is() ? "NUL" : "/dev/null")));
|
||||
|
||||
equal(Redirect.from(ifile).type(), Redirect.Type.READ);
|
||||
equal(Redirect.from(ifile).toString(),
|
||||
"redirect to read from file \"ifile\"");
|
||||
@ -925,6 +930,12 @@ public class Basic {
|
||||
pb.inheritIO();
|
||||
checkRedirects(pb, INHERIT, INHERIT, INHERIT);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check DISCARD for stdout,stderr
|
||||
//----------------------------------------------------------------
|
||||
redirectIO(pb, INHERIT, DISCARD, DISCARD);
|
||||
checkRedirects(pb, INHERIT, DISCARD, DISCARD);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check setters and getters agree
|
||||
//----------------------------------------------------------------
|
||||
@ -943,7 +954,8 @@ public class Basic {
|
||||
THROWS(IllegalArgumentException.class,
|
||||
() -> pb.redirectInput(Redirect.to(ofile)),
|
||||
() -> pb.redirectOutput(Redirect.from(ifile)),
|
||||
() -> pb.redirectError(Redirect.from(ifile)));
|
||||
() -> pb.redirectError(Redirect.from(ifile)),
|
||||
() -> pb.redirectInput(DISCARD));
|
||||
|
||||
THROWS(NullPointerException.class,
|
||||
() -> pb.redirectInput((File)null),
|
||||
@ -980,7 +992,7 @@ public class Basic {
|
||||
ProcessResults r = run(pb);
|
||||
equal(r.exitValue(), 0);
|
||||
equal(fileContents(ofile),
|
||||
"standard error" + "standard output");
|
||||
"standard error" + "standard output");
|
||||
equal(fileContents(efile), "");
|
||||
equal(r.out(), "");
|
||||
equal(r.err(), "");
|
||||
@ -1050,6 +1062,79 @@ public class Basic {
|
||||
efile.delete();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// DISCARDing output
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
setFileContents(ifile, "standard input");
|
||||
pb.redirectOutput(DISCARD);
|
||||
pb.redirectError(DISCARD);
|
||||
ProcessResults r = run(pb);
|
||||
equal(r.exitValue(), 0);
|
||||
equal(r.out(), "");
|
||||
equal(r.err(), "");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// DISCARDing output and redirecting error
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
setFileContents(ifile, "standard input");
|
||||
setFileContents(ofile, "ofile-contents");
|
||||
setFileContents(efile, "efile-contents");
|
||||
pb.redirectOutput(DISCARD);
|
||||
pb.redirectError(efile);
|
||||
ProcessResults r = run(pb);
|
||||
equal(r.exitValue(), 0);
|
||||
equal(fileContents(ofile), "ofile-contents");
|
||||
equal(fileContents(efile), "standard error");
|
||||
equal(r.out(), "");
|
||||
equal(r.err(), "");
|
||||
ofile.delete();
|
||||
efile.delete();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// DISCARDing error and redirecting output
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
setFileContents(ifile, "standard input");
|
||||
setFileContents(ofile, "ofile-contents");
|
||||
setFileContents(efile, "efile-contents");
|
||||
pb.redirectOutput(ofile);
|
||||
pb.redirectError(DISCARD);
|
||||
ProcessResults r = run(pb);
|
||||
equal(r.exitValue(), 0);
|
||||
equal(fileContents(ofile), "standard output");
|
||||
equal(fileContents(efile), "efile-contents");
|
||||
equal(r.out(), "");
|
||||
equal(r.err(), "");
|
||||
ofile.delete();
|
||||
efile.delete();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// DISCARDing output and merging error into output
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
setFileContents(ifile, "standard input");
|
||||
setFileContents(ofile, "ofile-contents");
|
||||
setFileContents(efile, "efile-contents");
|
||||
pb.redirectOutput(DISCARD);
|
||||
pb.redirectErrorStream(true);
|
||||
pb.redirectError(efile);
|
||||
ProcessResults r = run(pb);
|
||||
equal(r.exitValue(), 0);
|
||||
equal(fileContents(ofile), "ofile-contents"); // untouched
|
||||
equal(fileContents(efile), ""); // empty
|
||||
equal(r.out(), "");
|
||||
equal(r.err(), "");
|
||||
ifile.delete();
|
||||
ofile.delete();
|
||||
efile.delete();
|
||||
pb.redirectErrorStream(false); // reset for next test
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Testing INHERIT is harder.
|
||||
// Note that this requires __FOUR__ nested JVMs involved in one test,
|
||||
|
Loading…
x
Reference in New Issue
Block a user