18 Isabelle_System.gnutar(args, dir = dir, strip = strip).check |
17 Isabelle_System.gnutar(args, dir = dir, strip = strip).check |
19 |
18 |
20 private def bash_java_opens(args: String*): String = |
19 private def bash_java_opens(args: String*): String = |
21 Bash.strings(args.toList.flatMap(arg => List("--add-opens", arg + "=ALL-UNNAMED"))) |
20 Bash.strings(args.toList.flatMap(arg => List("--add-opens", arg + "=ALL-UNNAMED"))) |
22 |
21 |
23 object Release_Context |
22 object Release_Context { |
24 { |
|
25 def apply( |
23 def apply( |
26 target_dir: Path, |
24 target_dir: Path, |
27 release_name: String = "", |
25 release_name: String = "", |
28 components_base: Path = Components.default_components_base, |
26 components_base: Path = Components.default_components_base, |
29 progress: Progress = new Progress): Release_Context = |
27 progress: Progress = new Progress |
30 { |
28 ): Release_Context = { |
31 val date = Date.now() |
29 val date = Date.now() |
32 val dist_name = proper_string(release_name) getOrElse ("Isabelle_" + Date.Format.date(date)) |
30 val dist_name = proper_string(release_name) getOrElse ("Isabelle_" + Date.Format.date(date)) |
33 val dist_dir = (target_dir + Path.explode("dist-" + dist_name)).absolute |
31 val dist_dir = (target_dir + Path.explode("dist-" + dist_name)).absolute |
34 new Release_Context(release_name, dist_name, dist_dir, components_base, progress) |
32 new Release_Context(release_name, dist_name, dist_dir, components_base, progress) |
35 } |
33 } |
38 class Release_Context private[Build_Release]( |
36 class Release_Context private[Build_Release]( |
39 val release_name: String, |
37 val release_name: String, |
40 val dist_name: String, |
38 val dist_name: String, |
41 val dist_dir: Path, |
39 val dist_dir: Path, |
42 val components_base: Path, |
40 val components_base: Path, |
43 val progress: Progress) |
41 val progress: Progress |
44 { |
42 ) { |
45 override def toString: String = dist_name |
43 override def toString: String = dist_name |
46 |
44 |
47 val isabelle: Path = Path.explode(dist_name) |
45 val isabelle: Path = Path.explode(dist_name) |
48 val isabelle_dir: Path = dist_dir + isabelle |
46 val isabelle_dir: Path = dist_dir + isabelle |
49 val isabelle_archive: Path = dist_dir + isabelle.tar.gz |
47 val isabelle_archive: Path = dist_dir + isabelle.tar.gz |
52 def other_isabelle(dir: Path): Other_Isabelle = |
50 def other_isabelle(dir: Path): Other_Isabelle = |
53 Other_Isabelle(dir + isabelle, |
51 Other_Isabelle(dir + isabelle, |
54 isabelle_identifier = dist_name + "-build", |
52 isabelle_identifier = dist_name + "-build", |
55 progress = progress) |
53 progress = progress) |
56 |
54 |
57 def make_announce(id: String): Unit = |
55 def make_announce(id: String): Unit = { |
58 { |
|
59 if (release_name.isEmpty) { |
56 if (release_name.isEmpty) { |
60 File.write(isabelle_dir + Path.explode("ANNOUNCE"), |
57 File.write(isabelle_dir + Path.explode("ANNOUNCE"), |
61 """ |
58 """ |
62 IMPORTANT NOTE |
59 IMPORTANT NOTE |
63 ============== |
60 ============== |
65 This is a snapshot of Isabelle/""" + id + """ from the repository. |
62 This is a snapshot of Isabelle/""" + id + """ from the repository. |
66 """) |
63 """) |
67 } |
64 } |
68 } |
65 } |
69 |
66 |
70 def make_contrib(): Unit = |
67 def make_contrib(): Unit = { |
71 { |
|
72 Isabelle_System.make_directory(Components.contrib(isabelle_dir)) |
68 Isabelle_System.make_directory(Components.contrib(isabelle_dir)) |
73 File.write(Components.contrib(isabelle_dir, name = "README"), |
69 File.write(Components.contrib(isabelle_dir, name = "README"), |
74 """This directory contains add-on components that contribute to the main |
70 """This directory contains add-on components that contribute to the main |
75 Isabelle distribution. Separate licensing conditions apply, see each |
71 Isabelle distribution. Separate licensing conditions apply, see each |
76 directory individually. |
72 directory individually. |
102 val ISABELLE: Path = Path.basic("Isabelle") |
98 val ISABELLE: Path = Path.basic("Isabelle") |
103 val ISABELLE_ID: Path = Path.explode("etc/ISABELLE_ID") |
99 val ISABELLE_ID: Path = Path.explode("etc/ISABELLE_ID") |
104 val ISABELLE_TAGS: Path = Path.explode("etc/ISABELLE_TAGS") |
100 val ISABELLE_TAGS: Path = Path.explode("etc/ISABELLE_TAGS") |
105 val ISABELLE_IDENTIFIER: Path = Path.explode("etc/ISABELLE_IDENTIFIER") |
101 val ISABELLE_IDENTIFIER: Path = Path.explode("etc/ISABELLE_IDENTIFIER") |
106 |
102 |
107 object Release_Archive |
103 object Release_Archive { |
108 { |
104 def make(bytes: Bytes, rename: String = ""): Release_Archive = { |
109 def make(bytes: Bytes, rename: String = ""): Release_Archive = |
|
110 { |
|
111 Isabelle_System.with_tmp_dir("tmp")(dir => |
105 Isabelle_System.with_tmp_dir("tmp")(dir => |
112 Isabelle_System.with_tmp_file("archive", ext = "tar.gz")(archive_path => |
106 Isabelle_System.with_tmp_file("archive", ext = "tar.gz")(archive_path => { |
113 { |
|
114 val isabelle_dir = Isabelle_System.make_directory(dir + ISABELLE) |
107 val isabelle_dir = Isabelle_System.make_directory(dir + ISABELLE) |
115 |
108 |
116 Bytes.write(archive_path, bytes) |
109 Bytes.write(archive_path, bytes) |
117 execute_tar(isabelle_dir, "-xzf " + File.bash_path(archive_path), strip = 1) |
110 execute_tar(isabelle_dir, "-xzf " + File.bash_path(archive_path), strip = 1) |
118 |
111 |
134 } |
127 } |
135 |
128 |
136 def read(path: Path, rename: String = ""): Release_Archive = |
129 def read(path: Path, rename: String = ""): Release_Archive = |
137 make(Bytes.read(path), rename = rename) |
130 make(Bytes.read(path), rename = rename) |
138 |
131 |
139 def get(url: String, rename: String = "", progress: Progress = new Progress): Release_Archive = |
132 def get( |
140 { |
133 url: String, |
|
134 rename: String = "", |
|
135 progress: Progress = new Progress |
|
136 ): Release_Archive = { |
141 val bytes = |
137 val bytes = |
142 if (Path.is_wellformed(url)) Bytes.read(Path.explode(url)) |
138 if (Path.is_wellformed(url)) Bytes.read(Path.explode(url)) |
143 else Isabelle_System.download(url, progress = progress).bytes |
139 else Isabelle_System.download(url, progress = progress).bytes |
144 make(bytes, rename = rename) |
140 make(bytes, rename = rename) |
145 } |
141 } |
146 } |
142 } |
147 |
143 |
148 case class Release_Archive private[Build_Release]( |
144 case class Release_Archive private[Build_Release]( |
149 bytes: Bytes, id: String, tags: String, identifier: String) |
145 bytes: Bytes, id: String, tags: String, identifier: String) { |
150 { |
|
151 override def toString: String = identifier |
146 override def toString: String = identifier |
152 } |
147 } |
153 |
148 |
154 |
149 |
155 |
150 |
156 /** generated content **/ |
151 /** generated content **/ |
157 |
152 |
158 /* bundled components */ |
153 /* bundled components */ |
159 |
154 |
160 class Bundled(platform: Option[Platform.Family.Value] = None) |
155 class Bundled(platform: Option[Platform.Family.Value] = None) { |
161 { |
|
162 def detect(s: String): Boolean = |
156 def detect(s: String): Boolean = |
163 s.startsWith("#bundled") && !s.startsWith("#bundled ") |
157 s.startsWith("#bundled") && !s.startsWith("#bundled ") |
164 |
158 |
165 def apply(name: String): String = |
159 def apply(name: String): String = |
166 "#bundled" + (platform match { case None => "" case Some(plat) => "-" + plat }) + ":" + name |
160 "#bundled" + (platform match { case None => "" case Some(plat) => "-" + plat }) + ":" + name |
174 case Pattern2(Platform.Family(plat), name) if platform == Some(plat) => Some(name) |
168 case Pattern2(Platform.Family(plat), name) if platform == Some(plat) => Some(name) |
175 case _ => None |
169 case _ => None |
176 } |
170 } |
177 } |
171 } |
178 |
172 |
179 def record_bundled_components(dir: Path): Unit = |
173 def record_bundled_components(dir: Path): Unit = { |
180 { |
|
181 val catalogs = |
174 val catalogs = |
182 List("main", "bundled").map((_, new Bundled())) ::: |
175 List("main", "bundled").map((_, new Bundled())) ::: |
183 Platform.Family.list.flatMap(platform => |
176 Platform.Family.list.flatMap(platform => |
184 List(platform.toString, "bundled-" + platform.toString). |
177 List(platform.toString, "bundled-" + platform.toString). |
185 map((_, new Bundled(platform = Some(platform))))) |
178 map((_, new Bundled(platform = Some(platform))))) |
193 line <- split_lines(File.read(path)) |
186 line <- split_lines(File.read(path)) |
194 if line.nonEmpty && !line.startsWith("#") |
187 if line.nonEmpty && !line.startsWith("#") |
195 } yield bundled(line)).toList)) |
188 } yield bundled(line)).toList)) |
196 } |
189 } |
197 |
190 |
198 def get_bundled_components(dir: Path, platform: Platform.Family.Value): (List[String], String) = |
191 def get_bundled_components(dir: Path, platform: Platform.Family.Value): (List[String], String) = { |
199 { |
|
200 val Bundled = new Bundled(platform = Some(platform)) |
192 val Bundled = new Bundled(platform = Some(platform)) |
201 val components = |
193 val components = |
202 for { Bundled(name) <- Components.read_components(dir) } yield name |
194 for { Bundled(name) <- Components.read_components(dir) } yield name |
203 val jdk_component = |
195 val jdk_component = |
204 components.find(_.startsWith("jdk")) getOrElse error("Missing jdk component") |
196 components.find(_.startsWith("jdk")) getOrElse error("Missing jdk component") |
205 (components, jdk_component) |
197 (components, jdk_component) |
206 } |
198 } |
207 |
199 |
208 def activate_components( |
200 def activate_components( |
209 dir: Path, platform: Platform.Family.Value, more_names: List[String]): Unit = |
201 dir: Path, platform: Platform.Family.Value, more_names: List[String]): Unit = { |
210 { |
|
211 def contrib_name(name: String): String = |
202 def contrib_name(name: String): String = |
212 Components.contrib(name = name).implode |
203 Components.contrib(name = name).implode |
213 |
204 |
214 val Bundled = new Bundled(platform = Some(platform)) |
205 val Bundled = new Bundled(platform = Some(platform)) |
215 Components.write_components(dir, |
206 Components.write_components(dir, |
229 |
220 |
230 private def build_heaps( |
221 private def build_heaps( |
231 options: Options, |
222 options: Options, |
232 platform: Platform.Family.Value, |
223 platform: Platform.Family.Value, |
233 build_sessions: List[String], |
224 build_sessions: List[String], |
234 local_dir: Path): Unit = |
225 local_dir: Path |
235 { |
226 ): Unit = { |
236 val server_option = "build_host_" + platform.toString |
227 val server_option = "build_host_" + platform.toString |
237 val ssh = |
228 val ssh = |
238 options.string(server_option) match { |
229 options.string(server_option) match { |
239 case "" => |
230 case "" => |
240 if (Platform.family == platform) SSH.Local |
231 if (Platform.family == platform) SSH.Local |
242 case SSH.Target(user, host) => |
233 case SSH.Target(user, host) => |
243 SSH.open_session(options, host = host, user = user) |
234 SSH.open_session(options, host = host, user = user) |
244 case s => error("Malformed option " + server_option + ": " + quote(s)) |
235 case s => error("Malformed option " + server_option + ": " + quote(s)) |
245 } |
236 } |
246 try { |
237 try { |
247 Isabelle_System.with_tmp_file("tmp", ext = "tar")(local_tmp_tar => |
238 Isabelle_System.with_tmp_file("tmp", ext = "tar")(local_tmp_tar => { |
248 { |
|
249 execute_tar(local_dir, "-cf " + File.bash_path(local_tmp_tar) + " .") |
239 execute_tar(local_dir, "-cf " + File.bash_path(local_tmp_tar) + " .") |
250 ssh.with_tmp_dir(remote_dir => |
240 ssh.with_tmp_dir(remote_dir => { |
251 { |
|
252 val remote_tmp_tar = remote_dir + Path.basic("tmp.tar") |
241 val remote_tmp_tar = remote_dir + Path.basic("tmp.tar") |
253 ssh.write_file(remote_tmp_tar, local_tmp_tar) |
242 ssh.write_file(remote_tmp_tar, local_tmp_tar) |
254 val remote_commands = |
243 val remote_commands = |
255 List( |
244 List( |
256 "cd " + File.bash_path(remote_dir), |
245 "cd " + File.bash_path(remote_dir), |
267 } |
256 } |
268 |
257 |
269 |
258 |
270 /* Isabelle application */ |
259 /* Isabelle application */ |
271 |
260 |
272 def make_isabelle_options(path: Path, options: List[String], line_ending: String = "\n"): Unit = |
261 def make_isabelle_options(path: Path, options: List[String], line_ending: String = "\n"): Unit = { |
273 { |
|
274 val title = "# Java runtime options" |
262 val title = "# Java runtime options" |
275 File.write(path, (title :: options).map(_ + line_ending).mkString) |
263 File.write(path, (title :: options).map(_ + line_ending).mkString) |
276 } |
264 } |
277 |
265 |
278 def make_isabelle_app( |
266 def make_isabelle_app( |
279 platform: Platform.Family.Value, |
267 platform: Platform.Family.Value, |
280 isabelle_target: Path, |
268 isabelle_target: Path, |
281 isabelle_name: String, |
269 isabelle_name: String, |
282 jdk_component: String, |
270 jdk_component: String, |
283 classpath: List[Path], |
271 classpath: List[Path], |
284 dock_icon: Boolean = false): Unit = |
272 dock_icon: Boolean = false): Unit = { |
285 { |
|
286 val script = """#!/usr/bin/env bash |
273 val script = """#!/usr/bin/env bash |
287 # |
274 # |
288 # Author: Makarius |
275 # Author: Makarius |
289 # |
276 # |
290 # Main Isabelle application script. |
277 # Main Isabelle application script. |
328 isabelle_target + Path.explode(isabelle_name)) |
315 isabelle_target + Path.explode(isabelle_name)) |
329 Isabelle_System.rm_tree(component_dir) |
316 Isabelle_System.rm_tree(component_dir) |
330 } |
317 } |
331 |
318 |
332 |
319 |
333 def make_isabelle_plist(path: Path, isabelle_name: String, isabelle_rev: String): Unit = |
320 def make_isabelle_plist(path: Path, isabelle_name: String, isabelle_rev: String): Unit = { |
334 { |
|
335 File.write(path, """<?xml version="1.0" ?> |
321 File.write(path, """<?xml version="1.0" ?> |
336 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
322 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
337 <plist version="1.0"> |
323 <plist version="1.0"> |
338 <dict> |
324 <dict> |
339 <key>CFBundleDevelopmentRegion</key> |
325 <key>CFBundleDevelopmentRegion</key> |
392 /* main */ |
378 /* main */ |
393 |
379 |
394 def use_release_archive( |
380 def use_release_archive( |
395 context: Release_Context, |
381 context: Release_Context, |
396 archive: Release_Archive, |
382 archive: Release_Archive, |
397 id: String = ""): Unit = |
383 id: String = "" |
398 { |
384 ): Unit = { |
399 if (id.nonEmpty && id != archive.id) { |
385 if (id.nonEmpty && id != archive.id) { |
400 error("Mismatch of release identification " + id + " vs. archive " + archive.id) |
386 error("Mismatch of release identification " + id + " vs. archive " + archive.id) |
401 } |
387 } |
402 |
388 |
403 if (!context.isabelle_archive.is_file || Bytes.read(context.isabelle_archive) != archive.bytes) { |
389 if (!context.isabelle_archive.is_file || Bytes.read(context.isabelle_archive) != archive.bytes) { |
406 } |
392 } |
407 |
393 |
408 def build_release_archive( |
394 def build_release_archive( |
409 context: Release_Context, |
395 context: Release_Context, |
410 version: String, |
396 version: String, |
411 parallel_jobs: Int = 1): Unit = |
397 parallel_jobs: Int = 1 |
412 { |
398 ): Unit = { |
413 val progress = context.progress |
399 val progress = context.progress |
414 |
400 |
415 val hg = Mercurial.repository(Path.ISABELLE_HOME) |
401 val hg = Mercurial.repository(Path.ISABELLE_HOME) |
416 val id = |
402 val id = |
417 try { hg.id(version) } |
403 try { hg.id(version) } |
495 platform_families: List[Platform.Family.Value] = default_platform_families, |
481 platform_families: List[Platform.Family.Value] = default_platform_families, |
496 more_components: List[Path] = Nil, |
482 more_components: List[Path] = Nil, |
497 website: Option[Path] = None, |
483 website: Option[Path] = None, |
498 build_sessions: List[String] = Nil, |
484 build_sessions: List[String] = Nil, |
499 build_library: Boolean = false, |
485 build_library: Boolean = false, |
500 parallel_jobs: Int = 1): Unit = |
486 parallel_jobs: Int = 1 |
501 { |
487 ): Unit = { |
502 val progress = context.progress |
488 val progress = context.progress |
503 |
489 |
504 |
490 |
505 /* release directory */ |
491 /* release directory */ |
506 |
492 |
508 |
494 |
509 for (path <- List(context.isabelle, ISABELLE)) { |
495 for (path <- List(context.isabelle, ISABELLE)) { |
510 Isabelle_System.rm_tree(context.dist_dir + path) |
496 Isabelle_System.rm_tree(context.dist_dir + path) |
511 } |
497 } |
512 |
498 |
513 Isabelle_System.with_tmp_file("archive", ext = "tar.gz")(archive_path => |
499 Isabelle_System.with_tmp_file("archive", ext = "tar.gz")(archive_path => { |
514 { |
|
515 Bytes.write(archive_path, archive.bytes) |
500 Bytes.write(archive_path, archive.bytes) |
516 val extract = |
501 val extract = |
517 List("README", "NEWS", "ANNOUNCE", "COPYRIGHT", "CONTRIBUTORS", "doc"). |
502 List("README", "NEWS", "ANNOUNCE", "COPYRIGHT", "CONTRIBUTORS", "doc"). |
518 map(name => context.dist_name + "/" + name) |
503 map(name => context.dist_name + "/" + name) |
519 execute_tar(context.dist_dir, |
504 execute_tar(context.dist_dir, |
531 val isabelle_name = context.dist_name |
516 val isabelle_name = context.dist_name |
532 val platform = bundle_info.platform |
517 val platform = bundle_info.platform |
533 |
518 |
534 progress.echo("\nApplication bundle for " + platform) |
519 progress.echo("\nApplication bundle for " + platform) |
535 |
520 |
536 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
521 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => { |
537 { |
|
538 // release archive |
522 // release archive |
539 |
523 |
540 execute_tar(tmp_dir, "-xzf " + File.bash_path(context.isabelle_archive)) |
524 execute_tar(tmp_dir, "-xzf " + File.bash_path(context.isabelle_archive)) |
541 val other_isabelle = context.other_isabelle(tmp_dir) |
525 val other_isabelle = context.other_isabelle(tmp_dir) |
542 val isabelle_target = other_isabelle.isabelle_home |
526 val isabelle_target = other_isabelle.isabelle_home |
576 yield { |
560 yield { |
577 val s = "-Dapple.awt.application.name=" |
561 val s = "-Dapple.awt.application.name=" |
578 if (opt.startsWith(s)) s + isabelle_name else opt |
562 if (opt.startsWith(s)) s + isabelle_name else opt |
579 }) ::: List("-Disabelle.jedit_server=" + isabelle_name) |
563 }) ::: List("-Disabelle.jedit_server=" + isabelle_name) |
580 |
564 |
581 val classpath: List[Path] = |
565 val classpath: List[Path] = { |
582 { |
|
583 val base = isabelle_target.absolute |
566 val base = isabelle_target.absolute |
584 val classpath1 = Path.split(other_isabelle.getenv("ISABELLE_CLASSPATH")) |
567 val classpath1 = Path.split(other_isabelle.getenv("ISABELLE_CLASSPATH")) |
585 val classpath2 = Path.split(other_isabelle.getenv("ISABELLE_SETUP_CLASSPATH")) |
568 val classpath2 = Path.split(other_isabelle.getenv("ISABELLE_SETUP_CLASSPATH")) |
586 (classpath1 ::: classpath2).map(path => |
569 (classpath1 ::: classpath2).map(path => { |
587 { |
|
588 val abs_path = path.absolute |
570 val abs_path = path.absolute |
589 File.relative_path(base, abs_path) match { |
571 File.relative_path(base, abs_path) match { |
590 case Some(rel_path) => rel_path |
572 case Some(rel_path) => rel_path |
591 case None => error("Bad classpath element: " + abs_path) |
573 case None => error("Bad classpath element: " + abs_path) |
592 } |
574 } |
831 if (build_library) { |
813 if (build_library) { |
832 if (context.isabelle_library_archive.is_file) { |
814 if (context.isabelle_library_archive.is_file) { |
833 progress.echo_warning("Library archive already exists: " + context.isabelle_library_archive) |
815 progress.echo_warning("Library archive already exists: " + context.isabelle_library_archive) |
834 } |
816 } |
835 else { |
817 else { |
836 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => |
818 Isabelle_System.with_tmp_dir("build_release")(tmp_dir => { |
837 { |
|
838 val bundle = |
819 val bundle = |
839 context.dist_dir + Path.explode(context.dist_name + "_" + Platform.family + ".tar.gz") |
820 context.dist_dir + Path.explode(context.dist_name + "_" + Platform.family + ".tar.gz") |
840 execute_tar(tmp_dir, "-xzf " + File.bash_path(bundle)) |
821 execute_tar(tmp_dir, "-xzf " + File.bash_path(bundle)) |
841 |
822 |
842 val other_isabelle = context.other_isabelle(tmp_dir) |
823 val other_isabelle = context.other_isabelle(tmp_dir) |
860 |
841 |
861 |
842 |
862 |
843 |
863 /** command line entry point **/ |
844 /** command line entry point **/ |
864 |
845 |
865 def main(args: Array[String]): Unit = |
846 def main(args: Array[String]): Unit = { |
866 { |
|
867 Command_Line.tool { |
847 Command_Line.tool { |
868 var afp_rev = "" |
848 var afp_rev = "" |
869 var components_base: Path = Components.default_components_base |
849 var components_base: Path = Components.default_components_base |
870 var target_dir = Path.current |
850 var target_dir = Path.current |
871 var release_name = "" |
851 var release_name = "" |