1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 08:27:12 -07:00

Merge branch 'master' of github.com:cbeust/kobalt

Conflicts:
	src/main/kotlin/com/beust/kobalt/Main.kt
This commit is contained in:
Cedric Beust 2015-11-05 16:48:37 -08:00
commit dffcee0cd4
33 changed files with 470 additions and 404 deletions

View file

@ -32,6 +32,7 @@ To do:
Done:
- [x] Get rid of the $JAVA_HOME requirement
- [x] getDependencies() should return the transitive dependencies
- [x] Project ordering: kotlinProject(wrapper) {}
- [x] Make files appear in download list automatically on bintray (undocumented API)

View file

@ -16,30 +16,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta-1038" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.0-beta-1038" level="project" />
<orderEntry type="library" name="Gradle: com.beust:jcommander:1.48" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp:okhttp:2.4.0" level="project" />
<orderEntry type="library" name="Gradle: org.jsoup:jsoup:1.8.2" level="project" />
<orderEntry type="library" name="Gradle: com.google.inject:guice:4.0" level="project" />
<orderEntry type="library" name="Gradle: com.google.inject.extensions:guice-assistedinject:4.0" level="project" />
<orderEntry type="library" name="Gradle: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Gradle: org.apache.maven:maven-model:3.3.3" level="project" />
<orderEntry type="library" name="Gradle: com.github.spullara.mustache.java:compiler:0.8.18" level="project" />
<orderEntry type="library" name="Gradle: io.reactivex:rxjava:1.0.14" level="project" />
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.4" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-runtime:1.0.0-beta-1038" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.4.0" level="project" />
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1" level="project" />
<orderEntry type="library" name="Gradle: aopalliance:aopalliance:1.0" level="project" />
<orderEntry type="library" name="Gradle: org.codehaus.plexus:plexus-utils:3.0.20" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.testng:testng:6.9.6" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.google.inject:guice:4.0:no_aop" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.beanshell:bsh:2.0b4" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.apache.ant:ant:1.7.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.yaml:snakeyaml:1.15" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.10" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.apache.ant:ant-launcher:1.7.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.1" level="project" />
<orderEntry type="library" scope="TEST" name="kobalt (Test)" level="project" />
<orderEntry type="library" name="kobalt (Compile)" level="project" />
</component>
</module>

View file

@ -1 +1 @@
kobalt.version=0.217
kobalt.version=0.219

View file

@ -7,5 +7,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="kobalt (Test)" level="project" />
<orderEntry type="library" name="kobalt (Compile)" level="project" />
</component>
</module>

View file

