├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.sbt ├── project ├── build.properties └── plugins.sbt └── src ├── main └── scala │ ├── Keys.scala │ ├── KotlinCompile.scala │ ├── KotlinPlugin.scala │ ├── KotlinTest.scala │ ├── KotlinVersion.scala │ └── UpdateChecker.scala └── sbt-test └── kotlin ├── basic-android ├── build.sbt ├── project.properties ├── project │ ├── android.sbt │ └── plugins.sbt ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── MainActivity.kt │ │ └── res │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-ldpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── layout │ │ └── main.xml │ │ └── values │ │ └── strings.xml ├── test └── tests.sbt ├── basic-tests ├── build.sbt ├── project │ └── plugins.sbt ├── src │ ├── main │ │ └── kotlin │ │ │ └── simple.kt │ └── test │ │ └── kotlin │ │ └── SimpleTest.kt └── test ├── basic ├── build.sbt ├── project │ └── plugins.sbt ├── src │ └── main │ │ └── kotlin │ │ └── simple.kt └── test ├── extensions-android ├── build.sbt ├── project.properties ├── project │ ├── android.sbt │ └── plugins.sbt ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── MainActivity.kt │ │ └── res │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-ldpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── layout │ │ └── main.xml │ │ └── values │ │ └── strings.xml ├── test └── tests.sbt ├── kotlin-1.1-compat ├── build.sbt ├── project │ └── plugins.sbt ├── src │ └── main │ │ └── kotlin │ │ ├── SimpleScript.kts │ │ └── simple.kt └── test ├── kotlin-1.2-compat ├── build.sbt ├── project │ └── plugins.sbt ├── src │ └── main │ │ └── kotlin │ │ ├── SimpleScript.kts │ │ └── simple.kt └── test ├── kotlin-1.3-compat ├── build.sbt ├── project │ └── plugins.sbt ├── src │ └── main │ │ └── kotlin │ │ ├── SimpleScript.kts │ │ └── simple.kt └── test ├── kotlin-script ├── build.sbt ├── project │ ├── build.properties │ └── plugins.sbt ├── src │ └── main │ │ └── kotlin │ │ └── SimpleScript.kts └── test ├── mixed-tests ├── build.sbt ├── project │ └── plugins.sbt ├── src │ ├── main │ │ ├── java │ │ │ └── demo │ │ │ │ └── JavaCalculator.java │ │ └── kotlin │ │ │ └── Calculator.kt │ └── test │ │ └── kotlin │ │ └── MixedTest.kt └── test └── mixed ├── build.sbt ├── project └── plugins.sbt ├── src └── main │ ├── java │ └── demo │ │ ├── JavaA.java │ │ └── JavaB.java │ ├── kotlin │ ├── a.kt │ ├── b.kt │ ├── script.kts │ └── simple.kt │ └── scala │ └── ScalaA.scala ├── test └── tests.sbt /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | os: 3 | - linux 4 | jdk: 5 | - oraclejdk8 6 | cache: 7 | directories: 8 | - $HOME/.m2/repository 9 | - $HOME/.sbt 10 | - $HOME/.ivy2 11 | android: 12 | components: 13 | - build-tools-23.0.1 14 | - platform-tools 15 | - tools 16 | - extra 17 | script: 18 | - curl -o sbt-launcher.sh https://raw.githubusercontent.com/paulp/sbt-extras/master/sbt 19 | - chmod a+x ./sbt-launcher.sh 20 | - ./sbt-launcher.sh compile scripted 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Perry 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kotlin-plugin 2 | 3 | [![Build Status](https://travis-ci.org/pfn/kotlin-plugin.svg?branch=master)](https://travis-ci.org/pfn/kotlin-plugin) 4 | 5 | Build kotlin code using sbt 6 | 7 | Current version 2.0.0 8 | 9 | ## Usage 10 | 11 | * for sbt 1.0.0+ `addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % "2.0.0")` 12 | * for sbt 0.13.x `addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % "1.0.9")` 13 | * Kotlin code will build automatically from `src/XXX/kotlin` 14 | * If necessary, add `kotlinLib("stdlib")`, it is not included by default. 15 | * Loading standard kotlin libraries and plugins: use `kotlinLib(NAME)` as 16 | above to load standard kotlin modules provided by JetBrains. For JetBrains 17 | kotlin compiler plugins, use `kotlinPlugin(NAME)` (e.g. 18 | `kotlinPlugin("android-extensions")`). The difference is that the latter 19 | marks the module as a `compile-internal` dependency and will be excluded 20 | from the final build product. 21 | * Any other libraries can be loaded using the normal `libraryDependencies` 22 | mechanism. Compiler plugins should be added as a normal `libraryDependency` 23 | but specified to be `% "compile-internal"` 24 | * If a non-standard Classpath key needs to be added to the kotlin compile step, 25 | it can be added using the `kotlinClasspath(KEY)` function 26 | * For example, to compile with the android platform using `android-sdk-plugin`: 27 | `kotlinClasspath(Compile, bootClasspath in Android)` 28 | 29 | ## Options 30 | 31 | * `kotlincPluginOptions`: specifies options to pass to kotlin compiler plugins. 32 | Use `val plugin = KotlinPluginOptions(PLUGINID)` and 33 | `plugin.option(KEY, VALUE)` to populate this setting 34 | * `kotlinSource`: specifies kotlin source directory, defaults to 35 | `src/main/kotlin` and `src/test/kotlin` 36 | * `kotlinVersion`: specifies versions of kotlin compiler and libraries to use, 37 | defaults to `1.3.41` 38 | * `kotlinLib(LIB)`: load a standard kotlin library, for example 39 | `kotlinLib("stdlib")`; the library will utilize the version specified in 40 | `kotlinVersion` 41 | plugin 42 | * `kotlincOptions`: options to pass to the kotlin compiler 43 | 44 | ### Examples 45 | 46 | * See the [test cases](src/sbt-test/kotlin) for this plugin 47 | 48 | ### Limitations 49 | 50 | * currently requires kotlin 1.1.4+ 51 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | name := "kotlin-plugin" 2 | 3 | organization := "com.hanhuy.sbt" 4 | 5 | version := "2.0.1-SNAPSHOT" 6 | 7 | scalacOptions ++= Seq("-deprecation","-Xlint","-feature") 8 | /* 9 | libraryDependencies ++= Seq( 10 | "com.hanhuy.sbt" %% "bintray-update-checker" % "0.2" 11 | ) 12 | */ 13 | 14 | libraryDependencies ++= Seq( 15 | "io.argonaut" %% "argonaut" % "6.2", 16 | "org.scalaz" %% "scalaz-core" % "7.2.28" 17 | ) 18 | 19 | sbtPlugin := true 20 | 21 | // build info plugin 22 | 23 | enablePlugins(BuildInfoPlugin, SbtPlugin) 24 | 25 | buildInfoPackage := "kotlin" 26 | 27 | // bintray 28 | bintrayRepository := "sbt-plugins" 29 | 30 | publishMavenStyle := false 31 | 32 | licenses += ("MIT", url("http://opensource.org/licenses/MIT")) 33 | 34 | bintrayOrganization := None 35 | 36 | // scripted 37 | scriptedLaunchOpts ++= Seq( 38 | "-Xmx1024m", 39 | "-Dplugin.version=" + version.value 40 | ) 41 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.3 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value 2 | 3 | addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4") 4 | addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0") -------------------------------------------------------------------------------- /src/main/scala/Keys.scala: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import sbt._ 4 | 5 | /** 6 | * @author pfnguyen 7 | */ 8 | object Keys { 9 | sealed trait KotlinCompileOrder 10 | 11 | val Kotlin = config("kotlin") 12 | val KotlinInternal = config("kotlin-internal").hide 13 | 14 | val updateCheck = TaskKey[Unit]("update-check", "check for a new version of the plugin") 15 | val kotlinCompile = TaskKey[Unit]("kotlin-compile", 16 | "runs kotlin compilation, occurs before normal compilation") 17 | val kotlincPluginOptions = TaskKey[Seq[String]]("kotlinc-plugin-options", 18 | "kotlin compiler plugin options") 19 | val kotlinSource = SettingKey[File]("kotlin-source", "kotlin source directory") 20 | val kotlinVersion = SettingKey[String]("kotlin-version", 21 | "version of kotlin to use for building") 22 | val kotlincOptions = SettingKey[Seq[String]]("kotlinc-options", 23 | "options to pass to the kotlin compiler") 24 | val kotlincJvmTarget = SettingKey[String]("kotlinc-jvm-target", 25 | "jvm target to use for building") 26 | 27 | def kotlinLib(name: String) = sbt.Keys.libraryDependencies += 28 | "org.jetbrains.kotlin" % ("kotlin-" + name) % kotlinVersion.value 29 | 30 | def kotlinPlugin(name: String) = sbt.Keys.libraryDependencies += 31 | "org.jetbrains.kotlin" % ("kotlin-" + name) % kotlinVersion.value % "compile-internal" 32 | 33 | def kotlinClasspath(config: Configuration, classpathKey: Def.Initialize[sbt.Keys.Classpath]): Setting[_] = 34 | kotlincOptions in config ++= { 35 | "-cp" :: classpathKey.value.map(_.data.getAbsolutePath).mkString( 36 | java.io.File.pathSeparator) :: 37 | Nil 38 | } 39 | 40 | case class KotlinPluginOptions(pluginId: String) { 41 | def option(key: String, value: String) = 42 | s"plugin:$pluginId:$key=$value" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/KotlinCompile.scala: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import java.io.File 4 | import java.lang.reflect.{Field, Method} 5 | import java.util.jar.JarEntry 6 | 7 | import sbt.Keys.{Classpath, TaskStreams} 8 | import sbt._ 9 | import sbt.io._ 10 | import sbt.internal.inc.classpath.ClasspathUtilities 11 | 12 | import collection.JavaConverters._ 13 | import scala.util.Try 14 | 15 | /** 16 | * @author pfnguyen 17 | */ 18 | object KotlinCompile { 19 | 20 | def grepjar(jarfile: File)(pred: JarEntry => Boolean): Boolean = 21 | jarfile.isFile && Using.jarFile(false)(jarfile) { in => 22 | in.entries.asScala exists pred 23 | } 24 | 25 | lazy val kotlinMemo = scalaz.Memo.immutableHashMapMemo[Classpath, KotlinReflection](cp => 26 | KotlinReflection.fromClasspath(cp)) 27 | 28 | def compile(options: Seq[String], 29 | jvmTarget: String, 30 | sourceDirs: Seq[File], 31 | kotlinPluginOptions: Seq[String], 32 | classpath: Classpath, 33 | compilerClasspath: Classpath, 34 | output: File, s: TaskStreams): Unit = { 35 | import language.reflectiveCalls 36 | val stub = KotlinStub(s, kotlinMemo(compilerClasspath)) 37 | val args = stub.compilerArgs 38 | stub.parse(args.instance, options.toList) 39 | val kotlinFiles = "*.kt" || "*.kts" 40 | val javaFiles = "*.java" 41 | 42 | val kotlinSources = sourceDirs.flatMap(d => (d ** kotlinFiles).get).distinct 43 | val javaSources = sourceDirs.filterNot(f => sourceDirs.exists(f0 => 44 | f0.relativeTo(f).isDefined && f != f0)) map (d => 45 | (d, (d ** javaFiles).get)) filter (_._2.nonEmpty) 46 | if (kotlinSources.isEmpty) { 47 | s.log.debug("No sources found, skipping kotlin compile") 48 | } else { 49 | s.log.debug(s"Compiling sources $kotlinSources") 50 | def pluralizeSource(count: Int) = 51 | if (count == 1) "source" else "sources" 52 | val message = 53 | s"Compiling ${kotlinSources.size} Kotlin ${pluralizeSource(kotlinSources.size)}" 54 | s.log.info(message) 55 | args.freeArgs = (kotlinSources ++ javaSources.map(_._1)).map(_.getAbsolutePath).asJava 56 | args.noStdlib = true 57 | args.jvmTarget = jvmTarget 58 | val fcpjars = classpath.map(_.data.getAbsoluteFile) 59 | val (pluginjars, cpjars) = fcpjars.partition { 60 | grepjar(_)(_.getName.startsWith( 61 | "META-INF/services/org.jetbrains.kotlin.compiler.plugin")) 62 | } 63 | val cp = cpjars.mkString(File.pathSeparator) 64 | val pcp = pluginjars.map(_.getAbsolutePath).toArray 65 | args.classpath = Option(args.classpath[String]).fold(cp)(_ + File.pathSeparator + cp) 66 | args.pluginClasspaths = Option(args.pluginClasspaths[Array[String]]).fold(pcp)(_ ++ pcp) 67 | args.pluginOptions = Option(args.pluginOptions[Array[String]]).fold( 68 | kotlinPluginOptions.toArray)(_ ++ kotlinPluginOptions.toArray[String]) 69 | output.mkdirs() 70 | args.destination = output.getAbsolutePath 71 | stub.compile(args.instance) 72 | } 73 | } 74 | } 75 | 76 | object KotlinReflection { 77 | def fromClasspath(cp: Classpath): KotlinReflection = { 78 | val cl = ClasspathUtilities.toLoader(cp.map(_.data)) 79 | val compilerClass = cl.loadClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler") 80 | val servicesClass = cl.loadClass("org.jetbrains.kotlin.config.Services") 81 | val messageCollectorClass = cl.loadClass("org.jetbrains.kotlin.cli.common.messages.MessageCollector") 82 | val commonCompilerArgsClass = cl.loadClass("org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments") 83 | 84 | val compilerExec = Try( 85 | compilerClass.getMethod("exec", 86 | messageCollectorClass, servicesClass, commonCompilerArgsClass) 87 | ).toOption.getOrElse { 88 | 89 | val commonToolArguments = cl.loadClass( 90 | "org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments") 91 | val clitool = cl.loadClass( 92 | "org.jetbrains.kotlin.cli.common.CLITool") 93 | clitool.getMethod("exec", 94 | messageCollectorClass, servicesClass, commonToolArguments) 95 | } 96 | 97 | KotlinReflection( 98 | cl, 99 | servicesClass, 100 | compilerClass, 101 | cl.loadClass("org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments"), 102 | messageCollectorClass, 103 | commonCompilerArgsClass, 104 | compilerExec, 105 | servicesClass.getDeclaredField("EMPTY")) 106 | } 107 | } 108 | case class KotlinReflection(cl: ClassLoader, 109 | servicesClass: Class[_], 110 | compilerClass: Class[_], 111 | compilerArgsClass: Class[_], 112 | messageCollectorClass: Class[_], 113 | commonCompilerArgsClass: Class[_], 114 | compilerExec: Method, 115 | servicesEmptyField: Field) 116 | case class KotlinStub(s: TaskStreams, kref: KotlinReflection) { 117 | import language.reflectiveCalls 118 | import kref._ 119 | 120 | def messageCollector: AnyRef = { 121 | type CompilerMessageLocation = { 122 | def getPath: String 123 | def getLine: Int 124 | def getColumn: Int 125 | } 126 | 127 | import java.lang.reflect.{Proxy, InvocationHandler} 128 | val messageCollectorInvocationHandler = new InvocationHandler { 129 | override def invoke(proxy: scala.Any, method: Method, args: Array[AnyRef]) = { 130 | if (method.getName == "report") { 131 | val Array(severity, message, location) = args 132 | val l = location.asInstanceOf[CompilerMessageLocation] 133 | val msg = Option(l).map(x => x.getPath).fold(message.toString)(loc => 134 | loc + ": " + l.getLine + ", " + l.getColumn + ": " + message) 135 | severity.toString match { 136 | case "INFO" => s.log.info(msg) 137 | case "WARNING" => s.log.warn(msg) 138 | case "STRONG_WARNING" => s.log.warn(msg) 139 | case "ERROR" | "EXCEPTION" => s.log.error(msg) 140 | case "OUTPUT" | "LOGGING" => s.log.debug(msg) 141 | } 142 | } 143 | null 144 | } 145 | } 146 | 147 | Proxy.newProxyInstance(cl, Array(messageCollectorClass), messageCollectorInvocationHandler) 148 | } 149 | 150 | def parse(args: Object, options: List[String]): Unit = { 151 | // TODO FIXME, this is much worse than it used to be, the parsing api has been 152 | // deeply in flux since 1.1.x 153 | val parser = kref.cl.loadClass( 154 | "org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt") 155 | val commonToolArguments = cl.loadClass( 156 | "org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments") 157 | val parserMethod = parser.getMethod("parseCommandLineArguments", classOf[java.util.List[java.lang.String]], commonToolArguments) 158 | import collection.JavaConverters._ 159 | parserMethod.invoke(null, options.asJava, args) 160 | } 161 | 162 | def compilerArgs = { 163 | import language.dynamics 164 | new Dynamic { 165 | def withFirstUpper(string: String): String = string.head.toUpper + string.tail 166 | def getterName(field: String) = s"get${withFirstUpper(field)}" 167 | def setterName(field: String) = s"set${withFirstUpper(field)}" 168 | 169 | def selectDynamic[A](field: String): A = { 170 | val methodName = getterName(field) 171 | val getterOpt = compilerArgsClass.getMethods.find(_.getName == methodName) 172 | getterOpt match { 173 | case Some(getter) => getter.invoke(instance).asInstanceOf[A] 174 | case None => compilerArgsClass.getField(field).get(instance).asInstanceOf[A] 175 | } 176 | } 177 | 178 | def updateDynamic(field: String)(value: Any): Unit = { 179 | val methodName = setterName(field) 180 | val setterOpt = compilerArgsClass.getMethods.find(_.getName == methodName) 181 | setterOpt match { 182 | case Some(setter) => setter.invoke(instance, value.asInstanceOf[Object]) 183 | case None => compilerArgsClass.getField(field).set(instance, value) 184 | } 185 | } 186 | 187 | val instance = compilerArgsClass.getDeclaredConstructor().newInstance().asInstanceOf[AnyRef] 188 | } 189 | } 190 | 191 | def compile(args: AnyRef): Unit = { 192 | val compiler = compilerClass.getDeclaredConstructor().newInstance() 193 | val result = compilerExec.invoke(compiler, 194 | messageCollector, servicesEmptyField.get(null), args: java.lang.Object) 195 | result.toString match { 196 | case "COMPILATION_ERROR" | "INTERNAL_ERROR" => 197 | throw new MessageOnlyException("Compilation failed. See log for more details") 198 | case _ => 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/main/scala/KotlinPlugin.scala: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import Keys._ 4 | import sbt._ 5 | import sbt.Keys._ 6 | import sbt.plugins.JvmPlugin 7 | 8 | /** 9 | * @author pfnguyen 10 | */ 11 | object KotlinPlugin extends AutoPlugin { 12 | override def trigger = allRequirements 13 | override def requires = JvmPlugin 14 | 15 | override def projectConfigurations = KotlinInternal :: Nil 16 | 17 | override def globalSettings = (onLoad := onLoad.value andThen { s => 18 | Project.runTask(updateCheck in Keys.Kotlin, s).fold(s)(_._1) 19 | }) :: Nil 20 | 21 | private def kotlinScriptCompilerDeps(kotlinVer: String) = { 22 | import scala.math.Ordering.Implicits.infixOrderingOps 23 | 24 | if (KotlinVersion(kotlinVer) <= KotlinVersion("1.3.21")) { 25 | Seq( 26 | "org.jetbrains.kotlin" % "kotlin-script-runtime" % kotlinVer 27 | ) 28 | } else { 29 | Seq( 30 | "org.jetbrains.kotlin" % "kotlin-scripting-compiler-embeddable" % kotlinVer % KotlinInternal.name, 31 | "org.jetbrains.kotlin" % "kotlin-scripting-compiler-embeddable" % kotlinVer 32 | ) 33 | } 34 | } 35 | 36 | override def projectSettings = Seq( 37 | libraryDependencies ++= Seq( 38 | "org.jetbrains.kotlin" % "kotlin-compiler-embeddable" % kotlinVersion.value % KotlinInternal.name 39 | ) ++ kotlinScriptCompilerDeps(kotlinVersion.value), 40 | managedClasspath in KotlinInternal := Classpaths.managedJars(KotlinInternal, classpathTypes.value, update.value), 41 | updateCheck in Kotlin := { 42 | val log = streams.value.log 43 | UpdateChecker("pfn", "sbt-plugins", "kotlin-plugin") { 44 | case Left(t) => 45 | log.debug("Failed to load version info: " + t) 46 | case Right((versions, current)) => 47 | log.debug("available versions: " + versions) 48 | log.debug("current version: " + BuildInfo.version) 49 | log.debug("latest version: " + current) 50 | if (versions(BuildInfo.version)) { 51 | if (BuildInfo.version != current) { 52 | log.warn( 53 | s"UPDATE: A newer kotlin-plugin is available:" + 54 | s" $current, currently running: ${BuildInfo.version}") 55 | } 56 | } 57 | } 58 | }, 59 | kotlinVersion := "1.3.50", 60 | kotlincJvmTarget := "1.6", 61 | kotlincOptions := Nil, 62 | kotlincPluginOptions := Nil, 63 | watchSources ++= { 64 | import language.postfixOps 65 | val kotlinSources = "*.kt" || "*.kts" 66 | (sourceDirectories in Compile).value.flatMap(_ ** kotlinSources get) ++ 67 | (sourceDirectories in Test).value.flatMap(_ ** kotlinSources get) 68 | } 69 | ) ++ inConfig(Compile)(kotlinCompileSettings) ++ 70 | inConfig(Test)(kotlinCompileSettings) 71 | 72 | val autoImport = Keys 73 | 74 | // public to allow kotlin compile in other configs beyond Compile and Test 75 | val kotlinCompileSettings = List( 76 | unmanagedSourceDirectories += kotlinSource.value, 77 | kotlincOptions := kotlincOptions.value, 78 | kotlincJvmTarget := kotlincJvmTarget.value, 79 | kotlincPluginOptions := kotlincPluginOptions.value, 80 | kotlinCompile := Def.task { 81 | KotlinCompile.compile(kotlincOptions.value, 82 | kotlincJvmTarget.value, 83 | sourceDirectories.value, kotlincPluginOptions.value, 84 | dependencyClasspath.value, (managedClasspath in KotlinInternal).value, 85 | classDirectory.value, streams.value) 86 | }.dependsOn (compileInputs in (Compile,compile)).value, 87 | compile := (compile dependsOn kotlinCompile).value, 88 | kotlinSource := sourceDirectory.value / "kotlin", 89 | definedTests in Test ++= KotlinTest.kotlinTests.value 90 | ) 91 | } 92 | -------------------------------------------------------------------------------- /src/main/scala/KotlinTest.scala: -------------------------------------------------------------------------------- 1 | package sbt 2 | 3 | import sbt.Keys._ 4 | import sbt.internal.inc.classfile.Analyze 5 | import sbt.internal.inc.classpath.ClasspathUtilities 6 | import sbt.internal.inc._ 7 | import xsbti.compile._ 8 | 9 | object KotlinTest { 10 | private object EmptyLookup extends Lookup { 11 | def changedClasspathHash: Option[Vector[FileHash]] = None 12 | 13 | def analyses: Vector[CompileAnalysis] = Vector.empty 14 | 15 | def lookupOnClasspath(binaryClassName: String): Option[File] = None 16 | 17 | def lookupAnalysis(binaryClassName: String): Option[CompileAnalysis] = None 18 | def changedBinaries(previousAnalysis: xsbti.compile.CompileAnalysis): Option[Set[java.io.File]] = None 19 | def changedSources(previousAnalysis: xsbti.compile.CompileAnalysis): Option[xsbti.compile.Changes[java.io.File]] = None 20 | def removedProducts(previousAnalysis: xsbti.compile.CompileAnalysis): Option[Set[java.io.File]] = None 21 | def shouldDoIncrementalCompilation(changedClasses: Set[String],analysis: xsbti.compile.CompileAnalysis): Boolean = true 22 | 23 | def hashClasspath(x$1: Array[java.io.File]): java.util.Optional[Array[xsbti.compile.FileHash]] = java.util.Optional.empty() 24 | } 25 | 26 | val kotlinTests = Def.task { 27 | val out = ((target in Test).value ** "scala-*").get.head / "test-classes" 28 | val srcs = ((sourceDirectory in Test).value ** "*.kt").get.toList 29 | val xs = (out ** "*.class").get.toList 30 | 31 | val loader = ClasspathUtilities.toLoader((fullClasspath in Test).value map { 32 | _.data 33 | }) 34 | val log = streams.value.log 35 | val output = new SingleOutput { 36 | def getOutputDirectory: File = out 37 | } 38 | val a0 = IncrementalCompile( 39 | srcs.toSet, 40 | EmptyLookup, 41 | (fs, changs, callback, clsFileMgr) => { 42 | def readAPI(source: File, classes: Seq[Class[_]]): Set[(String, String)] = { 43 | val (apis, mainClasses, inherits) = ClassToAPI.process(classes) 44 | apis.foreach(callback.api(source, _)) 45 | mainClasses.foreach(callback.mainClass(source, _)) 46 | inherits.map { 47 | case (from, to) => (from.getName, to.getName) 48 | } 49 | } 50 | 51 | Analyze(xs, srcs, log, output, None)(callback, loader, readAPI) 52 | }, 53 | Analysis.Empty, 54 | output, 55 | log, 56 | incOptions.value, 57 | JarUtils.createOutputJarContent(output))._2 58 | val frameworks = (loadedTestFrameworks in Test).value.values.toList 59 | log.info(s"Compiling ${srcs.length} Kotlin source to $out...") 60 | Tests.discover(frameworks, a0, log)._1 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/scala/KotlinVersion.scala: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import scala.math.Ordering 4 | 5 | case class KotlinVersion(versionString: String) extends AnyVal 6 | 7 | object KotlinVersion { 8 | implicit val versionOrdering: Ordering[KotlinVersion] = 9 | Ordering.by { _.versionString.split("[.-]").map(_.toInt).toIterable } 10 | } -------------------------------------------------------------------------------- /src/main/scala/UpdateChecker.scala: -------------------------------------------------------------------------------- 1 | package kotlin 2 | 3 | import java.io.{InputStreamReader, BufferedReader, StringWriter} 4 | 5 | import argonaut._, Argonaut._ 6 | 7 | import scala.concurrent.Future 8 | import scala.util.{Failure, Success} 9 | 10 | object UpdateChecker { 11 | import scala.concurrent.ExecutionContext.Implicits.global 12 | type Result = (Set[String],String) 13 | type Callback[A] = Either[Throwable,Result] => A 14 | 15 | def apply[A](user: String, repo: String, name: String)(result: Callback[A]): Unit = { 16 | val bintray = new java.net.URL( 17 | s"https://api.bintray.com/packages/$user/$repo/$name") 18 | Future { 19 | val uc = bintray.openConnection() 20 | val in = new BufferedReader(new InputStreamReader(uc.getInputStream, "utf-8")) 21 | try { 22 | val sw = new StringWriter 23 | val buf = Array.ofDim[Char](8192) 24 | Stream.continually(in.read(buf, 0, 8192)) takeWhile ( 25 | _ != -1) foreach (sw.write(buf, 0, _)) 26 | sw.toString 27 | } finally { 28 | in.close() 29 | } 30 | } onComplete { 31 | case Success(json) => 32 | val decoded = json.decode[PackageInfo] 33 | val res: Either[Throwable, Result] = decoded match { 34 | case Left(Left(str)) => 35 | Left(new IllegalArgumentException(str)) 36 | case Left(Right(cursorHistory)) => 37 | Left(new IllegalArgumentException(cursorHistory._1)) 38 | case Right(packageInfo) => 39 | Right(packageInfo.versions.toSet -> packageInfo.version) 40 | } 41 | result(res) 42 | case Failure(t) => result(Left(t)) 43 | } 44 | } 45 | 46 | implicit def PackageInfoCodecJson: CodecJson[PackageInfo] = casecodec3( 47 | PackageInfo.apply, PackageInfo.unapply)("name", "latest_version", "versions") 48 | 49 | case class PackageInfo(name: String, version: String, versions: List[String]) 50 | } 51 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/build.sbt: -------------------------------------------------------------------------------- 1 | enablePlugins(AndroidApp) 2 | 3 | kotlinClasspath(Compile, bootClasspath in Android) 4 | 5 | kotlinLib("stdlib") 6 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/project.properties: -------------------------------------------------------------------------------- 1 | target=android-22 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/project/android.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scala-android" % "sbt-android" % "2.0.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package sbt.kotlin.test 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | 6 | class MainActivity : Activity() 7 | { 8 | /** Called when the activity is first created. */ 9 | override fun onCreate(savedInstanceState: Bundle?) 10 | { 11 | super.onCreate(savedInstanceState) 12 | setContentView(R.layout.main) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/basic-android/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/basic-android/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/basic-android/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/basic-android/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainActivity 4 | 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/test: -------------------------------------------------------------------------------- 1 | > android:package 2 | $ exists target/android/output/basic-android-debug.apk 3 | > checkDex 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-android/tests.sbt: -------------------------------------------------------------------------------- 1 | import android.Keys._ 2 | import sys.process._ 3 | 4 | val androidBuilder = SettingKey[Logger => com.android.builder.core.AndroidBuilder]("android-builder") in Android 5 | 6 | TaskKey[Unit]("checkDex") := { 7 | val p = androidBuilder.value 8 | val s = streams.value 9 | val layout = (projectLayout in Android).value 10 | implicit val out = outputLayout.value 11 | val tools = p(s.log).getTargetInfo.getBuildTools.getLocation 12 | val dexdump = tools / "dexdump" 13 | val lines = Seq( 14 | dexdump.getAbsolutePath, "-i", 15 | (layout.dex / "classes.dex").getAbsolutePath).lineStream 16 | val hasKotlinClasses = lines map (_.trim) exists { l => 17 | l.startsWith("Class descriptor") && l.endsWith("'Lkotlin/Unit;'") 18 | } 19 | if (!hasKotlinClasses) { 20 | lines filter (_.trim.startsWith("Class descriptor")) foreach (l => s.log.info(l)) 21 | sys.error("Kotlin classes not found") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-tests/build.sbt: -------------------------------------------------------------------------------- 1 | import sbt.complete.Parsers.spaceDelimited 2 | 3 | import scala.xml.{NodeSeq, XML} 4 | 5 | kotlinLib("stdlib") 6 | 7 | libraryDependencies ++= Seq( 8 | "com.novocode" % "junit-interface" % "0.11" % Test 9 | ) 10 | 11 | lazy val checkTestPass = inputKey[Unit]("Check if a given test-report has one success test") 12 | checkTestPass := { 13 | val args: Seq[String] = spaceDelimited("").parsed 14 | val testName = args.head 15 | 16 | val xml = XML.load(s"target/test-reports/$testName.xml") 17 | val totalTests = getInt(xml \\ "testsuite" \ "@tests") 18 | val failures = getInt(xml \\ "testsuite" \ "@failures") 19 | val errors = getInt(xml \\ "testsuite" \ "@errors") 20 | val skipped = getInt(xml \\ "testsuite" \ "@skipped") 21 | 22 | if (totalTests == 0 || failures > 0 || errors > 0 || skipped > 0) { 23 | sys.error("Tests not passed") 24 | } 25 | } 26 | 27 | def getInt(path: NodeSeq): Int = path.text.toInt -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-tests/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-tests/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | fun main(args: Array) { 4 | println("Hello, world!") 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-tests/src/test/kotlin/SimpleTest.kt: -------------------------------------------------------------------------------- 1 | import org.junit.Test 2 | import junit.framework.TestCase.assertEquals 3 | 4 | class SimpleTest { 5 | 6 | @Test 7 | fun `should works`() { 8 | assertEquals(4, 2 + 2) 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic-tests/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > test 3 | > "checkTestPass SimpleTest" -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | val listClasses = taskKey[Unit]("listClasses") 4 | 5 | listClasses := { 6 | val classes = (classDirectory in Compile).value.listFiles() 7 | streams.value.log.info("classes: " + classes) 8 | } 9 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | fun main(args: Array) { 3 | println("Hello, world!") 4 | } 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/basic/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > listClasses 3 | $ exists target/scala-2.12/classes/demo/SimpleKt.class 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/build.sbt: -------------------------------------------------------------------------------- 1 | enablePlugins(AndroidApp) 2 | javacOptions in Compile ++= "-source" :: "1.7" :: "-target" :: "1.7" :: Nil 3 | 4 | kotlinClasspath(Compile, bootClasspath in Android) 5 | kotlinPlugin("android-extensions") 6 | kotlinLib("stdlib") 7 | kotlincPluginOptions in Compile ++= { 8 | val plugin = KotlinPluginOptions("org.jetbrains.kotlin.android") 9 | val layout = (projectLayout in Android).value 10 | plugin.option("package", applicationId.value) :: 11 | plugin.option("variant", "main;" + layout.res.getCanonicalPath) :: 12 | Nil 13 | } 14 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/project.properties: -------------------------------------------------------------------------------- 1 | target=android-22 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/project/android.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scala-android" % "sbt-android" % "2.0.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package sbt.kotlin.test 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | 6 | import kotlinx.android.synthetic.main.main.* 7 | 8 | class MainActivity : Activity() 9 | { 10 | /** Called when the activity is first created. */ 11 | override fun onCreate(savedInstanceState: Bundle?) 12 | { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.main) 15 | this_is_test.setText("Wow?") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/extensions-android/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/extensions-android/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/extensions-android/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfn/kotlin-plugin/c5b0fe4f66982821520b2c4853830cf34d8ecc29/src/sbt-test/kotlin/extensions-android/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainActivity 4 | 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/test: -------------------------------------------------------------------------------- 1 | > android:package 2 | $ exists target/android/output/extensions-android-debug.apk 3 | > checkDex 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/extensions-android/tests.sbt: -------------------------------------------------------------------------------- 1 | import android.Keys._ 2 | import sys.process._ 3 | 4 | val androidBuilder = SettingKey[Logger => com.android.builder.core.AndroidBuilder]("android-builder") in Android 5 | 6 | TaskKey[Unit]("checkDex") := { 7 | implicit val out = outputLayout.value 8 | val p = androidBuilder.value 9 | val s = streams.value 10 | val layout = (projectLayout in Android).value 11 | val tools = p(s.log).getTargetInfo.getBuildTools.getLocation 12 | val dexdump = tools / "dexdump" 13 | val lines = Seq( 14 | dexdump.getAbsolutePath, "-i", 15 | (layout.dex / "classes.dex").getAbsolutePath).lineStream 16 | val hasKotlinClasses = lines map (_.trim) exists { l => 17 | l.startsWith("Class descriptor") && l.endsWith("'Lkotlin/Unit;'") 18 | } 19 | if (!hasKotlinClasses) { 20 | lines filter (_.trim.startsWith("Class descriptor")) foreach (l => s.log.info(l)) 21 | sys.error("Kotlin classes not found") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.1-compat/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | kotlinVersion := "1.1.4-3" 4 | 5 | val listClasses = taskKey[Unit]("listClasses") 6 | 7 | listClasses := { 8 | val classes = (classDirectory in Compile).value.listFiles() 9 | streams.value.log.info("classes: " + classes) 10 | } 11 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.1-compat/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % sys.props("plugin.version")) 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.1-compat/src/main/kotlin/SimpleScript.kts: -------------------------------------------------------------------------------- 1 | println("Hello world!") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.1-compat/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | fun main(args: Array) { 3 | val map = mapOf("key" to 42) 4 | val emptyMap = map - "key" 5 | 6 | val list1 = listOf("a", "b") 7 | val list2 = listOf("x", "y", "z") 8 | val minSize = minOf(list1.size, list2.size) 9 | val longestList = maxOf(list1, list2, compareBy { it.size }) 10 | } 11 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.1-compat/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > listClasses 3 | $ exists target/scala-2.12/classes/demo/SimpleKt.class 4 | $ exists target/scala-2.12/classes/SimpleScript.class 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.2-compat/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | kotlinVersion := "1.2.71" 4 | 5 | val listClasses = taskKey[Unit]("listClasses") 6 | 7 | listClasses := { 8 | val classes = (classDirectory in Compile).value.listFiles() 9 | streams.value.log.info("classes: " + classes) 10 | } 11 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.2-compat/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % sys.props("plugin.version")) 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.2-compat/src/main/kotlin/SimpleScript.kts: -------------------------------------------------------------------------------- 1 | println("Hello world!") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.2-compat/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | fun main(args: Array) { 3 | // Test some Kotlin 1.2 features 4 | val items = (1..9).map { it * it } 5 | 6 | val chunkedIntoLists = items.chunked(4) 7 | val points3d = items.chunked(3) { (x, y, z) -> Triple(x, y, z) } 8 | val windowed = items.windowed(4) 9 | val slidingAverage = items.windowed(4) { it.average() } 10 | val pairwiseDifferences = items.zipWithNext { a, b -> b - a } 11 | 12 | println("Hello, world!") 13 | } 14 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.2-compat/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > listClasses 3 | $ exists target/scala-2.12/classes/demo/SimpleKt.class 4 | $ exists target/scala-2.12/classes/SimpleScript.class 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.3-compat/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | kotlinVersion := "1.3.41" 4 | 5 | val listClasses = taskKey[Unit]("listClasses") 6 | 7 | listClasses := { 8 | val classes = (classDirectory in Compile).value.listFiles() 9 | streams.value.log.info("classes: " + classes) 10 | } 11 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.3-compat/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % sys.props("plugin.version")) 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.3-compat/src/main/kotlin/SimpleScript.kts: -------------------------------------------------------------------------------- 1 | println("Hello world!") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.3-compat/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | fun main(args: Array) { 3 | // Test some Kotlin 1.3 features 4 | val keys = 'a'..'f' 5 | val map = keys.associateWith { it.toString().repeat(5).capitalize() } 6 | map.forEach { println(it) } 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-1.3-compat/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > listClasses 3 | $ exists target/scala-2.12/classes/demo/SimpleKt.class 4 | $ exists target/scala-2.12/classes/SimpleScript.class 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-script/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | kotlinVersion := "1.3.21" 4 | 5 | val listClasses = taskKey[Unit]("listClasses") 6 | 7 | listClasses := { 8 | val classes = (classDirectory in Compile).value.listFiles() 9 | streams.value.log.info("classes: " + classes) 10 | } 11 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-script/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.2.8 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-script/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % sys.props("plugin.version")) 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-script/src/main/kotlin/SimpleScript.kts: -------------------------------------------------------------------------------- 1 | println("Hello world!") 2 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/kotlin-script/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > listClasses 3 | $ exists target/scala-2.12/classes/SimpleScript.class 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/build.sbt: -------------------------------------------------------------------------------- 1 | import sbt.complete.Parsers.spaceDelimited 2 | 3 | import scala.xml.{NodeSeq, XML} 4 | 5 | kotlinLib("stdlib") 6 | 7 | libraryDependencies ++= Seq( 8 | "com.novocode" % "junit-interface" % "0.11" % Test 9 | ) 10 | 11 | lazy val checkTestPass = inputKey[Unit]("Check if a given test-report has one success test") 12 | checkTestPass := { 13 | val args: Seq[String] = spaceDelimited("").parsed 14 | val testName = args.head 15 | 16 | val xml = XML.load(s"target/test-reports/$testName.xml") 17 | val totalTests = getInt(xml \\ "testsuite" \ "@tests") 18 | val failures = getInt(xml \\ "testsuite" \ "@failures") 19 | val errors = getInt(xml \\ "testsuite" \ "@errors") 20 | val skipped = getInt(xml \\ "testsuite" \ "@skipped") 21 | 22 | if (totalTests == 0 || failures > 0 || errors > 0 || skipped > 0) { 23 | sys.error("Tests not passed") 24 | } 25 | } 26 | 27 | def getInt(path: NodeSeq): Int = path.text.toInt -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/src/main/java/demo/JavaCalculator.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class JavaCalculator { 4 | 5 | public int sum(int a, int b) { 6 | return a + b; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/src/main/kotlin/Calculator.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | class Calculator(private val calculator: JavaCalculator) { 4 | 5 | fun sum(a: Int, b: Int): Int = calculator.sum(a, b) 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/src/test/kotlin/MixedTest.kt: -------------------------------------------------------------------------------- 1 | import org.junit.Test 2 | import junit.framework.TestCase.assertEquals 3 | import demo.Calculator 4 | import demo.JavaCalculator 5 | 6 | class MixedTest { 7 | 8 | @Test 9 | fun `should sum 2 plus 2`() { 10 | val calculator = Calculator(JavaCalculator()) 11 | assertEquals(4, calculator.sum(2, 2)) 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed-tests/test: -------------------------------------------------------------------------------- 1 | > compile 2 | > test 3 | > "checkTestPass MixedTest" -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/build.sbt: -------------------------------------------------------------------------------- 1 | kotlinLib("stdlib") 2 | 3 | kotlincOptions += "-verbose" 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | { 2 | val ver = System.getProperty("plugin.version") 3 | if (ver == null) 4 | throw new RuntimeException(""" 5 | |The system property 'plugin.version' is not defined. 6 | |Specify this property using scriptedLaunchOpts -Dplugin.version.""" 7 | .stripMargin) 8 | else addSbtPlugin("com.hanhuy.sbt" % "kotlin-plugin" % ver) 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/java/demo/JavaA.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class JavaA { 4 | } 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/java/demo/JavaB.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | public class JavaB extends KotlinA { 4 | } 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/kotlin/a.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | open class KotlinA { 3 | } 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/kotlin/b.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | class KotlinB : JavaA() { 4 | } 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/kotlin/script.kts: -------------------------------------------------------------------------------- 1 | 2 | println("Hello from Kotlin script") -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/kotlin/simple.kt: -------------------------------------------------------------------------------- 1 | package demo 2 | fun main(args: Array) { 3 | println("Hello, world!") 4 | } 5 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/src/main/scala/ScalaA.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | class ScalaA extends KotlinA 4 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/test: -------------------------------------------------------------------------------- 1 | > debug 2 | > compile 3 | > info 4 | $ exists target/scala-2.12/classes/demo/SimpleKt.class 5 | > checkClasses 6 | -------------------------------------------------------------------------------- /src/sbt-test/kotlin/mixed/tests.sbt: -------------------------------------------------------------------------------- 1 | TaskKey[Unit]("check-classes") := { 2 | val classes = (classDirectory in Compile).value 3 | val classList = (classes ** "*.class").get 4 | if (classList.size != 7) { 5 | throw new MessageOnlyException(s"Incorrect number of classes: ${classList.size} =>\n${classList.mkString("\n")}") 6 | } 7 | } 8 | --------------------------------------------------------------------------------