src/Tools/Setup/isabelle/setup/Build_Scala.java
author wenzelm
Fri, 02 Jul 2021 11:29:33 +0200
changeset 73916 c6631069357b
parent 73915 1f532f2b2f60
child 73917 b5d52a4d6fd9
permissions -rw-r--r--
tuned signature;

/*  Title:      Tools/Setup/isabelle/setup/Build_Scala.java
    Author:     Makarius

Build Isabelle/Scala modules.
*/

package isabelle.setup;


import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Stream;


public class Build_Scala
{
    public static class Context
    {
        private final Path component_dir;
        private Properties props;

        public Context(Path dir) throws IOException
        {
            component_dir = dir;
            props = new Properties();
            Path path = component_dir.resolve("etc/scala.props");
            if (Files.exists(path)) { props.load(Files.newBufferedReader(path)); }
        }

        @Override public String toString()
        {
            return component_dir.toString();
        }

        public String component_name()
        {
            return component_dir.toFile().getName();
        }

        public String name()
        {
            return props.getProperty("name", component_name());
        }

        public String description()
        {
            return props.getProperty("description", name());
        }

        public String lib_name()
        {
            return props.getProperty("lib", "lib") + "/" + name();
        }

        public String jar_name()
        {
            return lib_name() + ".jar";
        }

        public String shasum_name()
        {
            return lib_name() + ".shasum";
        }

        public String main()
        {
            return props.getProperty("main", "");
        }

        public String[] sources()
        {
            return props.getProperty("sources", "").split("\\s+");
        }

        public String[] services()
        {
            return props.getProperty("services", "").split("\\s+");
        }

        public Path path(String file)
        {
            return component_dir.resolve(file);
        }

        public boolean exists(String file)
        {
            return Files.exists(path(file));
        }

        public String shasum(String file)
            throws IOException, NoSuchAlgorithmException
        {
            if (exists(file)) {
                MessageDigest sha = MessageDigest.getInstance("SHA");
                sha.update(Files.readAllBytes(path(file)));
                String digest = new BigInteger(1, sha.digest()).toString(16);
                return digest + " *" + file + "\n";
            }
            else { return ""; }
        }
    }

    public static void build_scala(Context context, boolean fresh)
        throws IOException, InterruptedException, NoSuchAlgorithmException
    {
        String jar_name = context.jar_name();
        String shasum_name = context.shasum_name();

        String[] sources = context.sources();

        if (sources.length == 0) {
            Files.deleteIfExists(context.path(jar_name));
            Files.deleteIfExists(context.path(shasum_name));
        }
        else {
            String shasum_old =
                context.exists(shasum_name) ? Files.readString(context.path(shasum_name)) : "";
            String shasum_sources;
            {
                StringBuilder _shasum = new StringBuilder();
                for (String s : sources) {
                    _shasum.append(context.shasum(s));
                }
                shasum_sources = _shasum.toString();
            }
            if (fresh || !shasum_old.equals(context.shasum(jar_name) + shasum_sources)) {
                System.out.println("### Building " + context.description() + " ...");

                String java_home = Environment.getenv("JAVA_HOME");
                String scala_home = Environment.getenv("SCALA_HOME");
                String scalac_options = Environment.getenv("ISABELLE_SCALAC_OPTIONS");
                String isabelle_class_path = Environment.getenv("ISABELLE_CLASSPATH");

                if (java_home.isEmpty()) {
                    throw new RuntimeException("Unknown JAVA_HOME -- Java unavailable");
                }
                if (scala_home.isEmpty()) {
                    throw new RuntimeException("Unknown SCALA_HOME -- Scala unavailable");
                }

                Path build_dir = Files.createTempDirectory("isabelle");
                try {
                    /* classpath */

                    List<String> classpath = new LinkedList<String>();
                    for (String s : isabelle_class_path.split(":", -1)) {
                        classpath.add(Environment.platform_path(s));
                    }

                    Map<String,String> env = new HashMap<String,String>(Environment.settings());
                    env.put("CLASSPATH", String.join(File.pathSeparator, classpath));


                    /* scalac */

                    List<String> cmd = new LinkedList<String>();
                    Environment.Exec_Result res;

                    cmd.add(Environment.platform_path(scala_home + "/bin/scalac"));
                    for (String s : scalac_options.split("\\s+")) { cmd.add(s); }
                    cmd.add("-d");
                    cmd.add(build_dir.toString());
                    for (String s : sources) { cmd.add(context.path(s).toString()); }

                    res = Environment.exec_process(cmd, build_dir.toFile(), env, false);
                    if (!res.ok()) throw new RuntimeException(res.err());


                    /* jar */

                    cmd.clear();
                    cmd.add(Environment.platform_path(java_home + "/bin/jar"));
                    cmd.add("-c");
                    cmd.add("-f");
                    cmd.add(context.path(jar_name).toString());
                    if (!context.main().isEmpty()) {
                        cmd.add("-e");
                        cmd.add(context.main());
                    }
                    cmd.add(".");

                    res = Environment.exec_process(cmd, build_dir.toFile(), env, false);
                    if (!res.ok()) throw new RuntimeException(res.err());


                    /* shasum */

                    String shasum = context.shasum(jar_name) + shasum_sources;
                    Files.writeString(context.path(shasum_name), shasum);
                }
                finally {
                    try (Stream<Path> walk = Files.walk(build_dir)) {
                        walk.sorted(Comparator.reverseOrder())
                            .map(Path::toFile)
                            .forEach(File::delete);
                    }
                }
            }
        }
    }
}