@ -95,10 +95,13 @@ public open class Jvm constructor(
// }
override public fun findExecutable(command: String): File {
val exec = File(javaHome, "bin/" + command)
val executable = java.io.File(os.getExecutableName(exec.getAbsolutePath()))
if (executable.isFile()) {
return executable
if (javaHome != null) {
val jdkHome = if (javaHome!!.endsWith("jre")) javaHome!!.parentFile else javaHome
val exec = File(jdkHome, "bin/" + command)
var executable = File(os.getExecutableName(exec.absolutePath))
if (executable.isFile) {
return executable
}
}
// if (userSupplied) {
@ -108,12 +111,12 @@ public open class Jvm constructor(
val pathExecutable = os.findInPath(command)
if (pathExecutable != null) {
log(1, "Unable to find the ${command} executable using home: " +
"%{javaHome}. We found it on the PATH: ${pathExecutable}.")
log(1, "Unable to find the $command executable using home: " +
"%{javaHome}. We found it on the PATH: $pathExecutable.")
return pathExecutable
}
warn("Unable to find the ${command} executable. Tried the java home: ${javaHome}" +
warn("Unable to find the $command executable. Tried the java home: $javaHome" +
" and the PATH. We will assume the executable can be ran in the current " +
"working folder.")
return java.io.File(os.getExecutableName(command))

View file

@ -1,7 +1,9 @@
package com.beust.kobalt
import com.beust.jcommander.JCommander
import com.beust.kobalt.api.*
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginInfo
import com.beust.kobalt.api.Project
import com.beust.kobalt.internal.TaskManager
import com.beust.kobalt.internal.remote.KobaltClient
import com.beust.kobalt.internal.remote.KobaltServer
@ -18,7 +20,6 @@ import java.io.File
import java.nio.file.Paths
import java.util.*
import javax.inject.Inject
import javax.xml.bind.JAXBContext
public fun main(argv: Array<String>) {
val result = mainNoExit(argv)
@ -35,6 +36,7 @@ private fun parseArgs(argv: Array<String>): Main.RunInfo {
return Main.RunInfo(result, args)
}
public fun mainNoExit(argv: Array<String>) : Int {
val (jc, args) = parseArgs(argv)
Kobalt.INJECTOR = Guice.createInjector(MainModule(args))
@ -55,7 +57,8 @@ private class Main @Inject constructor(
val updateKobalt: UpdateKobalt,
val client: KobaltClient,
val server: KobaltServer,
val pluginInfoDescription: PluginInfoDescription) {
val pluginInfo: PluginInfo,
val projectGenerator: ProjectGenerator) {
data class RunInfo(val jc: JCommander, val args: Args)
@ -97,11 +100,11 @@ private class Main @Inject constructor(
public fun runTest() {
val file = File("src\\main\\resources\\META-INF\\plugin.xml")
val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java)
val kotlinPlugin : KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(file) as KobaltPluginXml
val pluginInfo = PluginInfo.create(kotlinPlugin)
System.out.println(kotlinPlugin.name)
// val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java)
//
// val kotlinPlugin : KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(file) as KobaltPluginXml
// val pluginInfo = PluginInfo.create(kotlinPlugin)
// System.out.println(kotlinPlugin.name)
}
private fun runWithArgs(jc: JCommander, args: Args) : Int {
@ -119,7 +122,7 @@ private class Main @Inject constructor(
// --init: create a new build project and install the wrapper
//
Wrapper().install()
ProjectGenerator().run(args)
projectGenerator.run(args)
} else if (args.usage) {
jc.usage()
} else if (args.serverMode) {
@ -128,8 +131,7 @@ private class Main @Inject constructor(
if (! buildFile.exists()) {
error(buildFile.path.toFile().path + " does not exist")
} else {
var allProjects = listOf<Project>()
val pluginInfo = PluginInfo(pluginInfoDescription)
var allProjects = arrayListOf<Project>()
try {
allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo).compileBuildFiles(args)
} catch(ex: KobaltException) {
@ -142,8 +144,8 @@ private class Main @Inject constructor(
return 1
} else {
log(1, "Deleted .kobalt")
allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
.compileBuildFiles(args)
allProjects.addAll(buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
.compileBuildFiles(args))
}
}
@ -178,7 +180,6 @@ private class Main @Inject constructor(
}
return result
}
private fun findBuildFile(): File {
val files = arrayListOf("Build.kt", "build.kobalt", KFiles.src("build.kobalt"),
KFiles.src("Build.kt"))

View file

@ -37,6 +37,9 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
companion object {
public val MANIFEST_PLUGIN_CLASS : String = "Kobalt-Plugin-Class"
/** The name of the XML file describing a plug-in */
val PLUGIN_XML = "plugin.xml"
private var pluginMap = hashMapOf<String, Plugin>()
// private var storageMap = HashMap<String, HashMap<String, Any>>()
// fun storeValue(pluginName: String, key: String, value: Any) {

View file

@ -1,133 +1,57 @@
package com.beust.kobalt
import com.beust.kobalt.api.ICompilerInfo
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.maven.Pom
import com.beust.kobalt.maven.Pom.Dependency
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.api.IInitContributor
import com.beust.kobalt.api.PluginInfo
import com.beust.kobalt.misc.log
import com.github.mustachejava.DefaultMustacheFactory
import com.google.inject.Inject
import java.io.File
import java.io.InputStreamReader
import java.io.PrintWriter
import java.io.StringWriter
import java.util.ArrayList
import java.util.Collections
import java.util.HashMap
import java.io.FileOutputStream
import java.util.*
/**
* Generate a new project.
* Invoked with --init. Generate a new project.
*/
public class ProjectGenerator {
public class ProjectGenerator @Inject constructor(val pluginInfo: PluginInfo){
companion object {
/**
* Turns a dot property into a proper Kotlin identifier, e.g. common.version -> commonVersion
*/
fun translate(key: String): String {
return key.split('.').mapIndexed( { index, value -> if (index == 0) value else value.upperFirst() })
fun toIdentifier(key: String): String {
fun upperFirst(s: String) = if (s.isBlank()) s else s.substring(0, 1).toUpperCase() + s.substring(1)
return key.split('.').mapIndexed( { index, value -> if (index == 0) value else upperFirst(value) })
.joinToString("")
}
}
fun run(args: Args) {
if (File(args.buildFile).exists()) {
log(1, "Build file ${args.buildFile} already exists, not overwriting it")
return
val contributor = findBestInitContributor(File("."))
if (contributor != null) {
contributor.generateBuildFile(FileOutputStream(File(args.buildFile)))
log(1, "Created ${args.buildFile}")
} else {
log(1, "Couldn't identify project, not generating any build file")
}
}
val compilerInfos = detect(File("."))
if (compilerInfos.size > 1) {
log(1, "Multi language project detected, not supported yet")
}
val map = hashMapOf<String, Any?>()
map.put("directive", if (compilerInfos.isEmpty()) "project" else compilerInfos.get(0).directive)
if (compilerInfos.size > 0) {
compilerInfos.get(0).let {
val currentDir = File(".").absoluteFile.parentFile
with(map) {
put("name", currentDir.name)
put("group", "com.example")
put("version", "0.1")
put("directory", currentDir.absolutePath)
put("sourceDirectories", it.defaultSourceDirectories)
put("sourceDirectoriesTest", it.defaultTestDirectories)
put("imports", "import com.beust.kobalt.plugin.${it.name}.*")
put("directive", it.name + "Project")
/**
* Run through all the IInitContributors and return the best one.
*/
private fun findBestInitContributor(dir: File) : IInitContributor? {
val result = arrayListOf<Pair<IInitContributor, Int>>()
pluginInfo.initContributors.forEach {
it.filesManaged(dir).let { count ->
if (count > 0) {
result.add(Pair(it, count))
}
}
}
var mainDeps = arrayListOf<Dependency>()
var testDeps = arrayListOf<Dependency>()
map.put("mainDependencies", mainDeps)
map.put("testDependencies", testDeps)
File("pom.xml").let {
if (it.absoluteFile.exists()) {
importPom(it, mainDeps, testDeps, map)
}
}
val fileInputStream = javaClass.classLoader.getResource("build-template.mustache").openStream()
val sw = StringWriter()
val pw = PrintWriter(sw)
var mf = DefaultMustacheFactory();
var mustache = mf.compile(InputStreamReader(fileInputStream), "kobalt");
mustache.execute(pw, map).flush();
KFiles.saveFile(File(args.buildFile), sw.toString())
}
private fun importPom(pomFile: File, mainDeps: ArrayList<Dependency>, testDeps: ArrayList<Dependency>,
map: HashMap<String, Any?>) {
var pom = Pom("imported", pomFile.absoluteFile)
with(map) {
put("group", pom.groupId ?: "com.example")
put("artifactId", pom.artifactId ?: "com.example")
put("version", pom.version ?: "0.1")
put("name", pom.name ?: pom.artifactId)
put("repositories", pom.repositories.map({ "\"${it}\"" }).joinToString(","))
}
val properties = pom.properties
val mapped = properties.entries.toMap({it.key}, {translate(it.key)})
map.put("properties", properties.entries.map({ Pair(mapped.get(it.key), it.value) }))
val partition = pom.dependencies.groupBy { it.scope }
.flatMap { it.value }
.map { updateVersion(it, mapped) }
.sortedBy { it.groupId + ":" + it.artifactId }
.partition { it.scope != "test" }
mainDeps.addAll(partition.first)
testDeps.addAll(partition.second)
}
private fun updateVersion(dep: Dependency, mapped: Map<String, String>) =
if ( dep.version.startsWith("\${")) {
val property = dep.version.substring(2, dep.version.length - 1)
Dependency(dep.groupId, dep.artifactId, dep.packaging, "\${${mapped.get(property)}}", dep.optional,
dep.scope)
if (result.size > 0) {
Collections.sort(result, { p1, p2 -> p2.second.compareTo(p1.second) })
return result[0].first
} else {
dep
return null
}
/**
* Detect all the languages contained in this project.
*/
private fun detect(dir: File) : List<ICompilerInfo> {
val result = arrayListOf<Pair<ICompilerInfo, List<File>>>()
Kobalt.compilers.forEach {
val managedFiles = it.findManagedFiles(dir)
if (managedFiles.size > 0) {
result.add(Pair(it, managedFiles))
}
}
Collections.sort(result, { p1, p2 -> p1.second.size.compareTo(p2.second.size) })
return result.map { it.first }
}
}
private fun String.upperFirst(): String {
return if (this.isBlank()) this else this.substring(0, 1).toUpperCase() + this.substring(1)
}

View file

@ -1,11 +1,9 @@
package com.beust.kobalt
import java.util.concurrent.locks.ReentrantLock
import javax.inject.Inject
public class SystemProperties {
companion object {
val javaBase = System.getenv("JAVA_HOME") ?: throw IllegalArgumentException("JAVA_HOME not defined")
val javaBase = System.getProperty("java.home") ?:
(System.getenv("JAVA_HOME") ?: throw IllegalArgumentException("JAVA_HOME not defined"))
val javaVersion = System.getProperty("java.version")
val homeDir = System.getProperty("user.home")
val tmpDir = System.getProperty("java.io.tmpdir")

View file

@ -2,38 +2,17 @@ package com.beust.kobalt.api
import com.beust.kobalt.Plugins
import com.google.inject.Injector
import java.io.File
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Paths
import java.util.*
public interface ICompilerInfo {
/** Used to detect what kind of language this project is */
fun findManagedFiles(dir: File) : List<File>
/** Used to generate the imports */
val name: String
/** Used to generate the imports */
val directive: String
val defaultSourceDirectories : ArrayList<String>
val defaultTestDirectories : ArrayList<String>
}
public class Kobalt {
companion object {
lateinit var INJECTOR : Injector
public val compilers : ArrayList<ICompilerInfo> = arrayListOf()
var context: KobaltContext? = null
fun registerCompiler(c: ICompilerInfo) {
compilers.add(c)
}
private val DEFAULT_REPOS = arrayListOf(
"http://repo1.maven.org/maven2/",
"https://repository.jboss.org/nexus/content/repositories/root_repository/",

View file

@ -1,104 +0,0 @@
package com.beust.kobalt.api
import com.beust.kobalt.maven.IClasspathDependency
import com.beust.kobalt.plugin.java.JavaPlugin
import com.beust.kobalt.plugin.kotlin.KotlinPlugin
import java.util.*
import javax.xml.bind.annotation.XmlElement
import javax.xml.bind.annotation.XmlRootElement
class ProjectDescription(val project: Project, val dependsOn: List<Project>)
interface IProjectContributor {
fun projects() : List<ProjectDescription>
}
/**
* Implement this interface in order to add your own entries to the classpath. A list of contributors
* can be found on the `KobaltContext`.
*/
interface IClasspathContributor {
fun entriesFor(project: Project) : Collection<IClasspathDependency>
}
interface IFactory {
fun <T> instanceOf(c: Class<T>) : T
}
class ContributorFactory : IFactory {
override fun <T> instanceOf(c: Class<T>) : T = Kobalt.INJECTOR.getInstance(c)
}
/**
* All the information gathered from the various plugin.xml that were collected.
*/
class PluginInfoDescription {
fun <T> instanceOf(c: Class<T>) : T = Kobalt.INJECTOR.getInstance(c)
val projectContributors : ArrayList<Class<out IProjectContributor>> =
arrayListOf(JavaPlugin::class.java, KotlinPlugin::class.java)
val classpathContributors: ArrayList<Class<out IClasspathContributor>> =
arrayListOf(KotlinPlugin::class.java)
// Future contributors:
// compilerArgs
// source files
// compilers
// --init
}
/**
* Turn the classes found in PluginInfoDescription into concrete objects that plugins can then use.
*/
class PluginInfo(val description: PluginInfoDescription?) {
val projectContributors = arrayListOf<IProjectContributor>()
val classpathContributors = arrayListOf<IClasspathContributor>()
companion object {
fun create(xml: KobaltPluginXml) : PluginInfo {
val factory = Class.forName(xml.factoryClassName).newInstance() as IFactory
val result = PluginInfo(null)
xml.classpathContributors?.className?.forEach {
result.classpathContributors.add(factory.instanceOf(Class.forName(it)) as IClasspathContributor)
}
xml.projectContributors?.className?.forEach {
result.projectContributors.add(factory.instanceOf(Class.forName(it)) as IProjectContributor)
}
return result
}
}
init {
if (description != null) {
classpathContributors.addAll(description.classpathContributors.map { description.instanceOf(it) })
projectContributors.addAll(description.projectContributors.map { description.instanceOf(it) })
}
}
}
class ContributorXml {
@XmlElement @JvmField
val name: String? = null
}
class ContributorsXml {
@XmlElement(name = "class-name") @JvmField
var className: List<String> = arrayListOf<String>()
}
@XmlRootElement(name = "kobalt-plugin")
class KobaltPluginXml {
@XmlElement @JvmField
var name: String? = null
@XmlElement(name = "factory-class-name") @JvmField
var factoryClassName: String? = null
@XmlElement(name = "classpath-contributors") @JvmField
var classpathContributors : ContributorsXml? = null
@XmlElement(name = "project-contributors") @JvmField
var projectContributors : ContributorsXml? = null
}

View file

@ -0,0 +1,155 @@
package com.beust.kobalt.api
import com.beust.kobalt.maven.IClasspathDependency
import com.beust.kobalt.misc.KFiles
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import javax.xml.bind.JAXBContext
import javax.xml.bind.annotation.XmlElement
import javax.xml.bind.annotation.XmlRootElement
//
// Operations related to the parsing of plugin.xml: contributors, XML mapping, etc...
//
/////
// Contributors
//
/**
* Plugins that create project need to implement this interface.
*/
interface IProjectContributor {
fun projects() : List<ProjectDescription>
}
class ProjectDescription(val project: Project, val dependsOn: List<Project>)
/**
* Plugins that export classpath entries need to implement this interface.
*/
interface IClasspathContributor {
fun entriesFor(project: Project) : Collection<IClasspathDependency>
}
/**
* The factory function to use to instantiate all the contributors and other entities
* found in plugin.xml.
*/
interface IFactory {
fun <T> instanceOf(c: Class<T>) : T
}
class ContributorFactory : IFactory {
override fun <T> instanceOf(c: Class<T>) : T = Kobalt.INJECTOR.getInstance(c)
}
/**
* Plugins that want to participate in the --init process (they can generate files to initialize
* a new project).
*/
interface IInitContributor {
/**
* How many files your plug-in understands in the given directory. The contributor with the
* highest number will be asked to generate the build file.
*/
fun filesManaged(dir: File): Int
/**
* Generate the Build.kt file into the given OutputStream.
*/
fun generateBuildFile(os: OutputStream)
}
/////
// XML parsing
//
// The following classes are used by JAXB to parse the plugin.xml file.
/**
* The root element of plugin.xml
*/
@XmlRootElement(name = "kobalt-plugin")
class KobaltPluginXml {
@XmlElement @JvmField
var name: String? = null
@XmlElement(name = "factory-class-name") @JvmField
var factoryClassName: String? = null
@XmlElement(name = "classpath-contributors") @JvmField
var classpathContributors : ContributorsXml? = null
@XmlElement(name = "project-contributors") @JvmField
var projectContributors : ContributorsXml? = null
@XmlElement(name = "init-contributors") @JvmField
var initContributors : ContributorsXml? = null
}
class ContributorXml {
@XmlElement @JvmField
val name: String? = null
}
class ContributorsXml {
@XmlElement(name = "class-name") @JvmField
var className: List<String> = arrayListOf()
}
/**
* Turn a KobaltPluginXml (the raw content of plugin.xml mapped to POJO's) into a PluginInfo object, which contains
* all the contributors instantiated and other information that Kobalt can actually use. Kobalt code that
* needs to access plug-in info can then just inject a PluginInfo object.
*/
class PluginInfo(val xml: KobaltPluginXml) {
val projectContributors = arrayListOf<IProjectContributor>()
val classpathContributors = arrayListOf<IClasspathContributor>()
val initContributors = arrayListOf<IInitContributor>()
// Future contributors:
// compilerArgs
// source files
// compilers
// repos
companion object {
/**
* Read Kobalt's own plugin.xml.
*/
fun readKobaltPluginXml() : PluginInfo {
val pluginXml = KFiles.joinDir("META-INF", "plugin.xml") // Plugins.PLUGIN_XML)
val url = Kobalt::class.java.classLoader.getResource(pluginXml)
if (url != null) {
return readPluginXml(url.openConnection().inputStream)
} else {
throw AssertionError("Couldn't find $pluginXml")
}
}
/**
* Read a general plugin.xml.
*/
private fun readPluginXml(ins: InputStream): PluginInfo {
val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java)
val kotlinPlugin: KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(ins)
as KobaltPluginXml
return PluginInfo(kotlinPlugin)
}
}
init {
val factory = Class.forName(xml.factoryClassName).newInstance() as IFactory
xml.classpathContributors?.className?.forEach {
classpathContributors.add(factory.instanceOf(Class.forName(it)) as IClasspathContributor)
}
xml.projectContributors?.className?.forEach {
projectContributors.add(factory.instanceOf(Class.forName(it)) as IProjectContributor)
}
xml.initContributors?.className?.forEach {
initContributors.add(factory.instanceOf(Class.forName(it)) as IInitContributor)
}
}
}

View file

@ -1,6 +1,7 @@
package com.beust.kobalt.api
import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.internal.IProjectInfo
import com.beust.kobalt.maven.IClasspathDependency
import com.beust.kobalt.maven.MavenDependency
import com.beust.kobalt.misc.KFiles
@ -16,11 +17,11 @@ open public class Project(
@Directive open var packaging: String? = null,
@Directive open var dependencies: Dependencies? = null,
@Directive open var sourceSuffix : String = "",
@Directive open var compilerInfo : ICompilerInfo,
@Directive open var description : String = "",
@Directive open var scm : Scm? = null,
@Directive open var url: String? = null,
@Directive open var licenses: List<License> = arrayListOf<License>()) {
@Directive open var licenses: List<License> = arrayListOf<License>(),
val projectInfo: IProjectInfo) {
var testArgs: ArrayList<String> = arrayListOf()
@ -44,7 +45,7 @@ open public class Project(
}
var sourceDirectories : ArrayList<String> = arrayListOf()
get() = if (field.isEmpty()) compilerInfo.defaultSourceDirectories else field
get() = if (field.isEmpty()) projectInfo.defaultSourceDirectories else field
set(value) {
field = value
}
@ -57,7 +58,7 @@ open public class Project(
}
var sourceDirectoriesTest : ArrayList<String> = arrayListOf()
get() = if (field.isEmpty()) compilerInfo.defaultTestDirectories
get() = if (field.isEmpty()) projectInfo.defaultTestDirectories
else field
set(value) {
field = value

View file

@ -0,0 +1,99 @@
package com.beust.kobalt.internal
import com.beust.kobalt.ProjectGenerator
import com.beust.kobalt.api.IInitContributor
import com.beust.kobalt.maven.Pom
import com.beust.kobalt.misc.KFiles
import com.github.mustachejava.DefaultMustacheFactory
import java.io.*
import java.util.*
/**
* Abstract base class for the build generators that use build-template.mustache.
*/
abstract class BuildGenerator : IInitContributor {
abstract val defaultSourceDirectories : ArrayList<String>
abstract val defaultTestDirectories : ArrayList<String>
abstract val directive : String
abstract val name : String
abstract val fileMatch : (String) -> Boolean
override fun generateBuildFile(os: OutputStream) {
PrintWriter(os).use {
it.print(buildFileContent)
}
}
override fun filesManaged(dir: File) = KFiles.findRecursively(dir, fileMatch).size
private fun importPom(pomFile: File, mainDeps: ArrayList<Pom.Dependency>, testDeps: ArrayList<Pom.Dependency>,
map: HashMap<String, Any?>) {
var pom = Pom("imported", pomFile.absoluteFile)
with(map) {
put("group", pom.groupId ?: "com.example")
put("artifactId", pom.artifactId ?: "com.example")
put("version", pom.version ?: "0.1")
put("name", pom.name ?: pom.artifactId)
put("repositories", pom.repositories.map({ "\"$it\"" }).joinToString(","))
}
val properties = pom.properties
val mapped = properties.entries.toMap({it.key}, { ProjectGenerator.toIdentifier(it.key) })
map.put("properties", properties.entries.map({ Pair(mapped[it.key], it.value) }))
val partition = pom.dependencies.groupBy { it.scope }
.flatMap { it.value }
.map { updateVersion(it, mapped) }
.sortedBy { it.groupId + ":" + it.artifactId }
.partition { it.scope != "test" }
mainDeps.addAll(partition.first)
testDeps.addAll(partition.second)
}
private fun updateVersion(dep: Pom.Dependency, mapped: Map<String, String>) =
if ( dep.version.startsWith("\${")) {
val property = dep.version.substring(2, dep.version.length - 1)
Pom.Dependency(dep.groupId, dep.artifactId, dep.packaging, "\${${mapped[property]}}", dep.optional,
dep.scope)
} else {
dep
}
private val buildFileContent: String
get() {
val map = hashMapOf<String, Any?>()
map.put("directive", directive)
val currentDir = File(".").absoluteFile.parentFile
with(map) {
put("name", currentDir.name)
put("group", "com.example")
put("version", "0.1")
put("directory", currentDir.absolutePath)
put("sourceDirectories", defaultSourceDirectories)
put("sourceDirectoriesTest", defaultTestDirectories)
put("imports", "import com.beust.kobalt.plugin.$name.*")
put("directive", name + "Project")
}
var mainDeps = arrayListOf<Pom.Dependency>()
var testDeps = arrayListOf<Pom.Dependency>()
map.put("mainDependencies", mainDeps)
map.put("testDependencies", testDeps)
File("pom.xml").let {
if (it.absoluteFile.exists()) {
importPom(it, mainDeps, testDeps, map)
}
}
val fileInputStream = javaClass.classLoader.getResource("build-template.mustache").openStream()
val sw = StringWriter()
val pw = PrintWriter(sw)
var mf = DefaultMustacheFactory();
var mustache = mf.compile(InputStreamReader(fileInputStream), "kobalt");
mustache.execute(pw, map).flush();
return sw.toString()
}
}

View file

@ -0,0 +1,11 @@
package com.beust.kobalt.internal
import java.util.*
/**
* Data that is useful for projects to have but should not be specified in the DSL.
*/
interface IProjectInfo {
val defaultSourceDirectories: ArrayList<String>
val defaultTestDirectories: ArrayList<String>
}

View file

@ -2,7 +2,6 @@ package com.beust.kobalt.internal.remote
import com.beust.kobalt.Args
import com.beust.kobalt.api.PluginInfo
import com.beust.kobalt.api.PluginInfoDescription
import com.beust.kobalt.kotlin.BuildFile
import com.beust.kobalt.kotlin.BuildFileCompiler
import com.beust.kobalt.maven.DependencyManager
@ -26,11 +25,11 @@ import javax.inject.Inject
*/
class GetDependenciesCommand @Inject constructor(val executors: KobaltExecutors,
val buildFileCompilerFactory: BuildFileCompiler.IFactory, val args: Args,
val dependencyManager: DependencyManager, val pluginInfoDescription: PluginInfoDescription) : ICommand {
val dependencyManager: DependencyManager, val pluginInfo: PluginInfo) : ICommand {
override val name = "getDependencies"
override fun run(sender: ICommandSender, received: JsonObject) {
val buildFile = BuildFile(Paths.get(received.get("buildFile").asString), "GetDependenciesCommand")
val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile), PluginInfo(pluginInfoDescription))
val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
scriptCompiler.observable.subscribe {
buildScriptInfo -> if (buildScriptInfo.projects.size > 0) {
sender.sendData(toData(buildScriptInfo))

View file

@ -55,7 +55,33 @@ public class KFiles {
public val TEST_CLASSES_DIR : String = "test-classes"
public fun joinDir(vararg ts: String): String = ts.toArrayList().joinToString(File.separator)
/**
* Join the paths elements with the file separator.
*/
fun joinDir(paths: List<String>): String = paths.joinToString(File.separator)
/**
* Join the paths elements with the file separator.
*/
fun joinDir(vararg ts: String): String = ts.toArrayList().joinToString(File.separator)
/**
* The paths elements are expected to be a directory. Make that directory and join the
* elements with the file separator.
*/
fun joinAndMakeDir(paths: List<String>) = joinDir(paths).apply { File(this).mkdirs() }
/**
* The paths elements are expected to be a directory. Make that directory and join the
* elements with the file separator.
*/
fun joinAndMakeDir(vararg ts: String) = joinAndMakeDir(ts.toList())
/**
* The paths elements are expected to be a file. Make that parent directory of that file and join the
* elements with the file separator.
*/
fun joinFileAndMakeDir(vararg ts: String) = joinDir(joinAndMakeDir(ts.slice(0..ts.size - 2)), ts[ts.size - 1])
fun makeDir(dir: String, s: String? = null) =
(if (s != null) File(dir, s) else File(dir)).apply { mkdirs() }
@ -148,20 +174,6 @@ public class KFiles {
}
}
// public fun copy(from: InputStream, to: OutputStream, bufSize: Int): Long {
// val buf = ByteArray(bufSize)
// var total: Long = 0
// while (true) {
// val r = from.read(buf, 0, buf.size())
// if (r == -1) {
// break
// }
// to.write(buf, 0, r)
// total += r.toLong()
// }
// return total
// }
public fun createTempFile(suffix : String = "", deleteOnExit: Boolean = false) : File =
File.createTempFile("kobalt", suffix, File(SystemProperties.tmpDir)).let {
if (deleteOnExit) it.deleteOnExit()

View file

@ -1,6 +1,7 @@
package com.beust.kobalt.misc
import com.beust.kobalt.Args
import com.beust.kobalt.api.PluginInfo
import com.beust.kobalt.kotlin.BuildFileCompiler
import com.beust.kobalt.maven.*
import com.beust.kobalt.plugin.publish.JCenterApi
@ -9,7 +10,6 @@ import com.google.inject.BindingAnnotation
import com.google.inject.Provider
import com.google.inject.TypeLiteral
import com.google.inject.assistedinject.FactoryModuleBuilder
import java.lang.annotation.RetentionPolicy
import java.util.concurrent.ExecutorService
//@Singleton
@ -49,9 +49,12 @@ public open class MainModule(val args: Args) : AbstractModule() {
bind(object: TypeLiteral<KobaltExecutors>() {}).toInstance(executors)
bind(object: TypeLiteral<ExecutorService>() {}).annotatedWith(DependencyExecutor::class.java)
.toInstance(executors.dependencyExecutor)
bind(Args::class.java).toProvider(object : Provider<Args> {
bind(Args::class.java).toProvider(object: Provider<Args> {
override fun get(): Args? = args
})
bind(PluginInfo::class.java).toProvider(object: Provider<PluginInfo> {
override fun get(): PluginInfo? = PluginInfo.readKobaltPluginXml()
})
// bindListener(Matchers.any(), object: TypeListener {

View file

@ -6,10 +6,13 @@ import java.io.InputStream
import java.io.InputStreamReader
open class RunCommand(val command: String) {
val defaultSuccess = { output: List<String> -> log(1, "Success:\n " + output.joinToString("\n"))}
val defaultError = { output: List<String> -> log(1, "Error:\n " + output.joinToString("\n"))}
val defaultSuccess = { output: List<String> -> log(2, "Success:\n " + output.joinToString("\n"))}
val defaultError = {
output: List<String> -> error("Error:\n " + output.joinToString("\n"))
}
var directory = File(".")
var env = hashMapOf<String, String>()
fun run(args: List<String>, error: Function1<List<String>, Unit>? = defaultError,
success: Function1<List<String>, Unit>? = defaultSuccess) : Int {
@ -19,9 +22,13 @@ open class RunCommand(val command: String) {
val pb = ProcessBuilder(allArgs)
pb.directory(directory)
log(2, "Running command: " + allArgs.joinToString(" "))
log(2, "Running command: " + allArgs.joinToString(" ") + "\n Current directory: $directory")
val process = pb.start()
pb.environment().put("ANDROID_HOME", "/Users/beust/android/adt-bundle-mac-x86_64-20140702/sdk")
pb.environment().let { pbEnv ->
env.forEach {
pbEnv.put(it.key, it.value)
}
}
val errorCode = process.waitFor()
if (errorCode != 0 && error != null) {
error(fromStream(process.errorStream))

View file

@ -62,14 +62,6 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
override fun accept(project: Project) = configurations.containsKey(project.name!!)
fun dirGet(dir: Path, vararg others: String) : String {
val result = Paths.get(dir.toString(), *others)
with(result.toFile()) {
mkdirs()
}
return result.toString()
}
val flavor = "debug"
fun compileSdkVersion(project: Project) = configurations[project.name!!]?.compileSdkVersion
@ -96,18 +88,16 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
fun androidJar(project: Project) : Path =
Paths.get(androidHome(project), "platforms", "android-${compileSdkVersion(project)}", "android.jar")
fun generated(project: Project) = Paths.get(project.directory, "app", "build", "generated")
private fun generated(project: Project) = Paths.get(project.buildDirectory, "app", "build", "generated")
private fun intermediates(project: Project) = Paths.get(project.buildDirectory, "app", "build", "intermediates")
private fun aapt(project: Project) = "${androidHome(project)}/build-tools/${buildToolsVersion(project)}/aapt"
private fun temporaryApk(project: Project, flavor: String) = apk(project, flavor, "ap_")
private fun temporaryApk(project: Project, flavor: String)
= KFiles.joinFileAndMakeDir(project.buildDirectory!!, "intermediates", "res", "resources-$flavor.ap_")
private fun apk(project: Project, flavor: String, suffix: String) : String {
val outputDir = dirGet(intermediates(project), "resources", "resources-$flavor")
return Paths.get(outputDir, "resources-$flavor.$suffix").toString()
}
private fun intermediates(project: Project) = Paths.get(project.directory, "app", "build", "intermediates")
private fun apk(project: Project, flavor: String)
= KFiles.joinFileAndMakeDir(project.buildDirectory!!, "outputs", "apk" ,"app-$flavor.apk")
@Task(name = "generateR", description = "Generate the R.java file",
runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
@ -119,8 +109,14 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
return TaskResult()
}
class AaptCommand(project: Project, aapt: String, val aaptCommand: String,
cwd: File = File(project.directory)) : RunCommand(aapt) {
open class AndroidCommand(androidHome: String, command: String) : RunCommand(command) {
init {
env.put("ANDROID_HOME", androidHome)
}
}
inner class AaptCommand(project: Project, aapt: String, val aaptCommand: String,
cwd: File = File(project.directory)) : AndroidCommand(androidHome(project), aapt) {
init {
directory = cwd
}
@ -134,7 +130,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
val manifestDir = Paths.get(project.directory, "app", "src", "main").toString()
val manifest = Paths.get(manifestDir, "AndroidManifest.xml")
val crunchedPngDir = dirGet(intermediates(project), "res", flavor)
val crunchedPngDir = KFiles.joinAndMakeDir(intermediates(project).toString(), "res", flavor)
AaptCommand(project, aapt, "crunch").call(listOf(
"-v",
@ -149,14 +145,16 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
"-M", manifest.toString(),
"-S", crunchedPngDir,
"-S", "app/src/main/res",
"-A", dirGet(intermediates(project), "assets", flavor), // where to find more assets
// where to find more assets
"-A", KFiles.joinAndMakeDir(intermediates(project).toString(), "assets", flavor),
"-m", // create directory
"-J", dirGet(generated, "sources", "r", flavor).toString(), // where all gets generated
// where all gets generated
"-J", KFiles.joinAndMakeDir(generated.toString(), "sources", "r", flavor).toString(),
"-F", temporaryApk(project, flavor),
"--debug-mode",
"-0", "apk",
"--custom-package", applicationId,
"--output-text-symbols", dirGet(intermediates(project), "symbol", flavor))
"--output-text-symbols", KFiles.joinAndMakeDir(intermediates(project).toString(), "symbol", flavor))
)
val rDirectory = KFiles.joinDir(generated.toFile().path, "sources", "r", flavor,
@ -202,21 +200,21 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
val buildToolsDir = buildToolsVersion(project)
val dx = "${androidHome(project)}/build-tools/$buildToolsDir/dx"
val buildDir = context.pluginProperties.get("java", JvmCompilerPlugin.BUILD_DIR)
val libsDir = context.pluginProperties.get("packaging", PackagingPlugin.LIBS_DIR)
File(libsDir!!.toString()).mkdirs()
val libsDir = (context.pluginProperties.get("packaging", PackagingPlugin.LIBS_DIR) as File).path
File(libsDir.toString()).mkdirs()
val classesDex = "classes.dex"
val outClassesDex = KFiles.joinDir(libsDir.toString(), classesDex)
val relClassesDex = File(outClassesDex).parentFile
RunCommand(dx).run(listOf("--dex", "--output", outClassesDex,
buildDir!!.toString()))
val classesDexDir = KFiles.joinAndMakeDir(libsDir, "intermediates", "dex", flavor)
val outClassesDex = KFiles.joinDir(classesDexDir, classesDex)
RunCommand(dx).run(listOf("--dex", "--output", outClassesDex, buildDir!!.toString()))
//
// Add classes.dex to existing .ap_
//
AaptCommand(project, aapt(project), "add", relClassesDex).call(listOf(
"-v", temporaryApk(project, flavor), classesDex
))
AaptCommand(project, aapt(project), "add").apply {
directory = File(outClassesDex).parentFile
}.call(listOf("-v", KFiles.joinDir("../../../../..", temporaryApk(project, flavor)), classesDex))
return TaskResult()
}
@ -230,7 +228,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler) :
@Task(name = "signApk", description = "Sign the apk file", runAfter = arrayOf(TASK_GENERATE),
runBefore = arrayOf("assemble"))
fun signApk(project: Project) : TaskResult {
val apk = apk(project, flavor, "apk")
val apk = apk(project, flavor)
val temporaryApk = temporaryApk(project, flavor)
RunCommand("jarsigner").run(listOf(
"-keystore", homeDir(".android", "debug.keystore"),

View file

@ -0,0 +1,12 @@
package com.beust.kobalt.plugin.java
import com.beust.kobalt.internal.BuildGenerator
import com.google.inject.Inject
public class JavaBuildGenerator @Inject constructor (val projectInfo: JavaProjectInfo) : BuildGenerator() {
override val defaultSourceDirectories = projectInfo.defaultSourceDirectories
override val defaultTestDirectories = projectInfo.defaultTestDirectories
override val directive = "javaProject"
override val name = "java"
override val fileMatch = { f: String -> f.endsWith(".java") }
}

View file

@ -1,24 +0,0 @@
package com.beust.kobalt.plugin.java
import com.beust.kobalt.api.ICompilerInfo
import com.beust.kobalt.misc.KFiles
import com.google.inject.Singleton
import java.io.File
@Singleton
public class JavaCompilerInfo : ICompilerInfo {
override val name = "java"
override fun findManagedFiles(dir: File) : List<File> {
val result = KFiles.findRecursively(dir, { it.endsWith(".java") })
.map { File(it) }
return result
}
override val defaultSourceDirectories = arrayListOf("src/main/java", "src/main/resources")
override val defaultTestDirectories = arrayListOf("src/test/java", "src/test/resources")
override val directive = "javaProject"
}

View file

@ -31,11 +31,6 @@ public class JavaPlugin @Inject constructor(
override val jvmCompiler: JvmCompiler)
: JvmCompilerPlugin(localRepo, files, depFactory, dependencyManager, executors, jvmCompiler),
IProjectContributor {
init {
Kobalt.registerCompiler(JavaCompilerInfo())
}
companion object {
public const val TASK_COMPILE : String = "compile"
public const val TASK_JAVADOC : String = "javadoc"

View file

@ -25,7 +25,7 @@ public class JavaProject(
@Directive
override var packaging: String? = null)
: Project(name, version, directory, buildDirectory, group, artifactId, packaging, dependencies,
".java", JavaCompilerInfo()) {
".java", projectInfo = JavaProjectInfo()) {
override public fun toString() = toString("JavaProject", "name", name!!)
}

View file

@ -0,0 +1,10 @@
package com.beust.kobalt.plugin.java
import com.beust.kobalt.internal.IProjectInfo
import com.google.inject.Singleton
@Singleton
class JavaProjectInfo : IProjectInfo {
override val defaultSourceDirectories = arrayListOf("src/main/java", "src/main/resources")
override val defaultTestDirectories = arrayListOf("src/test/java", "src/test/resources")
}

View file

@ -0,0 +1,13 @@
package com.beust.kobalt.plugin.kotlin
import com.beust.kobalt.internal.BuildGenerator
import com.google.inject.Inject
public class KotlinBuildGenerator @Inject constructor (val projectInfo: KotlinProjectInfo) : BuildGenerator() {
override val defaultSourceDirectories = projectInfo.defaultSourceDirectories
override val defaultTestDirectories = projectInfo.defaultTestDirectories
override val directive = "kotlinProject"
override val name = "kotlin"
override val fileMatch = { f: String -> f.endsWith(".kt") }
}

View file

@ -1,22 +0,0 @@
package com.beust.kobalt.plugin.kotlin
import com.beust.kobalt.api.ICompilerInfo
import com.beust.kobalt.misc.KFiles
import java.io.File
public class KotlinCompilerInfo : ICompilerInfo {
override val name = "kotlin"
override fun findManagedFiles(dir: File): List<File> {
val result = KFiles.findRecursively(dir, { it.endsWith(".kt") })
.map { File(it) }
return result
}
override val defaultSourceDirectories = arrayListOf("src/main/kotlin", "src/main/resources")
override val defaultTestDirectories = arrayListOf("src/test/kotlin", "src/test/resources")
override val directive = "javaProject"
}

View file

@ -24,10 +24,6 @@ class KotlinPlugin @Inject constructor(
: JvmCompilerPlugin(localRepo, files, depFactory, dependencyManager, executors, jvmCompiler),
IProjectContributor, IClasspathContributor {
init {
Kobalt.registerCompiler(KotlinCompilerInfo())
}
companion object {
public const val TASK_COMPILE: String = "compile"
public const val TASK_COMPILE_TEST: String = "compileTest"

View file

@ -25,7 +25,7 @@ public class KotlinProject(
@Directive
override var packaging: String? = null)
: Project(name, version, directory, buildDirectory, group, artifactId, packaging, dependencies, ".kt",
KotlinCompilerInfo()) {
projectInfo = KotlinProjectInfo()) {
override public fun toString() = toString("KotlinProject", "name", name!!)
}

View file

@ -0,0 +1,11 @@
package com.beust.kobalt.plugin.kotlin
import com.beust.kobalt.internal.IProjectInfo
import com.google.inject.Singleton
@Singleton
class KotlinProjectInfo : IProjectInfo {
override val defaultSourceDirectories = arrayListOf("src/main/kotlin", "src/main/resources")
override val defaultTestDirectories = arrayListOf("src/test/kotlin", "src/test/resources")
}

View file

@ -9,4 +9,8 @@
<class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name>
<class-name>com.beust.kobalt.plugin.kotlin.KotlinPlugin</class-name>
</project-contributors>
<init-contributors>
<class-name>com.beust.kobalt.plugin.java.JavaBuildGenerator</class-name>
<class-name>com.beust.kobalt.plugin.kotlin.KotlinBuildGenerator</class-name>
</init-contributors>
</kobalt-plugin>

View file

@ -1 +1 @@
kobalt.version=0.217
kobalt.version=0.219

View file

@ -2,11 +2,13 @@ package com.beust.kobalt.maven
import com.beust.kobalt.Args
import com.beust.kobalt.ProjectGenerator
import com.beust.kobalt.api.PluginInfo
import com.google.inject.Inject
import org.testng.Assert
import org.testng.annotations.Test
import java.io.File
class PomTest {
class PomTest @Inject constructor(val pluginInfo: PluginInfo){
@Test
fun importPom() {
val pomSrc = File("src/test/resources/pom.xml")
@ -52,13 +54,13 @@ class PomTest {
val args = Args()
args.buildFile = file.absolutePath
args.init = true
ProjectGenerator().run(args)
ProjectGenerator(pluginInfo).run(args)
var contents = file.readText()
Assert.assertTrue(contents.contains("group = \"${pom.groupId}\""), "Should find the group defined")
Assert.assertTrue(contents.contains("name = \"${pom.name}\""), "Should find the name defined")
Assert.assertTrue(contents.contains("version = \"${pom.version}\""), "Should find the version defined")
pom.properties.forEach {
Assert.assertTrue(contents.contains("val ${ProjectGenerator.translate(it.key)} = \"${it.value}\""), "Should find the " +
Assert.assertTrue(contents.contains("val ${ProjectGenerator.toIdentifier(it.key)} = \"${it.value}\""), "Should find the " +
"property defined")
}
pom.repositories.forEach {