diff options
author | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-16 02:22:01 -0400 |
---|---|---|
committer | Christopher Vogt <oss.nsp@cvogt.org> | 2016-03-20 22:12:06 -0400 |
commit | 2c20a0dddc70a5eee207fb1c588bfd53eaaa7841 (patch) | |
tree | 8ae901ccafdc509ebb9717b116fdfc4f0244773f /nailgun_launcher | |
parent | 450fc5d3defcdc279cfeef0ae622ebe4f90988e2 (diff) | |
download | cbt-2c20a0dddc70a5eee207fb1c588bfd53eaaa7841.tar.gz cbt-2c20a0dddc70a5eee207fb1c588bfd53eaaa7841.tar.bz2 cbt-2c20a0dddc70a5eee207fb1c588bfd53eaaa7841.zip |
merged most bootstrapping logic into launcher
Diffstat (limited to 'nailgun_launcher')
-rw-r--r-- | nailgun_launcher/CBTUrlClassLoader.java | 31 | ||||
-rw-r--r-- | nailgun_launcher/Dependency.java | 29 | ||||
-rw-r--r-- | nailgun_launcher/NailgunLauncher.java | 162 |
3 files changed, 185 insertions, 37 deletions
diff --git a/nailgun_launcher/CBTUrlClassLoader.java b/nailgun_launcher/CBTUrlClassLoader.java new file mode 100644 index 0000000..72423a0 --- /dev/null +++ b/nailgun_launcher/CBTUrlClassLoader.java @@ -0,0 +1,31 @@ +package cbt; +import java.io.*; +import java.net.*; +import java.util.*; +class CbtURLClassLoader extends URLClassLoader{ + public String toString(){ + return ( + super.toString() + + "(\n " + + Arrays.toString(getURLs()) + + ",\n " + + String.join("\n ",getParent().toString().split("\n")) + + "\n)" + ); + } + void assertExist(URL[] urls){ + for(URL url: urls){ + if(!new File(url.getPath()).exists()){ + throw new AssertionError("File does not exist when trying to create CbtURLClassLoader: "+url); + } + } + } + public CbtURLClassLoader(URL[] urls, ClassLoader parent){ + super(urls, parent); + assertExist(urls); + } + public CbtURLClassLoader(URL[] urls){ + super(urls); + assertExist(urls); + } +}
\ No newline at end of file diff --git a/nailgun_launcher/Dependency.java b/nailgun_launcher/Dependency.java new file mode 100644 index 0000000..93f4785 --- /dev/null +++ b/nailgun_launcher/Dependency.java @@ -0,0 +1,29 @@ +package cbt; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +class EarlyDependency { + + final URL url; + final Path path; + final String hash; + + public EarlyDependency(String folder, String file, String hash) throws MalformedURLException { + this.path = Paths.get(NailgunLauncher.CBT_HOME + "/cache/maven/" + folder + "/" + file + ".jar"); + this.url = new URL("https://repo1.maven.org/maven2/" + folder + "/" + file + ".jar"); + this.hash = hash; + } + + // scala-lang dependency + public static EarlyDependency scala(String scalaModule, String hash) + throws MalformedURLException { + return new EarlyDependency( + "org/scala-lang/scala-" + scalaModule + "/" + NailgunLauncher.SCALA_VERSION, + "scala-" + scalaModule + "-" + NailgunLauncher.SCALA_VERSION, + hash + ); + } + +} diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java index cd9e499..9121797 100644 --- a/nailgun_launcher/NailgunLauncher.java +++ b/nailgun_launcher/NailgunLauncher.java @@ -4,16 +4,15 @@ import java.lang.reflect.*; import java.net.*; import java.nio.*; import java.nio.file.*; +import java.security.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import javax.xml.bind.annotation.adapters.HexBinaryAdapter; /** * 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. - * - * The main method loads the given class from the given class path, calls it's main - * methods passing in the additional arguments. */ public class NailgunLauncher{ @@ -26,30 +25,100 @@ public class NailgunLauncher{ public static SecurityManager defaultSecurityManager = System.getSecurityManager(); + public static String CBT_HOME = System.getenv("CBT_HOME"); + public static String NAILGUN = System.getenv("NAILGUN"); + public static String STAGE1 = CBT_HOME + "/stage1/"; + public static String TARGET = System.getenv("TARGET"); + + public static String SCALA_VERSION = "2.11.8"; + + public static void _assert(Boolean condition, Object msg){ + if(!condition){ + throw new AssertionError("Assertion failed: "+msg); + } + } + public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, - MalformedURLException { - String CBT_HOME = System.getenv("CBT_HOME"); - String SCALA_VERSION = System.getenv("SCALA_VERSION"); - String NAILGUN = System.getenv("NAILGUN"); - String STAGE1 = System.getenv("STAGE1"); - String TARGET = System.getenv("TARGET"); - assert(CBT_HOME != null); - assert(SCALA_VERSION != null); - assert(NAILGUN != null); - assert(STAGE1 != null); - assert(TARGET != null); - - String library = CBT_HOME+"/bootstrap_scala/cache/"+SCALA_VERSION+"/scala-library-"+SCALA_VERSION+".jar"; + MalformedURLException, + IOException, + NoSuchAlgorithmException { + _assert(CBT_HOME != null, CBT_HOME); + _assert(NAILGUN != null, NAILGUN); + _assert(TARGET != null, TARGET); + _assert(STAGE1 != null, STAGE1); + + File f2 = new File(STAGE1); + _assert(f2.listFiles() != null, f2); + long lastCompiled = new File(STAGE1 + TARGET + "/cbt/Stage1.class").lastModified(); + for( File file: f2.listFiles() ){ + if( file.isFile() && file.toString().endsWith(".scala") + && file.lastModified() > lastCompiled ){ + + EarlyDependency[] dependencies = new EarlyDependency[]{ + EarlyDependency.scala("library", "DDD5A8BCED249BEDD86FB4578A39B9FB71480573"), + EarlyDependency.scala("compiler","FE1285C9F7B58954C5EF6D80B59063569C065E9A"), + EarlyDependency.scala("reflect", "B74530DEEBA742AB4F3134DE0C2DA0EDC49CA361"), + new EarlyDependency("org/scala-lang/modules/scala-xml_2.11/1.0.5", "scala-xml_2.11-1.0.5", "77ac9be4033768cf03cc04fbd1fc5e5711de2459") + }; + + ArrayList<String> scalaClassPath = new ArrayList<String>(); + + for (EarlyDependency d: dependencies) { + download( d.url, d.path, d.hash ); + scalaClassPath.add( d.path.toString() ); + } + + File stage1ClassFiles = new File(STAGE1 + TARGET + "/cbt/"); + if( stage1ClassFiles.exists() ){ + for( File f: stage1ClassFiles.listFiles() ){ + if( f.toString().endsWith(".class") ){ + f.delete(); + } + } + } + + new File(STAGE1 + TARGET).mkdirs(); + + String s = File.pathSeparator; + ArrayList<String> scalacArgsList = new ArrayList<String>( + Arrays.asList( + new String[]{ + "-deprecation", "-feature", + "-cp", String.join( s, scalaClassPath.toArray(new String[scalaClassPath.size()])) + s + NAILGUN+TARGET, + "-d", STAGE1+TARGET + } + ) + ); + + for( File f: new File(STAGE1).listFiles() ){ + if( f.isFile() && f.toString().endsWith(".scala") ){ + scalacArgsList.add( f.toString() ); + } + } + + ArrayList<URL> urls = new ArrayList<URL>(); + for( String c: scalaClassPath ){ + urls.add(new URL("file:"+c)); + } + ClassLoader cl = new CbtURLClassLoader( (URL[]) urls.toArray(new URL[urls.size()]) ); + cl.loadClass("scala.tools.nsc.Main") + .getMethod("main", String[].class) + .invoke( null/* _cls.newInstance()*/, (Object) scalacArgsList.toArray(new String[scalacArgsList.size()])); + break; + } + } + + String library = CBT_HOME+"/cache/maven/org/scala-lang/scala-library/"+SCALA_VERSION+"/scala-library-"+SCALA_VERSION+".jar"; if(!classLoaderCacheKeys.containsKey(library)){ Object libraryKey = new Object(); classLoaderCacheKeys.put(library,libraryKey); ClassLoader libraryClassLoader = new CbtURLClassLoader( new URL[]{ new URL("file:"+library) } ); classLoaderCacheValues.put(libraryKey, libraryClassLoader); - String xml = CBT_HOME+"/bootstrap_scala/cache/"+SCALA_VERSION+"/scala-xml_2.11-1.0.5.jar"; + String xml = CBT_HOME+"/cache/maven/org/scala-lang/modules/scala-xml_2.11/1.0.5/scala-xml_2.11-1.0.5.jar"; Object xmlKey = new Object(); classLoaderCacheKeys.put(xml,xmlKey); ClassLoader xmlClassLoader = new CbtURLClassLoader( @@ -72,34 +141,53 @@ public class NailgunLauncher{ return; } - ClassLoader cl = new URLClassLoader( + ClassLoader cl = new CbtURLClassLoader( new URL[]{ new URL("file:"+STAGE1+TARGET) }, classLoaderCacheValues.get( classLoaderCacheKeys.get( NAILGUN+TARGET ) ) ); - cl.loadClass("cbt.Stage1") - .getMethod("main", String[].class, ClassLoader.class) - .invoke( null/* _cls.newInstance()*/, (Object) args, cl); + try{ + cl.loadClass("cbt.Stage1") + .getMethod("main", String[].class, ClassLoader.class) + .invoke( null/* _cls.newInstance()*/, (Object) args, cl); + }catch(ClassNotFoundException e){ + System.err.println(cl); + throw e; + }catch(NoClassDefFoundError e){ + System.err.println(cl); + throw e; + }catch(InvocationTargetException e){ + System.err.println(cl); + throw e; + } } -} -class CbtURLClassLoader extends URLClassLoader{ - public String toString(){ - return ( - super.toString() - + "(\n " - + Arrays.toString(getURLs()) - + ",\n " - + String.join("\n ",getParent().toString().split("\n")) - + "\n)" - ); - } - public CbtURLClassLoader(URL[] urls, ClassLoader parent){ - super(urls, parent); + public static void download(URL urlString, Path target, String sha1) throws IOException, NoSuchAlgorithmException { + final Path unverified = Paths.get(target+".unverified"); + if(!Files.exists(target)) { + new File(target.toString()).getParentFile().mkdirs(); + System.err.println("downloading " + urlString); + System.err.println("to " + target); + final InputStream stream = urlString.openStream(); + Files.copy(stream, unverified, StandardCopyOption.REPLACE_EXISTING); + stream.close(); + final String checksum = sha1(Files.readAllBytes(unverified)); + if(sha1 == null || sha1.toUpperCase().equals(checksum)) { + Files.move(unverified, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + } else { + System.err.println(target + " checksum does not match.\nExpected: |" + sha1 + "|\nFound: |" + checksum + "|"); + System.exit(1); + } + } } - public CbtURLClassLoader(URL[] urls){ - super(urls); + + public static String sha1(byte[] bytes) throws NoSuchAlgorithmException { + final MessageDigest sha1 = MessageDigest.getInstance("SHA1"); + sha1.update(bytes, 0, bytes.length); + return (new HexBinaryAdapter()).marshal(sha1.digest()); } } + + |