aboutsummaryrefslogblamecommitdiff
path: root/nailgun_launcher/Stage0Lib.java
blob: 456e9d167d23759f665c8defeac51b25809b7420 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                           
                                    

                                        
                                 
                                  

                       
                                                            




                                                         
                                                                                        












                                              
       
      

   
                                                                          




                                                                
                                            
   
 


























                                                                                   
                                                                                              
                                  
                                                            


                

                                                       
                                                       
                     
                                                                     




                                                                                               
                                  



                                                                                             
     

                                         

                                                    
                       




                                                                    
                             


                             

                                      


           
 






                                      
                                                                                                                          
                            
                                  






                                                                                       


                                                                                                                                


     
                                                                        



                                        
                                                                                            



                                                


                                                      
                                          







                                                                                              
                                                                                                  












                                                                               
                                                














                                                                               
                                                                                         




                                                            
                                                                                            


                                                                          
                                                               

                                                                                                            
                                                                                                                             




                       
                                                            

                                                                 
                                                                         

   

                                                                  
                                          
                                                


                  





                                                               





                                                                      
 
package cbt;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.nio.*;
import java.nio.file.*;
import java.security.*;
import java.util.*;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import static java.io.File.pathSeparator;
import static cbt.NailgunLauncher.*;
import java.nio.file.*;
import java.nio.file.attribute.FileTime;
import static java.lang.Math.min;
import cbt.reflect.TrapSystemExit;

public class Stage0Lib{
  public static void _assert(boolean condition, Object msg){
    if(!condition){
      throw new AssertionError("Assertion failed: "+msg);
    }
  }

  public static int runMain(String cls, String[] args, ClassLoader cl) throws Throwable{
    return TrapSystemExit.run(
      new TrapSystemExit<Integer>(){
        @Override
        public Integer run() throws Throwable{
          cl.loadClass(cls)
            .getMethod("main", String[].class)
            .invoke( null, (Object) args);
          return 0;
        }
        @Override
        public Integer wrap(int exitCode){
          return exitCode;
        }
      }
    );
  }

  public static Object get(Object object, String method) throws Throwable{
    return object.getClass().getMethod( method ).invoke(object);
  }

  public static String classpath( String... files ){
    Arrays.sort(files);
    return mkString( pathSeparator, files );
  }

  public static long lastModified( String... files ){
    List<Long> lastModified = new ArrayList<Long>();
    for( String file: files ){
      lastModified.add( new File(file).lastModified() );
    }
    return Collections.max( lastModified );
  }

  public static ClassLoader loadDependency(
    String url,
    String file,
    String hash,
    ClassLoaderCache classLoaderCache,
    ClassLoader parent,
    String... classpathArray
  ) throws Throwable {
    download(new URL(url), Paths.get(file), hash);

    final long lastModified = lastModified( classpathArray );
    final String classpath = classpath( classpathArray );

    if( !classLoaderCache.containsKey( classpath, lastModified ) )
      classLoaderCache.put( classpath, classLoader( file, parent ), lastModified );

    return classLoaderCache.get( classpath, lastModified );
  }

  public static File write(File file, String content, OpenOption... options) throws Throwable{
    file.getParentFile().mkdirs();
    Files.write(file.toPath(), content.getBytes(), options);
    return file;
  }

