10 object Build_Release |
10 object Build_Release |
11 { |
11 { |
12 /** release info **/ |
12 /** release info **/ |
13 |
13 |
14 sealed case class Bundle_Info( |
14 sealed case class Bundle_Info( |
15 platform_family: String, |
15 platform: Platform.Family.Value, |
16 platform_description: String, |
16 platform_description: String, |
17 main: String, |
17 main: String, |
18 fallback: Option[String]) |
18 fallback: Option[String]) |
19 { |
19 { |
20 def names: List[String] = main :: fallback.toList |
20 def names: List[String] = main :: fallback.toList |
35 def other_isabelle(dir: Path): Other_Isabelle = |
35 def other_isabelle(dir: Path): Other_Isabelle = |
36 Other_Isabelle(dir + Path.explode(dist_name), |
36 Other_Isabelle(dir + Path.explode(dist_name), |
37 isabelle_identifier = dist_name + "-build", |
37 isabelle_identifier = dist_name + "-build", |
38 progress = progress) |
38 progress = progress) |
39 |
39 |
40 def bundle_info(platform_family: String): Bundle_Info = |
40 def bundle_info(platform: Platform.Family.Value): Bundle_Info = |
41 platform_family match { |
41 platform match { |
42 case "linux" => Bundle_Info("linux", "Linux", dist_name + "_app.tar.gz", None) |
42 case Platform.Family.linux => |
43 case "windows" => Bundle_Info("windows", "Windows", dist_name + ".exe", None) |
43 Bundle_Info(platform, "Linux", dist_name + "_app.tar.gz", None) |
44 case "macos" => |
44 case Platform.Family.macos => |
45 Bundle_Info("macos", "Mac OS X", dist_name + ".dmg", Some(dist_name + "_dmg.tar.gz")) |
45 Bundle_Info(platform, "Mac OS X", dist_name + ".dmg", Some(dist_name + "_dmg.tar.gz")) |
46 case _ => error("Unknown platform family " + quote(platform_family)) |
46 case Platform.Family.windows => |
|
47 Bundle_Info(platform, "Windows", dist_name + ".exe", None) |
47 } |
48 } |
48 } |
49 } |
49 |
50 |
50 |
51 |
51 |
52 |
133 } |
134 } |
134 |
135 |
135 |
136 |
136 /* bundled components */ |
137 /* bundled components */ |
137 |
138 |
138 class Bundled(platform: String = "") |
139 class Bundled(platform: Option[Platform.Family.Value] = None) |
139 { |
140 { |
140 def detect(s: String): Boolean = |
141 def detect(s: String): Boolean = |
141 s.startsWith("#bundled") && !s.startsWith("#bundled ") |
142 s.startsWith("#bundled") && !s.startsWith("#bundled ") |
142 |
143 |
143 def apply(name: String): String = |
144 def apply(name: String): String = |
144 "#bundled" + (if (platform == "") "" else "-" + platform) + ":" + name |
145 "#bundled" + (platform match { case None => "" case Some(plat) => "-" + plat }) + ":" + name |
145 |
146 |
146 private val Pattern1 = ("""^#bundled:(.*)$""").r |
147 private val Pattern1 = ("""^#bundled:(.*)$""").r |
147 private val Pattern2 = ("""^#bundled-(.*):(.*)$""").r |
148 private val Pattern2 = ("""^#bundled-(.*):(.*)$""").r |
148 |
149 |
149 def unapply(s: String): Option[String] = |
150 def unapply(s: String): Option[String] = |
150 s match { |
151 s match { |
151 case Pattern1(name) => Some(name) |
152 case Pattern1(name) => Some(name) |
152 case Pattern2(platform1, name) if platform == platform1 => Some(name) |
153 case Pattern2(Platform.Family(plat), name) if platform == Some(plat) => Some(name) |
153 case _ => None |
154 case _ => None |
154 } |
155 } |
155 } |
156 } |
156 |
157 |
157 def record_bundled_components(dir: Path) |
158 def record_bundled_components(dir: Path) |
158 { |
159 { |
159 val catalogs = |
160 val catalogs = |
160 List("main", "bundled").map((_, new Bundled())) ::: |
161 List("main", "bundled").map((_, new Bundled())) ::: |
161 default_platform_families.flatMap(platform => |
162 default_platform_families.flatMap(platform => |
162 List(platform, "bundled-" + platform).map((_, new Bundled(platform = platform)))) |
163 List(platform.toString, "bundled-" + platform.toString). |
|
164 map((_, new Bundled(platform = Some(platform))))) |
163 |
165 |
164 File.append(Components.components(dir), |
166 File.append(Components.components(dir), |
165 terminate_lines("#bundled components" :: |
167 terminate_lines("#bundled components" :: |
166 (for { |
168 (for { |
167 (catalog, bundled) <- catalogs.iterator |
169 (catalog, bundled) <- catalogs.iterator |
170 line <- split_lines(File.read(path)) |
172 line <- split_lines(File.read(path)) |
171 if line.nonEmpty && !line.startsWith("#") && !line.startsWith("jedit_build") |
173 if line.nonEmpty && !line.startsWith("#") && !line.startsWith("jedit_build") |
172 } yield bundled(line)).toList)) |
174 } yield bundled(line)).toList)) |
173 } |
175 } |
174 |
176 |
175 def get_bundled_components(dir: Path, platform: String): (List[String], String) = |
177 def get_bundled_components(dir: Path, platform: Platform.Family.Value): (List[String], String) = |
176 { |
178 { |
177 val Bundled = new Bundled(platform) |
179 val Bundled = new Bundled(platform = Some(platform)) |
178 val components = |
180 val components = |
179 for { |
181 for { |
180 Bundled(name) <- Components.read_components(dir) |
182 Bundled(name) <- Components.read_components(dir) |
181 if !name.startsWith("jedit_build") |
183 if !name.startsWith("jedit_build") |
182 } yield name |
184 } yield name |
183 val jdk_component = |
185 val jdk_component = |
184 components.find(_.startsWith("jdk")) getOrElse error("Missing jdk component") |
186 components.find(_.startsWith("jdk")) getOrElse error("Missing jdk component") |
185 (components, jdk_component) |
187 (components, jdk_component) |
186 } |
188 } |
187 |
189 |
188 def activate_bundled_components(dir: Path, platform: String) |
190 def activate_bundled_components(dir: Path, platform: Platform.Family.Value) |
189 { |
191 { |
190 val Bundled = new Bundled(platform) |
192 val Bundled = new Bundled(platform = Some(platform)) |
191 Components.write_components(dir, |
193 Components.write_components(dir, |
192 Components.read_components(dir).flatMap(line => |
194 Components.read_components(dir).flatMap(line => |
193 line match { |
195 line match { |
194 case Bundled(name) => |
196 case Bundled(name) => |
195 if (Components.check_dir(Components.contrib(dir, name))) |
197 if (Components.check_dir(Components.contrib(dir, name))) |
220 Isabelle_System.gnutar(args, cwd = dir.file).check |
222 Isabelle_System.gnutar(args, cwd = dir.file).check |
221 |
223 |
222 private def tar_options: String = |
224 private def tar_options: String = |
223 if (Platform.is_macos) "--owner=root --group=staff" else "--owner=root --group=root" |
225 if (Platform.is_macos) "--owner=root --group=staff" else "--owner=root --group=root" |
224 |
226 |
225 private val default_platform_families = List("linux", "windows", "macos") |
227 private val default_platform_families = |
|
228 List(Platform.Family.linux, Platform.Family.windows, Platform.Family.macos) |
226 |
229 |
227 def build_release(base_dir: Path, |
230 def build_release(base_dir: Path, |
228 options: Options, |
231 options: Options, |
229 components_base: Option[Path] = None, |
232 components_base: Option[Path] = None, |
230 progress: Progress = No_Progress, |
233 progress: Progress = No_Progress, |
231 rev: String = "", |
234 rev: String = "", |
232 afp_rev: String = "", |
235 afp_rev: String = "", |
233 official_release: Boolean = false, |
236 official_release: Boolean = false, |
234 proper_release_name: Option[String] = None, |
237 proper_release_name: Option[String] = None, |
235 platform_families: List[String] = default_platform_families, |
238 platform_families: List[Platform.Family.Value] = default_platform_families, |
236 website: Option[Path] = None, |
239 website: Option[Path] = None, |
237 build_library: Boolean = false, |
240 build_library: Boolean = false, |
238 parallel_jobs: Int = 1, |
241 parallel_jobs: Int = 1, |
239 remote_mac: String = ""): Release = |
242 remote_mac: String = ""): Release = |
240 { |
243 { |
394 val bundle_archive = release.dist_dir + Path.explode(bundle) |
397 val bundle_archive = release.dist_dir + Path.explode(bundle) |
395 if (bundle_archive.is_file) |
398 if (bundle_archive.is_file) |
396 progress.echo_warning("Application bundle already exists: " + bundle_archive) |
399 progress.echo_warning("Application bundle already exists: " + bundle_archive) |
397 else { |
400 else { |
398 val isabelle_name = release.dist_name |
401 val isabelle_name = release.dist_name |
399 val platform = bundle_info.platform_family |
402 val platform = bundle_info.platform |
400 |
403 |
401 progress.echo("\nApplication bundle for " + platform + ": " + bundle_archive) |
404 progress.echo("\nApplication bundle for " + platform + ": " + bundle_archive) |
402 |
405 |
403 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
406 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
404 { |
407 { |
454 val jedit_props = Path.explode("src/Tools/jEdit/dist/properties/jEdit.props") |
457 val jedit_props = Path.explode("src/Tools/jEdit/dist/properties/jEdit.props") |
455 |
458 |
456 |
459 |
457 // platform-specific setup (inside archive) |
460 // platform-specific setup (inside archive) |
458 |
461 |
459 if (platform == "linux") { |
462 if (platform == Platform.Family.linux) { |
460 File.write(isabelle_target + Path.explode(isabelle_name + ".options"), |
463 File.write(isabelle_target + Path.explode(isabelle_name + ".options"), |
461 terminate_lines(java_options_title :: java_options)) |
464 terminate_lines(java_options_title :: java_options)) |
462 |
465 |
463 val isabelle_run = isabelle_target + Path.explode(isabelle_name + ".run") |
466 val isabelle_run = isabelle_target + Path.explode(isabelle_name + ".run") |
464 File.write(isabelle_run, |
467 File.write(isabelle_run, |
471 val linux_app = isabelle_target + Path.explode("contrib/linux_app") |
474 val linux_app = isabelle_target + Path.explode("contrib/linux_app") |
472 File.move(linux_app + Path.explode("Isabelle"), |
475 File.move(linux_app + Path.explode("Isabelle"), |
473 isabelle_target + Path.explode(isabelle_name)) |
476 isabelle_target + Path.explode(isabelle_name)) |
474 Isabelle_System.rm_tree(linux_app) |
477 Isabelle_System.rm_tree(linux_app) |
475 } |
478 } |
476 else if (platform == "macos") { |
479 else if (platform == Platform.Family.macos) { |
477 File.move(isabelle_target + Path.explode("contrib/macos_app"), tmp_dir) |
480 File.move(isabelle_target + Path.explode("contrib/macos_app"), tmp_dir) |
478 File.write(isabelle_target + jedit_props, |
481 File.write(isabelle_target + jedit_props, |
479 File.read(isabelle_target + jedit_props) |
482 File.read(isabelle_target + jedit_props) |
480 .replaceAll("lookAndFeel=.*", "lookAndFeel=com.apple.laf.AquaLookAndFeel") |
483 .replaceAll("lookAndFeel=.*", "lookAndFeel=com.apple.laf.AquaLookAndFeel") |
481 .replaceAll("delete-line.shortcut=.*", "delete-line.shortcut=C+d") |
484 .replaceAll("delete-line.shortcut=.*", "delete-line.shortcut=C+d") |
482 .replaceAll("delete.shortcut2=.*", "delete.shortcut2=A+d") |
485 .replaceAll("delete.shortcut2=.*", "delete.shortcut2=A+d") |
483 .replaceAll("plugin-blacklist.MacOSX.jar=true", "plugin-blacklist.MacOSX.jar=")) |
486 .replaceAll("plugin-blacklist.MacOSX.jar=true", "plugin-blacklist.MacOSX.jar=")) |
484 } |
487 } |
485 else if (platform == "windows") { |
488 else if (platform == Platform.Family.windows) { |
486 val app_template = Path.explode("~~/Admin/Windows/launch4j") |
489 val app_template = Path.explode("~~/Admin/Windows/launch4j") |
487 val cygwin_template = Path.explode("~~/Admin/Windows/Cygwin") |
490 val cygwin_template = Path.explode("~~/Admin/Windows/Cygwin") |
488 |
491 |
489 File.move(isabelle_target + Path.explode("contrib/windows_app"), tmp_dir) |
492 File.move(isabelle_target + Path.explode("contrib/windows_app"), tmp_dir) |
490 |
493 |
563 |
566 |
564 // platform-specific application (outside archive) |
567 // platform-specific application (outside archive) |
565 |
568 |
566 progress.echo("Application for " + platform + " ...") |
569 progress.echo("Application for " + platform + " ...") |
567 |
570 |
568 if (platform == "linux") { |
571 if (platform == Platform.Family.linux) { |
569 File.link( |
572 File.link( |
570 Path.explode(isabelle_name + "_linux.tar.gz"), |
573 Path.explode(isabelle_name + "_linux.tar.gz"), |
571 release.dist_dir + Path.explode(isabelle_name + "_app.tar.gz"), |
574 release.dist_dir + Path.explode(isabelle_name + "_app.tar.gz"), |
572 force = true) |
575 force = true) |
573 } |
576 } |
574 else if (platform == "macos") { |
577 else if (platform == Platform.Family.macos) { |
575 val dmg_dir = tmp_dir + Path.explode("macos_app/dmg") |
578 val dmg_dir = tmp_dir + Path.explode("macos_app/dmg") |
576 val app_dir = dmg_dir + Path.explode(isabelle_name + ".app") |
579 val app_dir = dmg_dir + Path.explode(isabelle_name + ".app") |
577 File.move(dmg_dir + Path.explode("Isabelle.app"), app_dir) |
580 File.move(dmg_dir + Path.explode("Isabelle.app"), app_dir) |
578 |
581 |
579 val app_contents = app_dir + Path.explode("Contents") |
582 val app_contents = app_dir + Path.explode("Contents") |
692 progress.echo_warning("Library archive already exists: " + release.isabelle_library_archive) |
695 progress.echo_warning("Library archive already exists: " + release.isabelle_library_archive) |
693 } |
696 } |
694 else { |
697 else { |
695 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
698 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
696 { |
699 { |
697 val platform = Isabelle_System.getenv_strict("ISABELLE_PLATFORM_FAMILY") |
|
698 val bundle = |
700 val bundle = |
699 release.dist_dir + Path.explode(release.dist_name + "_" + platform + ".tar.gz") |
701 release.dist_dir + Path.explode(release.dist_name + "_" + Platform.family + ".tar.gz") |
700 execute_tar(tmp_dir, "-xzf " + File.bash_path(bundle)) |
702 execute_tar(tmp_dir, "-xzf " + File.bash_path(bundle)) |
701 |
703 |
702 val other_isabelle = release.other_isabelle(tmp_dir) |
704 val other_isabelle = release.other_isabelle(tmp_dir) |
703 |
705 |
704 Isabelle_System.mkdirs(other_isabelle.etc) |
706 Isabelle_System.mkdirs(other_isabelle.etc) |
765 "R:" -> (arg => proper_release_name = Some(arg)), |
767 "R:" -> (arg => proper_release_name = Some(arg)), |
766 "W:" -> (arg => website = Some(Path.explode(arg))), |
768 "W:" -> (arg => website = Some(Path.explode(arg))), |
767 "j:" -> (arg => parallel_jobs = Value.Int.parse(arg)), |
769 "j:" -> (arg => parallel_jobs = Value.Int.parse(arg)), |
768 "l" -> (_ => build_library = true), |
770 "l" -> (_ => build_library = true), |
769 "o:" -> (arg => options = options + arg), |
771 "o:" -> (arg => options = options + arg), |
770 "p:" -> (arg => platform_families = space_explode(',', arg)), |
772 "p:" -> (arg => platform_families = space_explode(',', arg).map(Platform.Family.parse)), |
771 "r:" -> (arg => rev = arg)) |
773 "r:" -> (arg => rev = arg)) |
772 |
774 |
773 val more_args = getopts(args) |
775 val more_args = getopts(args) |
774 val base_dir = more_args match { case List(base_dir) => base_dir case _ => getopts.usage() } |
776 val base_dir = more_args match { case List(base_dir) => base_dir case _ => getopts.usage() } |
775 |
777 |