From 8f25db02bbaf367e40a4114d1160cd4ce06cfcad Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Sat, 16 Jan 2021 21:06:11 +0200 Subject: [PATCH 1/2] Java Renderers (code generators for Java only sbt projects) --- .../scala/sbtbuildinfo/JavaRenderer.scala | 208 ++++++++++++++++++ .../sbtbuildinfo/JavaSingletonRenderer.scala | 22 ++ .../JavaStaticFieldsRenderer.scala | 15 ++ .../ScalaCaseObjectRenderer.scala | 2 +- .../javasingletonrenderer/build.sbt | 150 +++++++++++++ .../javasingletonrenderer/project/plugins.sbt | 7 + .../sbt-buildinfo/javasingletonrenderer/test | 4 + .../javastaticfieldsrenderer/build.sbt | 148 +++++++++++++ .../project/plugins.sbt | 7 + .../javastaticfieldsrenderer/test | 4 + 10 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/sbtbuildinfo/JavaRenderer.scala create mode 100644 src/main/scala/sbtbuildinfo/JavaSingletonRenderer.scala create mode 100644 src/main/scala/sbtbuildinfo/JavaStaticFieldsRenderer.scala create mode 100644 src/sbt-test/sbt-buildinfo/javasingletonrenderer/build.sbt create mode 100644 src/sbt-test/sbt-buildinfo/javasingletonrenderer/project/plugins.sbt create mode 100644 src/sbt-test/sbt-buildinfo/javasingletonrenderer/test create mode 100644 src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/build.sbt create mode 100644 src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/project/plugins.sbt create mode 100644 src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/test diff --git a/src/main/scala/sbtbuildinfo/JavaRenderer.scala b/src/main/scala/sbtbuildinfo/JavaRenderer.scala new file mode 100644 index 0000000..7f89d6c --- /dev/null +++ b/src/main/scala/sbtbuildinfo/JavaRenderer.scala @@ -0,0 +1,208 @@ +package sbtbuildinfo + +abstract class JavaRenderer(pkg: String, cl: String, makeStatic: Boolean) extends BuildInfoRenderer { + + override def fileType = BuildInfoType.Source + override def extension = "java" + + def header = List( + "// $COVERAGE-OFF$", + s"package $pkg;", + "", + s"/** This file was generated by sbt-buildinfo. */", + s"public final class $cl {", + s" private $cl() {}", + "" + ) + + protected def footer = List("}", "// $COVERAGE-ON$") + + protected def line(result: BuildInfoResult): Seq[String] = { + import result._ + val mod = if (makeStatic) " static" else "" + getJavaType(result.typeExpr) + .map(typeDecl => + List( + s" /** The value is ${quote(value)}. */", + s" public$mod final $typeDecl $identifier = ${quote(value)};" + ) + ) + .getOrElse(List.empty) + } + + protected val buildUrlLines: String = + """ private static java.net.URL internalAsUrl(String urlString) { + | try { + | return new java.net.URL(urlString); + | } catch (Exception e) { + | return null; + | } + | } + |""".stripMargin + + protected val buildMapLines: String = + """ @SuppressWarnings({"unchecked", "rawtypes"}) + | private static java.util.Map internalAsMap(java.util.Map.Entry... entries) { + | java.util.Map m = new java.util.HashMap<>(); + | for (java.util.Map.Entry e : entries) { + | m.put((K) e.getKey(), (V) e.getValue()); + | } + | return java.util.Collections.unmodifiableMap(m); + | } + |""".stripMargin + + protected def toStringLines(results: Seq[BuildInfoResult]): String = { + val mod = if (makeStatic) " static" else "" + val methodPrefix = if (makeStatic) "make" else "to" + val idents = results.filter(v => getJavaType(v.typeExpr).isDefined).map(_.identifier) + val fmt = idents.map("%s: %%s" format _).mkString(", ") + val vars = idents.mkString(", ") + s""" + | public$mod String ${methodPrefix}String() { + | return String.format("$fmt", + | $vars + | ); + | } + |""".stripMargin + } + + protected def toMapLines(results: Seq[BuildInfoResult]): Seq[String] = + if (options.contains(BuildInfoOption.ToMap) || options.contains(BuildInfoOption.ToJson)) { + val mod = if (makeStatic) " static" else "" + val methodPrefix = if (makeStatic) "make" else "to" + List( + s" public$mod java.util.Map ${methodPrefix}Map() {", + " java.util.Map m = new java.util.HashMap<>();" + ) ++ + results + .filter(v => getJavaType(v.typeExpr).isDefined) + .map(result => " m.put(\"%s\", %s);".format(result.identifier, result.identifier)) ++ + List( + " return java.util.Collections.unmodifiableMap(m);", + " }", + "" + ) + } else Nil + + protected def buildJsonLines: Seq[String] = + if (options contains BuildInfoOption.ToJson) + List( + s""" private static String quote(Object x) { + | return "\\"" + x + "\\""; + | } + | + | @SuppressWarnings({"unchecked"}) + | private static String toJsonValue(Object value) { + | if (value instanceof java.util.Collection) { + | return ((java.util.Collection) value) + | .stream().map($cl::toJsonValue).collect(java.util.stream.Collectors.joining(",", "[", "]")); + | } else if (value instanceof java.util.Optional) { + | return ((java.util.Optional) value).map($cl::toJsonValue).orElse("null"); + | } else if (value instanceof java.util.Map) { + | return ((java.util.Map) value) + | .entrySet().stream() + | .map(e -> toJsonValue(e.getKey().toString()) + ":" + toJsonValue(e.getValue())) + | .collect(java.util.stream.Collectors.joining(", ", "{", "}")); + | } else if (value instanceof Double) { + | return value.toString(); + | } else if (value instanceof Float) { + | return value.toString(); + | } else if (value instanceof Long) { + | return value.toString(); + | } else if (value instanceof Integer) { + | return value.toString(); + | } else if (value instanceof Short) { + | return value.toString(); + | } else if (value instanceof Boolean) { + | return value.toString(); + | } else if (value instanceof String) { + | return quote(value); + | } else { + | return quote(value.toString()); + | } + | } + |""".stripMargin + ) + else + Nil + + protected def toJsonLines: Seq[String] = + if (options contains BuildInfoOption.ToJson) { + val mod = if (makeStatic) " static" else "" + val methodPrefix = if (makeStatic) "make" else "to" + List( + s""" public$mod final String ${methodPrefix}Json = toJsonValue(${methodPrefix}Map());""".stripMargin + ) + } else + Nil + + protected def getJavaType(typeExpr: TypeExpression): Option[String] = { + def tpeToReturnType(tpe: TypeExpression): Option[String] = + tpe match { + case TypeExpression("Any", Nil) => None + case TypeExpression("Short", Nil) => Some("Short") + case TypeExpression("Int", Nil) => Some("Integer") + case TypeExpression("Long", Nil) => Some("Long") + case TypeExpression("Double", Nil) => Some("Double") + case TypeExpression("Float", Nil) => Some("Float") + case TypeExpression("Boolean", Nil) => Some("Boolean") + case TypeExpression("scala.Symbol", Nil) => Some("String") + case TypeExpression("java.lang.String", Nil) => Some("String") + case TypeExpression("java.net.URL", Nil) => Some("java.net.URL") + case TypeExpression("sbt.URL", Nil) => Some("java.net.URL") + case TypeExpression("java.io.File", Nil) => Some("java.io.File") + case TypeExpression("sbt.File", Nil) => Some("java.io.File") + case TypeExpression("scala.xml.NodeSeq", Nil) => None + + case TypeExpression("sbt.ModuleID", Nil) => Some("String") + case TypeExpression("sbt.Resolver", Nil) => Some("String") + + case TypeExpression("sbt.librarymanagement.ModuleID", Nil) => Some("String") + case TypeExpression("sbt.librarymanagement.Resolver", Nil) => Some("String") + + case TypeExpression("sbt.internal.util.Attributed", Seq(TypeExpression("java.io.File", Nil))) => + Some("java.io.File") + + case TypeExpression("scala.Option", Seq(arg)) => + tpeToReturnType(arg) map { x => s"java.util.Optional<$x>" } + case TypeExpression("scala.collection.Seq" | "scala.collection.immutable.Seq", Seq(arg)) => + tpeToReturnType(arg) map { x => s"java.util.Collection<$x>" } + case TypeExpression("scala.collection.immutable.Map", Seq(arg0, arg1)) => + for { + x0 <- tpeToReturnType(arg0) + x1 <- tpeToReturnType(arg1) + } yield s"java.util.Map<$x0, $x1>" + case TypeExpression("scala.Tuple2", Seq(arg0, arg1)) => + for { + x0 <- tpeToReturnType(arg0) + x1 <- tpeToReturnType(arg1) + } yield s"java.util.Map.Entry<$x0, $x1>" + case _ => None + } + tpeToReturnType(typeExpr) + } + + protected def quote(v: Any): String = v match { + case x @ (_: Int | _: Short | _: Double | _: Boolean) => x.toString + case x: Float => x.toString + "f" + case x: Symbol => s"""("${x.name}").intern()""" + case x: Long => x.toString + "L" + case node: scala.xml.NodeSeq if node.toString().trim.nonEmpty => node.toString() + case node: scala.xml.NodeSeq => scala.xml.NodeSeq.Empty.toString() + case (k, _v) => "new java.util.AbstractMap.SimpleImmutableEntry<>(%s, %s)" format (quote(k), quote(_v)) + case mp: Map[_, _] => mp.toList.map(quote(_)).mkString("internalAsMap(", ", ", ")") + case seq: collection.Seq[_] => + seq.map(quote).mkString("java.util.Collections.unmodifiableList(java.util.Arrays.asList(", ", ", "))") + case op: Option[_] => + op map { x => "java.util.Optional.of(" + quote(x) + ")" } getOrElse { "java.util.Optional.empty()" } + case url: java.net.URL => "internalAsUrl(%s)" format quote(url.toString) + case file: java.io.File => "new java.io.File(%s)" format quote(file.toString) + case attr: sbt.Attributed[_] => quote(attr.data) + case s => "\"%s\"" format encodeStringLiteral(s.toString) + } + + protected def encodeStringLiteral(str: String): String = + str.replace("\\", "\\\\").replace("\n", "\\n").replace("\b", "\\b").replace("\r", "\\r") + .replace("\t", "\\t").replace("\'", "\\'").replace("\f", "\\f").replace("\"", "\\\"") + +} diff --git a/src/main/scala/sbtbuildinfo/JavaSingletonRenderer.scala b/src/main/scala/sbtbuildinfo/JavaSingletonRenderer.scala new file mode 100644 index 0000000..8b56ad3 --- /dev/null +++ b/src/main/scala/sbtbuildinfo/JavaSingletonRenderer.scala @@ -0,0 +1,22 @@ +package sbtbuildinfo + +case class JavaSingletonRenderer(options: Seq[BuildInfoOption], pkg: String, cl: String) extends JavaRenderer(pkg, cl, false) { + + override def renderKeys(buildInfoResults: Seq[BuildInfoResult]): Seq[String] = + header ++ + instanceLine ++ + buildInfoResults.flatMap(line) ++ + Seq(toStringLines(buildInfoResults)) ++ + toMapLines(buildInfoResults) ++ + Seq(buildUrlLines, buildMapLines) ++ + buildJsonLines ++ + toJsonLines ++ + footer + + private def instanceLine: Seq[String] = + List( + s" public static final $cl instance = new $cl();", + "" + ) + +} diff --git a/src/main/scala/sbtbuildinfo/JavaStaticFieldsRenderer.scala b/src/main/scala/sbtbuildinfo/JavaStaticFieldsRenderer.scala new file mode 100644 index 0000000..6e9918b --- /dev/null +++ b/src/main/scala/sbtbuildinfo/JavaStaticFieldsRenderer.scala @@ -0,0 +1,15 @@ +package sbtbuildinfo + +case class JavaStaticFieldsRenderer(options: Seq[BuildInfoOption], pkg: String, cl: String) extends JavaRenderer(pkg, cl, true) { + + override def renderKeys(buildInfoResults: Seq[BuildInfoResult]): Seq[String] = + header ++ + buildInfoResults.flatMap(line) ++ + Seq(toStringLines(buildInfoResults)) ++ + toMapLines(buildInfoResults) ++ + Seq(buildUrlLines, buildMapLines) ++ + buildJsonLines ++ + toJsonLines ++ + footer + +} diff --git a/src/main/scala/sbtbuildinfo/ScalaCaseObjectRenderer.scala b/src/main/scala/sbtbuildinfo/ScalaCaseObjectRenderer.scala index 5bc3fab..cd3d4ca 100644 --- a/src/main/scala/sbtbuildinfo/ScalaCaseObjectRenderer.scala +++ b/src/main/scala/sbtbuildinfo/ScalaCaseObjectRenderer.scala @@ -1,6 +1,6 @@ package sbtbuildinfo -private[sbtbuildinfo] case class ScalaCaseObjectRenderer(options: Seq[BuildInfoOption], pkg: String, obj: String) extends ScalaRenderer { +case class ScalaCaseObjectRenderer(options: Seq[BuildInfoOption], pkg: String, obj: String) extends ScalaRenderer { override def fileType = BuildInfoType.Source override def extension = "scala" diff --git a/src/sbt-test/sbt-buildinfo/javasingletonrenderer/build.sbt b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/build.sbt new file mode 100644 index 0000000..cfe741e --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/build.sbt @@ -0,0 +1,150 @@ +import sbtbuildinfo.JavaSingletonRenderer + +lazy val check = taskKey[Unit]("checks this plugin") + +ThisBuild / version := "0.1" +ThisBuild / scalaVersion := "2.12.12" +ThisBuild / homepage := Some(url("http://example.com")) +ThisBuild / licenses := Seq("MIT License" -> url("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE")) + +lazy val root = (project in file(".")) + .enablePlugins(BuildInfoPlugin) + .settings( + name := "helloworld", + crossPaths := false, + autoScalaLibrary := false, + buildInfoKeys := Seq( + name, + BuildInfoKey.map(version) { case (n, v) => "projectVersion" -> v.toDouble }, + scalaVersion, + ivyXML, + homepage, + licenses, + apiMappings, + isSnapshot, + "year" -> 2012, + "sym" -> 'Foo, + BuildInfoKey.action("buildTime") { 1234L }, + target), + buildInfoOptions ++= Seq( + BuildInfoOption.ToJson, + BuildInfoOption.ToMap, + ), + buildInfoRenderFactory := JavaSingletonRenderer.apply, + buildInfoPackage := "hello", + scalacOptions ++= Seq("-Ywarn-unused-import", "-Xfatal-warnings", "-Yno-imports"), + check := { + val f = (sourceManaged in Compile).value / "sbt-buildinfo" / ("%s.java" format "BuildInfo") + val lines = scala.io.Source.fromFile(f).getLines.toList + lines match { + case """// $COVERAGE-OFF$""" :: + """package hello;""" :: + """""" :: + """/** This file was generated by sbt-buildinfo. */""" :: + """public final class BuildInfo {""" :: + """ private BuildInfo() {}""" :: + """""" :: + """ public static final BuildInfo instance = new BuildInfo();""" :: + """""" :: + """ /** The value is "helloworld". */""" :: + """ public final String name = "helloworld";""" :: + """ /** The value is "2.12.12". */""" :: + """ public final String scalaVersion = "2.12.12";""" :: + """ /** The value is java.util.Optional.of(internalAsUrl("http://example.com")). */""" :: + """ public final java.util.Optional homepage = java.util.Optional.of(internalAsUrl("http://example.com"));""" :: + """ /** The value is java.util.Collections.unmodifiableList(java.util.Arrays.asList(new java.util.AbstractMap.SimpleImmutableEntry<>("MIT License", internalAsUrl("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE")))). */""" :: + """ public final java.util.Collection> licenses = java.util.Collections.unmodifiableList(java.util.Arrays.asList(new java.util.AbstractMap.SimpleImmutableEntry<>("MIT License", internalAsUrl("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE"))));""" :: + """ /** The value is internalAsMap(). */""" :: + """ public final java.util.Map apiMappings = internalAsMap();""" :: + """ /** The value is false. */""" :: + """ public final Boolean isSnapshot = false;""" :: + """ /** The value is 2012. */""" :: + """ public final Integer year = 2012;""" :: + """ /** The value is ("Foo").intern(). */""" :: + """ public final String sym = ("Foo").intern();""" :: + """ /** The value is 1234L. */""" :: + """ public final Long buildTime = 1234L;""" :: + targetInfoComment :: + targetInfo :: + """""" :: + """ public String toString() {""" :: + """ return String.format("name: %s, scalaVersion: %s, homepage: %s, licenses: %s, apiMappings: %s, isSnapshot: %s, year: %s, sym: %s, buildTime: %s, target: %s",""" :: + """ name, scalaVersion, homepage, licenses, apiMappings, isSnapshot, year, sym, buildTime, target""" :: + """ );""" :: + """ }""" :: + """""" :: + """ public java.util.Map toMap() {""" :: + """ java.util.Map m = new java.util.HashMap<>();""" :: + """ m.put("name", name);""" :: + """ m.put("scalaVersion", scalaVersion);""" :: + """ m.put("homepage", homepage);""" :: + """ m.put("licenses", licenses);""" :: + """ m.put("apiMappings", apiMappings);""" :: + """ m.put("isSnapshot", isSnapshot);""" :: + """ m.put("year", year);""" :: + """ m.put("sym", sym);""" :: + """ m.put("buildTime", buildTime);""" :: + """ m.put("target", target);""" :: + """ return java.util.Collections.unmodifiableMap(m);""" :: + """ }""" :: + """""" :: + """ private static java.net.URL internalAsUrl(String urlString) {""" :: + """ try {""" :: + """ return new java.net.URL(urlString);""" :: + """ } catch (Exception e) {""" :: + """ return null;""" :: + """ }""" :: + """ }""" :: + """""" :: + """ @SuppressWarnings({"unchecked", "rawtypes"})""" :: + """ private static java.util.Map internalAsMap(java.util.Map.Entry... entries) {""" :: + """ java.util.Map m = new java.util.HashMap<>();""" :: + """ for (java.util.Map.Entry e : entries) {""" :: + """ m.put((K) e.getKey(), (V) e.getValue());""" :: + """ }""" :: + """ return java.util.Collections.unmodifiableMap(m);""" :: + """ }""" :: + """""" :: + """ private static String quote(Object x) {""" :: + """ return "\"" + x + "\"";""" :: + """ }""" :: + """""" :: + """ @SuppressWarnings({"unchecked"})""" :: + """ private static String toJsonValue(Object value) {""" :: + """ if (value instanceof java.util.Collection) {""" :: + """ return ((java.util.Collection) value)""" :: + """ .stream().map(BuildInfo::toJsonValue).collect(java.util.stream.Collectors.joining(",", "[", "]"));""" :: + """ } else if (value instanceof java.util.Optional) {""" :: + """ return ((java.util.Optional) value).map(BuildInfo::toJsonValue).orElse("null");""" :: + """ } else if (value instanceof java.util.Map) {""" :: + """ return ((java.util.Map) value)""" :: + """ .entrySet().stream()""" :: + """ .map(e -> toJsonValue(e.getKey().toString()) + ":" + toJsonValue(e.getValue()))""" :: + """ .collect(java.util.stream.Collectors.joining(", ", "{", "}"));""" :: + """ } else if (value instanceof Double) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Float) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Long) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Integer) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Short) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Boolean) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof String) {""" :: + """ return quote(value);""" :: + """ } else {""" :: + """ return quote(value.toString());""" :: + """ }""" :: + """ }""" :: + """""" :: + """ public final String toJson = toJsonValue(toMap());""" :: + """}""" :: + """// $COVERAGE-ON$""" :: Nil if ((targetInfo contains "public final java.io.File target = new java.io.File(") && (targetInfoComment contains "/** The value is new java.io.File(")) => + case _ => sys.error("unexpected output: \n" + lines.mkString("\n")) + } + () + } + ) diff --git a/src/sbt-test/sbt-buildinfo/javasingletonrenderer/project/plugins.sbt b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/project/plugins.sbt new file mode 100644 index 0000000..e392da8 --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/project/plugins.sbt @@ -0,0 +1,7 @@ +{ + val pluginVersion = System.getProperty("plugin.version") + if(pluginVersion == null) + throw new RuntimeException("""|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) + else addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % pluginVersion) +} diff --git a/src/sbt-test/sbt-buildinfo/javasingletonrenderer/test b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/test new file mode 100644 index 0000000..db36f0b --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javasingletonrenderer/test @@ -0,0 +1,4 @@ +> compile +$ exists target/src_managed/main/sbt-buildinfo/BuildInfo.java + +> check diff --git a/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/build.sbt b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/build.sbt new file mode 100644 index 0000000..660e87e --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/build.sbt @@ -0,0 +1,148 @@ +import sbtbuildinfo.JavaStaticFieldsRenderer + +lazy val check = taskKey[Unit]("checks this plugin") + +ThisBuild / version := "0.1" +ThisBuild / scalaVersion := "2.12.12" +ThisBuild / homepage := Some(url("http://example.com")) +ThisBuild / licenses := Seq("MIT License" -> url("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE")) + +lazy val root = (project in file(".")) + .enablePlugins(BuildInfoPlugin) + .settings( + name := "helloworld", + crossPaths := false, + autoScalaLibrary := false, + buildInfoKeys := Seq( + name, + BuildInfoKey.map(version) { case (n, v) => "projectVersion" -> v.toDouble }, + scalaVersion, + ivyXML, + homepage, + licenses, + apiMappings, + isSnapshot, + "year" -> 2012, + "sym" -> 'Foo, + BuildInfoKey.action("buildTime") { 1234L }, + target), + buildInfoOptions ++= Seq( + BuildInfoOption.ToJson, + BuildInfoOption.ToMap, + ), + buildInfoRenderFactory := JavaStaticFieldsRenderer.apply, + buildInfoPackage := "hello", + scalacOptions ++= Seq("-Ywarn-unused-import", "-Xfatal-warnings", "-Yno-imports"), + check := { + val f = (sourceManaged in Compile).value / "sbt-buildinfo" / ("%s.java" format "BuildInfo") + val lines = scala.io.Source.fromFile(f).getLines.toList + lines match { + case """// $COVERAGE-OFF$""" :: + """package hello;""" :: + """""" :: + """/** This file was generated by sbt-buildinfo. */""" :: + """public final class BuildInfo {""" :: + """ private BuildInfo() {}""" :: + """""" :: + """ /** The value is "helloworld". */""" :: + """ public static final String name = "helloworld";""" :: + """ /** The value is "2.12.12". */""" :: + """ public static final String scalaVersion = "2.12.12";""" :: + """ /** The value is java.util.Optional.of(internalAsUrl("http://example.com")). */""" :: + """ public static final java.util.Optional homepage = java.util.Optional.of(internalAsUrl("http://example.com"));""" :: + """ /** The value is java.util.Collections.unmodifiableList(java.util.Arrays.asList(new java.util.AbstractMap.SimpleImmutableEntry<>("MIT License", internalAsUrl("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE")))). */""" :: + """ public static final java.util.Collection> licenses = java.util.Collections.unmodifiableList(java.util.Arrays.asList(new java.util.AbstractMap.SimpleImmutableEntry<>("MIT License", internalAsUrl("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE"))));""" :: + """ /** The value is internalAsMap(). */""" :: + """ public static final java.util.Map apiMappings = internalAsMap();""" :: + """ /** The value is false. */""" :: + """ public static final Boolean isSnapshot = false;""" :: + """ /** The value is 2012. */""" :: + """ public static final Integer year = 2012;""" :: + """ /** The value is ("Foo").intern(). */""" :: + """ public static final String sym = ("Foo").intern();""" :: + """ /** The value is 1234L. */""" :: + """ public static final Long buildTime = 1234L;""" :: + targetInfoComment :: + targetInfo :: + """""" :: + """ public static String makeString() {""" :: + """ return String.format("name: %s, scalaVersion: %s, homepage: %s, licenses: %s, apiMappings: %s, isSnapshot: %s, year: %s, sym: %s, buildTime: %s, target: %s",""" :: + """ name, scalaVersion, homepage, licenses, apiMappings, isSnapshot, year, sym, buildTime, target""" :: + """ );""" :: + """ }""" :: + """""" :: + """ public static java.util.Map makeMap() {""" :: + """ java.util.Map m = new java.util.HashMap<>();""" :: + """ m.put("name", name);""" :: + """ m.put("scalaVersion", scalaVersion);""" :: + """ m.put("homepage", homepage);""" :: + """ m.put("licenses", licenses);""" :: + """ m.put("apiMappings", apiMappings);""" :: + """ m.put("isSnapshot", isSnapshot);""" :: + """ m.put("year", year);""" :: + """ m.put("sym", sym);""" :: + """ m.put("buildTime", buildTime);""" :: + """ m.put("target", target);""" :: + """ return java.util.Collections.unmodifiableMap(m);""" :: + """ }""" :: + """""" :: + """ private static java.net.URL internalAsUrl(String urlString) {""" :: + """ try {""" :: + """ return new java.net.URL(urlString);""" :: + """ } catch (Exception e) {""" :: + """ return null;""" :: + """ }""" :: + """ }""" :: + """""" :: + """ @SuppressWarnings({"unchecked", "rawtypes"})""" :: + """ private static java.util.Map internalAsMap(java.util.Map.Entry... entries) {""" :: + """ java.util.Map m = new java.util.HashMap<>();""" :: + """ for (java.util.Map.Entry e : entries) {""" :: + """ m.put((K) e.getKey(), (V) e.getValue());""" :: + """ }""" :: + """ return java.util.Collections.unmodifiableMap(m);""" :: + """ }""" :: + """""" :: + """ private static String quote(Object x) {""" :: + """ return "\"" + x + "\"";""" :: + """ }""" :: + """""" :: + """ @SuppressWarnings({"unchecked"})""" :: + """ private static String toJsonValue(Object value) {""" :: + """ if (value instanceof java.util.Collection) {""" :: + """ return ((java.util.Collection) value)""" :: + """ .stream().map(BuildInfo::toJsonValue).collect(java.util.stream.Collectors.joining(",", "[", "]"));""" :: + """ } else if (value instanceof java.util.Optional) {""" :: + """ return ((java.util.Optional) value).map(BuildInfo::toJsonValue).orElse("null");""" :: + """ } else if (value instanceof java.util.Map) {""" :: + """ return ((java.util.Map) value)""" :: + """ .entrySet().stream()""" :: + """ .map(e -> toJsonValue(e.getKey().toString()) + ":" + toJsonValue(e.getValue()))""" :: + """ .collect(java.util.stream.Collectors.joining(", ", "{", "}"));""" :: + """ } else if (value instanceof Double) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Float) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Long) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Integer) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Short) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof Boolean) {""" :: + """ return value.toString();""" :: + """ } else if (value instanceof String) {""" :: + """ return quote(value);""" :: + """ } else {""" :: + """ return quote(value.toString());""" :: + """ }""" :: + """ }""" :: + """""" :: + """ public static final String makeJson = toJsonValue(makeMap());""" :: + """}""" :: + """// $COVERAGE-ON$""" :: Nil if ((targetInfo contains "public static final java.io.File target = new java.io.File(") && (targetInfoComment contains "/** The value is new java.io.File(")) => + case _ => sys.error("unexpected output: \n" + lines.mkString("\n")) + } + () + } + ) diff --git a/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/project/plugins.sbt b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/project/plugins.sbt new file mode 100644 index 0000000..e392da8 --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/project/plugins.sbt @@ -0,0 +1,7 @@ +{ + val pluginVersion = System.getProperty("plugin.version") + if(pluginVersion == null) + throw new RuntimeException("""|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) + else addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % pluginVersion) +} diff --git a/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/test b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/test new file mode 100644 index 0000000..db36f0b --- /dev/null +++ b/src/sbt-test/sbt-buildinfo/javastaticfieldsrenderer/test @@ -0,0 +1,4 @@ +> compile +$ exists target/src_managed/main/sbt-buildinfo/BuildInfo.java + +> check From bb59b15d8d983899b48c91c6705dc2d445a4d62c Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Sun, 17 Jan 2021 02:29:08 +0200 Subject: [PATCH 2/2] Increasing stack for tests --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3ee6e22..eb142c2 100644 --- a/build.sbt +++ b/build.sbt @@ -17,7 +17,7 @@ lazy val root = (project in file(".")) description := "sbt plugin to generate build info", homepage := Some(url("https://github.com/sbt/sbt-buildinfo")), licenses := Seq("MIT License" -> url("https://github.com/sbt/sbt-buildinfo/blob/master/LICENSE")), - scriptedLaunchOpts ++= Seq("-Xmx1024M", "-Dplugin.version=" + version.value), + scriptedLaunchOpts ++= Seq("-Xmx1024M", "-Xss4M", "-Dplugin.version=" + version.value), scriptedBufferLog := false, publishTo := (bintray / publishTo).value, publishMavenStyle := false,