mirror of https://github.com/x64dbg/deps
				
				
				
			Add files via upload
This commit is contained in:
		
							parent
							
								
									275eda1d13
								
							
						
					
					
						commit
						7dc45d2620
					
				| 
						 | 
				
			
			@ -0,0 +1,955 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedOutputStream;
 | 
			
		||||
import java.io.Closeable;
 | 
			
		||||
import java.io.EOFException;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileFilter;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.math.BigInteger;
 | 
			
		||||
import java.net.Authenticator;
 | 
			
		||||
import java.net.HttpURLConnection;
 | 
			
		||||
import java.net.PasswordAuthentication;
 | 
			
		||||
import java.net.SocketException;
 | 
			
		||||
import java.net.SocketTimeoutException;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.net.URLConnection;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.security.MessageDigest;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
import java.util.zip.ZipEntry;
 | 
			
		||||
import java.util.zip.ZipFile;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.ceylon.common.Constants;
 | 
			
		||||
import org.eclipse.ceylon.common.Versions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the earliest bootstrap class for the Ceylon tool chain.
 | 
			
		||||
 * It does nothing more than trying to locate the system repository
 | 
			
		||||
 * and load an appropriate ceylon.bootstrap module.
 | 
			
		||||
 * Appropriate in this case means it will try to find the version this
 | 
			
		||||
 * class was compiled with (see <code>Versions.CEYLON_VERSION_NUMBER</code>)
 | 
			
		||||
 * or the version specified by the <code>CEYLON_VERSION</code> environment
 | 
			
		||||
 * variable.
 | 
			
		||||
 * After it locates the module it will pass the execution on to the
 | 
			
		||||
 * <code>Launcher.main()</code> it contains.
 | 
			
		||||
 * 
 | 
			
		||||
 * IMPORTANT This class should contain as little logic as possible and
 | 
			
		||||
 * delegate as soon as it can to the <code>Launcher</code> in the
 | 
			
		||||
 * ceylon.bootstrap module. This way we can maintain backward and forward
 | 
			
		||||
 * compatibility as much as possible.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Tako Schotanus
 | 
			
		||||
 */
 | 
			
		||||
public class Bootstrap {
 | 
			
		||||
 | 
			
		||||
    public static final String CEYLON_DOWNLOAD_BASE_URL = "https://ceylon-lang.org/download/dist/";
 | 
			
		||||
    
 | 
			
		||||
    public static final String FILE_BOOTSTRAP_PROPERTIES = "ceylon-bootstrap.properties";
 | 
			
		||||
    public static final String FILE_BOOTSTRAP_JAR = "ceylon-bootstrap.jar";
 | 
			
		||||
    public static final String FILE_BS_ORIGIN = "BS_ORIGIN";
 | 
			
		||||
    
 | 
			
		||||
    public static final String KEY_SHA256SUM = "sha256sum";
 | 
			
		||||
    public static final String KEY_INSTALLATION = "installation";
 | 
			
		||||
    public static final String KEY_DISTRIBUTION = "distribution";
 | 
			
		||||
 | 
			
		||||
    private static final String FOLDER_DISTS = "dists";
 | 
			
		||||
    
 | 
			
		||||
    private static final int DOWNLOAD_TIMEOUT_READ = 30000;
 | 
			
		||||
    private static final int DOWNLOAD_TIMEOUT_CONNECT = 15000;
 | 
			
		||||
    private static final int DOWNLOAD_BUFFER_SIZE = 4096;
 | 
			
		||||
 | 
			
		||||
    private static final String ENV_CEYLON_BOOTSTRAP_DISTS = "CEYLON_BOOTSTRAP_DISTS";
 | 
			
		||||
    private static final String ENV_CEYLON_BOOTSTRAP_PROPS = "CEYLON_BOOTSTRAP_PROPERTIES";
 | 
			
		||||
    
 | 
			
		||||
    private static final String PROP_CEYLON_BOOTSTRAP_DISTS = "ceylon.bootstrap.dists";
 | 
			
		||||
    private static final String PROP_CEYLON_BOOTSTRAP_PROPS = "ceylon.bootstrap.properties";
 | 
			
		||||
 | 
			
		||||
    private static final String VERSION_BOOTSTRAP_NAME = "CeylonBootstrap";
 | 
			
