aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap_scala/BootstrapScala.java85
-rw-r--r--bootstrap_scala/Dependency.java29
-rwxr-xr-xbootstrap_scala/bootstrap_scala27
-rwxr-xr-xcbt42
-rw-r--r--nailgun_launcher/CBTUrlClassLoader.java31
-rw-r--r--nailgun_launcher/Dependency.java29
-rw-r--r--nailgun_launcher/NailgunLauncher.java162
-rw-r--r--stage1/constants.scala2
-rw-r--r--stage1/paths.scala2
9 files changed, 190 insertions, 219 deletions
diff --git a/bootstrap_scala/BootstrapScala.java b/bootstrap_scala/BootstrapScala.java
deleted file mode 100644
index e2d7a5a..0000000
--- a/bootstrap_scala/BootstrapScala.java
+++ /dev/null
@@ -1,85 +0,0 @@
-import java.io.File;
-import java.io.InputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.Iterator;
-import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
-
-/**
- * This file class allows bootstrapping out of Java into Scala. It downloads the Scala jars for the
- * version number given as the first argument into the directory given as the second argument and
- * returns a classpath String.
- */
-public class BootstrapScala {
-
- public final static Dependency[] dependencies(String target, String scalaVersion) throws MalformedURLException {
- return new Dependency[] {
- Dependency.scala(target, scalaVersion, "library", "DDD5A8BCED249BEDD86FB4578A39B9FB71480573"),
- Dependency.scala(target, scalaVersion, "compiler","FE1285C9F7B58954C5EF6D80B59063569C065E9A"),
- Dependency.scala(target, scalaVersion, "reflect", "B74530DEEBA742AB4F3134DE0C2DA0EDC49CA361"),
- new Dependency(target, "modules/scala-xml_2.11/1.0.5", "scala-xml_2.11-1.0.5", "77ac9be4033768cf03cc04fbd1fc5e5711de2459")
- };
- }
-
- public static void main(String args[]) throws IOException, NoSuchAlgorithmException {
-
- if(args.length < 2){
- System.err.println("Usage: bootstrap_scala <scala version> <download directory>");
- System.exit(1);
- }
-
- Dependency[] ds = dependencies( args[1], args[0] );
- new File(args[1]).mkdirs();
- for (Dependency d: ds) {
- download( d.url, d.path, d.hash );
- }
-
- // Join dep. paths as a classpath
- String classpath = "";
- Iterator<Dependency> depsIter = Arrays.asList(ds).iterator();
- while (depsIter.hasNext()) {
- Dependency dep = depsIter.next();
- classpath += dep.path.toString();
- if (depsIter.hasNext()) {
- classpath += File.pathSeparator;
- }
- }
-
- System.out.println(classpath);
-
- }
-
- 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 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());
- }
-
-}
diff --git a/bootstrap_scala/Dependency.java b/bootstrap_scala/Dependency.java
deleted file mode 100644
index 571047b..0000000
--- a/bootstrap_scala/Dependency.java
+++ /dev/null
@@ -1,29 +0,0 @@
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-class Dependency {
-
- final URL url;
- final Path path;
- final String hash;
-
- public Dependency(String target, String folder, String file, String hash) throws MalformedURLException {
- this.path = Paths.get(target + file + ".jar");
- this.url = new URL("https://repo1.maven.org/maven2/org/scala-lang/" + folder + "/" + file + ".jar");
- this.hash = hash;
- }
-
- // scala-lang dependency
- public static Dependency scala(String target, String scalaVersion, String scalaModule, String hash)
- throws MalformedURLException {
- return new Dependency(
- target,
- "scala-" + scalaModule + "/" + scalaVersion,
- "scala-" + scalaModule + "-" + scalaVersion,
- hash
- );
- }
-
-}
diff --git a/bootstrap_scala/bootstrap_scala b/bootstrap_scala/bootstrap_scala
deleted file mode 100755
index b004c8d..0000000
--- a/bootstrap_scala/bootstrap_scala
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-_DIR=$(dirname $(readlink "$0") 2>/dev/null || dirname "$0" 2>/dev/null )
-DIR=$(dirname $($_DIR/../realpath/realpath.sh $0))
-JAVAC="javac -Xlint:deprecation"
-TARGET=$DIR/target
-CLASSES=$TARGET/classes/
-VERSION=$1
-CACHE=$DIR/cache/$VERSION/
-
-COMPILER_JAR=scala-compiler-$VERSION.jar
-LIBRARY_JAR=scala-library-$VERSION.jar
-REFLECT_JAR=scala-reflect-$VERSION.jar
-XML_JAR=scala-xml_2.11-1.0.5.jar # this is a bit fishy, because it doesn't take version into account
-
-mkdir -p $CLASSES
-
-if [ ! -f $CACHE$COMPILER_JAR ] || [ ! -f $CACHE$LIBRARY_JAR ] || [ ! -f $CACHE$REFLECT_JAR ]\
- || [ ! -f $CACHE$XML_JAR ] || [ $DIR/BootstrapScala.java -nt $CLASSES/BootstrapScala.class ] || [ $DIR/Dependency.java -nt $CLASSES/Dependency.class ]
-then
- echo "Compiling cbt/bootstrap_scala" 1>&2
- $JAVAC -d $CLASSES $DIR/BootstrapScala.java $DIR/Dependency.java
- java -cp $CLASSES BootstrapScala $1 $CACHE
-else
- # for speedup
- echo `for f in $CACHE*; do printf "$f "; done`|tr " " ":"
-fi
diff --git a/cbt b/cbt
index a5feb54..372c145 100755
--- a/cbt
+++ b/cbt
@@ -78,12 +78,9 @@ log "Find out real path. Build realpath if needed." $*
export CBT_HOME=$(dirname $($_DIR/realpath/realpath.sh $0))
-export SCALA_VERSION="2.11.8"
export NAILGUN=$CBT_HOME/nailgun_launcher/
-export STAGE1=$CBT_HOME/stage1/
export TARGET=target/scala-2.11/classes/
mkdir -p $NAILGUN$TARGET
-mkdir -p $STAGE1$TARGET
nailgun_out=$NAILGUN/target/nailgun.stdout.log
nailgun_err=$NAILGUN/target/nailgun.strerr.log
@@ -135,18 +132,6 @@ if [ $use_nailgun -eq 0 ] && [ ! $server_up -eq 0 ]; then
ng-server 127.0.0.1:$NAILGUN_PORT >> $nailgun_out 2>> $nailgun_err &
fi
-log "Downloading Scala jars if necessary..." $*
-export SCALA_CLASSPATH=`$CBT_HOME/bootstrap_scala/bootstrap_scala $SCALA_VERSION`
-if [ ! $? -eq 0 ]; then echo "Problem with bootstrap_scala" 1>&2; exit 1; fi
-
-SCALAC="java -Xmx256M -Xms32M\
- -Xbootclasspath/a:$SCALA_CLASSPATH\
- -Dscala.usejavacp=true\
- -Denv.emacs=\
- scala.tools.nsc.Main\
- -deprecation\
- -feature"
-
stage1 () {
log "Checking for changes in cbt/nailgun_launcher" $*
NAILGUN_INDICATOR=$NAILGUN$TARGET/cbt/NailgunLauncher.class
@@ -172,29 +157,8 @@ stage1 () {
fi
fi
- log "Checking for changes in cbt/stage1" $*
- STAGE1_INDICATOR=$STAGE1$TARGET/cbt/Stage1.class
- changed2=0
- for file in `ls $STAGE1*.scala`; do
- if [ $file -nt $STAGE1_INDICATOR ]; then changed2=1; fi
- done
- compiles2=0
-
- if [ $changed2 -eq 1 ]; then
- rm $STAGE1$TARGET/cbt/*.class 2>/dev/null # defensive delete of potentially broken class files
- echo "Compiling cbt/stage1" 1>&2
- $SCALAC -cp $NAILGUN$TARGET -d $STAGE1$TARGET `ls $STAGE1/*.scala`
- compiles2=$?
- if [ $compiles2 -ne 0 ]; then
- rm $STAGE1$TARGET/cbt/*.class 2>/dev/null # triggers recompilation next time.
- break
- fi
- fi
-
log "run CBT and loop if desired. This allows recompiling CBT itself as part of compile looping." $*
- mainClass=cbt.Stage1
- CP=$STAGE1$TARGET:$SCALA_CLASSPATH
if [ $use_nailgun -eq 1 ]
then
log "Running JVM directly" $*
@@ -221,11 +185,11 @@ stage1 () {
fi
sleep 0.3
done
- log "Running $mainClass via Nailgun." $*
+ log "Running CBT via Nailgun." $*
$NG cbt.NailgunLauncher "$CWD" $*
fi
exitCode=$?
- log "Done running $mainClass." $*
+ log "Done running CBT." $*
}
while true; do
@@ -236,7 +200,7 @@ while true; do
echo "======= Restarting CBT =======" 1>&2
done
-if [ $compiles -ne 0 ] || [ $compiles2 -ne 0 ]; then
+if [ $compiles -ne 0 ]; then
exitCode=1
fi
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());
}
}
+
+
diff --git a/stage1/constants.scala b/stage1/constants.scala
index a14754e..147e10c 100644
--- a/stage1/constants.scala
+++ b/stage1/constants.scala
@@ -1,5 +1,5 @@
package cbt
object constants{
- val scalaVersion = Option(System.getenv("SCALA_VERSION")).get
+ val scalaVersion = NailgunLauncher.SCALA_VERSION
val scalaMajorVersion = scalaVersion.split("\\.").take(2).mkString(".")
}
diff --git a/stage1/paths.scala b/stage1/paths.scala
index 2006ae8..e8e3cc5 100644
--- a/stage1/paths.scala
+++ b/stage1/paths.scala
@@ -6,7 +6,7 @@ object paths{
val userHome: File = new File(Option(System.getProperty("user.home")).get)
val bootstrapScala: File = cbtHome ++ "/bootstrap_scala"
val nailgun: File = new File(Option(System.getenv("NAILGUN")).get)
- val stage1: File = new File(Option(System.getenv("STAGE1")).get)
+ val stage1: File = new File(NailgunLauncher.STAGE1)
val stage2: File = cbtHome ++ "/stage2"
private val target = Option(System.getenv("TARGET")).get.stripSuffix("/")
val stage1Target: File = stage1 ++ ("/" ++ target)