diff --git a/sbt-tzdb/src/main/resources/native/TzdbZoneRulesProvider.scala b/sbt-tzdb/src/main/resources/native/TzdbZoneRulesProvider.scala new file mode 100644 index 0000000..5b5b469 --- /dev/null +++ b/sbt-tzdb/src/main/resources/native/TzdbZoneRulesProvider.scala @@ -0,0 +1,52 @@ +package + +import org.threeten.bp.DateTimeException + +import org.portablescala.reflect.annotation.EnableReflectiveInstantiation + +@EnableReflectiveInstantiation +final class TzdbZoneRulesProvider extends ZoneRulesProvider { + import zonedb.threeten.tzdb._ + + override protected def provideZoneIds: java.util.Set[String] = { + val zones = new java.util.HashSet[String]() + val zonesSet = (stdZones.keySet ++ fixedZones.keySet ++ zoneLinks.keySet) + zonesSet.foreach(zones.add(_)) + // I'm not totallly sure the reason why but TTB removes these ZoneIds + // zones.remove("UTC") + // zones.remove("GMT") + zones.remove("GMT0") + zones.remove("GMT+0") + zones.remove("GMT-0") + zones + } + + override protected def provideRules(regionId: String, + forCaching: Boolean): ZoneRules = { + val actualRegion = zoneLinks.getOrElse(regionId, regionId) + stdZones + .get(actualRegion) + .orElse( + fixedZones + .get(actualRegion)) + .getOrElse( + throw new DateTimeException(s"TimeZone Region $actualRegion unknown")) + } + + override protected def provideVersions( + zoneId: String): java.util.NavigableMap[String, ZoneRules] = { + val actualRegion = zoneLinks.getOrElse(zoneId, zoneId) + stdZones + .get(actualRegion) + .orElse( + fixedZones + .get(actualRegion)) + .map { z => + val r = new ZoneMap[String, ZoneRules] + r.put(version, z) + r + } + .getOrElse( + throw new DateTimeException(s"TimeZone Region $actualRegion unknown")) + } +} diff --git a/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/IOTasks.scala b/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/IOTasks.scala index 3e9f48a..1968294 100644 --- a/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/IOTasks.scala +++ b/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/IOTasks.scala @@ -1,4 +1,4 @@ -package io.gitub.sbt.tzdb +package io.github.sbt.tzdb import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream import java.io._ @@ -49,30 +49,29 @@ object IOTasks { } def generateTZDataSources( - base: File, - data: File, - log: Logger, - includeTTBP: Boolean, - jsOptimized: Boolean, - zonesFilter: String => Boolean + base: File, + data: File, + log: Logger, + includeTTBP: Boolean, + tzdbPlatform: TzdbPlugin.Platform, + zonesFilter: String => Boolean ): cats.effect.IO[List[File]] = for { paths <- tzDataSources(base, includeTTBP) _ <- cats.effect.IO(log.info(s"Generating tzdb from db at $data to $base")) _ <- cats.effect.IO(paths.foreach(t => t._3.getParentFile().mkdirs())) - f <- paths - .map(p => - if (jsOptimized) { - import kuyfi.TZDBCodeGenerator.OptimizedTreeGenerator._ + f <- paths.map { p => + tzdbPlatform match { + case TzdbPlugin.Platform.Js => + import kuyfi.TZDBCodeGenerator.OptimizedTreeGenerator.* TZDBCodeGenerator .exportAll(data, p._3, p._1, p._2, zonesFilter) - } else { - import kuyfi.TZDBCodeGenerator.PureTreeGenerator._ + case _ => + import kuyfi.TZDBCodeGenerator.PureTreeGenerator.* TZDBCodeGenerator .exportAll(data, p._3, p._1, p._2, zonesFilter) - } - ) - .sequence + } + }.sequence } yield f def providerFile(base: File, name: String, packageDir: String): cats.effect.IO[File] = @@ -125,8 +124,11 @@ object IOTasks { def download(url: String, to: File) = cats.effect.IO { - import gigahorse._, support.okhttp.Gigahorse - import scala.concurrent._, duration._ + import gigahorse.* + import support.okhttp.Gigahorse + + import scala.concurrent.* + import duration.* Gigahorse.withHttp(gigahorse.Config()) { http => val r = Gigahorse.url(url) val f = http.download(r, to) diff --git a/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/SbtTzdb.scala b/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/SbtTzdb.scala index 1e853cf..c55a42e 100644 --- a/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/SbtTzdb.scala +++ b/sbt-tzdb/src/main/scala/io/github/sbt/tzdb/SbtTzdb.scala @@ -1,4 +1,4 @@ -package io.gitub.sbt.tzdb +package io.github.sbt.tzdb import java.io.{ File => JFile } import sbt._ @@ -21,19 +21,27 @@ object TzdbPlugin extends AutoPlugin { val path: String = s"releases/tzdata$version" } + sealed abstract class Platform(val name: String) extends Product with Serializable + final object Platform { + final case object Jvm extends Platform("jvm") + final case object Js extends Platform("js") + final case object Native extends Platform("native") + } + object autoImport { /* * Settings */ - val zonesFilter = settingKey[String => Boolean]("Filter for zones") - val dbVersion = settingKey[TZDBVersion]("Version of the tzdb") - val tzdbCodeGen = + val zonesFilter = settingKey[String => Boolean]("Filter for zones") + val dbVersion = settingKey[TZDBVersion]("Version of the tzdb") + val tzdbCodeGen = taskKey[Seq[JFile]]("Generate scala.js compatible database of tzdb data") - val includeTTBP: SettingKey[Boolean] = + val includeTTBP: SettingKey[Boolean] = settingKey[Boolean]("Include also a provider for threeten bp") - val jsOptimized: SettingKey[Boolean] = - settingKey[Boolean]("Generates a version with smaller size but only usable on scala.js") + val tzdbPlatform: SettingKey[Platform] = settingKey[Platform]( + "The generated code is platform specific. Specify what is the target platform." + ) } import autoImport._ @@ -42,7 +50,7 @@ object TzdbPlugin extends AutoPlugin { zonesFilter := { case _ => true }, dbVersion := LatestVersion, includeTTBP := false, - jsOptimized := true + tzdbPlatform := Platform.Js ) override val projectSettings = Seq( @@ -62,7 +70,7 @@ object TzdbPlugin extends AutoPlugin { zonesFilter = zonesFilter.value, dbVersion = dbVersion.value, includeTTBP = includeTTBP.value, - jsOptimized = jsOptimized.value, + tzdbPlatform = tzdbPlatform.value, log = log ) } @@ -76,7 +84,7 @@ object TzdbPlugin extends AutoPlugin { zonesFilter: String => Boolean, dbVersion: TZDBVersion, includeTTBP: Boolean, - jsOptimized: Boolean, + tzdbPlatform: Platform, log: Logger ): Set[JFile] = { @@ -84,26 +92,28 @@ object TzdbPlugin extends AutoPlugin { import cats.syntax.all._ val tzdbData: JFile = resourcesManaged / "tzdb" - val sub = if (jsOptimized) "js" else "jvm" - val ttbp = IOTasks.copyProvider(sourceManaged, - sub, - "TzdbZoneRulesProvider.scala", - "org.threeten.bp.zone", - false + val ttbp = IOTasks.copyProvider( + sourceManaged, + tzdbPlatform.name, + "TzdbZoneRulesProvider.scala", + "org.threeten.bp.zone", + false + ) + val jt = IOTasks.copyProvider( + sourceManaged, + tzdbPlatform.name, + "TzdbZoneRulesProvider.scala", + "java.time.zone", + true ) - val jt = - IOTasks.copyProvider(sourceManaged, - sub, - "TzdbZoneRulesProvider.scala", - "java.time.zone", - true - ) val providerCopy = if (includeTTBP) List(ttbp, jt) else List(jt) (for { _ <- IOTasks.downloadTZDB(log, resourcesManaged, dbVersion) // Use it to detect if files have been already generated - p <- - IOTasks.providerFile(sourceManaged / sub, "TzdbZoneRulesProvider.scala", "java.time.zone") + p <- IOTasks.providerFile(sourceManaged / tzdbPlatform.name, + "TzdbZoneRulesProvider.scala", + "java.time.zone" + ) e <- effect.IO(p.exists) j <- if (e) effect.IO(List(p)) else providerCopy.sequence f <- if (e) IOTasks.tzDataSources(sourceManaged, includeTTBP).map(_.map(_._3)) @@ -112,7 +122,7 @@ object TzdbPlugin extends AutoPlugin { tzdbData, log, includeTTBP, - jsOptimized, + tzdbPlatform, zonesFilter ) } yield (j ::: f).toSet).unsafeRunSync diff --git a/sbt-tzdb/src/sbt-test/sbt-tzdb/jvm/build.sbt b/sbt-tzdb/src/sbt-test/sbt-tzdb/jvm/build.sbt index daf6c50..a50fff0 100644 --- a/sbt-tzdb/src/sbt-test/sbt-tzdb/jvm/build.sbt +++ b/sbt-tzdb/src/sbt-test/sbt-tzdb/jvm/build.sbt @@ -7,7 +7,7 @@ scalaVersion := "2.13.1" crossScalaVersions := Seq("2.13.1", "2.12.10") -jsOptimized := false +tzdbPlatform := TzdbPlugin.Platform.Jvm dbVersion := TzdbPlugin.Version("2019c")