aboutsummaryrefslogtreecommitdiff
path: root/nailgun_launcher/NailgunLauncher.java
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2016-11-07 02:21:50 -0500
committerChristopher Vogt <oss.nsp@cvogt.org>2016-11-07 02:21:50 -0500
commitc6b9a480879c101028b20b9cc8716b8ffa773630 (patch)
treefff15c1d6595455f6994f5793b63b08c5bf24d4a /nailgun_launcher/NailgunLauncher.java
parentc89f87c9c9a0c7b256f225e37c55cb34f060aa6c (diff)
parentfd849d293448d55c6bcb6f8440f44838b51fc860 (diff)
downloadcbt-c6b9a480879c101028b20b9cc8716b8ffa773630.tar.gz
cbt-c6b9a480879c101028b20b9cc8716b8ffa773630.tar.bz2
cbt-c6b9a480879c101028b20b9cc8716b8ffa773630.zip
Merge remote-tracking branch 'origin/master' into integrate-eval
Diffstat (limited to 'nailgun_launcher/NailgunLauncher.java')
-rw-r--r--nailgun_launcher/NailgunLauncher.java200
1 files changed, 200 insertions, 0 deletions
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
new file mode 100644
index 0000000..6639218
--- /dev/null
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -0,0 +1,200 @@
+package cbt;
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.security.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import static cbt.Stage0Lib.*;
+import static java.io.File.pathSeparator;
+
+/**
+ * This launcher allows to start the JVM without loading anything else permanently into its
+ * classpath except for the launcher itself. That's why it is written in Java without
+ * dependencies outside the JDK.
+ */
+public class NailgunLauncher{
+ /** Persistent cache for caching classloaders for the JVM life time. */
+ private final static ClassLoaderCache2<ClassLoader> classLoaderCache = new ClassLoaderCache2<ClassLoader>(
+ new ConcurrentHashMap<String,Object>(),
+ new ConcurrentHashMap<Object,ClassLoader>()
+ );
+
+ public final static SecurityManager initialSecurityManager
+ = System.getSecurityManager();
+
+ public static String TARGET = System.getenv("TARGET");
+ private static String NAILGUN = "nailgun_launcher/";
+ private static String STAGE1 = "stage1/";
+
+ @SuppressWarnings("unchecked")
+ public static Object getBuild( Object context ) throws Throwable{
+ BuildStage1Result res = buildStage1(
+ (Boolean) get(context, "cbtHasChangedCompat"),
+ (Long) get(context, "startCompat"),
+ ((File) get(context, "cache")).toString() + "/",
+ ((File) get(context, "cbtHome")).toString(),
+ ((File) get(context, "compatibilityTarget")).toString() + "/",
+ new ClassLoaderCache2<ClassLoader>(
+ (ConcurrentHashMap<String,Object>) get(context, "permanentKeys"),
+ (ConcurrentHashMap<Object,ClassLoader>) get(context, "permanentClassLoaders")
+ )
+ );
+ return
+ res
+ .classLoader
+ .loadClass("cbt.Stage1")
+ .getMethod( "getBuild", Object.class, Boolean.class )
+ .invoke(null, context, res.changed);
+ }
+
+ public static void main( String[] args ) throws Throwable {
+ Long _start = System.currentTimeMillis();
+ if(args[0].equals("check-alive")){
+ System.exit(33);
+ return;
+ }
+
+ System.setSecurityManager( new TrapSecurityManager() );
+ 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), true) );
+ }
+ try{
+ System.err.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream
+ assert(System.err.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream");
+ } catch( NoSuchFieldException e ){
+ System.setErr( new PrintStream(new ThreadLocalOutputStream(System.err), true) );
+ }
+ // ---------------------
+
+ _assert(System.getenv("CBT_HOME") != null, "environment variable CBT_HOME not defined");
+ String CBT_HOME = System.getenv("CBT_HOME");
+ String cache = CBT_HOME + "/cache/";
+ String compatibilityTarget = CBT_HOME + "/compatibility/" + TARGET;
+ BuildStage1Result res = buildStage1(
+ false, start, cache, CBT_HOME, compatibilityTarget, classLoaderCache
+ );
+
+ try{
+ System.exit(
+ (Integer) res
+ .classLoader
+ .loadClass("cbt.Stage1")
+ .getMethod(
+ "run",
+ String[].class, File.class, File.class, Boolean.class,
+ File.class, Long.class, ConcurrentHashMap.class, ConcurrentHashMap.class
+ )
+ .invoke(
+ null,
+ (Object) args, new File(cache), new File(CBT_HOME), res.changed,
+ new File(compatibilityTarget), start, classLoaderCache.keys, classLoaderCache.values
+ )
+ );
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ throw unwrapInvocationTargetException(e);
+ }
+ }
+
+ public static Throwable unwrapInvocationTargetException(Throwable e){
+ if(e instanceof java.lang.reflect.InvocationTargetException){
+ return unwrapInvocationTargetException(((java.lang.reflect.InvocationTargetException) e).getCause());
+ } else{
+ return e;
+ }
+ }
+
+ public static BuildStage1Result buildStage1(
+ Boolean changed, long start, String cache, String cbtHome, String compatibilityTarget, ClassLoaderCache2<ClassLoader> classLoaderCache
+ ) throws Throwable {
+ _assert(TARGET != null, "environment variable TARGET not defined");
+ String nailgunTarget = cbtHome + "/" + NAILGUN + TARGET;
+ String stage1Sources = cbtHome + "/" + STAGE1;
+ String stage1Target = stage1Sources + TARGET;
+ File compatibilitySources = new File(cbtHome + "/compatibility");
+ String mavenCache = cache + "maven";
+ String mavenUrl = "https://repo1.maven.org/maven2";
+
+ ClassLoader rootClassLoader = new CbtURLClassLoader( new URL[]{}, ClassLoader.getSystemClassLoader().getParent() ); // wrap for caching
+ EarlyDependencies earlyDeps = new EarlyDependencies(mavenCache, mavenUrl, classLoaderCache, rootClassLoader);
+
+ ClassLoader compatibilityClassLoader;
+ if(!compatibilityTarget.startsWith(cbtHome)){
+ compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
+ } else {
+ List<File> compatibilitySourceFiles = new ArrayList<File>();
+ for( File f: compatibilitySources.listFiles() ){
+ if( f.isFile() && (f.toString().endsWith(".scala") || f.toString().endsWith(".java")) ){
+ compatibilitySourceFiles.add(f);
+ }
+ }
+ changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
+
+ if( classLoaderCache.contains( compatibilityTarget ) ){
+ compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
+ } else {
+ compatibilityClassLoader = classLoaderCache.put( classLoader(compatibilityTarget, rootClassLoader), compatibilityTarget );
+ }
+ }
+
+ String[] nailgunClasspathArray = append( earlyDeps.classpathArray, nailgunTarget );
+ String nailgunClasspath = classpath( nailgunClasspathArray );
+ ClassLoader nailgunClassLoader = new CbtURLClassLoader( new URL[]{}, NailgunLauncher.class.getClassLoader() ); // wrap for caching
+ if( !classLoaderCache.contains( nailgunClasspath ) ){
+ nailgunClassLoader = classLoaderCache.put( nailgunClassLoader, nailgunClasspath );
+ }
+
+ String[] stage1ClasspathArray =
+ append( append( nailgunClasspathArray, compatibilityTarget ), stage1Target );
+ String stage1Classpath = classpath( stage1ClasspathArray );
+
+ List<File> stage1SourceFiles = new ArrayList<File>();
+ for( File f: new File(stage1Sources).listFiles() ){
+ if( f.isFile() && f.toString().endsWith(".scala") ){
+ stage1SourceFiles.add(f);
+ }
+ }
+ changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles);
+
+ ClassLoader stage1classLoader;
+ if( !changed && classLoaderCache.contains( stage1Classpath ) ){
+ stage1classLoader = classLoaderCache.get( stage1Classpath );
+ } else {
+ stage1classLoader =
+ classLoaderCache.put(
+ classLoader(
+ stage1Target,
+ new MultiClassLoader2(
+ nailgunClassLoader,
+ compatibilityClassLoader,
+ earlyDeps.classLoader
+ )
+ ),
+ stage1Classpath
+ );
+ }
+
+ return new BuildStage1Result(
+ changed,
+ stage1classLoader
+ );
+ }
+}
+class BuildStage1Result{
+ Boolean changed;
+ ClassLoader classLoader;
+ BuildStage1Result( Boolean changed, ClassLoader classLoader ){
+ this.changed = changed;
+ this.classLoader = classLoader;
+ }
+}