aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2016-10-13 01:29:48 +0000
committerChristopher Vogt <oss.nsp@cvogt.org>2016-10-13 23:21:04 -0400
commitcf94008b6fded5f58cea764d48beb0dcbbd4bb97 (patch)
tree5a26f2e2c50e7d5776a56c86dba62a5f129ed45f
parente7dab60a0a38f40b75b919a91b73052b510f1711 (diff)
downloadcbt-cf94008b6fded5f58cea764d48beb0dcbbd4bb97.tar.gz
cbt-cf94008b6fded5f58cea764d48beb0dcbbd4bb97.tar.bz2
cbt-cf94008b6fded5f58cea764d48beb0dcbbd4bb97.zip
swap out System.out and System.err in a way that affects JDK and Scala
Before it only affected jdk, because scala.Console captures our and err before the swap. This is needed when running main classes like Scaladoc or the compiler and wanting to redirect output to standard error
-rw-r--r--nailgun_launcher/NailgunLauncher.java19
-rw-r--r--nailgun_launcher/ThreadLocalOutputStream.java30
-rw-r--r--stage1/Stage1Lib.scala35
3 files changed, 77 insertions, 7 deletions
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
index 37bfa06..b1daf2a 100644
--- a/nailgun_launcher/NailgunLauncher.java
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -59,7 +59,24 @@ public class NailgunLauncher{
installProxySettings();
String[] diff = args[0].split("\\.");
long start = _start - (Long.parseLong(diff[0]) * 1000L) - Long.parseLong(diff[1]);
-
+
+ // if nailgun didn't install it's threadLocal stdout/err replacements, install CBT's.
+ // this hack allows to later swap out System.out/err while still affecting things like
+ // scala.Console, which captured them at startup
+ try{
+ System.out.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream
+ assert(System.out.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream");
+ } catch( NoSuchFieldException e ){
+ System.setOut( new PrintStream(new ThreadLocalOutputStream(System.out)) );
+ }
+ try{
+ System.err.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream
+ assert(System.out.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream");
+ } catch( NoSuchFieldException e ){
+ System.setErr( new PrintStream(new ThreadLocalOutputStream(System.err)) );
+ }
+ // ---------------------
+
_assert(System.getenv("CBT_HOME") != null, "environment variable CBT_HOME not defined");
String CBT_HOME = System.getenv("CBT_HOME");
String cache = CBT_HOME + "/cache/";
diff --git a/nailgun_launcher/ThreadLocalOutputStream.java b/nailgun_launcher/ThreadLocalOutputStream.java
new file mode 100644
index 0000000..c12b775
--- /dev/null
+++ b/nailgun_launcher/ThreadLocalOutputStream.java
@@ -0,0 +1,30 @@
+package cbt;
+import java.io.*;
+
+public class ThreadLocalOutputStream extends OutputStream{
+ final public ThreadLocal<OutputStream> threadLocal;
+ final private OutputStream initialValue;
+
+ public ThreadLocalOutputStream( OutputStream initialValue ){
+ this.initialValue = initialValue;
+ threadLocal = new ThreadLocal<OutputStream>() {
+ @Override protected OutputStream initialValue() {
+ return ThreadLocalOutputStream.this.initialValue;
+ }
+ };
+ }
+
+ public OutputStream get(){
+ return threadLocal.get();
+ }
+
+ public void set( OutputStream outputStream ){
+ threadLocal.set( outputStream );
+ }
+
+ public void write( int b ) throws IOException{
+ // after implementing this I realized NailgunLauncher uses the same hack,
+ // so probably this is not a problem performance
+ get().write(b);
+ }
+}
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala
index 68648fe..273b9af 100644
--- a/stage1/Stage1Lib.scala
+++ b/stage1/Stage1Lib.scala
@@ -302,13 +302,36 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
}
}
def redirectOutToErr[T](code: => T): T = {
- val oldOut = System.out
- try{
- System.setOut(System.err)
- code
- } finally{
- System.setOut(oldOut)
+ val ( out, err ) = try{
+ // trying nailgun's System.our/err wrapper
+ val field = System.out.getClass.getDeclaredField("streams")
+ assert(System.out.getClass.getName == "com.martiansoftware.nailgun.ThreadLocalPrintStream")
+ assert(System.err.getClass.getName == "com.martiansoftware.nailgun.ThreadLocalPrintStream")
+ field.setAccessible(true)
+ val out = field.get(System.out).asInstanceOf[ThreadLocal[PrintStream]]
+ val err = field.get(System.err).asInstanceOf[ThreadLocal[PrintStream]]
+ ( out, err )
+ } catch {
+ case e: NoSuchFieldException =>
+ // trying cbt's System.our/err wrapper
+ val field = classOf[FilterOutputStream].getDeclaredField("out")
+ field.setAccessible(true)
+ val outStream = field.get(System.out)
+ val errStream = field.get(System.err)
+ assert(outStream.getClass.getName == "cbt.ThreadLocalOutputStream")
+ assert(errStream.getClass.getName == "cbt.ThreadLocalOutputStream")
+ val field2 = outStream.getClass.getDeclaredField("threadLocal")
+ field2.setAccessible(true)
+ val out = field2.get(outStream).asInstanceOf[ThreadLocal[PrintStream]]
+ val err = field2.get(errStream).asInstanceOf[ThreadLocal[PrintStream]]
+ ( out, err )
}
+
+ val oldOut: PrintStream = out.get
+ out.set( err.get: PrintStream )
+ val res = code
+ out.set( oldOut )
+ res
}
def trapExitCode( code: => ExitCode ): ExitCode = {