All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.tools.bootstrap.CeylonBootstrapTool Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
package com.redhat.ceylon.tools.bootstrap;

import java.io.File;
import java.io.FileOutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Properties;

import com.redhat.ceylon.common.Constants;
import com.redhat.ceylon.common.FileUtil;
import com.redhat.ceylon.common.Versions;
import com.redhat.ceylon.common.tool.Argument;
import com.redhat.ceylon.common.tool.CeylonBaseTool;
import com.redhat.ceylon.common.tool.Description;
import com.redhat.ceylon.common.tool.Option;
import com.redhat.ceylon.common.tool.OptionArgument;
import com.redhat.ceylon.common.tool.Summary;
import com.redhat.ceylon.common.tools.CeylonTool;
import com.redhat.ceylon.launcher.Bootstrap;
import com.redhat.ceylon.launcher.LauncherUtil;

@Summary("Generates a Ceylon bootstrap script in the current directory")
@Description("This tool generates a `ceylonb` bootstrap shell script "
        + "(and a `ceylonb.bat` batch file for Windows) that functions "
        + "exactly like the normal `ceylon` command, except that it is "
        + "not necessary to install Ceylon yourself. On first execution "
        + "the scripts will check if the required Ceylon distribution is "
        + "already available locally and if not they will download and "
        + "install it."
        + "\n\n"
        + "A bootstrap script can be used to make it very easy for "
        + "authors of Ceylon projects to distribute their code to users "
        + "without them having to install Ceylon. It is also useful for "
        + "making sure that users use the exact same version of Ceylon "
        + "the code was tested with without forcing them to install "
        + "that exact same version themselves."
        + "\n\n"
        + "The `distribution` argument determines which distribution "
        + "the bootstrap script will install. It can either be a version "
        + "string, which will then be combined with the URL to the official "
        + "Ceylon download site, or it can be a URL pointing directly to "
        + "the desired Ceylon distribution download. If this option is not "
        + "specified the current version will be used "
        + "(default: " + Versions.CEYLON_VERSION_NUMBER + ")")
public class CeylonBootstrapTool extends CeylonBaseTool {
    private URI distribution;
    private File installation;
    private String shaSum;
    private boolean force;
        
    private static final String FILE_CEYLON_SCRIPT = "ceylon";
    private static final String FILE_CEYLONB_SCRIPT = "ceylonb";
    
    public CeylonBootstrapTool() {
    }
    
    @Argument(argumentName="distribution", multiplicity="?")
    public void setDistribution(URI distribution) {
        this.distribution = distribution;
    }

    @OptionArgument(argumentName="path")
    @Description("Determines where the bootstrap script will install the distribution. " +
            "This can either be a path that starts with `~` or `${user.home}` to " + 
            "indicate a location in the user's home directory or it can start with " +
            "`${ceylon.user.dir}` to indicate a location in the user's Ceylon " +
            "directory. (default: ${ceylon.user.dir}/dists/)")
    public void setInstallation(File installation) {
        this.installation = installation;
    }

    @OptionArgument(argumentName = "sum")
    @Description("The SHA-256 sum to be included for the bootstrap script (default: no sum)")
    public void setShaSum(String shaSum) {
        this.shaSum = shaSum;
    }

    @Option
    @Description("Create the bootstrap files even if they already exist")
    public void setForce(boolean force) {
        this.force = force;
    }