		||||
    private static final String VERSION_BOOTSTRAP_NUMBER = Versions.CEYLON_VERSION;
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws Throwable {
 | 
			
		||||
        // we don't need to clean up the class loader when run from main because the JVM will either exit, or
 | 
			
		||||
        // keep running with daemon threads in which case it will keep needing this classloader open 
 | 
			
		||||
        int exit = run(args);
 | 
			
		||||
        // WARNING: NEVER CALL EXIT IF WE STILL HAVE DAEMON THREADS RUNNING AND WE'VE NO REASON TO EXIT WITH A NON-ZERO CODE
 | 
			
		||||
        if (exit != 0) {
 | 
			
		||||
            System.exit(exit);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int run(String... args) throws Throwable {
 | 
			
		||||
        return new Bootstrap().runInternal(args);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int runInternal(String... args) throws Throwable {
 | 
			
		||||
        boolean canRetry = false;
 | 
			
		||||
        String ceylonVersion;
 | 
			
		||||
        if (isDistBootstrap()) {
 | 
			
		||||
            // Load configuration
 | 
			
		||||
            Config cfg = loadBootstrapConfig();
 | 
			
		||||
            setupDistHome(cfg);
 | 
			
		||||
            ceylonVersion = determineDistVersion();
 | 
			
		||||
        } else if (distArgument(args) != null) {
 | 
			
		||||
            String dist = distArgument(args);
 | 
			
		||||
            args = stripDistArgument(args);
 | 
			
		||||
            Config cfg = createDistributionConfig(dist);
 | 
			
		||||
            setupDistHome(cfg);
 | 
			
		||||
            ceylonVersion = determineDistVersion();
 | 
			
		||||
        } else {
 | 
			
		||||
            ceylonVersion = LauncherUtil.determineSystemVersion();
 | 
			
		||||
            //canRetry = true; // Disabled for now, enable if we want automatic fall-back to the current version
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            if (!canRetry || Versions.CEYLON_VERSION_NUMBER.equals(ceylonVersion)) {
 | 
			
		||||
                // Using current Ceylon version, or no retries allowed
 | 
			
		||||
                return runVersion(ceylonVersion, args);
 | 
			
		||||
            } else {
 | 
			
		||||
                // Using Ceylon version different from current, if the first
 | 
			
		||||
                // run fails we'll retry with the current one
 | 
			
		||||
                try {
 | 
			
		||||
                    return runVersion(ceylonVersion, args);
 | 
			
		||||
                } catch (ClassNotFoundException ex) {
 | 
			
		||||
                    System.err.println("Fatal: Ceylon distribution could not be found for version: " + ceylonVersion + ", using default");
 | 
			
		||||
                    ceylonVersion = Versions.CEYLON_VERSION_NUMBER;
 | 
			
		||||
                    System.setProperty(Constants.PROP_CEYLON_SYSTEM_VERSION, ceylonVersion);
 | 
			
		||||
                    return runVersion(Versions.CEYLON_VERSION_NUMBER, args);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (ClassNotFoundException ex) {
 | 
			
		||||
            System.err.println("Fatal: Ceylon distribution could not be found for version: " + ceylonVersion);
 | 
			
		||||
            return -1;
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            System.err.println("Fatal: Ceylon command could not be executed");
 | 
			
		||||
            if (e.getCause() != null) {
 | 
			
		||||
                throw e;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!(e instanceof RuntimeException) || e.getMessage() == null) {
 | 
			
		||||
                    System.err.println("   --> " + e.toString());
 | 
			
		||||
                } else {
 | 
			
		||||
                    System.err.println("   --> " + e.getMessage());
 | 
			
		||||
                }
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private int runVersion(String ceylonVersion, String... args) throws Throwable {
 | 
			
		||||
        CeylonClassLoader cl = null;
 | 
			
		||||
        try {
 | 
			
		||||
            Integer result = -1;
 | 
			
		||||
            Method runMethod = null;
 | 
			
		||||
            File module = CeylonClassLoader.getRepoJar("ceylon.bootstrap", ceylonVersion);
 | 
			
		||||
            if (!module.exists()) {
 | 
			
		||||
                File homeLib = new File(System.getProperty(Constants.PROP_CEYLON_HOME_DIR), "lib");
 | 
			
		||||
                module = new File(homeLib, FILE_BOOTSTRAP_JAR);
 | 
			
		||||
            }
 | 
			
		||||
            cl = CeylonClassLoader.newInstance(Arrays.asList(module));
 | 
			
		||||
            Class<?> launcherClass = cl.loadClass("org.eclipse.ceylon.launcher.Launcher");
 | 
			
		||||
            runMethod = launcherClass.getMethod("run", String[].class);
 | 
			
		||||
            try {
 | 
			
		||||
                result = (Integer)runMethod.invoke(null, (Object)args);
 | 
			
		||||
            } catch (InvocationTargetException e) {
 | 
			
		||||
                throw e.getCause();
 | 
			
		||||
            }
 | 
			
		||||
            return result.intValue();
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (cl != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    cl.close();
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    // Ignore
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected boolean isDistBootstrap() throws URISyntaxException {
 | 
			
		||||
        File propsFile = getPropertiesFile();
 | 
			
		||||
        return propsFile.exists();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static String distArgument(String[] args) {
 | 
			
		||||
        for (String arg : args) {
 | 
			
		||||
            if (!arg.startsWith("-")) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if (arg.startsWith("--distribution=") && arg.length() > 15) {
 | 
			
		||||
                return arg.substring(15);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String[] stripDistArgument(String[] args) {
 | 
			
		||||
        ArrayList<String> lst = new ArrayList<String>();
 | 
			
		||||
        for (String arg : args) {
 | 
			
		||||
            if (!arg.startsWith("--distribution=") || arg.length() <= 15) {
 | 
			
		||||
                lst.add(arg);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        String[] buf = new String[lst.size()];
 | 
			
		||||
        return lst.toArray(buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void setupDistHome(Config cfg) throws Exception {
 | 
			
		||||
        // If hash doesn't exist in dists folder we must download & install
 | 
			
		||||
        if (!cfg.distributionDir.exists()) {
 | 
			
		||||
            install(cfg);
 | 
			
		||||
            if (!cfg.distributionDir.exists()) {
 | 
			
		||||
                throw new RuntimeException("Unable to install distribution");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Set the correct home folder
 | 
			
		||||
        System.setProperty(Constants.PROP_CEYLON_HOME_DIR, cfg.distributionDir.getAbsolutePath());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void install(Config cfg) throws Exception {
 | 
			
		||||
        File tmpFile = null;
 | 
			
		||||
        File tmpFolder = null;
 | 
			
		||||
        try {
 | 
			
		||||
            // Check if the distribution URI refers to a remote or a local file
 | 
			
		||||
            File zipFile;
 | 
			
		||||
            if (cfg.distribution.getScheme() != null) {
 | 
			
		||||
                // Set up a download progress monitor if we have a console
 | 
			
		||||
                ProgressMonitor monitor = null;
 | 
			
		||||
                if (System.console() != null) {
 | 
			
		||||
                    monitor = new ProgressMonitor() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void update(long read, long size) {
 | 
			
		||||
                            String progress;
 | 
			
		||||
                            if (size == -1) {
 | 
			
		||||
                                progress = String.valueOf(read / 1024L) + "K";
 | 
			
		||||
                            } else {
 | 
			
		||||
                                progress = String.valueOf(read * 100 / size) + "%";
 | 
			
		||||
                            }
 | 
			
		||||
                            System.out.print("Downloading Ceylon... " + progress + "\r");
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                // Start download of URL to temp file
 | 
			
		||||
                tmpFile = zipFile = File.createTempFile("ceylon-bootstrap-dist-", ".part");
 | 
			
		||||
                setupProxyAuthentication();
 | 
			
		||||
                download(cfg.distribution, zipFile, monitor);
 | 
			
		||||
            } else {
 | 
			
		||||
                // It's a local file, no need to download
 | 
			
		||||
                zipFile = new File(cfg.properties.getParentFile(), cfg.distribution.getPath()).getAbsoluteFile();
 | 
			
		||||
            }
 | 
			
		||||
            // Verify zip file if we have a sha sum
 | 
			
		||||
            if (cfg.sha256sum != null) {
 | 
			
		||||
                String sum = calculateSha256Sum(zipFile);
 | 
			
		||||
                if (!sum.equals(cfg.sha256sum)) {
 | 
			
		||||
                    throw new RuntimeException("Error verifying Ceylon distribution archive: SHA sums do not match");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Unzip file to temp folder in dists folder
 | 
			
		||||
            mkdirs(cfg.resolvedInstallation);
 | 
			
		||||
            tmpFolder = Files.createTempDirectory(cfg.resolvedInstallation.toPath(), "ceylon-bootstrap-dist-").toFile();
 | 
			
		||||
            extractArchive(zipFile, tmpFolder);
 | 
			
		||||
            validateDistribution(cfg, tmpFolder);
 | 
			
		||||
            writeDistributionInfo(cfg, tmpFolder);
 | 
			
		||||
            // Rename temp folder to hash
 | 
			
		||||
            tmpFolder.renameTo(cfg.distributionDir);
 | 
			
		||||
            if (System.console() != null) {
 | 
			
		||||
                // Clearing the download progress text on the console
 | 
			
		||||
                System.out.print("                              \r");
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            // Delete temp file and folder
 | 
			
		||||
            if (tmpFile != null) {
 | 
			
		||||
                delete(tmpFile);
 | 
			
		||||
            }
 | 
			
		||||
            if (tmpFolder != null) {
 | 
			
		||||
                delete(tmpFolder);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void validateDistribution(Config cfg, File tmpFolder) {
 | 
			
		||||
        File binDir = new File(tmpFolder, Constants.CEYLON_BIN_DIR);
 | 
			
		||||
        File libDir = new File(tmpFolder, "lib");
 | 
			
		||||
        File repoDir = new File(tmpFolder, "repo");
 | 
			
		||||
        boolean valid = binDir.exists() && libDir.exists() && repoDir.exists();
 | 
			
		||||
        if (!valid) {
 | 
			
		||||
            throw new RuntimeException("Not a valid Ceylon distribution archive: " + cfg.distribution);
 | 
			
		||||
        }
 | 
			
		||||
        File bootstrapLibJar = new File(libDir, FILE_BOOTSTRAP_JAR);
 | 
			
		||||
        if (!bootstrapLibJar.exists()) {
 | 
			
		||||
            throw new RuntimeException("Ceylon distribution archive is too old and not supported: " + cfg.distribution);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void writeDistributionInfo(Config cfg, File tmpFolder) throws IOException {
 | 
			
		||||
        writeFile(new File(tmpFolder, FILE_BS_ORIGIN), cfg.distribution.toString() + "\n");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void writeFile(File file, String contents) throws IOException {
 | 
			
		||||
        FileOutputStream output = null;
 | 
			
		||||
        try {
 | 
			
		||||
            output = new FileOutputStream(file);
 | 
			
		||||
            output.write(contents.getBytes());
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (output != null) {
 | 
			
		||||
                output.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static File getPropertiesFile() throws URISyntaxException {
 | 
			
		||||
        String cbp;
 | 
			
		||||
        if ((cbp  = System.getProperty(PROP_CEYLON_BOOTSTRAP_PROPS)) != null) {
 | 
			
		||||
            return new File(cbp);
 | 
			
		||||
        } else if ((cbp  = System.getenv(ENV_CEYLON_BOOTSTRAP_PROPS)) != null) {
 | 
			
		||||
            return new File(cbp);
 | 
			
		||||
        } else {
 | 
			
		||||
            File jar = LauncherUtil.determineRuntimeJar();
 | 
			
		||||
            return new File(jar.getParentFile(), FILE_BOOTSTRAP_PROPERTIES);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static Properties loadBootstrapProperties() throws Exception {
 | 
			
		||||
        File propsFile = getPropertiesFile();
 | 
			
		||||
        FileInputStream fileInput = null;
 | 
			
		||||
        try {
 | 
			
		||||
            fileInput = new FileInputStream(propsFile);
 | 
			
		||||
            Properties properties = new Properties();
 | 
			
		||||
            properties.load(fileInput);
 | 
			
		||||
            return properties;
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (fileInput != null) {
 | 
			
		||||
                fileInput.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected static class Config {
 | 
			
		||||
        public Config () {}
 | 
			
		||||
        public File properties;
 | 
			
		||||
        public URI distribution;
 | 
			
		||||
        public File installation;
 | 
			
		||||
        public File resolvedInstallation;
 | 
			
		||||
        public File distributionDir;
 | 
			
		||||
        public String hash;
 | 
			
		||||
        public String sha256sum;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected Config loadBootstrapConfig() throws Exception {
 | 
			
		||||
        Properties properties = loadBootstrapProperties();
 | 
			
		||||
        Config cfg = new Config();
 | 
			
		||||
        
 | 
			
		||||
        cfg.properties = getPropertiesFile();
 | 
			
		||||
        
 | 
			
		||||
        // Obtain dist download URL
 | 
			
		||||
        if (!properties.containsKey(KEY_DISTRIBUTION)) {
 | 
			
		||||
            throw new RuntimeException("Error in bootstrap properties file: missing 'distribution'");
 | 
			
		||||
        }
 | 
			
		||||
        cfg.distribution = new URI(properties.getProperty(KEY_DISTRIBUTION));
 | 
			
		||||
 | 
			
		||||
        // See if the distribution should be installed in some other place than the default
 | 
			
		||||
        if (properties.containsKey(KEY_INSTALLATION)) {
 | 
			
		||||
            // Get the installation path
 | 
			
		||||
            String installString = properties.getProperty(KEY_INSTALLATION);
 | 
			
		||||
            // Do some simple variable expansion
 | 
			
		||||
            installString = installString
 | 
			
		||||
                    .replaceAll("^~", System.getProperty("user.home"))
 | 
			
		||||
                    .replace("${user.home}", System.getProperty("user.home"))
 | 
			
		||||
                    .replace("${ceylon.user.dir}", getUserDir().getAbsolutePath());
 | 
			
		||||
            cfg.installation = new File(installString);
 | 
			
		||||
            cfg.resolvedInstallation = cfg.properties.getParentFile().toPath().resolve(cfg.installation.toPath()).toFile().getAbsoluteFile();
 | 
			
		||||
        } else {
 | 
			
		||||
            File distsDir;
 | 
			
		||||
            String distsDirStr;
 | 
			
		||||
            if ((distsDirStr = System.getProperty(PROP_CEYLON_BOOTSTRAP_DISTS)) != null) {
 | 
			
		||||
                distsDir = new File(distsDirStr);
 | 
			
		||||
            } else if ((distsDirStr = System.getenv(ENV_CEYLON_BOOTSTRAP_DISTS)) != null) {
 | 
			
		||||
                distsDir = new File(distsDirStr);
 | 
			
		||||
            } else {
 | 
			
		||||
                distsDir = new File(getUserDir(), FOLDER_DISTS);
 | 
			
		||||
            }
 | 
			
		||||
            cfg.resolvedInstallation = distsDir;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If the properties contain a sha256sum store it for later
 | 
			
		||||
        cfg.sha256sum = properties.getProperty(KEY_SHA256SUM);
 | 
			
		||||
 | 
			
		||||
        return updateConfig(cfg);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected Config createDistributionConfig(String dist) throws URISyntaxException {
 | 
			
		||||
        Config cfg = new Config();
 | 
			
		||||
        cfg.distribution = getDistributionUri(dist);
 | 
			
		||||
        return updateConfig(cfg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected URI getDistributionUri(String dist) throws URISyntaxException {
 | 
			
		||||
        URI uri = new URI(dist);
 | 
			
		||||
        if (uri.getScheme() != null) {
 | 
			
		||||
            return uri;
 | 
			
		||||
        } else {
 | 
			
		||||
            return new URI(CEYLON_DOWNLOAD_BASE_URL + dist.replace('.', '_'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static Config updateConfig(Config cfg) {
 | 
			
		||||
        // Hash the URI, it will be our distribution's folder name
 | 
			
		||||
        cfg.hash = hash(cfg.distribution.toString());
 | 
			
		||||
        
 | 
			
		||||
        // Make sure resolvedInstallation points to a proper installation folder
 | 
			
		||||
        if (cfg.installation != null) {
 | 
			
		||||
            cfg.resolvedInstallation = cfg.properties.getParentFile().toPath().resolve(cfg.installation.toPath()).toFile().getAbsoluteFile();
 | 
			
		||||
        } else {
 | 
			
		||||
            cfg.resolvedInstallation = new File(getUserDir(), FOLDER_DISTS);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // The actual installation directory for the distribution
 | 
			
		||||
        cfg.distributionDir = new File(cfg.resolvedInstallation, cfg.hash);
 | 
			
		||||
        
 | 
			
		||||
        return cfg;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static File mkdirs(File dir) {
 | 
			
		||||
        if (!dir.exists() && !dir.mkdirs()) {
 | 
			
		||||
            throw new RuntimeException("Unable to create destination directory: " + dir);
 | 
			
		||||
        }
 | 
			
		||||
        return dir;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void delete(File f) {
 | 
			
		||||
        if (!delete_(f)) {
 | 
			
		||||
            // As a last resort
 | 
			
		||||
            f.deleteOnExit();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static boolean delete_(File f) {
 | 
			
		||||
        boolean ok = true;
 | 
			
		||||
        if (f.exists()) {
 | 
			
		||||
            if (f.isDirectory()) {
 | 
			
		||||
                for (File c : f.listFiles()) {
 | 
			
		||||
                    ok = ok && delete_(c);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            try {
 | 
			
		||||
                boolean deleted = f.delete();
 | 
			
		||||
                ok = ok && deleted;
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                ok = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ok;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static File getDefaultUserDir() {
 | 
			
		||||
        String userHome = System.getProperty("user.home");
 | 
			
		||||
        return new File(userHome, ".ceylon");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static File getUserDir() {
 | 
			
		||||
        String ceylonUserDir = System.getProperty(Constants.PROP_CEYLON_USER_DIR);
 | 
			
		||||
        if (ceylonUserDir != null) {
 | 
			
		||||
            return new File(ceylonUserDir);
 | 
			
		||||
        } else {
 | 
			
		||||
            return getDefaultUserDir();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void extractArchive(File zip, File dir) throws IOException {
 | 
			
		||||
        if (dir.exists()) {
 | 
			
		||||
            if (!dir.isDirectory()) {
 | 
			
		||||
                throw new RuntimeException("Error extracting archive: destination not a directory: " + dir);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            mkdirs(dir);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ZipFile zf = null;
 | 
			
		||||
        try {
 | 
			
		||||
            zf = new ZipFile(zip);
 | 
			
		||||
            Enumeration<? extends ZipEntry> entries = zf.entries();
 | 
			
		||||
            while (entries.hasMoreElements()) {
 | 
			
		||||
                ZipEntry entry = entries.nextElement();
 | 
			
		||||
                String entryName = stripRoot(entry.getName());
 | 
			
		||||
                try {
 | 
			
		||||
                    if (entryName.isEmpty()) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    File out = new File(dir, entryName);
 | 
			
		||||
                    if (entry.isDirectory()) {
 | 
			
		||||
                        mkdirs(out);
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    mkdirs(out.getParentFile());
 | 
			
		||||
                    InputStream zipIn = null;
 | 
			
		||||
                    try {
 | 
			
		||||
                        zipIn = zf.getInputStream(entry);
 | 
			
		||||
                        BufferedOutputStream fileOut = null;
 | 
			
		||||
                        try {
 | 
			
		||||
                            fileOut = new BufferedOutputStream(new FileOutputStream(out));
 | 
			
		||||
                            copyStream(zipIn, fileOut, false, false);
 | 
			
		||||
                        } finally {
 | 
			
		||||
                            if (fileOut != null) {
 | 
			
		||||
                                fileOut.close();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } finally {
 | 
			
		||||
                        if (zipIn != null) {
 | 
			
		||||
                            zipIn.close();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    throw new RuntimeException("Error extracting archive", e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (zf != null) {
 | 
			
		||||
                zf.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static String stripRoot(String name) {
 | 
			
		||||
        int p = name.indexOf('/');
 | 
			
		||||
        if (p > 0) {
 | 
			
		||||
            name = name.substring(p + 1);
 | 
			
		||||
        }
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void copyStream(InputStream in, OutputStream out, boolean closeIn, boolean closeOut) throws IOException {
 | 
			
		||||
        try {
 | 
			
		||||
            copyStreamNoClose(in, out);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (closeIn) {
 | 
			
		||||
                safeClose(in);
 | 
			
		||||
            }
 | 
			
		||||
            if (closeOut) {
 | 
			
		||||
                safeClose(out);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void copyStreamNoClose(InputStream in, OutputStream out) throws IOException {
 | 
			
		||||
        final byte[] bytes = new byte[8192];
 | 
			
		||||
        int cnt;
 | 
			
		||||
        while ((cnt = in.read(bytes)) != -1) {
 | 
			
		||||
            out.write(bytes, 0, cnt);
 | 
			
		||||
        }
 | 
			
		||||
        out.flush();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void safeClose(Closeable c) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (c != null) {
 | 
			
		||||
                c.close();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException ignored) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This method computes a hash of the provided {@code string}.
 | 
			
		||||
     * Copied from Gradle's PathAssembler
 | 
			
		||||
     */
 | 
			
		||||
    private static String hash(String string) {
 | 
			
		||||
        try {
 | 
			
		||||
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
 | 
			
		||||
            byte[] bytes = string.getBytes();
 | 
			
		||||
            messageDigest.update(bytes);
 | 
			
		||||
            return new BigInteger(1, messageDigest.digest()).toString(36);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw new RuntimeException("Error creating hash", e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This method calculates the SHA256 sum of the provided {@code file}
 | 
			
		||||
     * Copied from Gradle's Install
 | 
			
		||||
     */
 | 
			
		||||
    private static String calculateSha256Sum(File file) throws Exception {
 | 
			
		||||
        MessageDigest md = MessageDigest.getInstance("SHA-256");
 | 
			
		||||
        InputStream fis = null;
 | 
			
		||||
        try {
 | 
			
		||||
            fis = new FileInputStream(file);
 | 
			
		||||
            int n = 0;
 | 
			
		||||
            byte[] buffer = new byte[4096];
 | 
			
		||||
            while (n != -1) {
 | 
			
		||||
                n = fis.read(buffer);
 | 
			
		||||
                if (n > 0) {
 | 
			
		||||
                    md.update(buffer, 0, n);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            byte byteData[] = md.digest();
 | 
			
		||||
    
 | 
			
		||||
            StringBuffer hexString = new StringBuffer();
 | 
			
		||||
            for (int i=0; i < byteData.length; i++) {
 | 
			
		||||
                String hex=Integer.toHexString(0xff & byteData[i]);
 | 
			
		||||
                if (hex.length() == 1) {
 | 
			
		||||
                    hexString.append('0');
 | 
			
		||||
                }
 | 
			
		||||
                hexString.append(hex);
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            return hexString.toString();
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (fis != null) {
 | 
			
		||||
                fis.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static interface ProgressMonitor {
 | 
			
		||||
        void update(long read, long size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected int getReadTimeout() {
 | 
			
		||||
        return DOWNLOAD_TIMEOUT_READ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected int getConnectTimeout() {
 | 
			
		||||
        return DOWNLOAD_TIMEOUT_CONNECT;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * A {@link SizedInputStream} that can reconnect some number f times
 | 
			
		||||
     */
 | 
			
		||||
    class RetryingSizedInputStream {
 | 
			
		||||
        
 | 
			
		||||
        private final URL url;
 | 
			
		||||
        /** 
 | 
			
		||||
         * Whether range requests should be made when 
 | 
			
		||||
         * the {@link ReconnectingInputStream} has to reconnect.
 | 
			
		||||
         */
 | 
			
		||||
        private boolean rangeRequests;
 | 
			
		||||
        /** The number of attempts to download the resource */
 | 
			
		||||
        /** The total number of attempts (including the initial one) */
 | 
			
		||||
        private final int attempts = 3;
 | 
			
		||||
        private int reattemptsLeft = attempts-1;
 | 
			
		||||
        /**
 | 
			
		||||
         * For selected exceptions returns normally if there are 
 | 
			
		||||
         * attempts left, otherwise rethrows the given exception. 
 | 
			
		||||
         */
 | 
			
		||||
        private void giveup(URL url, IOException e) throws IOException{
 | 
			
		||||
            if (e instanceof SocketTimeoutException
 | 
			
		||||
                    || e instanceof SocketException
 | 
			
		||||
                    || e instanceof EOFException) {
 | 
			
		||||
                if (reattemptsLeft-- > 0) {
 | 
			
		||||
                    //log.debug("Retry download of "+ url + " after " + e + " (" + getReattemptsLeft() + " reattempts left)");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (e instanceof SocketTimeoutException) {
 | 
			
		||||
                // Include url in exception message
 | 
			
		||||
                SocketTimeoutException newException = new SocketTimeoutException("Timed out downloading "+url);
 | 
			
		||||
                newException.initCause(e);
 | 
			
		||||
                e = newException;
 | 
			
		||||
            }
 | 
			
		||||
            //log.debug("Giving up request to " + url + " (after "+ getAttemptsMade() + " attempts) due to: " + e );
 | 
			
		||||
            throw e;
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        /** The <em>current</em> stream: Gets mutated when {@link ReconnectingInputStream} reconnects */
 | 
			
		||||
        
 | 
			
		||||
        private HttpURLConnection connection = null;
 | 
			
		||||
        private InputStream stream = null;
 | 
			
		||||
        long bytesRead = 0;
 | 
			
		||||
        private final ReconnectingInputStream reconnectingStream;
 | 
			
		||||
        private final long contentLength;
 | 
			
		||||
        
 | 
			
		||||
        public RetryingSizedInputStream(URL url) throws IOException {
 | 
			
		||||
            this.url = url;
 | 
			
		||||
            long length = 0;
 | 
			
		||||
            connecting: while (true) {
 | 
			
		||||
                try{
 | 
			
		||||
                    connection = makeConnection(url, -1);
 | 
			
		||||
                    int code = connection.getResponseCode();
 | 
			
		||||
                    if (code != -1 && code != 200) {
 | 
			
		||||
                        //log.info("Got " + code + " for url: " + url);
 | 
			
		||||
                        RuntimeException notGettable = new RuntimeException("Connection error: " + code);
 | 
			
		||||
                        cleanUpStreams(notGettable);
 | 
			
		||||
                        throw notGettable;
 | 
			
		||||
                    }
 | 
			
		||||
                    String acceptRange = connection.getHeaderField("Accept-Range");
 | 
			
		||||
                    rangeRequests = acceptRange == null || !acceptRange.equalsIgnoreCase("none");
 | 
			
		||||
                    //debug("Connection: "+connection.getHeaderField("Connection"));
 | 
			
		||||
                    //debug("Got " + code + " for url: " + url);
 | 
			
		||||
                    length = connection.getContentLengthLong();
 | 
			
		||||
                    stream = connection.getInputStream();
 | 
			
		||||
                    break connecting;
 | 
			
		||||
                } catch(IOException connectException) {
 | 
			
		||||
                    maybeRetry(url, connectException);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            this.contentLength = length;
 | 
			
		||||
            this.reconnectingStream = new ReconnectingInputStream();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void maybeRetry(URL url, IOException e) throws IOException {
 | 
			
		||||
            cleanUpStreams(e);
 | 
			
		||||
            giveup(url, e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * According to https://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html
 | 
			
		||||
         * we should read the error stream so the connection can be reused.
 | 
			
		||||
         */
 | 
			
		||||
        private void cleanUpStreams(Exception inflight) {
 | 
			
		||||
            if (stream != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    stream.close();
 | 
			
		||||
                    stream = null;
 | 
			
		||||
                } catch (IOException closeException) {
 | 
			
		||||
                    inflight.addSuppressed(closeException);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (connection != null) {
 | 
			
		||||
                byte[] buf = new byte[8*2014];
 | 
			
		||||
                InputStream es = connection.getErrorStream();
 | 
			
		||||
                if (es != null) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        try {
 | 
			
		||||
                            while (es.read(buf) > 0) {}
 | 
			
		||||
                        } finally {
 | 
			
		||||
                            es.close();
 | 
			
		||||
                        }
 | 
			
		||||
                    } catch (IOException errorStreamError) {
 | 
			
		||||
                        inflight.addSuppressed(errorStreamError);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private HttpURLConnection makeConnection(URL url, long start)
 | 
			
		||||
                throws IOException, SocketTimeoutException {
 | 
			
		||||
            URLConnection conn;
 | 
			
		||||
            conn = url.openConnection();
 | 
			
		||||
            if (!(conn instanceof HttpURLConnection)) {
 | 
			
		||||
                throw new RuntimeException();
 | 
			
		||||
            }
 | 
			
		||||
            HttpURLConnection huc = (HttpURLConnection)conn;
 | 
			
		||||
            huc.setRequestProperty("User-Agent", getUserAgent());
 | 
			
		||||
            huc.setConnectTimeout(getConnectTimeout());
 | 
			
		||||
            huc.setReadTimeout(getReadTimeout());
 | 
			
		||||
            boolean useRangeRequest = start > 0;
 | 
			
		||||
            if (useRangeRequest) {
 | 
			
		||||
                String range = "bytes "+start+"-";
 | 
			
		||||
                //debug("Using Range request for" + range + " of " + url);
 | 
			
		||||
                huc.setRequestProperty("Range", range);
 | 
			
		||||
            }
 | 
			
		||||
            //debug("Connecting to " + url);
 | 
			
		||||
            conn.connect();
 | 
			
		||||
            return huc;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public long getSize() {
 | 
			
		||||
            return contentLength;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public InputStream getInputStream() {
 | 
			
		||||
            return reconnectingStream;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /**
 | 
			
		||||
         * An InputStream that can reconnects on SocketTimeoutException.
 | 
			
		||||
         * If it reconnects it makes a {@code Range} request to get just the 
 | 
			
		||||
         * remainder of the resource, unless {@link #rangeRequests} is false.
 | 
			
		||||
         */
 | 
			
		||||
        class ReconnectingInputStream extends InputStream {
 | 
			
		||||
            public void close() throws IOException {
 | 
			
		||||
                if (stream != null) {
 | 
			
		||||
                    stream.close();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            public int read(byte[] buf, int offset, int length) throws IOException {
 | 
			
		||||
                /*
 | 
			
		||||
                 * Overridden because {@link InputStream#read(byte[], int, int)}
 | 
			
		||||
                 * behaves badly wrt non-initial {@link #read()}s throwing.
 | 
			
		||||
                 */
 | 
			
		||||
                while (true) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        int result = stream.read(buf, offset, length);
 | 
			
		||||
                        if (result != -1) {
 | 
			
		||||
                            bytesRead+=result;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // did we get all the stream?
 | 
			
		||||
                            if (bytesRead == getSize()) {
 | 
			
		||||
                                return result;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                throw new EOFException();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        return result;
 | 
			
		||||
                    } catch (IOException readException) {
 | 
			
		||||
                        recover(readException);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            @Override
 | 
			
		||||
            public int read() throws IOException {
 | 
			
		||||
                while (true) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        int result = stream.read();
 | 
			
		||||
                        if (result != -1) {
 | 
			
		||||
                            bytesRead++;
 | 
			
		||||
                        }
 | 
			
		||||
                        return result;
 | 
			
		||||
                    } catch (IOException readException) {
 | 
			
		||||
                        recover(readException);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            /**
 | 
			
		||||
             * Reconnects, reassigning {@link RetryingSizedInputStream#connection} 
 | 
			
		||||
             * and {@link RetryingSizedInputStream#stream}, or 
 | 
			
		||||
             * throws {@code IOException} if we can't retry.
 | 
			
		||||
             */
 | 
			
		||||
            protected void recover(IOException readException) throws IOException {
 | 
			
		||||
                maybeRetry(url, readException);
 | 
			
		||||
                // if we maybeRetry didn't propage the exception let's retry...
 | 
			
		||||
                reconnect: while (true) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        // otherwise open another connection...
 | 
			
		||||
                        // using a range request unless initial request had Accept-Ranges: none
 | 
			
		||||
                        connection = makeConnection(url, rangeRequests ? bytesRead : -1);
 | 
			
		||||
                        final int code = connection.getResponseCode();
 | 
			
		||||
                        //debug("Got " + code + " for reconnection to url: " + url);
 | 
			
		||||
                        if (rangeRequests && code == 206) {
 | 
			
		||||
                            stream = connection.getInputStream();
 | 
			
		||||
                        } else if (code == 200) {
 | 
			
		||||
                            if (rangeRequests) {
 | 
			
		||||
                                //debug("Looks like " + url.getHost() + ":" + url.getPort() + " does support range request, to reading first " + bytesRead + " bytes");
 | 
			
		||||
                            }
 | 
			
		||||
                            // we didn't make a range request
 | 
			
		||||
                            // (or the server didn't understand the Range header)
 | 
			
		||||
                            // so spool the appropriate number of bytes
 | 
			
		||||
                            stream = connection.getInputStream();
 | 
			
		||||
                            try {
 | 
			
		||||
                                for (long ii = 0; ii < bytesRead; ii++) {
 | 
			
		||||
                                    stream.read();
 | 
			
		||||
                                }
 | 
			
		||||
                            } catch (IOException spoolException) {
 | 
			
		||||
                                maybeRetry(url, spoolException);
 | 
			
		||||
                                continue reconnect;
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            throw new RuntimeException("Connection error: " + code + " on reconnect");
 | 
			
		||||
                        }
 | 
			
		||||
                        //debug("Reconnected to url: " + url);
 | 
			
		||||
                        break reconnect;
 | 
			
		||||
                    } catch (IOException reconnectionException) {
 | 
			
		||||
                        maybeRetry(url, reconnectionException);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void download(URI uri, File file, ProgressMonitor progress) throws IOException {
 | 
			
		||||
        InputStream input = null;
 | 
			
		||||
        OutputStream output = null;
 | 
			
		||||
        try {
 | 
			
		||||
            URL url = uri.toURL();
 | 
			
		||||
            RetryingSizedInputStream r = new RetryingSizedInputStream(url);
 | 
			
		||||
            input = r.getInputStream();
 | 
			
		||||
            output = new FileOutputStream(file);
 | 
			
		||||
            int n;
 | 
			
		||||
            long read = 0;
 | 
			
		||||
            long size = r.getSize();
 | 
			
		||||
            byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
 | 
			
		||||
            while ((n = input.read(buffer)) != -1) {
 | 
			
		||||
                output.write(buffer, 0, n);
 | 
			
		||||
                read += n;
 | 
			
		||||
                if (progress != null) {
 | 
			
		||||
                    progress.update(read, size);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (output != null) {
 | 
			
		||||
                output.close();
 | 
			
		||||
            }
 | 
			
		||||
            if (input != null) {
 | 
			
		||||
                input.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up proxy authentication if the associated system properties
 | 
			
		||||
     * are available: "http.proxyUser" and "http.proxyPassword"
 | 
			
		||||
     * Copied from Gradle's Download
 | 
			
		||||
     */
 | 
			
		||||
    private static void setupProxyAuthentication() {
 | 
			
		||||
        if (System.getProperty("http.proxyUser") != null) {
 | 
			
		||||
            Authenticator.setDefault(new ProxyAuthenticator());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static class ProxyAuthenticator extends Authenticator {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected PasswordAuthentication getPasswordAuthentication() {
 | 
			
		||||
            return new PasswordAuthentication(
 | 
			
		||||
                    System.getProperty("http.proxyUser"),
 | 
			
		||||
                    System.getProperty("http.proxyPassword", "").toCharArray());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up a User Agent string to be able to unique identify this tool in all the web traffic
 | 
			
		||||
     * Copied from Gradle's Download
 | 
			
		||||
     */
 | 
			
		||||
    private String getUserAgent() {
 | 
			
		||||
        String javaVendor = System.getProperty("java.vendor");
 | 
			
		||||
        String javaVersion = System.getProperty("java.version");
 | 
			
		||||
        String javaVendorVersion = System.getProperty("java.vm.version");
 | 
			
		||||
        String osName = System.getProperty("os.name");
 | 
			
		||||
        String osVersion = System.getProperty("os.version");
 | 
			
		||||
        String osArch = System.getProperty("os.arch");
 | 
			
		||||
        return String.format("%s/%s (%s;%s;%s) (%s;%s;%s)", VERSION_BOOTSTRAP_NAME, VERSION_BOOTSTRAP_NUMBER, osName, osVersion, osArch, javaVendor, javaVersion, javaVendorVersion);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static File determineDistLanguage(File distHome) {
 | 
			
		||||
        File distRepo = new File(distHome, "repo");
 | 
			
		||||
        File bootstrap = new File(new File(distRepo, "ceylon"), "language");
 | 
			
		||||
        File[] versions = bootstrap.listFiles(new FileFilter() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean accept(File f) {
 | 
			
		||||
                return f.isDirectory();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        if (versions == null || versions.length != 1) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return versions[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String determineDistVersion() {
 | 
			
		||||
        File distHome = new File(System.getProperty(Constants.PROP_CEYLON_HOME_DIR));
 | 
			
		||||
        File versionDir = determineDistLanguage(distHome);
 | 
			
		||||
        if (versionDir == null) {
 | 
			
		||||
            throw new RuntimeException("Error in distribution: missing bootstrap in " + distHome.getAbsolutePath());
 | 
			
		||||
        }
 | 
			
		||||
        return versionDir.getName();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,254 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.net.MalformedURLException;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.net.URLClassLoader;
 | 
			
		||||
import java.net.URLConnection;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.ceylon.common.Versions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Ceylon-specific class loader that knows how to find and add
 | 
			
		||||
 * all needed dependencies for compiler and runtime.
 | 
			
		||||
 * Implements child-first class loading to prevent mix-ups with
 | 
			
		||||
 * Java's own tool-chain.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Tako Schotanus
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
public class CeylonClassLoader extends URLClassLoader {
 | 
			
		||||
 | 
			
		||||
    public static CeylonClassLoader newInstance() throws URISyntaxException, MalformedURLException, FileNotFoundException {
 | 
			
		||||
        return new CeylonClassLoader(getClassPath());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CeylonClassLoader newInstance(List<File> classPath) throws URISyntaxException, MalformedURLException, FileNotFoundException {
 | 
			
		||||
        return new CeylonClassLoader(classPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String signature;
 | 
			
		||||
    
 | 
			
		||||
    private CeylonClassLoader(List<File> classPath) throws URISyntaxException, MalformedURLException, FileNotFoundException {
 | 
			
		||||
        super(toUrls(classPath));
 | 
			
		||||
        this.signature = toString(classPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CeylonClassLoader(List<File> classPath, ClassLoader parentLoader) throws URISyntaxException, MalformedURLException, FileNotFoundException {
 | 
			
		||||
        super(toUrls(classPath), parentLoader);
 | 
			
		||||
        this.signature = toString(classPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getSignature(){
 | 
			
		||||
        return signature;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public boolean hasSignature(String signature){
 | 
			
		||||
        return signature != null && this.signature.equals(signature);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static URL[] toUrls(List<File> cp) throws MalformedURLException {
 | 
			
		||||
        URL[] urls = new URL[cp.size()];
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        for (File f : cp) {
 | 
			
		||||
            urls[i++] = f.toURI().toURL();
 | 
			
		||||
        }
 | 
			
		||||
        return urls;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String toString(List<File> cp) {
 | 
			
		||||
        StringBuilder classPath = new StringBuilder();
 | 
			
		||||
        for (File f : cp) {
 | 
			
		||||
            if (classPath.length() > 0) {
 | 
			
		||||
                classPath.append(File.pathSeparatorChar);
 | 
			
		||||
            }
 | 
			
		||||
            classPath.append(f.getAbsolutePath());
 | 
			
		||||
        }
 | 
			
		||||
        return classPath.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getClassPathAsString() throws URISyntaxException, FileNotFoundException {
 | 
			
		||||
        return toString(getClassPath());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getClassPathSignature(List<File> cp) {
 | 
			
		||||
        return toString(cp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static List<File> getClassPath() throws URISyntaxException, FileNotFoundException {
 | 
			
		||||
        // Determine the necessary folders
 | 
			
		||||
        File ceylonHome = LauncherUtil.determineHome();
 | 
			
		||||
        File ceylonRepo = LauncherUtil.determineRepo(ceylonHome);
 | 
			
		||||
 | 
			
		||||
        // Perform some sanity checks
 | 
			
		||||
        checkFolders(ceylonHome, ceylonRepo);
 | 
			
		||||
 | 
			
		||||
        List<File> archives = new LinkedList<File>();
 | 
			
		||||
 | 
			
		||||
        // List all the necessary Ceylon JARs and CARs
 | 
			
		||||
        String version = LauncherUtil.determineSystemVersion();
 | 
			
		||||
        archives.add(getRepoCar(ceylonRepo, "ceylon.language", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "ceylon.runtime", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.common", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.model", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.typechecker", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.compiler.java", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.compiler.js", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.cli", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.tool.provider", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.tools", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.langtools.classfile", version));
 | 
			
		||||
        
 | 
			
		||||
        //CMR
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.module-loader", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.module-resolver", version));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.module-resolver-aether", version)); // optional
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.module-resolver-webdav", version)); // optional
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.module-resolver-javascript", version)); // optional
 | 
			
		||||
        
 | 
			
		||||
        //JBoss Modules
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.jboss.modules", Versions.DEPENDENCY_JBOSS_MODULES_VERSION));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.jboss.logmanager", Versions.DEPENDENCY_LOGMANAGER_VERSION));
 | 
			
		||||
        
 | 
			
		||||
        // Maven, HTTP, and WebDAV support used by CMR
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.eclipse.ceylon.aether", "3.3.9")); // optional
 | 
			
		||||
 | 
			
		||||
        // For the typechecker
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.antlr.runtime", "3.5.2"));
 | 
			
		||||
        // For the JS backend
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "net.minidev.json-smart", "1.3.1"));
 | 
			
		||||
        // For the "doc" tool
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "org.tautua.markdownpapers.core", "1.3.4"));
 | 
			
		||||
        archives.add(getRepoJar(ceylonRepo, "com.github.rjeschke.txtmark", "0.13"));
 | 
			
		||||
        
 | 
			
		||||
        return archives;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static File getRepoJar(File repo, String moduleName, String version) {
 | 
			
		||||
        return getRepoUrl(repo, moduleName, version, "jar");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static File getRepoCar(File repo, String moduleName, String version) {
 | 
			
		||||
        return getRepoUrl(repo, moduleName, version, "car");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static File getRepoUrl(File repo, String moduleName, String version, String extension) {
 | 
			
		||||
        return new File(repo, moduleName.replace('.', '/') + "/" + version + "/" + moduleName + "-" + version + "." + extension);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static File getRepoJar(String moduleName, String version) throws FileNotFoundException, URISyntaxException {
 | 
			
		||||
        return getRepoUrl(moduleName, version, "jar");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static File getRepoCar(String moduleName, String version) throws FileNotFoundException, URISyntaxException {
 | 
			
		||||
        return getRepoUrl(moduleName, version, "car");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static File getRepoUrl(String moduleName, String version, String extension) throws URISyntaxException, FileNotFoundException {
 | 
			
		||||
        // Determine the necessary folders
 | 
			
		||||
        File ceylonHome = LauncherUtil.determineHome();
 | 
			
		||||
        File ceylonRepo = LauncherUtil.determineRepo(ceylonHome);
 | 
			
		||||
 | 
			
		||||
        // Perform some sanity checks
 | 
			
		||||
        checkFolders(ceylonHome, ceylonRepo);
 | 
			
		||||
        
 | 
			
		||||
        return new File(ceylonRepo, moduleName.replace('.', '/') + "/" + version + "/" + moduleName + "-" + version + "." + extension);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void checkFolders(File ceylonHome, File ceylonRepo) throws FileNotFoundException {
 | 
			
		||||
        if (!ceylonHome.isDirectory()) {
 | 
			
		||||
            throw new FileNotFoundException("Could not determine the Ceylon home directory (" + ceylonHome + ")");
 | 
			
		||||
        }
 | 
			
		||||
        if (!ceylonRepo.isDirectory()) {
 | 
			
		||||
            throw new FileNotFoundException("The Ceylon system repository could not be found (" + ceylonRepo + ")");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected synchronized Class<?> loadClass(String name, boolean resolve)
 | 
			
		||||
            throws ClassNotFoundException {
 | 
			
		||||
        // First, check if the class has already been loaded
 | 
			
		||||
        Class<?> c = findLoadedClass(name);
 | 
			
		||||
        if (c == null) {
 | 
			
		||||
            try {
 | 
			
		||||
                // checking local
 | 
			
		||||
                c = findClass(name);
 | 
			
		||||
            } catch (ClassNotFoundException e) {
 | 
			
		||||
                // checking parent
 | 
			
		||||
                // This call to loadClass may eventually call findClass again, in case the parent doesn't find anything.
 | 
			
		||||
                c = super.loadClass(name, resolve);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (resolve) {
 | 
			
		||||
            resolveClass(c);
 | 
			
		||||
        }
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public URL getResource(String name) {
 | 
			
		||||
        URL url = findResource(name);
 | 
			
		||||
        if (url == null) {
 | 
			
		||||
            // This call to getResource may eventually call findResource again, in case the parent doesn't find anything.
 | 
			
		||||
            url = super.getResource(name);
 | 
			
		||||
        }
 | 
			
		||||
        return url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Enumeration<URL> getResources(String name) throws IOException {
 | 
			
		||||
        /**
 | 
			
		||||
        * Similar to super, but local resources are enumerated before parent resources
 | 
			
		||||
        */
 | 
			
		||||
        Enumeration<URL> localUrls = findResources(name);
 | 
			
		||||
        Enumeration<URL> parentUrls = null;
 | 
			
		||||
        if (getParent() != null) {
 | 
			
		||||
            parentUrls = getParent().getResources(name);
 | 
			
		||||
        }
 | 
			
		||||
        final List<URL> urls = new ArrayList<URL>();
 | 
			
		||||
        if (localUrls != null) {
 | 
			
		||||
            while (localUrls.hasMoreElements()) {
 | 
			
		||||
                urls.add(localUrls.nextElement());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (parentUrls != null) {
 | 
			
		||||
            while (parentUrls.hasMoreElements()) {
 | 
			
		||||
                urls.add(parentUrls.nextElement());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return Collections.enumeration(urls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public InputStream getResourceAsStream(String name) {
 | 
			
		||||
        URL url = getResource(name);
 | 
			
		||||
        if (url != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                URLConnection con = url.openConnection();
 | 
			
		||||
                con.setUseCaches(false);
 | 
			
		||||
                return con.getInputStream();
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
import java.util.logging.Formatter;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.LogRecord;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fix log format.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Stephane Epardaud
 | 
			
		||||
 * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
 | 
			
		||||
 */
 | 
			
		||||
class CeylonLogFormatter extends Formatter {
 | 
			
		||||
    static final Formatter INSTANCE = new CeylonLogFormatter();
 | 
			
		||||
    private static final String MESSAGE_PATTERN = "%s: %s %s\n";
 | 
			
		||||
 | 
			
		||||
    private CeylonLogFormatter() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String format(LogRecord record) {
 | 
			
		||||
        //noinspection ThrowableResultOfMethodCallIgnored
 | 
			
		||||
        return String.format(
 | 
			
		||||
                MESSAGE_PATTERN,
 | 
			
		||||
                getErrorType(record.getLevel()),
 | 
			
		||||
                record.getMessage(),
 | 
			
		||||
                record.getThrown() == null ? "" : record.getThrown());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String getErrorType(Level level) {
 | 
			
		||||
        if (level == Level.WARNING)
 | 
			
		||||
            return "Warning";
 | 
			
		||||
        if (level == Level.INFO)
 | 
			
		||||
            return "Note";
 | 
			
		||||
        if (level == Level.SEVERE)
 | 
			
		||||
            return "Error";
 | 
			
		||||
        return "Debug";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
public class ClassLoaderSetupException extends Exception {
 | 
			
		||||
    private static final long serialVersionUID = -260387041605744118L;
 | 
			
		||||
 | 
			
		||||
    public ClassLoaderSetupException(Throwable cause){
 | 
			
		||||
        super(cause);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class Java7Checker {
 | 
			
		||||
 | 
			
		||||
    public static void check() {
 | 
			
		||||
        String version = System.getProperty("java.version");
 | 
			
		||||
        String[] elems = (version != null) ? version.split("\\.|_|-") : null;
 | 
			
		||||
        if (version != null && !version.isEmpty() && elems != null && elems.length >= 1) {
 | 
			
		||||
            try {
 | 
			
		||||
                int major = Integer.parseInt(elems[0]);
 | 
			
		||||
                int minor = 0;
 | 
			
		||||
                try {
 | 
			
		||||
                    // text minor such as 9-Ubuntu is allowed now
 | 
			
		||||
                    minor = elems.length > 1 ? Integer.parseInt(elems[1]) : 0;
 | 
			
		||||
                } catch (NumberFormatException ex) {}
 | 
			
		||||
                //int release = Integer.parseInt(elems[2]);
 | 
			
		||||
                if (major == 1 && minor < 7) {
 | 
			
		||||
                    System.err.println("Your Java version is not supported: " + version);
 | 
			
		||||
                    System.err.println("Ceylon needs Java 7 or newer. Please install it from http://www.java.com");
 | 
			
		||||
                    System.err.println("Aborting.");
 | 
			
		||||
                    System.exit(1);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            } catch (NumberFormatException ex) {}
 | 
			
		||||
        }
 | 
			
		||||
        System.err.println("Unable to determine Java version (java.version property missing, empty or has unexpected format: '" + version +"'). Aborting.");
 | 
			
		||||
        System.exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,231 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.net.MalformedURLException;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.ConsoleHandler;
 | 
			
		||||
import java.util.logging.Handler;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.LogManager;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.ceylon.common.Constants;
 | 
			
		||||
 | 
			
		||||
public class Launcher {
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws Throwable {
 | 
			
		||||
        // we don't need to clean up the class loader when run from main because the JVM will either exit, or
 | 
			
		||||
        // keep running with daemon threads in which case it will keep needing this classloader open 
 | 
			
		||||
        int exit = run(args);
 | 
			
		||||
        // WARNING: NEVER CALL EXIT IF WE STILL HAVE DAEMON THREADS RUNNING AND WE'VE NO REASON TO EXIT WITH A NON-ZERO CODE
 | 
			
		||||
        if(exit != 0)
 | 
			
		||||
            System.exit(exit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int run(String... args) throws Throwable {
 | 
			
		||||
        return run(false, args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int run(boolean cleanupClassLoader, String... args) throws Throwable {
 | 
			
		||||
        Java7Checker.check();
 | 
			
		||||
        CeylonClassLoader loader = getClassLoader();
 | 
			
		||||
        try{
 | 
			
		||||
            return runInJava7Checked(loader, args);
 | 
			
		||||
        }finally{
 | 
			
		||||
            if(cleanupClassLoader)
 | 
			
		||||
                loader.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // FIXME: perhaps we should clear all the properties we set in there on exit?
 | 
			
		||||
    // this may not work for run, if they leave threads running 
 | 
			
		||||
    public static int runInJava7Checked(CeylonClassLoader loader, String... args) throws Throwable {
 | 
			
		||||
        // If the --sysrep option was set on the command line we set the corresponding system property
 | 
			
		||||
        String ceylonSystemRepo = LauncherUtil.getArgument(args, "--sysrep", false);
 | 
			
		||||
        if (ceylonSystemRepo != null) {
 | 
			
		||||
            System.setProperty(Constants.PROP_CEYLON_SYSTEM_REPO, ceylonSystemRepo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
 | 
			
		||||
        try{
 | 
			
		||||
            // This is mostly required by CeylonTool.getPluginLoader(), and perhaps by jboss modules
 | 
			
		||||
            Thread.currentThread().setContextClassLoader(loader);
 | 
			
		||||
            
 | 
			
		||||
            // We actually need to construct and set a new class path for the compiler
 | 
			
		||||
            // which doesn't use the actual class path used by the JVM but it constructs
 | 
			
		||||
            // it's own list looking at the arguments passed on the command line or
 | 
			
		||||
            // at the system property "env.class.path" which we will be using here.
 | 
			
		||||
            String cp = CeylonClassLoader.getClassPathAsString();
 | 
			
		||||
            System.setProperty("env.class.path", cp);
 | 
			
		||||
 | 
			
		||||
            // Find the main tool class
 | 
			
		||||
            String verbose = null;
 | 
			
		||||
            Class<?> mainClass = loader.loadClass("org.eclipse.ceylon.common.tools.CeylonTool");
 | 
			
		||||
 | 
			
		||||
            // Set up the arguments for the tool
 | 
			
		||||
            Object mainTool = mainClass.newInstance();
 | 
			
		||||
            Integer result;
 | 
			
		||||
            Method setupMethod = mainClass.getMethod("setup", args.getClass());
 | 
			
		||||
            try {
 | 
			
		||||
                result = (Integer)setupMethod.invoke(mainTool, (Object)args);
 | 
			
		||||
            } catch (InvocationTargetException e) {
 | 
			
		||||
                throw e.getCause();
 | 
			
		||||
            }
 | 
			
		||||
            if (result == 0 /* SC_OK */) {
 | 
			
		||||
                try {
 | 
			
		||||
                    Method toolGetter = mainClass.getMethod("getTools");
 | 
			
		||||
                    Object[] tools = (Object[]) toolGetter.invoke(mainTool);
 | 
			
		||||
                    // just use the first one since they share args
 | 
			
		||||
                    if(tools != null && tools.length > 0){
 | 
			
		||||
                        Method verboseGetter = tools[0].getClass().getMethod("getVerbose");
 | 
			
		||||
                        verbose = (String)verboseGetter.invoke(tools[0]);
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (Exception ex) {
 | 
			
		||||
                    // Probably doesn't have a --verbose option
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //boolean verbose = hasArgument(args, "--verbose") && getArgument(args, "--verbose", true) == null;
 | 
			
		||||
                initGlobalLogger(verbose);
 | 
			
		||||
 | 
			
		||||
                try{
 | 
			
		||||
                    if (hasVerboseFlag(verbose, "loader")) {
 | 
			
		||||
                        Logger log = Logger.getLogger("org.eclipse.ceylon.log.loader");
 | 
			
		||||
                        log.info("Current directory is '" + LauncherUtil.absoluteFile(new File(".")).getPath() + "'");
 | 
			
		||||
                        log.info("Ceylon home directory is '" + LauncherUtil.determineHome() + "'");
 | 
			
		||||
                        for (File f : CeylonClassLoader.getClassPath()) {
 | 
			
		||||
                            log.info("path = " + f + " (" + (f.exists() ? "OK" : "Not found!") + ")");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // And finally execute the tool
 | 
			
		||||
                    Method execMethod = mainClass.getMethod("execute");
 | 
			
		||||
                    try {
 | 
			
		||||
                        result = (Integer)execMethod.invoke(mainTool);
 | 
			
		||||
                    } catch (InvocationTargetException e) {
 | 
			
		||||
                        throw e.getCause();
 | 
			
		||||
                    }
 | 
			
		||||
                }finally{
 | 
			
		||||
                    // make sure we reset it, otherwise it will keep a reference to the CeylonClassLoader
 | 
			
		||||
                    LogManager.getLogManager().reset();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result.intValue();
 | 
			
		||||
        }finally{
 | 
			
		||||
            // be sure to restore it to avoid memory leaks
 | 
			
		||||
            Thread.currentThread().setContextClassLoader(ccl);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CeylonClassLoader getClassLoader() throws ClassLoaderSetupException {
 | 
			
		||||
        try{
 | 
			
		||||
            // Create the class loader that knows where to find all the Ceylon dependencies
 | 
			
		||||
            CeylonClassLoader ceylonClassLoader = CeylonClassLoader.newInstance();
 | 
			
		||||
 | 
			
		||||
            // Set some important system properties
 | 
			
		||||
            initGlobalProperties();
 | 
			
		||||
 | 
			
		||||
            return ceylonClassLoader;
 | 
			
		||||
        }catch(URISyntaxException e){
 | 
			
		||||
            throw new ClassLoaderSetupException(e);
 | 
			
		||||
        }catch(MalformedURLException e){
 | 
			
		||||
            throw new ClassLoaderSetupException(e);
 | 
			
		||||
        }catch(FileNotFoundException e){
 | 
			
		||||
            throw new ClassLoaderSetupException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void initGlobalProperties() throws URISyntaxException {
 | 
			
		||||
        File ceylonHome = LauncherUtil.determineHome();
 | 
			
		||||
        initGlobalProperties(ceylonHome);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void initGlobalProperties(File ceylonHome) throws URISyntaxException {
 | 
			
		||||
        System.setProperty(Constants.PROP_CEYLON_HOME_DIR, ceylonHome.getAbsolutePath());
 | 
			
		||||
        System.setProperty(Constants.PROP_CEYLON_SYSTEM_REPO, LauncherUtil.determineRepo(ceylonHome).getAbsolutePath());
 | 
			
		||||
        System.setProperty(Constants.PROP_CEYLON_SYSTEM_VERSION, LauncherUtil.determineSystemVersion());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void initGlobalLogger(String verbose) {
 | 
			
		||||
        try {
 | 
			
		||||
            //if no log Manager specified use JBoss LogManager
 | 
			
		||||
            String logManager = System.getProperty("java.util.logging.manager");
 | 
			
		||||
            if (logManager == null) {
 | 
			
		||||
                System.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (verbose != null) {
 | 
			
		||||
                String[] flags = verbose.split(",");
 | 
			
		||||
                for (String flag : flags) {
 | 
			
		||||
                    flag = flag.trim();
 | 
			
		||||
                    if ("all".equals(flag) || flag.isEmpty()) {
 | 
			
		||||
                        initLogger(Logger.getLogger(""), true);
 | 
			
		||||
                    } else if (flag.matches("^[a-z]+$")) {
 | 
			
		||||
                        initLogger(Logger.getLogger("org.eclipse.ceylon.log." + flag), true);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                initLogger(Logger.getLogger(""), false);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Throwable ex) {
 | 
			
		||||
            System.err.println("Warning: log configuration failed: " + ex.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void initLogger(Logger logger, boolean verbose) {
 | 
			
		||||
        boolean handlersExists = false;
 | 
			
		||||
        for (Handler handler : logger.getHandlers()) {
 | 
			
		||||
            handlersExists = true;
 | 
			
		||||
 | 
			
		||||
            //TODO Should we remove this hack? If handler are configured then levels should be too.
 | 
			
		||||
            // This is a hack, but at least it works. With a property file our log
 | 
			
		||||
            // formatter has to be in the boot class path. This way it doesn't.
 | 
			
		||||
            if (handler instanceof ConsoleHandler) {
 | 
			
		||||
                handler.setFormatter(CeylonLogFormatter.INSTANCE);
 | 
			
		||||
                if (verbose) {
 | 
			
		||||
                    handler.setLevel(Level.ALL);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (verbose) {
 | 
			
		||||
            //TODO do not configure root logger, make it flags aware
 | 
			
		||||
            logger.setLevel(Level.ALL);
 | 
			
		||||
            if (handlersExists == false) {
 | 
			
		||||
                ConsoleHandler handler = new ConsoleHandler();
 | 
			
		||||
                handler.setFormatter(CeylonLogFormatter.INSTANCE);
 | 
			
		||||
                handler.setLevel(Level.ALL);
 | 
			
		||||
                logger.addHandler(handler);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Returns true if one of the argument passed matches one of the flags given to
 | 
			
		||||
    // --verbose=... on the command line or if one of the flags is "all"
 | 
			
		||||
    private static boolean hasVerboseFlag(String verbose, String flag) {
 | 
			
		||||
        if (verbose == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (verbose.isEmpty()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        List<String> lst = Arrays.asList(verbose.split(","));
 | 
			
		||||
        if (lst.contains("all")) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return lst.contains(flag);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,203 @@
 | 
			
		|||
/********************************************************************************
 | 
			
		||||
 * Copyright (c) 2011-2017 Red Hat Inc. and/or its affiliates and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the 
 | 
			
		||||
 * terms of the Apache License, Version 2.0 which is available at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0 
 | 
			
		||||
 ********************************************************************************/
 | 
			
		||||
package org.eclipse.ceylon.launcher;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.ceylon.common.Constants;
 | 
			
		||||
import org.eclipse.ceylon.common.Versions;
 | 
			
		||||
 | 
			
		||||
public class LauncherUtil {
 | 
			
		||||
    private LauncherUtil() {}
 | 
			
		||||
    
 | 
			
		||||
    private static final String CEYLON_REPO = "repo";
 | 
			
		||||
    private static final String CEYLON_LIBS = "lib";
 | 
			
		||||
    
 | 
			
		||||
    // Can't use OSUtil.isWindows() here because these classes are put in the
 | 
			
		||||
    // ceylon-bootstrap.jar that doesn't have access to ceylon-common
 | 
			
		||||
    private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0;
 | 
			
		||||
    
 | 
			
		||||
    public static File determineHome() throws URISyntaxException {
 | 
			
		||||
        // Determine the Ceylon home/install folder
 | 
			
		||||
        File ceylonHome;
 | 
			
		||||
        // First try the ceylon.home system property
 | 
			
		||||
        String ceylonHomeStr = System.getProperty(Constants.PROP_CEYLON_HOME_DIR);
 | 
			
		||||
        if (ceylonHomeStr == null) {
 | 
			
		||||
            // Second try to deduce it from the location of the current JAR file
 | 
			
		||||
            // (assuming either $CEYLON_HOME/lib/ceylon-bootstrap.jar or
 | 
			
		||||
            // $CEYLON_HOME/repo/ceylon/bootstrap/x.x.x/ceylon-bootstrap-x.x.x.jar)
 | 
			
		||||
            File jar = determineRuntimeJar();
 | 
			
		||||
            ceylonHome = jar.getParentFile().getParentFile();
 | 
			
		||||
            if (ceylonHome.getName().equals("bootstrap") && ceylonHome.getParentFile().getName().equals("ceylon")) {
 | 
			
		||||
                ceylonHome = ceylonHome.getParentFile().getParentFile().getParentFile();
 | 
			
		||||
            }
 | 
			
		||||
            if (!checkHome(ceylonHome)) {
 | 
			
		||||
                // Third try the CEYLON_HOME environment variable
 | 
			
		||||
                ceylonHomeStr = System.getenv(Constants.ENV_CEYLON_HOME_DIR);
 | 
			
		||||
                if (ceylonHomeStr == null) {
 | 
			
		||||
                    // As a last ditch effort see if we can find "ceylon" in the system's shell
 | 
			
		||||
                    // path and decuce the home folder from that (assuming $CEYLON_HOME/bin/ceylon)
 | 
			
		||||
                    File script = findCeylonScript();
 | 
			
		||||
                    if (script != null) {
 | 
			
		||||
                        ceylonHome = script.getParentFile().getParentFile();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            ceylonHome = new File(ceylonHomeStr);
 | 
			
		||||
        }
 | 
			
		||||
        return ceylonHome;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static File determineRepo(File ceylonHome) throws URISyntaxException {
 | 
			
		||||
        // Determine the Ceylon system repository folder
 | 
			
		||||
        File ceylonRepo;
 | 
			
		||||
        String ceylonSystemRepo = System.getProperty(Constants.PROP_CEYLON_SYSTEM_REPO);
 | 
			
		||||
        if (ceylonSystemRepo != null) {
 | 
			
		||||
            ceylonRepo = new File(ceylonSystemRepo);
 | 
			
		||||
        } else {
 | 
			
		||||
            ceylonRepo = new File(ceylonHome, CEYLON_REPO);
 | 
			
		||||
        }
 | 
			
		||||
        return ceylonRepo;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static File determineLibs(File ceylonHome) throws URISyntaxException {
 | 
			
		||||
        // Determine the Ceylon system library folder
 | 
			
		||||
        File ceylonLib;
 | 
			
		||||
        String ceylonSystemRepo = System.getProperty(Constants.PROP_CEYLON_SYSLIBS_DIR);
 | 
			
		||||
        if (ceylonSystemRepo != null) {
 | 
			
		||||
            ceylonLib = new File(ceylonSystemRepo);
 | 
			
		||||
        } else {
 | 
			
		||||
            ceylonLib = new File(ceylonHome, CEYLON_LIBS);
 | 
			
		||||
        }
 | 
			
		||||
        return ceylonLib;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static String determineSystemVersion() {
 | 
			
		||||
        // Determine the Ceylon system/language/runtime version
 | 
			
		||||
        String ceylonVersion = System.getProperty(Constants.PROP_CEYLON_SYSTEM_VERSION);
 | 
			
		||||
        if (ceylonVersion == null) {
 | 
			
		||||
            ceylonVersion = System.getenv(Constants.ENV_CEYLON_VERSION);
 | 
			
		||||
            if (ceylonVersion == null) {
 | 
			
		||||
                ceylonVersion = Versions.CEYLON_VERSION_NUMBER;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ceylonVersion;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public static File determineRuntimeJar() throws URISyntaxException {
 | 
			
		||||
        return new File(LauncherUtil.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static File findCeylonScript() {
 | 
			
		||||
        String path = System.getenv("PATH");
 | 
			
		||||
        if (path != null) {
 | 
			
		||||
            String ceylonScriptName;
 | 
			
		||||
            if (IS_WINDOWS) {
 | 
			
		||||
                ceylonScriptName = "ceylon.bat";
 | 
			
		||||
            } else {
 | 
			
		||||
                ceylonScriptName = "ceylon";
 | 
			
		||||
            }
 | 
			
		||||
            String[] elems = path.split(File.pathSeparator);
 | 
			
		||||
            for (String elem : elems) {
 | 
			
		||||
                File script = new File(elem, ceylonScriptName);
 | 
			
		||||
                if (script.isFile() && script.canExecute() && isSameScriptVersion(script)) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        // only if the version is compatible with this version!
 | 
			
		||||
                        return script.getCanonicalFile();
 | 
			
		||||
                    } catch (IOException e) {
 | 
			
		||||
                        // Ignore errors and keep on trying
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static boolean isSameScriptVersion(File script) {
 | 
			
		||||
        List<String> args = new ArrayList<String>(4);
 | 
			
		||||
        if (IS_WINDOWS) {
 | 
			
		||||
            args.add("cmd.exe");
 | 
			
		||||
            args.add("/C");
 | 
			
		||||
        }
 | 
			
		||||
        args.add(script.getAbsolutePath());
 | 
			
		||||
        args.add("--version");
 | 
			
		||||
        ProcessBuilder processBuilder = new ProcessBuilder(args);
 | 
			
		||||
        try{
 | 
			
		||||
            Process process = processBuilder.start();
 | 
			
		||||
            InputStream in = process.getInputStream();
 | 
			
		||||
            InputStreamReader inread = new InputStreamReader(in);
 | 
			
		||||
            BufferedReader bufferedreader = new BufferedReader(inread);
 | 
			
		||||
            String line;
 | 
			
		||||
            StringBuilder sb = new StringBuilder();
 | 
			
		||||
            while ((line = bufferedreader.readLine()) != null) {
 | 
			
		||||
                sb.append(line);
 | 
			
		||||
            }
 | 
			
		||||
            int exit = process.waitFor();
 | 
			
		||||
            bufferedreader.close();
 | 
			
		||||
            if(exit != 0)
 | 
			
		||||
                return false;
 | 
			
		||||
            return sb.toString().startsWith("ceylon version "+Versions.CEYLON_VERSION_MAJOR+"."+Versions.CEYLON_VERSION_MINOR);
 | 
			
		||||
        }catch(Throwable t){
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean checkHome(File ceylonHome) {
 | 
			
		||||
        return (new File(ceylonHome, CEYLON_REPO)).isDirectory() && (new File(ceylonHome, CEYLON_LIBS)).isDirectory();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean hasArgument(final String[] args, final String test) {
 | 
			
		||||
        for (String arg : args) {
 | 
			
		||||
            if ("--".equals(arg)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if (arg.equals(test) || arg.startsWith(test + "=")) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getArgument(final String[] args, final String test, boolean optionalArgument) {
 | 
			
		||||
        for (int i=0; i < args.length; i++) {
 | 
			
		||||
            String arg = args[i];
 | 
			
		||||
            if ("--".equals(arg)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if (!optionalArgument && i < (args.length - 1) && arg.equals(test)) {
 | 
			
		||||
                return args[i + 1];
 | 
			
		||||
            }
 | 
			
		||||
            if (arg.startsWith(test + "=")) {
 | 
			
		||||
                return arg.substring(test.length() + 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static File absoluteFile(File file) {
 | 
			
		||||
        if (file != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                file = file.getCanonicalFile();
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                file = file.getAbsoluteFile();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return file;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue