72558
|
1 |
/* Title: Pure/General/mailman.scala
|
|
2 |
Author: Makarius
|
|
3 |
|
|
4 |
Support for Mailman list servers.
|
|
5 |
*/
|
|
6 |
|
|
7 |
package isabelle
|
|
8 |
|
|
9 |
|
|
10 |
import java.net.URL
|
|
11 |
|
74906
|
12 |
import scala.util.matching.Regex
|
|
13 |
|
72558
|
14 |
|
|
15 |
object Mailman
|
|
16 |
{
|
72559
|
17 |
/* mailing list archives */
|
|
18 |
|
74906
|
19 |
def archive(url: URL, msg_format: Msg_Format, name: String = ""): Archive =
|
72558
|
20 |
{
|
74906
|
21 |
val list_url =
|
|
22 |
Url(Library.take_suffix[Char](_ == '/', Url.trim_index(url).toString.toList)._1.mkString + "/")
|
|
23 |
|
|
24 |
val html = Url.read(list_url)
|
72558
|
25 |
val title =
|
74905
|
26 |
"""<title>The ([^</>]*) Archives</title>""".r.findFirstMatchIn(html).map(_.group(1))
|
|
27 |
val hrefs_text =
|
|
28 |
"""href="([^"]+\.txt(?:\.gz)?)"""".r.findAllMatchIn(html).map(_.group(1)).toList
|
|
29 |
|
72558
|
30 |
val list_name =
|
|
31 |
(proper_string(name) orElse title).getOrElse(error("Failed to determine mailing list name"))
|
74906
|
32 |
new Archive(list_url, list_name, msg_format, hrefs_text)
|
72558
|
33 |
}
|
|
34 |
|
74906
|
35 |
abstract class Msg_Format
|
|
36 |
{
|
|
37 |
def regex: Regex
|
|
38 |
}
|
|
39 |
|
|
40 |
class Archive private[Mailman](
|
|
41 |
val list_url: URL,
|
|
42 |
val list_name: String,
|
|
43 |
msg_format: Msg_Format,
|
|
44 |
hrefs_text: List[String])
|
72558
|
45 |
{
|
|
46 |
override def toString: String = list_name
|
|
47 |
|
74906
|
48 |
private def hrefs_msg: List[String] =
|
|
49 |
(for {
|
|
50 |
href <- """href="([^"]+)/date.html"""".r.findAllMatchIn(Url.read(list_url)).map(_.group(1))
|
|
51 |
html = Url.read(new URL(list_url, href + "/date.html"))
|
|
52 |
msg <- msg_format.regex.findAllMatchIn(html).map(_.group(1))
|
|
53 |
} yield href + "/" + msg).toList
|
|
54 |
|
|
55 |
def get(target_dir: Path, href: String, progress: Progress = new Progress): Option[Path] =
|
72558
|
56 |
{
|
|
57 |
val dir = target_dir + Path.basic(list_name)
|
74906
|
58 |
val path = dir + Path.explode(href)
|
|
59 |
val url = new URL(list_url, href)
|
|
60 |
val connection = url.openConnection
|
|
61 |
try {
|
|
62 |
val length = connection.getContentLengthLong
|
|
63 |
val timestamp = connection.getLastModified
|
|
64 |
val file = path.file
|
|
65 |
if (file.isFile && file.length == length && file.lastModified == timestamp) None
|
|
66 |
else {
|
|
67 |
Isabelle_System.make_directory(path.dir)
|
|
68 |
progress.echo("Getting " + url)
|
|
69 |
val bytes =
|
|
70 |
using(connection.getInputStream)(Bytes.read_stream(_, hint = length.toInt max 1024))
|
|
71 |
Bytes.write(file, bytes)
|
|
72 |
file.setLastModified(timestamp)
|
|
73 |
Some(path)
|
|
74 |
}
|
|
75 |
}
|
|
76 |
finally { connection.getInputStream.close() }
|
|
77 |
}
|
72558
|
78 |
|
74906
|
79 |
def download_text(target_dir: Path, progress: Progress = new Progress): List[Path] =
|
|
80 |
hrefs_text.flatMap(get(target_dir, _, progress = progress))
|
|
81 |
|
|
82 |
def download_msg(target_dir: Path, progress: Progress = new Progress): List[Path] =
|
|
83 |
hrefs_msg.flatMap(get(target_dir, _, progress = progress))
|
74907
|
84 |
|
|
85 |
def download(target_dir: Path, progress: Progress = new Progress): List[Path] =
|
|
86 |
download_text(target_dir, progress = progress) :::
|
|
87 |
download_msg(target_dir, progress = progress)
|
72558
|
88 |
}
|
72559
|
89 |
|
|
90 |
|
|
91 |
/* Isabelle mailing lists */
|
|
92 |
|
|
93 |
def isabelle_users: Archive =
|
74906
|
94 |
archive(Url("https://lists.cam.ac.uk/pipermail/cl-isabelle-users"), name = "isabelle-users",
|
|
95 |
msg_format =
|
|
96 |
new Msg_Format { val regex: Regex = """<li><a name="\d+" href="(msg\d+\.html)">""".r })
|
72559
|
97 |
|
|
98 |
def isabelle_dev: Archive =
|
74906
|
99 |
archive(Url("https://mailmanbroy.in.tum.de/pipermail/isabelle-dev"),
|
|
100 |
new Msg_Format { val regex: Regex = """<LI><A HREF="(\d+\.html)">""".r })
|
72558
|
101 |
}
|