aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 = {