Commit e5de8b0c authored by 35V LG84's avatar 35V LG84

Merge branch '35VLG84/wip/scala-2.13'

Initial Scala 2.13 support

See merge request: !14Signed-off-by: 35V LG84's avatar35V LG84 <35vlg84-x4e6b92@e257.fi>
parents 3140123a e4a17b09
Pipeline #75479706 passed with stage
in 16 minutes and 34 seconds
......@@ -3,36 +3,53 @@
### E257.FI: tackler
### https://gitlab.com/e257/accounting/tackler
###
# hseeberger images have ready-to-go sbt and scala at user's home,
# but that location and especially ~/.ivy2 is not cache-able by GitLab:
# https://gitlab.com/gitlab-org/gitlab-runner/issues/327
before_script:
- mkdir -p sbt-cache
- "[ -d sbt-cache/sbt ] || cp -a $HOME/.sbt/ sbt-cache/sbt/"
- "[ -d sbt-cache/ivy ] || cp -a $HOME/.ivy2/ sbt-cache/ivy/"
cache:
key: "$CI_BUILD_REF_NAME"
untracked: true
paths:
- "sbt-cache/sbt/1.0"
- "sbt-cache/sbt/boot"
- "sbt-cache/ivy/cache"
- "sbt-cache/boot"
- "sbt-cache/sbtboot"
test·jdk11:
image: "hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8"
variables:
SBT_OPTS: "-Dsbt.log.noformat=true -Dsbt.global.base=sbt-cache/sbt/1.0 -Dsbt.boot.directory=sbt-cache/sbt/boot -Dsbt.ivy.home=sbt-cache/ivy"
variables:
SBT_OPTS: "-Dsbt.global.base=sbt-cache/sbtboot -Dsbt.boot.directory=sbt-cache/boot -Dsbt.ivy.home=sbt-cache/ivy"
test·jdk11:
image: "hseeberger/scala-sbt:11.0.3_1.2.8_2.12.8"
stage: "test"
script:
- sbt clean test it:test
- sbt "+clean" "+test" "+it:test" "+cli/assembly"
test·jdk8:
image: "hseeberger/scala-sbt:8u181_2.12.8_1.2.8"
image: "hseeberger/scala-sbt:8u212_1.2.8_2.12.8"
variables:
SBT_OPTS: "-Dsbt.global.base=sbt-cache/sbtboot -Dsbt.boot.directory=sbt-cache/boot -Dsbt.ivy.home=sbt-cache/ivy"
stage: "test"
script:
- sbt "+clean" "+test" "+it:test" "+cli/assembly"
codecov:
image: "hseeberger/scala-sbt:8u212_1.2.8_2.12.8"
stage: "test"
script:
- sbt clean coverage test it:test
- sbt coverageAggregate
- sbt "+clean" coverage "++2.13.0! test" "++2.13.0! it:test"
- sbt "++2.13.0! coverageAggregate"
coverage: '/All done. Coverage was \[\d+.\d+%\]/'
......@@ -53,7 +53,7 @@ class GeoPoint protected (val lat: BigDecimal, val lon: BigDecimal, val alt: Opt
object GeoPoint {
def frmt(v: BigDecimal): String = {
s"%.${v.scale}f".format(v)
f"""%%.${v.scale}%df""".format(v)
}
/**
......
......@@ -19,6 +19,10 @@ import Dependencies._
import sbtcrossproject.{crossProject, CrossType}
lazy val scala_12 = "2.12.8"
lazy val scala_13 = "2.13.0"
lazy val supportedScalaVersions = List(scala_12, scala_13)
lazy val noPublishSettings = Seq(
publish := {},
publishLocal := {},
......@@ -28,7 +32,8 @@ lazy val noPublishSettings = Seq(
lazy val commonSettings = Seq(
organization := "fi.e257",
version := "0.32.0-SNAPSHOT",
scalaVersion := "2.12.8",
scalaVersion := scala_13,
crossScalaVersions := supportedScalaVersions,
compileOrder := CompileOrder.JavaThenScala,
scalacOptions ++= Seq(
"-deprecation",
......@@ -37,19 +42,38 @@ lazy val commonSettings = Seq(
"-feature",
"-unchecked",
"-Xcheckinit",
"-Xfatal-warnings",
"-Xlint",
"-Ywarn-dead-code",
"-Ywarn-extra-implicit",
"-Ywarn-numeric-widen",
"-Ywarn-unused:implicits",
"-Ywarn-unused:imports",
"-Ywarn-unused:locals",
"-Ywarn-unused:params",
"-Ywarn-unused:patvars",
"-Ywarn-unused:privates",
"-Ywarn-value-discard"
),
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 12)) =>
Seq(
//"-Xfatal-warnings",
// These won't work with 2.13
"-Ywarn-inaccessible",
"-Ywarn-infer-any",
"-Ywarn-nullary-override",
"-Ywarn-nullary-unit",
"-Yno-adapted-args",
"-Ypartial-unification",
)
case Some((2, 13)) =>
Seq(
// WIP: Disable fatal-warnings for Scala 2.13 "-Xfatal-warnings",
"-Ywarn-unused:imports",
)
case _ => Nil
}
},
Compile / console / scalacOptions --= Seq(
"-Ywarn-unused:imports",
"-Xfatal-warnings"
......@@ -73,6 +97,8 @@ lazy val tackler = (project in file(".")).
settings(noPublishSettings).
settings(commonSettings: _*).
settings(
// crossScalaVersions must be set to Nil on the aggregating project
crossScalaVersions := Nil,
run / fork := true
)
......@@ -114,10 +140,18 @@ lazy val core = (project in file("core")).
libraryDependencies += betterFiles,
libraryDependencies += cats_core,
libraryDependencies ++= circe_deps,
libraryDependencies ++= circe_deps_test,
libraryDependencies += typesafeConfig,
libraryDependencies += jgit,
libraryDependencies += scalaCollCompat,
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) =>
Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "0.2.0")
case _ => Nil
}
},
libraryDependencies += scalatest % "it,test",
libraryDependencies ++= circe_deps_test,
)
val gitCommitId = SettingKey[String]("gitCommit")
......@@ -168,6 +202,7 @@ lazy val cli = (project in file("cli")).
libraryDependencies += scallop,
libraryDependencies += typesafeConfig,
libraryDependencies += logback,
libraryDependencies += scalaCollCompat,
libraryDependencies += scalatest % "it,test",
libraryDependencies += dirsuite % "it,test"
)
......
......@@ -26,6 +26,7 @@ import fi.e257.tackler.core._
import fi.e257.tackler.model.TxnData
import fi.e257.tackler.parser.{TacklerParseException, TacklerTxns}
import fi.e257.tackler.report.Reports
import io.circe
import io.circe.parser.decode
import org.slf4j.{Logger, LoggerFactory}
......@@ -135,7 +136,7 @@ object TacklerCli {
def runExceptions(args: Array[String]): Unit = {
val tsStart = System.currentTimeMillis()
val cliCfg = new TacklerCliArgs(args)
val cliCfg = new TacklerCliArgs(args.toIndexedSeq)
val settings = Settings(getCfgPath(cliCfg.cfg.toOption), cliCfg.toConfig)
val output: Option[Path] = cliCfg.output.toOption.map(o => settings.getPathWithSettings(o))
......@@ -174,10 +175,9 @@ object TacklerCli {
decode[TxnFilterDefinition](filterStr)
}
if (jsonDecodeResult.isLeft) {
val err = jsonDecodeResult.left.get
jsonDecodeResult.left.foreach[circe.Error](err => {
throw new TxnException("JSON parse error: " + err.getMessage())
}
})
jsonDecodeResult.toOption.map(txnFilterRoot => {
txnDataAll.filter(txnFilterRoot)
......
......@@ -20,7 +20,7 @@ import com.typesafe.config.{Config, ConfigFactory, ConfigValueFactory}
import org.rogach.scallop.exceptions.{Help, ScallopException, Version}
import org.rogach.scallop.{ScallopConf, ScallopOption}
import scala.collection.JavaConverters
import scala.jdk.CollectionConverters._
import fi.e257.tackler.core.CfgKeys
......@@ -58,7 +58,7 @@ class TacklerCliArgs(args: Seq[String]) extends ScallopConf(args) {
val optsAsMap: Map[String, String] = opts.flatMap(o => opt2MapItem(o)).toMap
ConfigFactory.parseMap(JavaConverters.mapAsJavaMap(optsAsMap))
ConfigFactory.parseMap(optsAsMap.asJava)
}
version(TacklerCli.version())
......@@ -117,7 +117,7 @@ class TacklerCliArgs(args: Seq[String]) extends ScallopConf(args) {
case Some(reports) =>
stringArgsConf.withValue(
CfgKeys.reporting_reports,
ConfigValueFactory.fromIterable(JavaConverters.asJavaIterable(reports)))
ConfigValueFactory.fromIterable(reports.asJava))
case None =>
stringArgsConf
}
......@@ -126,7 +126,7 @@ class TacklerCliArgs(args: Seq[String]) extends ScallopConf(args) {
case Some(exports) =>
reportsConfig.withValue(
CfgKeys.reporting_exports,
ConfigValueFactory.fromIterable(JavaConverters.asJavaIterable(exports)))
ConfigValueFactory.fromIterable(exports.asJava))
case None =>
reportsConfig
}
......@@ -135,7 +135,7 @@ class TacklerCliArgs(args: Seq[String]) extends ScallopConf(args) {
case Some(accounts) =>
exportsConfig.withValue(
CfgKeys.reporting_accounts,
ConfigValueFactory.fromIterable(JavaConverters.asJavaIterable(accounts)))
ConfigValueFactory.fromIterable(accounts.asJava))
case None =>
exportsConfig
}
......@@ -144,7 +144,7 @@ class TacklerCliArgs(args: Seq[String]) extends ScallopConf(args) {
case Some(formats) =>
reportingAccountsConfig.withValue(
CfgKeys.reporting_formats,
ConfigValueFactory.fromIterable(JavaConverters.asJavaIterable(formats)))
ConfigValueFactory.fromIterable(formats.asJava))
case None =>
reportingAccountsConfig
}
......
......@@ -23,7 +23,7 @@ class BuildInfoTest extends FlatSpec {
behavior of "BuildInfo"
it should "scalaVersion" in {
assert(BuildInfo.scalaVersion.startsWith("2.12.8"))
assert(BuildInfo.scalaVersion.startsWith(util.Properties.versionString.substring(8)))
}
it should "name" in {
......
......@@ -28,7 +28,9 @@ import fi.e257.tackler.core.Settings
* CLI args and Settings (conf-file).
*/
class TacklerCliSettingsTest extends FlatSpec with Matchers with Inside {
val respath = "core/target/scala-2.12/test-classes/"
val scalaVer = util.Properties.versionString.substring(8,12)
val respath = "core/target/scala-" + scalaVer + "/test-classes/"
it should "respect *ALL* cli args (input.txn)" in {
val absBasepath = File(respath)
......@@ -36,7 +38,8 @@ class TacklerCliSettingsTest extends FlatSpec with Matchers with Inside {
"--basedir", absBasepath.toString, // this must be real path so that --input.fs.dir works correctly with rel-path
"--input.fs.dir", "cli-args-txns/",
"--input.fs.glob", "**/cliargs*.txn"
)
).toIndexedSeq
val cliCfg = new TacklerCliArgs(args)
val settings = Settings(Paths.get("/not/there/cfg.conf"), cliCfg.toConfig)
......@@ -52,7 +55,8 @@ class TacklerCliSettingsTest extends FlatSpec with Matchers with Inside {
"--basedir", absBasepath.toString, // this must be real path so that --input.fs.dir works correctly with rel-path
"--input.file", (absBasepath / "filename.txn").toString,
"--accounts.strict", "false"
)
).toIndexedSeq
val cliCfg = new TacklerCliArgs(args)
val settings = Settings(Paths.get("/not/there/cfg.conf"), cliCfg.toConfig)
......@@ -67,7 +71,8 @@ class TacklerCliSettingsTest extends FlatSpec with Matchers with Inside {
it should "merge configs (cli, ext-conf, embedded conf)" in {
val args = Array(
"--input.fs.glob", "**/cli-args*.txn"
)
).toIndexedSeq
val cliCfg = new TacklerCliArgs(args)
val settings = Settings(Paths.get(respath + "cfg-as-ext-file-rel.conf"), cliCfg.toConfig)
......
/*
* Copyright 2019 E257.FI
*
* Scala12to13 is based on following examples:
* url: https://github.com/scala/scala-parallel-collections/issues/22
* url: https://github.com/scala/scala-collection-compat/issues/208
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package fi.e257.tackler
/**
* author: https://github.com/sjrd
* url: https://github.com/scala/scala-parallel-collections/issues/22#issuecomment-288389306
*/
private[tackler] object Scala12to13 {
val Converters = {
import Compat._
{
import scala.collection.parallel._
CollectionConverters
}
}
object Compat {
object CollectionConverters
}
}
......@@ -20,6 +20,7 @@ import fi.e257.tackler.math.{TacklerReal, ZERO}
import fi.e257.tackler.model._
import scala.collection.mutable
import fi.e257.tackler.Scala12to13.Converters._
object Accumulator {
......
......@@ -23,9 +23,10 @@ import better.files._
import com.typesafe.config.{Config, ConfigFactory}
import org.slf4j.{Logger, LoggerFactory}
import scala.collection.JavaConverters._
import fi.e257.tackler.model.AccountTreeNode
import scala.jdk.CollectionConverters._
/**
* Config keys / paths. All of these keys / paths
* must be available (by embedded default conf).
......
......@@ -123,7 +123,7 @@ object TxnData {
if (dup._3 =!= 0) {
val msg =
s"""Found ${dup._3 + 1} duplicate txn uuids with txn set checksum. """ +
f"""Found ${dup._3 + 1}%d duplicate txn uuids with txn set checksum. """ +
s"""At least "${dup._2}" is duplicate, there could be others."""
throw new TxnException(msg)
}
......
......@@ -31,6 +31,8 @@ import scala.collection.JavaConverters
import scala.util.control.NonFatal
import scala.util.{Failure, Success}
import scala.jdk.CollectionConverters._
/**
* Handler utilities for ANTLR Parser Contexts.
*
......@@ -91,7 +93,7 @@ abstract class CtxHandler {
"org.wartremover.warts.ListOps"))
protected def handleAccount(accountCtx: AccountContext, commodity: Option[Commodity]): AccountTreeNode = {
val account: String = JavaConverters.asScalaIterator(accountCtx.children.iterator())
val account: String = accountCtx.children.iterator().asScala
.map(_.getText)
.mkString("")
......@@ -316,7 +318,7 @@ abstract class CtxHandler {
// txnCtx.txn_comment is never null, even when there aren't any comments
// (in that case it will be an empty list)
val comments = {
val l = JavaConverters.asScalaIterator(txnCtx.txn_comment().iterator())
val l = txnCtx.txn_comment().iterator().asScala
.map(c => c.comment().text().getText).toList
if (l.isEmpty) {
None
......@@ -326,7 +328,7 @@ abstract class CtxHandler {
}
val posts: Posts =
JavaConverters.asScalaIterator(txnCtx.postings().posting().iterator()).map(p => {
txnCtx.postings().posting().iterator().asScala.map(p => {
handleRawPosting(p)
}).toList
......@@ -358,7 +360,7 @@ abstract class CtxHandler {
* @return sequence of Transactions.
*/
protected def handleTxns(txnsCtx: TxnsContext): Txns = {
JavaConverters.asScalaIterator(txnsCtx.txn().iterator())
txnsCtx.txn().iterator().asScala
.map({ case (txnCtx) =>
try {
handleTxn(txnCtx)
......
......@@ -37,6 +37,7 @@ import org.eclipse.jgit.treewalk.filter.{AndTreeFilter, PathFilter, PathSuffixFi
import org.slf4j.{Logger, LoggerFactory}
import scala.util.control.NonFatal
import fi.e257.tackler.Scala12to13.Converters._
/**
* Helper methods for [[TacklerTxns]] and Txns Input handling.
......
......@@ -21,6 +21,7 @@ import io.circe.syntax._
import fi.e257.tackler.api.{BalanceGroupReport, Metadata, TxnTS}
import fi.e257.tackler.core._
import fi.e257.tackler.model.{Transaction, TxnData}
import fi.e257.tackler.Scala12to13.Converters._
class BalanceGroupReporter(val mySettings: BalanceGroupSettings) extends BalanceReporterLike(mySettings) {
......
......@@ -23,12 +23,13 @@ import org.scalatest.FunSpec
class SettingsTest extends FunSpec {
val scalaVer = util.Properties.versionString.substring(8,12)
/*
* "./" := non-forked JVM
* "../" := forked JVM
*/
val testbase = "../"
val respath = "core/target/scala-2.12/test-classes/"
val respath = "core/target/scala-" + scalaVer + "/test-classes/"
describe("Configuration and path handling") {
......
......@@ -22,11 +22,12 @@ object Dependencies {
* Versions
*/
val betterFilesVersion = "3.8.0"
val catsVersion = "2.0.0-M4"
val circeVersion = "0.12.0-M4"
val circeOpticsVersion = "0.11.0"
val catsVersion = "2.0.0-RC1"
val circeVersion = "0.12.0-RC1"
val circeOpticsVersion = "0.12.0-RC1"
val scalatestVersion = "3.0.8"
val scallopVersion = "3.3.1"
val scalaCollCompatVersion = "2.1.1"
val configVersion = "1.3.4"
val dirsuiteVersion = "0.30.1"
val jgitVersion = "5.4.0.201906121030-r"
......@@ -49,6 +50,8 @@ object Dependencies {
"io.circe" %% "circe-optics"
).map(_ % circeOpticsVersion % "it,test")
val scalaCollCompat = "org.scala-lang.modules" %% "scala-collection-compat" % scalaCollCompatVersion
val scalatest = "org.scalatest" %% "scalatest" % scalatestVersion
val scallop = "org.rogach" %% "scallop" % scallopVersion
val dirsuite = "fi.e257.testing" %% "dirsuite" % dirsuiteVersion
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment