Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial port to Scala 3.1.0 #181

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ ThisBuild / publishTo :=(if (!isSnapshot.value) {
Some(Opts.resolver.sonatypeSnapshots)
})

ThisBuild / libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.10" % Test

val defaultScalaVersions = Seq(ScalaVersions.scala_310, ScalaVersions.scala_213, ScalaVersions.scala_212)

val scalaJsVersion = "1.7.0"
val scalaNativeVersion = "0.4.1"
val crossProjectVersion = "1.1.0"
Expand Down Expand Up @@ -90,21 +94,21 @@ val scalaOpts = scalacOptions ++= ((isSnapshot.value, scalaVersion.value) match

lazy val sbtmeta = (project in file("sbtmeta"))
.settings(
crossScalaVersions := Seq(ScalaVersions.scala_213, ScalaVersions.scala_212),
crossScalaVersions := defaultScalaVersions,
scalaVersion := crossScalaVersions.value.head,
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided,
libraryDependencies ++=
Some("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided)
.filterNot(_ => scalaVersion.value == ScalaVersions.scala_310),
scalaOpts,
)

lazy val sbtgen = (project in file("sbtgen"))
.dependsOn(sbtmeta)
.settings(
crossScalaVersions := Seq(ScalaVersions.scala_213, ScalaVersions.scala_212),
crossScalaVersions := defaultScalaVersions,
scalaVersion := crossScalaVersions.value.head,
// libraryDependencies += "com.github.scopt" %% "scopt" % "4.0.0-RC2",
libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.1",
libraryDependencies += "com.github.scopt" %% "scopt" % "4.0.1",
libraryDependencies += "org.scala-lang.modules" %% "scala-collection-compat" % "2.6.0",
(ThisBuild / libraryDependencies) += "org.scalatest" %% "scalatest" % "3.2.10" % Test,
scalacOptions ++= Seq(
s"-Xmacro-settings:product-version=${version.value}",
s"-Xmacro-settings:product-group=${organization.value}",
Expand Down
1 change: 1 addition & 0 deletions project/ScalaVersions.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
object ScalaVersions {
val scala_212 = "2.12.15"
val scala_213 = "2.13.7"
val scala_310 = "3.1.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ object ProjectAttributeMacro {
}

def extractAttrMacro(c: blackbox.Context)(name: c.Expr[String]): c.Expr[Option[String]] = {
val nameStr = TreeTools.stringLiteral(c)(c.universe)(name.tree)
extractAttr(c, nameStr)
}

def extractAttrMandatoryMacro(c: blackbox.Context)(name: c.Expr[String]): c.Expr[Option[String]] = {
val nameStr = TreeTools.stringLiteral(c)(c.universe)(name.tree)
extractAttr(c, nameStr, force = true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ object SbtgenMeta {

def extract(name: String): Option[String] = macro ProjectAttributeMacro.extractAttrMacro

def extractMandatory(name: String): Option[String] = macro ProjectAttributeMacro.extractAttrMacro
def extractMandatory(name: String): Option[String] = macro ProjectAttributeMacro.extractAttrMandatoryMacro
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package izumi.sbtgen.sbtmeta

import java.nio.file.{Path, Paths}
import java.time.LocalDateTime
import scala.annotation.tailrec
import scala.quoted.{Expr, Quotes, quotes}
import scala.util.chaining.scalaUtilChainingOps

object ProjectAttributeMacro {

def buildTimestampMacro(using Quotes): Expr[LocalDateTime] = {
val time = LocalDateTime.now()
'{ LocalDateTime.of(${Expr(time.getYear)}, ${Expr(time.getMonthValue)}, ${Expr(time.getDayOfMonth)}, ${Expr(time.getHour)}, ${Expr(time.getMinute)}, ${Expr(time.getSecond)}, ${Expr(time.getNano)}) }
}

def extractAttrMacro(name: Expr[String])(using Quotes): Expr[Option[String]] = {
val nameStr = name.valueOrAbort
extractAttr(nameStr)
}

def extractAttrMandatoryMacro(name: Expr[String])(using Quotes): Expr[Option[String]] = {
val nameStr = name.valueOrAbort
extractAttr(nameStr, force = true)
}

def extractProjectGroupIdMacro(using Quotes): Expr[Option[String]] = {
extractAttr("product-group")
}

def extractSbtVersionMacro(using Quotes): Expr[Option[String]] = {
extractAttr("sbt-version")
}

def extractScalatestVersionMacro(using Quotes): Expr[Option[String]] = {
extractAttr("scalatest-version")
}

def extractScalaVersionsMacro(using Quotes): Expr[Option[String]] = {
extractAttr("scala-versions")
}

def extractScalaVersionMacro(using Quotes): Expr[Option[String]] = {
extractAttr("scala-version")
}

def extractProjectVersionMacro(using Quotes): Expr[Option[String]] = {
extractAttr("product-version")
}

private def extractAttr(name: String, force: Boolean = false)(using Quotes): Expr[Option[String]] = {
var scala3MacroSettingsExist: Boolean = true
val macroSettings: List[String] = {
quotes.reflect.report.warning(
"""Required implementation of -Xmacro-settings doesn't exist in Scala 3 yet.
|
|Please fix Dotty issue #12038 to proceed.
|
|See: https://github.com/lampepfl/dotty/issues/12038
| - https://github.com/lampepfl/dotty/pull/12039""".stripMargin
)
scala3MacroSettingsExist = false
Nil
}
val prefix = s"$name="
val value = macroSettings.find(_.startsWith(prefix)).filterNot(_.isEmpty).map(_.stripPrefix(prefix))
if (value.isEmpty) {
s"Undefined macro parameter $name, add `-Xmacro-settings:$prefix<value>` into `scalac` options"
`pipe` (if (force && scala3MacroSettingsExist) quotes.reflect.report.errorAndAbort else quotes.reflect.report.warning)
}
Expr[Option[String]](value)
}

def findProjectRootMacro(using Quotes): Expr[Option[String]] = {
val srcPath = quotes.reflect.Position.ofMacroExpansion.sourceFile.getJPath.getOrElse(
quotes.reflect.report.errorAndAbort("Couldn't find file path of the current file")
)
val result = projectRoot(srcPath).map(_.toFile.getCanonicalPath)
Expr[Option[String]](result)
}

@tailrec
private def projectRoot(cp: Path): Option[Path] = {
if (cp.resolve("build.sbt").toFile.exists()) {
Some(cp)
} else {
val parent = cp.getParent

if (parent == null || parent == cp.getRoot) {
None
} else {
projectRoot(parent)
}
}
}

}
16 changes: 16 additions & 0 deletions sbtmeta/src/main/scala-3/izumi/sbtgen/sbtmeta/SbtgenMeta.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package izumi.sbtgen.sbtmeta

import java.time.LocalDateTime

object SbtgenMeta {
inline def buildTimestamp(): LocalDateTime = ${ ProjectAttributeMacro.buildTimestampMacro }
inline def projectRoot(): Option[String] = ${ ProjectAttributeMacro.findProjectRootMacro }
inline def extractSbtProjectGroupId(): Option[String] = ${ ProjectAttributeMacro.extractProjectGroupIdMacro }
inline def extractSbtProjectVersion(): Option[String] = ${ ProjectAttributeMacro.extractProjectVersionMacro }
inline def extractSbtVersion(): Option[String] = ${ ProjectAttributeMacro.extractSbtVersionMacro }
inline def extractScalatestVersion(): Option[String] = ${ ProjectAttributeMacro.extractScalatestVersionMacro }
inline def extractScalaVersion(): Option[String] = ${ ProjectAttributeMacro.extractScalaVersionMacro }
inline def extractScalaVersions(): Option[String] = ${ ProjectAttributeMacro.extractScalaVersionsMacro }
inline def extract(inline name: String): Option[String] = ${ ProjectAttributeMacro.extractAttrMacro('{name}) }
inline def extractMandatory(inline name: String): Option[String] = ${ ProjectAttributeMacro.extractAttrMandatoryMacro('{name}) }
}