    @Override
    public void initialize(CeylonTool mainTool) throws Exception {
        if (!force) {
            File sourceDir = applyCwd(new File(Constants.DEFAULT_SOURCE_DIR));
            File configDir = applyCwd(new File(Constants.CEYLON_CONFIG_DIR));
            if (!sourceDir.isDirectory() && !configDir.isDirectory()) {
                throw new IllegalStateException(CeylonBootstrapMessages.msg("error.not.project"));
            }
            
            File scriptFile = applyCwd(new File(FILE_CEYLONB_SCRIPT));
            File batFile = applyCwd(new File(FILE_CEYLONB_SCRIPT + ".bat"));
            File bootstrapDir = new File(applyCwd(new File(Constants.CEYLON_CONFIG_DIR)), "bootstrap");
            File propsFile = new File(bootstrapDir, Bootstrap.FILE_BOOTSTRAP_PROPERTIES);
            File jarFile = new File(bootstrapDir, Bootstrap.FILE_BOOTSTRAP_JAR);
            if (scriptFile.exists() || batFile.exists() || propsFile.exists() || jarFile.exists()) {
                throw new IllegalStateException(CeylonBootstrapMessages.msg("error.bootstrap.exists"));
            }
        }
        
        if (installation != null && installation.isAbsolute()) {
            throw new IllegalArgumentException(CeylonBootstrapMessages.msg("error.path.not.absolute"));
        }
        
        if (shaSum != null && shaSum.length() != 64) {
            throw new IllegalArgumentException(CeylonBootstrapMessages.msg("error.shasum.length"));
        }
    }
    
    @Override
    public void run() throws Exception {
        setupBootstrap(validCwd().getAbsoluteFile(), distribution, installation, shaSum);
    }

    public static void setupBootstrap(File targetDir, URI distribution, File installation, String shaSum) throws Exception {
        File srcJar = new File(LauncherUtil.determineLibs(LauncherUtil.determineHome()), Bootstrap.FILE_BOOTSTRAP_JAR);
        File srcScripts = new File(LauncherUtil.determineHome(), Constants.CEYLON_BIN_DIR);
        setupBootstrap(targetDir, srcJar, srcScripts, distribution, installation, shaSum);
    }

    public static void setupBootstrap(File targetDir, File srcJar, File srcScripts, URI distribution, File installation, String shaSum) throws Exception {
        // Create the target "bootstrap" directory
        File bootstrapDir = new File(new File(targetDir, Constants.CEYLON_CONFIG_DIR), "bootstrap");
        FileUtil.mkdirs(bootstrapDir);
        
        // Create the "ceylon-bootstrap.properties" file
        Properties props = new Properties();
        props.setProperty(Bootstrap.KEY_DISTRIBUTION, getDistributionUri(distribution).toString());
        if (installation != null) {
            props.setProperty(Bootstrap.KEY_INSTALLATION, installation.getPath());
        }
        if (shaSum != null) {
            props.setProperty(Bootstrap.KEY_SHA256SUM, shaSum);
        }
        File propsFile = new File(bootstrapDir, Bootstrap.FILE_BOOTSTRAP_PROPERTIES);
        try (FileOutputStream out = new FileOutputStream(propsFile)) {
            props.store(out, CeylonBootstrapMessages.msg("info.generated.by"));
        }
        
        // Copy the "ceylon-bootstrap.jar"
        File destJar = new File(bootstrapDir, Bootstrap.FILE_BOOTSTRAP_JAR);
        Files.copy(srcJar.toPath(), destJar.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
        
        // Copy the "ceylon" startup script to "./ceylonb"
        File srcScript = new File(srcScripts, FILE_CEYLON_SCRIPT);
        File destScript = new File(targetDir, FILE_CEYLONB_SCRIPT);
        Files.copy(srcScript.toPath(), destScript.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
        destScript.setExecutable(true, false);
        
        // Copy the "ceylon.bat" startup script to "./ceylonb.bat"
        File srcBat = new File(srcScripts, FILE_CEYLON_SCRIPT + ".bat");
        File destBat = new File(targetDir, FILE_CEYLONB_SCRIPT + ".bat");
        Files.copy(srcBat.toPath(), destBat.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
    }
    
    private static URI getDistributionUri(URI distribution) throws URISyntaxException {
        if (distribution == null || distribution.getScheme() == null) {
            String version;
            if (distribution != null) {
                version = distribution.getPath();
            } else {
                version = Versions.CEYLON_VERSION_NUMBER;
            }
            return new URI(Bootstrap.CEYLON_DOWNLOAD_BASE_URL + version.replace('.', '_'));
        } else {
            return distribution;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy