11#! / usr/ bin/ env kotlin
22
33@file:JvmName(" ReleaseNotesGenerator" )
4- @file:CompilerOptions(" -jvm-target" , " 11 " )
4+ @file:CompilerOptions(" -jvm-target" , " 17 " )
55@file:Repository(" https://repo.maven.apache.org/maven2" )
6- @file:Repository(" https://jcenter.bintray.com" )
7- @file:Repository(" https://jitpack.io" )
86@file:DependsOn(" com.rometools:rome:2.1.0" )
9- @file:DependsOn(" org.jsoup:jsoup:1.18.3" )
7+ @file:DependsOn(" org.jsoup:jsoup:1.21.1" )
8+
9+ @file:Import(" retry.kts" )
1010
1111import com.rometools.rome.io.SyndFeedInput
1212import com.rometools.rome.io.XmlReader
@@ -17,16 +17,17 @@ import java.net.URI
1717import kotlin.io.path.Path
1818import kotlin.io.path.bufferedWriter
1919import kotlin.io.path.writeText
20- import kotlin.time.Duration.Companion.seconds
20+
21+ typealias LinkString = String
22+ typealias LinkDocument = Pair <LinkString , Document >
2123
2224val resultFile = Path (" release-notes.html" )
23- val waitTime = 10 .seconds
2425val feedUrl = URI (" https://developer.android.com/feeds/androidx-release-notes.xml" ).toURL()
2526val writer = resultFile.bufferedWriter()
2627val reader = tryTo(" initialize the feed reader" ) {
2728 // NOTE: Use this to test for a complicated release notes
2829 // XmlReader(File("test-feed-result.xml"))
29- XmlReader (feedUrl)
30+ XmlReader (feedUrl.openStream() )
3031}
3132val feed = SyndFeedInput ().build(reader)
3233val latestRelease = feed.entries.first()
4041 .parse(latestReleaseItems)
4142 .select(" a" )
4243 .asSequence()
43- .map(::toLink)
44- .map(::toDocument )
45- .map(::toReleaseNote)
44+ .map(Element ::toLink)
45+ .map(LinkString ::toLinkDocument )
46+ .map(LinkDocument ::toReleaseNote)
4647 .forEach(writer::write)
4748 .also { writer.close() }
4849 .also { reader.close() }
@@ -51,44 +52,16 @@ Jsoup
5152val text = Jsoup .parse(resultFile).wholeText()
5253Path (" release-notes.txt" ).writeText(text)
5354
54- // TODO: Duplicate; use the retry.main.kts script.
55- // See other scripts for example usage.
56- // NOTE that currently, IntelliJ code features break when importing external scripts.
57- /* *
58- * Try [forAtMost] times to run the block without exception.
59- *
60- * We could also make subsequent runs wait
61- * for an [exponential delay](https://en.wikipedia.org/wiki/Exponential_backoff).
62- * See [this article](https://dzone.com/articles/understanding-retry-pattern-with-exponential-back).
63- *
64- * I wrote this function myself.
65- * It is interesting that [this solution](https://stackoverflow.com/a/46890009)
66- * proposed by Roman Elizarov is very similar to mine.
67- */
68- fun <T > tryTo (
69- description : String ,
70- forAtMost : Int = 5,
71- block : () -> T
72- ): T {
73- repeat(forAtMost) {
74- runCatching(block).onSuccess { return it }
75- println (" Failed to $description ." )
76- println (" Trying again in $waitTime \n " )
77- Thread .sleep(waitTime.inWholeMilliseconds)
78- }
79- error(" All attempts to $description failed." )
80- }
81-
82- fun toLink (element : Element ) = element.attr(" href" )
55+ fun Element.toLink () = this .attr(" href" )
8356
8457// FIXME: Use plain Jsoup.connect()... and remove Pair creation (to)
8558// See https://github.com/jhy/jsoup/issues/1686 for the reason.
86- fun toDocument ( link : String ) = tryTo(" get $link " ) {
87- link to Jsoup .connect(link ).get()
59+ fun LinkString. toLinkDocument ( ) = tryTo(" get $this " ) {
60+ this to Jsoup .connect(this ).get()
8861}
8962
90- fun toReleaseNote (pair : Pair < String , Document > ): String {
91- val (link, document) = pair
63+ fun LinkDocument. toReleaseNote (): String {
64+ val (link, document) = this
9265 val id = link.substringAfter(" #" )
9366 val name = document.extractName(id)
9467 val version = document.extractVersion(id)
0 commit comments