src/Pure/Admin/component_scala.scala
changeset 77566 2a99fcb283ee
parent 77369 df17355f1e2c
child 78125 96e2c2bbacbd
equal deleted inserted replaced
77565:fd87490429aa 77566:2a99fcb283ee
       
     1 /*  Title:      Pure/Admin/component_scala.scala
       
     2     Author:     Makarius
       
     3 
       
     4 Build Isabelle Scala component from official downloads.
       
     5 */
       
     6 
       
     7 package isabelle
       
     8 
       
     9 
       
    10 object Component_Scala {
       
    11   /* downloads */
       
    12 
       
    13   sealed case class Download(
       
    14     name: String,
       
    15     version: String,
       
    16     url: String,
       
    17     physical_url: String = "",
       
    18     base_version: String = "3"
       
    19   ) {
       
    20     def make_url(template: String): String =
       
    21       template.replace("{V}", version).replace("{B}", base_version)
       
    22 
       
    23     def proper_url: String = make_url(proper_string(physical_url).getOrElse(url))
       
    24 
       
    25     def artifact: String =
       
    26       Library.take_suffix[Char](_ != '/', proper_url.toList)._2.mkString
       
    27 
       
    28     def get(path: Path, progress: Progress = new Progress): Unit =
       
    29       Isabelle_System.download_file(proper_url, path, progress = progress)
       
    30 
       
    31     def print: String =
       
    32       "  * " + name + " " + version + if_proper(base_version, " for Scala " + base_version) +
       
    33         ":\n    " + make_url(url)
       
    34   }
       
    35 
       
    36   val main_download: Download =
       
    37     Download("scala", "3.2.1", base_version = "",
       
    38       url = "https://github.com/lampepfl/dotty/releases/download/{V}/scala3-{V}.tar.gz")
       
    39 
       
    40   val lib_downloads: List[Download] = List(
       
    41     Download("scala-parallel-collections", "1.0.4",
       
    42       "https://mvnrepository.com/artifact/org.scala-lang.modules/scala-parallel-collections_{B}/{V}",
       
    43       physical_url = "https://repo1.maven.org/maven2/org/scala-lang/modules/scala-parallel-collections_{B}/{V}/scala-parallel-collections_{B}-{V}.jar"),
       
    44     Download("scala-parser-combinators", "2.1.1",
       
    45       "https://mvnrepository.com/artifact/org.scala-lang.modules/scala-parser-combinators_{B}/{V}",
       
    46       physical_url = "https://repo1.maven.org/maven2/org/scala-lang/modules/scala-parser-combinators_{B}/{V}/scala-parser-combinators_{B}-{V}.jar"),
       
    47     Download("scala-swing", "3.0.0",
       
    48       "https://mvnrepository.com/artifact/org.scala-lang.modules/scala-swing_{B}/{V}",
       
    49       physical_url = "https://repo1.maven.org/maven2/org/scala-lang/modules/scala-swing_{B}/{V}/scala-swing_{B}-{V}.jar"),
       
    50     Download("scala-xml", "2.1.0",
       
    51       "https://mvnrepository.com/artifact/org.scala-lang.modules/scala-xml_{B}/{V}",
       
    52       physical_url = "https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_{B}/{V}/scala-xml_{B}-{V}.jar")
       
    53   )
       
    54 
       
    55 
       
    56   /* build Scala component */
       
    57 
       
    58   def build_scala(
       
    59     target_dir: Path = Path.current,
       
    60     progress: Progress = new Progress
       
    61   ): Unit = {
       
    62     /* component */
       
    63 
       
    64     val component_name = main_download.name + "-" + main_download.version
       
    65     val component_dir =
       
    66       Components.Directory(target_dir + Path.basic(component_name)).create(progress = progress)
       
    67 
       
    68 
       
    69     /* download */
       
    70 
       
    71     Isabelle_System.with_tmp_file("archive", ext = "tar.gz") { archive_path =>
       
    72       main_download.get(archive_path, progress = progress)
       
    73       Isabelle_System.extract(archive_path, component_dir.path, strip = true)
       
    74     }
       
    75 
       
    76     lib_downloads.foreach(download =>
       
    77       download.get(component_dir.lib + Path.basic(download.artifact), progress = progress))
       
    78 
       
    79     File.write(component_dir.LICENSE,
       
    80       Url.read("https://www.apache.org/licenses/LICENSE-2.0.txt"))
       
    81 
       
    82 
       
    83     /* classpath */
       
    84 
       
    85     val classpath: List[String] = {
       
    86       def no_function(name: String): String = "function " + name + "() {\n:\n}"
       
    87       val script =
       
    88         cat_lines(List(
       
    89           no_function("stty"),
       
    90           no_function("tput"),
       
    91           "PROG_HOME=" + File.bash_path(component_dir.path),
       
    92           File.read(component_dir.path + Path.explode("bin/common"))
       
    93             .replace("scala_exit_status=127", "scala_exit_status=0"),
       
    94           "compilerJavaClasspathArgs",
       
    95           "echo \"$jvm_cp_args\""))
       
    96 
       
    97       val main_classpath = Path.split(Isabelle_System.bash(script).check.out).map(_.file_name)
       
    98       val lib_classpath = lib_downloads.map(_.artifact)
       
    99 
       
   100       main_classpath ::: lib_classpath
       
   101     }
       
   102 
       
   103     val interfaces =
       
   104       classpath.find(_.startsWith("scala3-interfaces"))
       
   105         .getOrElse(error("Missing jar for scala3-interfaces"))
       
   106 
       
   107 
       
   108     /* settings */
       
   109 
       
   110     component_dir.write_settings("""
       
   111 SCALA_HOME="$COMPONENT"
       
   112 SCALA_INTERFACES="$SCALA_HOME/lib/""" + interfaces + """"
       
   113 """ + terminate_lines(classpath.map(jar => "classpath \"$SCALA_HOME/lib/" + jar + "\"")))
       
   114 
       
   115 
       
   116     /* adhoc changes */
       
   117 
       
   118     val patched_scripts = List("bin/scala", "bin/scalac")
       
   119     for (name <- patched_scripts) {
       
   120       File.change(component_dir.path + Path.explode(name)) {
       
   121         _.replace(""""-Dscala.home=$PROG_HOME"""", """"-Dscala.home=\"$PROG_HOME\""""")
       
   122       }
       
   123     }
       
   124 
       
   125 
       
   126     /* README */
       
   127 
       
   128     File.write(component_dir.README,
       
   129       "This distribution of Scala integrates the following parts:\n\n" +
       
   130       (main_download :: lib_downloads).map(_.print).mkString("\n\n") + """
       
   131 
       
   132 Minor changes to """ + patched_scripts.mkString(" and ") + """ allow an installation location
       
   133 with spaces in the directory name.
       
   134 
       
   135 
       
   136         Makarius
       
   137         """ + Date.Format.date(Date.now()) + "\n")
       
   138   }
       
   139 
       
   140 
       
   141   /* Isabelle tool wrapper */
       
   142 
       
   143   val isabelle_tool =
       
   144     Isabelle_Tool("component_scala", "build Isabelle Scala component from official downloads",
       
   145       Scala_Project.here,
       
   146       { args =>
       
   147         var target_dir = Path.current
       
   148 
       
   149         val getopts = Getopts("""
       
   150 Usage: isabelle component_scala [OPTIONS]
       
   151 
       
   152   Options are:
       
   153     -D DIR       target directory (default ".")
       
   154 
       
   155   Build Isabelle Scala component from official downloads.
       
   156 """,
       
   157           "D:" -> (arg => target_dir = Path.explode(arg)))
       
   158 
       
   159         val more_args = getopts(args)
       
   160         if (more_args.nonEmpty) getopts.usage()
       
   161 
       
   162         val progress = new Console_Progress()
       
   163 
       
   164         build_scala(target_dir = target_dir, progress = progress)
       
   165       })
       
   166 }