  public static long compile(
    long lastModified, String classpath, String target,
    EarlyDependencies earlyDeps, List<File> sourceFiles
  ) throws Throwable{
    File statusFile = new File( new File(target) + ".last-success" );
    long lastCompiled = statusFile.lastModified();

    long maxLastModified = lastModified;
    final long start = System.currentTimeMillis(); // <- before recursing, so we catch them all

    for( File file: sourceFiles ){
      long l = file.lastModified();
      if( l > maxLastModified ) maxLastModified = l;
      // performance optimization because we'll recompile and don't need to check other files
      if( l > lastCompiled ) break;
    }

    if( maxLastModified > lastCompiled ){
      List<String> zincArgs = new ArrayList<String>(
        Arrays.asList(
          new String[]{
            "-scala-compiler", earlyDeps.scalaCompiler_File,
            "-scala-library", earlyDeps.scalaLibrary_File,
            "-scala-extra", earlyDeps.scalaReflect_File,
            "-sbt-interface", earlyDeps.sbtInterface_File,
            "-compiler-interface", earlyDeps.compilerInterface_File,
            "-cp", classpath,
            "-d", target,
            "-S-deprecation",
            "-S-feature",
            "-S-unchecked",
            "-S-language:existentials"
          }
        )
      );

      for( File f: sourceFiles ){
        zincArgs.add(f.toString());
      }

      PrintStream oldOut = System.out;
      try{
        System.setOut(System.err);
        int exitCode = runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc );
        if( exitCode == 0 ){
          write( statusFile, "" );
          Files.setLastModifiedTime( statusFile.toPath(), FileTime.fromMillis(start) );
        } else {
          System.exit( exitCode );
        }
      } finally {
        System.setOut(oldOut);
      }
      return statusFile.lastModified(); // can't just use `start` here as system time precision is less than milliseconds on OSX
    } else {
      return lastCompiled;
    }
  }

  public static ClassLoader classLoader( String file ) throws Throwable{
    return new CbtURLClassLoader(
      new URL[]{ new URL("file:"+file) }
    );
  }
  public static ClassLoader classLoader( String file, ClassLoader parent ) throws Throwable{
    return new CbtURLClassLoader(
      new URL[]{ new URL("file:"+file) }, parent
    );
  }

  private static String getVarFromEnv(String envKey) {
    String value = System.getenv(envKey);
    if(value == null || value.isEmpty()) {
      value = System.getenv(envKey.toUpperCase());
    }
    return value;
  }

  private static void setProxyfromPropOrEnv(String envKey, String propKeyH, String propKeyP) {
    String proxyHost = System.getProperty(propKeyH);
    String proxyPort = System.getProperty(propKeyP);
    if((proxyHost == null || proxyHost.isEmpty()) && (proxyPort == null || proxyPort.isEmpty())) {
      String envVar = getVarFromEnv(envKey);
      if(envVar != null && !envVar.isEmpty()) {
        String[] proxy = envVar.replaceFirst("^https?://", "").split(":", 2);
        System.setProperty(propKeyH, proxy[0]);
        System.setProperty(propKeyP, proxy[1]);
      }
    }
  }

  public static void installProxySettings() throws URISyntaxException {
    setProxyfromPropOrEnv("http_proxy", "http.proxyHost", "http.proxyPort");
    setProxyfromPropOrEnv("https_proxy", "https.proxyHost", "https.proxyPort");
    String nonHosts = System.getProperty("http.nonProxyHosts");
    if(nonHosts == null || nonHosts.isEmpty()) {
      String envVar = getVarFromEnv("no_proxy");
      if(envVar != null && !envVar.isEmpty()) {
        System.setProperty("http.nonProxyHosts", envVar.replaceAll(",","|"));
      }
    }
  }

  private static final ProxySelector ps = ProxySelector.getDefault();

  public static HttpURLConnection openConnectionConsideringProxy(URL urlString)
      throws IOException, URISyntaxException {
    java.net.Proxy proxy = ps.select(urlString.toURI()).get(0);
    return (HttpURLConnection) urlString.openConnection(proxy);
  }

  public static void download(URL urlString, Path target, String sha1) throws Throwable {
    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 = openConnectionConsideringProxy(urlString).getInputStream();
      Files.copy(stream, unverified, StandardCopyOption.REPLACE_EXISTING);
      stream.close();
      final String checksum = sha1(Files.readAllBytes(unverified));
      if(sha1 == null || sha1.toLowerCase().equals(checksum)) {
        Files.move(unverified, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
      } else {
        System.err.println(unverified + " checksum does not match.\nExpected: |" + sha1 + "|\nFound:    |" + checksum + "|");
        System.exit(1);
      }
    }
  }

  public static String sha1(byte[] bytes) throws Throwable {
    final MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    sha1.update(bytes, 0, bytes.length);
    return (new HexBinaryAdapter()).marshal(sha1.digest()).toLowerCase();
  }

  public static String mkString(String separator, Object[] parts){
    String result = parts[0].toString();
    for(int i = 1; i < parts.length; i++){
      result += separator + parts[i].toString();
    }
    return result;
  }

  public static String[] append( String[] array, String item ){
    String[] copy = Arrays.copyOf(array, array.length + 1);
    copy[array.length] = item;
    return copy;
  }

  public static String[] concat( String[] left, String[] right ){
    String[] result = Arrays.copyOf(left, left.length + right.length);
    System.arraycopy(right, 0, result, left.length, right.length);
    return result;
  }
}