src/Pure/Tools/scala_project.scala
changeset 74030 39e05601faeb
parent 73987 fc363a3b690a
child 74032 c9ec6f03ab91
equal deleted inserted replaced
74029:0701ff55780d 74030:39e05601faeb
     3 
     3 
     4 Setup Gradle project for Isabelle/Scala/jEdit.
     4 Setup Gradle project for Isabelle/Scala/jEdit.
     5 */
     5 */
     6 
     6 
     7 package isabelle
     7 package isabelle
       
     8 
       
     9 import scala.jdk.CollectionConverters._
     8 
    10 
     9 
    11 
    10 object Scala_Project
    12 object Scala_Project
    11 {
    13 {
    12   /* groovy syntax */
    14   /* groovy syntax */
    21   }
    23   }
    22 
    24 
    23 
    25 
    24   /* file and directories */
    26   /* file and directories */
    25 
    27 
    26   lazy val isabelle_files: List[String] =
    28   lazy val isabelle_files: (List[Path], List[Path]) =
    27   {
    29   {
    28     val files1 =
    30     val component_contexts =
    29     {
    31       isabelle.setup.Build.component_contexts().asScala.toList
    30       val isabelle_home = Path.ISABELLE_HOME.canonical
       
    31       Path.split(Isabelle_System.getenv("ISABELLE_CLASSPATH")).
       
    32         map(path => File.relative_path(isabelle_home, path).getOrElse(path).implode)
       
    33     }
       
    34 
    32 
    35     val isabelle_jar = Path.explode("$ISABELLE_SCALA_JAR").java_path
    33     val jars1 = Path.split(Isabelle_System.getenv("ISABELLE_CLASSPATH"))
    36     val isabelle_shasum = isabelle.setup.Build.get_shasum(isabelle_jar)
    34     val jars2 =
       
    35       (for {
       
    36         context <- component_contexts.iterator
       
    37         s <- context.requirements().asScala.iterator
       
    38         path <- context.requirement_paths(s).asScala.iterator
       
    39       } yield File.path(path.toFile)).toList
    37 
    40 
    38     val files2 =
    41     val jar_files =
    39       for {
    42       (jars1 ::: jars2).filterNot(path =>
    40         line <- Library.trim_split_lines(isabelle_shasum)
    43         component_contexts.exists(context =>
    41         name =
    44         {
    42           if (line.length > 41 && line(40) == ' ') line.substring(41)
    45           val name: String = context.module_name()
    43           else error("Bad shasum entry: " + quote(line))
    46           name.nonEmpty && File.eq(context.path(name).toFile, path.file)
    44         if Path.is_wellformed(name) && name != "<props>"
    47         }))
    45       } yield name
       
    46 
    48 
    47     files1 ::: files2
    49     val source_files =
       
    50       (for {
       
    51         context <- component_contexts.iterator
       
    52         file <- context.sources.asScala.iterator
       
    53         if file.endsWith(".scala") || file.endsWith(".java")
       
    54       } yield File.path(context.path(file).toFile)).toList
       
    55 
       
    56     (jar_files, source_files)
    48   }
    57   }
    49 
    58 
    50   lazy val isabelle_scala_files: Map[String, Path] =
    59   lazy val isabelle_scala_files: Map[String, Path] =
    51     isabelle_files.foldLeft(Map.empty[String, Path]) {
    60   {
       
    61     val context = isabelle.setup.Build.component_context(Path.ISABELLE_HOME.java_path)
       
    62     context.sources().asScala.iterator.foldLeft(Map.empty[String, Path]) {
    52       case (map, name) =>
    63       case (map, name) =>
    53         if (!name.startsWith("src/Tools/jEdit/") && name.endsWith(".scala")) {
    64         if (name.endsWith(".scala")) {
    54           val path = Path.explode("~~/" + name)
    65         val path = File.path(context.path(name).toFile)
    55           val base = path.base.implode
    66         val base = path.base.implode
    56           map.get(base) match {
    67           map.get(base) match {
    57             case None => map + (base -> path)
    68             case None => map + (base -> path)
    58             case Some(path1) => error("Conflicting base names: " + path + " vs. " + path1)
    69             case Some(path2) => error("Conflicting base names: " + path + " vs. " + path2)
    59           }
    70           }
    60         }
    71         }
    61         else map
    72         else map
    62     }
    73     }
    63 
       
    64   private def guess_package(path: Path): String =
       
    65   {
       
    66     val lines = split_lines(File.read(path))
       
    67     val Package = """\bpackage\b +(?:object +)?\b((?:\w|\.)+)\b""".r
       
    68 
       
    69     lines.collectFirst({ case Package(name) => name }) getOrElse
       
    70       error("Failed to guess package from " + path)
       
    71   }
    74   }
    72 
    75 
    73 
    76 
    74   /* compile-time position */
    77   /* compile-time position */
    75 
    78 
    96   }
    99   }
    97 
   100 
    98 
   101 
    99   /* scala project */
   102   /* scala project */
   100 
   103 
       
   104   def package_dir(source_file: Path): Option[Path] =
       
   105   {
       
   106     val is_java = source_file.file_name.endsWith(".java")
       
   107     val lines = split_lines(File.read(source_file))
       
   108     val Package = """\s*\bpackage\b\s*(?:object\b\s*)?((?:\w|\.)+)\b.*""".r
       
   109     lines.collectFirst(
       
   110       {
       
   111         case Package(name) =>
       
   112           if (is_java) Path.explode(space_explode('.', name).mkString("/"))
       
   113           else Path.basic(name)
       
   114       })
       
   115   }
       
   116 
       
   117   def the_package_dir(source_file: Path): Path =
       
   118     package_dir(source_file) getOrElse error("Failed to guess package from " + source_file)
       
   119 
   101   def scala_project(project_dir: Path, symlinks: Boolean = false): Unit =
   120   def scala_project(project_dir: Path, symlinks: Boolean = false): Unit =
   102   {
   121   {
   103     if (symlinks && Platform.is_windows)
   122     if (symlinks && Platform.is_windows)
   104       error("Cannot create symlinks on Windows")
   123       error("Cannot create symlinks on Windows")
   105 
   124 
   106     if (project_dir.is_file || project_dir.is_dir)
   125     if (project_dir.is_file || project_dir.is_dir)
   107       error("Project directory already exists: " + project_dir)
   126       error("Project directory already exists: " + project_dir)
   108 
   127 
   109     val java_src_dir = project_dir + Path.explode("src/main/java")
   128     val java_src_dir = Isabelle_System.make_directory(project_dir + Path.explode("src/main/java"))
   110     val scala_src_dir = Isabelle_System.make_directory(project_dir + Path.explode("src/main/scala"))
   129     val scala_src_dir = Isabelle_System.make_directory(project_dir + Path.explode("src/main/scala"))
   111 
   130 
   112     Isabelle_System.copy_dir(Path.explode("$JEDIT_HOME/jEdit"), java_src_dir)
   131     val (jar_files, source_files) = isabelle_files
   113 
       
   114     val isabelle_setup_dir = Path.explode("~~/src/Tools/Setup/isabelle")
       
   115     if (symlinks) Isabelle_System.symlink(isabelle_setup_dir, java_src_dir)
       
   116     else Isabelle_System.copy_dir(isabelle_setup_dir, java_src_dir)
       
   117 
       
   118     val files = isabelle_files
       
   119     isabelle_scala_files
   132     isabelle_scala_files
   120 
   133 
   121     for (file <- files if file.endsWith(".scala")) {
   134     for (source <- source_files) {
   122       val path = Path.ISABELLE_HOME + Path.explode(file)
   135       val dir = if (source.file_name.endsWith(".java")) java_src_dir else scala_src_dir
   123       val target = scala_src_dir + Path.basic(guess_package(path))
   136       val target = dir + the_package_dir(source)
   124       Isabelle_System.make_directory(target)
   137       Isabelle_System.make_directory(target)
   125       if (symlinks) Isabelle_System.symlink(path, target)
   138       if (symlinks) Isabelle_System.symlink(source, target)
   126       else Isabelle_System.copy_file(path, target)
   139       else Isabelle_System.copy_file(source, target)
   127     }
   140     }
   128 
       
   129     val jars =
       
   130       for (file <- files if file.endsWith(".jar"))
       
   131       yield {
       
   132         if (file.startsWith("/")) file
       
   133         else Isabelle_System.getenv("ISABELLE_HOME") + "/" + file
       
   134       }
       
   135 
   141 
   136     File.write(project_dir + Path.explode("settings.gradle"), "rootProject.name = 'Isabelle'\n")
   142     File.write(project_dir + Path.explode("settings.gradle"), "rootProject.name = 'Isabelle'\n")
   137     File.write(project_dir + Path.explode("build.gradle"),
   143     File.write(project_dir + Path.explode("build.gradle"),
   138 """plugins {
   144 """plugins {
   139   id 'scala'
   145   id 'scala'
   144 }
   150 }
   145 
   151 
   146 dependencies {
   152 dependencies {
   147   implementation 'org.scala-lang:scala-library:""" + scala.util.Properties.versionNumberString + """'
   153   implementation 'org.scala-lang:scala-library:""" + scala.util.Properties.versionNumberString + """'
   148   compile files(
   154   compile files(
   149     """ + jars.map(jar => groovy_string(File.platform_path(jar))).mkString("", ",\n    ", ")") +
   155     """ + jar_files.map(jar => groovy_string(File.platform_path(jar))).mkString("", ",\n    ", ")") +
   150 """
   156 """
   151 }
   157 }
   152 """)
   158 """)
   153   }
   159   }
   154 
   160