├── settings.gradle ├── ceylon-gradle-plugin-tests ├── spark-web-sample │ ├── .gitignore │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── sparkweb │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ └── build.gradle ├── spring-boot-sample │ ├── .gitignore │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── springboot │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ ├── build.gradle │ └── README.md ├── module-with-tests-sample │ ├── .gitignore │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── simple │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ ├── test-source │ │ └── test │ │ │ └── com │ │ │ └── athaydes │ │ │ └── simple │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ └── build.gradle ├── fat-jar-tests │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── fatJar │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ ├── resource │ │ └── com │ │ │ └── athaydes │ │ │ └── fatJar │ │ │ └── ROOT │ │ │ └── log4j2.xml │ └── build.gradle ├── log4j-sample │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── maven │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── example │ │ │ └── Example.java │ ├── build.gradle │ └── resource │ │ └── com │ │ └── athaydes │ │ └── maven │ │ └── ROOT │ │ └── log4j2.xml ├── multi-modules-sample │ ├── module1 │ │ ├── source │ │ │ └── com │ │ │ │ └── athaydes │ │ │ │ └── module1 │ │ │ │ ├── module.ceylon │ │ │ │ ├── package.ceylon │ │ │ │ └── Module1.ceylon │ │ └── build.gradle │ ├── module2 │ │ ├── source │ │ │ ├── com │ │ │ │ └── athaydes │ │ │ │ │ └── module2 │ │ │ │ │ ├── package.ceylon │ │ │ │ │ ├── module.ceylon │ │ │ │ │ └── run.ceylon │ │ │ └── test │ │ │ │ └── com │ │ │ │ └── athaydes │ │ │ │ └── module2 │ │ │ │ ├── module.ceylon │ │ │ │ └── tests.ceylon │ │ └── build.gradle │ ├── java-module │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── athaydes │ │ │ └── ceylon_gradle_plugin │ │ │ └── java_module │ │ │ └── MyJavaClass.java │ └── README.md ├── module-with-whitespace-path │ ├── All Ceylon Sources │ │ └── com │ │ │ └── athaydes │ │ │ └── simple │ │ │ ├── package.ceylon │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ └── build.gradle ├── cross-language-modules │ ├── java-example │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── athaydes │ │ │ └── java │ │ │ └── JavaExample.java │ ├── kotlin-example │ │ ├── src │ │ │ └── main │ │ │ │ └── kotlin │ │ │ │ └── com │ │ │ │ └── athaydes │ │ │ │ └── kotlin │ │ │ │ └── KotlinExample.kt │ │ └── build.gradle │ ├── groovy-example │ │ ├── src │ │ │ └── main │ │ │ │ └── groovy │ │ │ │ └── com │ │ │ │ └── athaydes │ │ │ │ └── groovy │ │ │ │ └── MyGroovyClass.groovy │ │ └── build.gradle │ └── ceylon-example │ │ ├── source │ │ └── com │ │ │ └── athaydes │ │ │ └── ceylon_example │ │ │ ├── module.ceylon │ │ │ └── run.ceylon │ │ └── build.gradle ├── build.gradle └── settings.gradle ├── .travis.yml ├── src ├── main │ ├── resources │ │ └── META-INF │ │ │ └── gradle-plugins │ │ │ └── com.athaydes.ceylon.properties │ └── groovy │ │ └── com │ │ └── athaydes │ │ └── gradle │ │ └── ceylon │ │ ├── util │ │ ├── ModuleDescriptorCreator.groovy │ │ ├── CommandOption.groovy │ │ ├── MavenPomCreator.groovy │ │ ├── MavenSettingsFileCreator.groovy │ │ ├── CeylonRunner.groovy │ │ ├── DependencyTree.groovy │ │ ├── CeylonCommandOptions.groovy │ │ └── CeylonToolLocator.groovy │ │ ├── task │ │ ├── RunCeylonTask.groovy │ │ ├── CleanTask.groovy │ │ ├── CompileCeylonTestTask.groovy │ │ ├── CompileCeylonTask.groovy │ │ ├── FatJarTask.groovy │ │ ├── CreateDependenciesPomsTask.groovy │ │ ├── CreateModuleDescriptorsTask.groovy │ │ ├── TestCeylonTask.groovy │ │ ├── CreateMavenRepoTask.groovy │ │ ├── ResolveCeylonDependenciesTask.groovy │ │ ├── GenerateOverridesFileTask.groovy │ │ ├── ImportJarsTask.groovy │ │ └── CreateJavaRuntimeTask.groovy │ │ ├── CeylonConfig.groovy │ │ ├── CeylonPlugin.groovy │ │ └── parse │ │ └── CeylonModuleParser.groovy └── test │ └── groovy │ └── com │ └── athaydes │ └── gradle │ └── ceylon │ ├── CeylonPluginTest.groovy │ └── parse │ └── CeylonModuleParserTest.groovy ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradlew.bat ├── release-notes.md ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ceylon-gradle-plugin' 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spark-web-sample/.gitignore: -------------------------------------------------------------------------------- 1 | /classes/ 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/.gitignore: -------------------------------------------------------------------------------- 1 | /classes/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: groovy 2 | 3 | jdk: 4 | - oraclejdk7 5 | - oraclejdk8 -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/.gitignore: -------------------------------------------------------------------------------- 1 | /classes/ 2 | target/ -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/fat-jar-tests/source/com/athaydes/fatJar/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.fatJar; 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/source/com/athaydes/maven/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.maven; 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/source/com/athaydes/simple/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.simple; -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/source/com/athaydes/springboot/package.ceylon: -------------------------------------------------------------------------------- 1 | package com.athaydes.springboot; 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/src/main/java/example/Example.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | public class Example { 4 | 5 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/source/com/athaydes/simple/module.ceylon: -------------------------------------------------------------------------------- 1 | module com.athaydes.simple "1.0.0" {} -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spark-web-sample/source/com/athaydes/sparkweb/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.sparkweb; 2 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/gradle-plugins/com.athaydes.ceylon.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.athaydes.gradle.ceylon.CeylonPlugin -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module1/source/com/athaydes/module1/module.ceylon: -------------------------------------------------------------------------------- 1 | module com.athaydes.module1 "1.0" {} 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module1/source/com/athaydes/module1/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.module1; -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renatoathaydes/ceylon-gradle-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-whitespace-path/All Ceylon Sources/com/athaydes/simple/package.ceylon: -------------------------------------------------------------------------------- 1 | shared package com.athaydes.simple; 2 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-whitespace-path/All Ceylon Sources/com/athaydes/simple/module.ceylon: -------------------------------------------------------------------------------- 1 | module com.athaydes.simple "1.0.0" { 2 | } 3 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/source/com/athaydes/module2/package.ceylon: -------------------------------------------------------------------------------- 1 | "This is a shared package, so we can write tests for it." 2 | shared package com.athaydes.module2; -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-whitespace-path/All Ceylon Sources/com/athaydes/simple/run.ceylon: -------------------------------------------------------------------------------- 1 | "Run the module `com.athaydes.simple`." 2 | shared void run() { 3 | print("Simple module is running"); 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.jar 3 | 4 | .classpath 5 | .project 6 | *.iml 7 | .idea/ 8 | .gradle/ 9 | build/ 10 | auto-generated/ 11 | 12 | .ceylon/ 13 | .exploded/ 14 | .settings/ 15 | modules/ 16 | .exploded/ 17 | bin/ -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/java-example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/test-source/test/com/athaydes/simple/module.ceylon: -------------------------------------------------------------------------------- 1 | module test.com.athaydes.simple "1.0.0" { 2 | import ceylon.test "1.2.1"; 3 | import com.athaydes.simple "1.0.0"; 4 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module1/source/com/athaydes/module1/Module1.ceylon: -------------------------------------------------------------------------------- 1 | shared object module1 { 2 | shared String name = "module1"; 3 | } 4 | 5 | shared void run() { 6 | print("Hello from Module 1"); 7 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spark-web-sample/source/com/athaydes/sparkweb/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") 2 | module com.athaydes.sparkweb "1.0.0" { 3 | import java.base "8"; 4 | import maven:"com.sparkjava:spark-core" "2.5.4"; 5 | } 6 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module1/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | ceylon { 7 | module = 'com.athaydes.module1' 8 | } 9 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/source/test/com/athaydes/module2/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") module test.com.athaydes.module2 "1.0" { 2 | import com.athaydes.module2 "1.0"; 3 | import ceylon.test "1.2.1"; 4 | } 5 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/source/com/athaydes/module2/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") module com.athaydes.module2 "1.0" { 2 | import com.athaydes.module1 "1.0"; 3 | import com.athaydes.ceylon_gradle_plugin.java_module "1.0"; 4 | } 5 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/kotlin-example/src/main/kotlin/com/athaydes/kotlin/KotlinExample.kt: -------------------------------------------------------------------------------- 1 | package com.athaydes.kotlin 2 | 3 | public class KotlinExample() { 4 | public fun sayHi(name: String): String = "Hello $name from Kotlin!" 5 | } 6 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/source/com/athaydes/maven/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") 2 | module com.athaydes.maven "1.0.0" { 3 | import java.base "8"; 4 | import ceylon.interop.java "1.2.1"; 5 | import "org.apache.logging.log4j:log4j-core" "2.4.1"; 6 | } 7 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/fat-jar-tests/source/com/athaydes/fatJar/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") 2 | module com.athaydes.fatJar "1.0.0" { 3 | import java.base "8"; 4 | import ceylon.interop.java "1.3.1"; 5 | import maven:"org.apache.logging.log4j:log4j-core" "2.4.1"; 6 | } 7 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/groovy-example/src/main/groovy/com/athaydes/groovy/MyGroovyClass.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.groovy 2 | 3 | class MyGroovyClass { 4 | 5 | static String groovyMultiply( String a, int b ) { 6 | a * b 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Nov 19 21:20:15 CET 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip 7 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'com.athaydes.ceylon' 3 | 4 | group 'com.athaydes.gradle.ceylon' 5 | version '1.0' 6 | 7 | repositories { 8 | mavenLocal() 9 | } 10 | 11 | ceylon { 12 | module = "com.athaydes.maven" 13 | } 14 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/java-module/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | compile "com.google.guava:guava:19.0" 12 | } 13 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/source/com/athaydes/springboot/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") 2 | module com.athaydes.springboot "1.0.0" { 3 | import java.base "8"; 4 | import ceylon.interop.java "1.2.1"; 5 | import "org.springframework.boot:spring-boot-starter-web" "1.3.0.RELEASE"; 6 | } 7 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/groovy-example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | compile "org.codehaus.groovy:groovy-all:2.4.5" 12 | } 13 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/java-example/src/main/java/com/athaydes/java/JavaExample.java: -------------------------------------------------------------------------------- 1 | package com.athaydes.java; 2 | 3 | public class JavaExample { 4 | 5 | public static String replace( String text, String toReplace, String replacement ) { 6 | return text.replace( toReplace, replacement ); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/test-source/test/com/athaydes/simple/run.ceylon: -------------------------------------------------------------------------------- 1 | import ceylon.test { 2 | ... 3 | } 4 | import com.athaydes.simple { add } 5 | 6 | test 7 | shared void ceylonTest() { 8 | assertEquals(add(2, 2), 4); 9 | } 10 | 11 | test 12 | shared void anotherTest() { 13 | assertEquals(add(1, 0), 1); 14 | } 15 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-whitespace-path/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'com.athaydes.ceylon' 3 | 4 | group 'com.athaydes.gradle.ceylon' 5 | version '1.0' 6 | 7 | repositories { 8 | mavenLocal() 9 | } 10 | 11 | ceylon { 12 | module = "com.athaydes.simple" 13 | sourceRoots = [ "All Ceylon Sources" ] 14 | testRoots = [ "All Ceylon Sources" ] 15 | } 16 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/ceylon-example/source/com/athaydes/ceylon_example/module.ceylon: -------------------------------------------------------------------------------- 1 | native("jvm") 2 | module com.athaydes.ceylon_example "1.0" { 3 | import maven:"com.athaydes.ceylon-gradle-plugin:java-example" "1.0"; 4 | import maven:"com.athaydes.ceylon-gradle-plugin:groovy-example" "1.0"; 5 | import maven:"com.athaydes.ceylon-gradle-plugin:kotlin-example" "1.0"; 6 | } 7 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/fat-jar-tests/source/com/athaydes/fatJar/run.ceylon: -------------------------------------------------------------------------------- 1 | import org.apache.logging.log4j { 2 | Logger, 3 | LogManager 4 | } 5 | import ceylon.interop.java { javaClass } 6 | 7 | shared class MyTestClass() {} 8 | 9 | Logger logger = LogManager.getLogger(javaClass()); 10 | 11 | "Run the module `com.athaydes.fatJar`." 12 | shared void run() { 13 | logger.info("Hello from Ceylon fatJAR!"); 14 | } 15 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spark-web-sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group 'com.athaydes.gradle.ceylon' 4 | version '1.0' 5 | 6 | repositories { 7 | mavenLocal() 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | ceylonCompile "com.sparkjava:spark-core:2.3", { 13 | exclude group: 'org.eclipse.jetty.websocket' 14 | } 15 | } 16 | 17 | ceylon { 18 | module = "com.athaydes.sparkweb" 19 | } 20 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/source/com/athaydes/maven/run.ceylon: -------------------------------------------------------------------------------- 1 | import org.apache.logging.log4j { 2 | Logger, 3 | LogManager 4 | } 5 | import java.lang { 6 | Thread 7 | } 8 | import ceylon.interop.java { javaClass } 9 | 10 | shared class MyTest() {} 11 | 12 | Logger logger = LogManager.getLogger(javaClass()); 13 | 14 | "Run the module `com.athaydes.maven`." 15 | shared void run() { 16 | logger.info("Hello Maven!"); 17 | Thread.sleep(1000); 18 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group 'com.athaydes.gradle.ceylon' 4 | version '1.0' 5 | 6 | repositories { 7 | mavenLocal() 8 | mavenCentral() 9 | } 10 | 11 | ceylon { 12 | module = "com.athaydes.springboot" 13 | } 14 | 15 | dependencies { 16 | ceylonCompile "org.springframework.boot:spring-boot-starter-web:1.3.0.RELEASE", { 17 | exclude group: "ch.qos.logback" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/build.gradle: -------------------------------------------------------------------------------- 1 | subprojects { 2 | buildscript { 3 | repositories { 4 | flatDir { 5 | dirs rootProject.file( '../build/libs' ) 6 | } 7 | mavenLocal() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath "com.athaydes.gradle.ceylon:ceylon-gradle-plugin:1.3.1" 13 | classpath 'org.ceylon-lang:com.redhat.ceylon.common:1.3.1' 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/fat-jar-tests/resource/com/athaydes/fatJar/ROOT/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/log4j-sample/resource/com/athaydes/maven/ROOT/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/ceylon-example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | repositories { 7 | jcenter() 8 | } 9 | 10 | ceylon { 11 | module = 'com.athaydes.ceylon_example' 12 | } 13 | 14 | dependencies { 15 | ceylonCompile project( ':cross-language-modules:java-example' ) 16 | ceylonCompile project( ':cross-language-modules:groovy-example' ) 17 | ceylonCompile project( ':cross-language-modules:kotlin-example' ) 18 | } 19 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group = 'com.athaydes.ceylon-gradle-plugin' 4 | version = '1.0' 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | 10 | ceylon { 11 | module = 'com.athaydes.module2' 12 | testModule = 'test.com.athaydes.module2' 13 | importJars = true 14 | flatClasspath = false 15 | } 16 | 17 | dependencies { 18 | ceylonCompile project( ':multi-modules-sample:module1' ) 19 | ceylonCompile project( ':multi-modules-sample:java-module' ) 20 | } 21 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/kotlin-example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'kotlin' 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.0.0' 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | group 'com.athaydes.ceylon-gradle-plugin' 14 | version '1.0' 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 22 | } 23 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/source/test/com/athaydes/module2/tests.ceylon: -------------------------------------------------------------------------------- 1 | import ceylon.test { ... } 2 | 3 | import com.athaydes.module2 { getPaddedMessage } 4 | 5 | shared test 6 | void getPaddedMessageTest() { 7 | assertEquals(getPaddedMessage(" Hello!", 10, '*'), "*** Hello!"); 8 | assertEquals(getPaddedMessage("", 10, '*'), "**********"); 9 | assertEquals(getPaddedMessage("Hej", 2, '*'), "Hej"); 10 | assertEquals(getPaddedMessage("Hej", 0, '*'), "Hej"); 11 | assertEquals(getPaddedMessage("Hej", -10, '*'), "Hej"); 12 | } 13 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/settings.gradle: -------------------------------------------------------------------------------- 1 | include 'log4j-sample', 2 | 'spark-web-sample', 3 | 'spring-boot-sample', 4 | 'module-with-tests-sample', 5 | 'multi-modules-sample:module1', 6 | 'multi-modules-sample:module2', 7 | 'multi-modules-sample:java-module', 8 | 'cross-language-modules:ceylon-example', 9 | 'cross-language-modules:java-example', 10 | 'cross-language-modules:groovy-example', 11 | 'cross-language-modules:kotlin-example', 12 | 'fat-jar-tests', 13 | 'module-with-whitespace-path' 14 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/java-module/src/main/java/com/athaydes/ceylon_gradle_plugin/java_module/MyJavaClass.java: -------------------------------------------------------------------------------- 1 | package com.athaydes.ceylon_gradle_plugin.java_module; 2 | 3 | import com.google.common.base.Strings; 4 | 5 | public class MyJavaClass { 6 | 7 | private final String message; 8 | 9 | public MyJavaClass(String message) { 10 | this.message = message; 11 | } 12 | 13 | public String getMessage() { 14 | return message; 15 | } 16 | 17 | public String getPaddedMessage(int minLength, char padChar) { 18 | return Strings.padStart(message, minLength, padChar); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Multi-modules Gradle Project Demo 2 | 3 | If you have 2 or more Ceylon projects with inter-dependencies, you must declare the dependency of one project on 4 | another in the Gradle build file. 5 | 6 | In this Demo, there are 2 modules: 7 | 8 | * `:multi-modules-sample:module1` 9 | * `:multi-modules-sample:module2` 10 | 11 | `module2` depends on `module1`. 12 | 13 | To build both project, from this directory, run the following command: 14 | 15 | ``` 16 | gradle compileCeylon 17 | ``` 18 | 19 | After that, to run `module2`, run: 20 | 21 | ``` 22 | gradle :multi-modules-sample:module2:runCeylon 23 | ``` 24 | 25 | `module1` is not runnable. 26 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/multi-modules-sample/module2/source/com/athaydes/module2/run.ceylon: -------------------------------------------------------------------------------- 1 | import com.athaydes.module1 { ... } 2 | import com.athaydes.ceylon_gradle_plugin.java_module { MyJavaClass } 3 | 4 | shared void run() { 5 | print("Module2 running..."); 6 | print("Hi, what's your name, other module? ``module1.name``"); 7 | 8 | value javaClass = MyJavaClass("Running in Java"); 9 | value paddedMessage = javaClass.getPaddedMessage(50, '_'); 10 | 11 | print("Hey, Java class, give me a padded message! ``paddedMessage``"); 12 | } 13 | 14 | shared String getPaddedMessage(String message, Integer characterCount, Character paddingCharacter) 15 | => MyJavaClass(message).getPaddedMessage(characterCount, paddingCharacter); 16 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/cross-language-modules/ceylon-example/source/com/athaydes/ceylon_example/run.ceylon: -------------------------------------------------------------------------------- 1 | import com.athaydes.groovy { MyGroovyClass } 2 | import com.athaydes.java { JavaExample } 3 | import com.athaydes.kotlin { KotlinExample } 4 | 5 | shared void run() { 6 | // use Groovy 7 | value separator = MyGroovyClass.groovyMultiply("=", 50); 8 | print(separator); 9 | 10 | print("This is the ceylon_example module running!"); 11 | 12 | // use Java 13 | value urlEncoded = JavaExample.replace("This is a text message", " ", "%20"); 14 | print("URL encoded message: ``urlEncoded``"); 15 | 16 | // use Kotlin 17 | value greeting = KotlinExample().sayHi("Ceylon"); 18 | print(greeting); 19 | 20 | print(separator); 21 | } 22 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/source/com/athaydes/springboot/run.ceylon: -------------------------------------------------------------------------------- 1 | import org.springframework.boot { ... } 2 | import org.springframework.boot.autoconfigure { ... } 3 | import org.springframework.stereotype { ... } 4 | import org.springframework.web.bind.annotation { ... } 5 | 6 | import java.lang { JString=String } 7 | import ceylon.interop.java { javaClass, javaString } 8 | 9 | controller 10 | enableAutoConfiguration 11 | shared class SampleController() { 12 | 13 | requestMapping({ "/" }) 14 | responseBody 15 | shared JString home() { 16 | return javaString("Hello World!"); 17 | } 18 | 19 | } 20 | 21 | "Run the module `com.athaydes.springboot`." 22 | shared void run() { 23 | SpringApplication.run(javaClass()); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/ModuleDescriptorCreator.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import org.gradle.api.artifacts.ResolvedDependency 4 | 5 | class ModuleDescriptorCreator { 6 | 7 | static void createModuleDescriptorFor( ResolvedDependency dependency, Writer writer ) { 8 | def dependencies = DependencyTree.transitiveDependenciesOf( dependency ) 9 | 10 | if ( dependencies ) { 11 | for ( child in dependencies ) { 12 | def entry = "+${child.moduleGroup}\\:${child.moduleName}=${child.moduleVersion}" 13 | writer.write entry 14 | writer.write '\n' 15 | } 16 | } else { 17 | writer.write '' // create an empty file 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group 'com.athaydes.gradle.ceylon' 4 | version '1.0' 5 | 6 | repositories { 7 | mavenLocal() 8 | mavenCentral() 9 | } 10 | 11 | // example of providing arguments directly to the Ceylon tool 12 | project.ext.'ceylon-args' = '--fully-export-maven-dependencies' 13 | 14 | ceylon { 15 | moduleName = "com.athaydes.simple" 16 | testModule = "test.com.athaydes.simple" 17 | testRoots = [ 'test-source' ] 18 | testReportDestination = 'test-reports' 19 | generateTestReport = true 20 | flatClasspath = false 21 | javaRuntimeDestination = file( 'target/jvm' ) 22 | entryPoint = 'com.athaydes.simple::addArgs' 23 | //entryPoint = 'com.athaydes.simple::TopLevelRunnable' 24 | } 25 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spark-web-sample/source/com/athaydes/sparkweb/run.ceylon: -------------------------------------------------------------------------------- 1 | import spark { 2 | Spark 3 | } 4 | import java.lang { 5 | Thread, 6 | Runnable 7 | } 8 | 9 | object stop satisfies Runnable { 10 | shared actual void run() { 11 | Thread.sleep(250); // so the server responds to the request before dying! 12 | print("Stopping Server"); 13 | Spark.stop(); 14 | } 15 | } 16 | 17 | "Run the module `com.athaydes.sparkweb`." 18 | shared void run() { 19 | Spark.get("hello", (request, response) { 20 | print("Received request accepting ``request.headers("Accept") else "null"``"); 21 | return "Hello Ceylon!"; 22 | }); 23 | Spark.get("bye", (request, response) { 24 | Thread(stop).start(); 25 | return "Bye!"; 26 | }); 27 | } -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/module-with-tests-sample/source/com/athaydes/simple/run.ceylon: -------------------------------------------------------------------------------- 1 | "Run the module `com.athaydes.simple`." 2 | shared void run() { 3 | print("Hello World!"); 4 | print("Args: ``process.arguments``"); 5 | } 6 | 7 | shared void addArgs() { 8 | value args = process.arguments.collect(parseFloat); 9 | if (args.any((n) => n is Null)) { 10 | print("Invalid input. Only numbers are acceptable. Arguments: ``process.arguments``"); 11 | } else { 12 | value numbers = args.coalesced; 13 | value total = numbers.fold(0.0)(plus); 14 | print("The sum of ``numbers`` is: ``total``"); 15 | } 16 | } 17 | 18 | shared Integer add(Integer a, Integer b) 19 | => a + b; 20 | 21 | shared class TopLevelRunnable() { 22 | 23 | print("Running TopLevelRunnable"); 24 | 25 | } -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/RunCeylonTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.tasks.TaskAction 9 | 10 | @CompileStatic 11 | class RunCeylonTask extends DefaultTask { 12 | 13 | @TaskAction 14 | void run() { 15 | final config = project.extensions.getByType( CeylonConfig ) 16 | final List finalArgs = [ ] 17 | 18 | if ( project.hasProperty( 'app-args' ) ) { 19 | finalArgs << project.property( 'app-args' )?.toString() 20 | } 21 | 22 | CeylonRunner.run 'run', config.module, project, config, 23 | CeylonCommandOptions.getRunOptions( project, config ), finalArgs 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/CommandOption.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.Immutable 5 | import org.gradle.api.Nullable 6 | 7 | /** 8 | * A simple command option. 9 | * 10 | * {@link CommandOption#toString} returns the option without quoting the argument (if there is an argument). 11 | * 12 | * To get the argument quoted, use {@link CommandOption#withQuotedArgument()}. 13 | */ 14 | @Immutable 15 | @CompileStatic 16 | class CommandOption { 17 | String option 18 | @Nullable 19 | String argument 20 | 21 | @Override 22 | String toString() { 23 | option + ( argument ? '=' + argument : '' ) 24 | } 25 | 26 | String withQuotedArgument() { 27 | option + ( argument ? '="' + argument + '"' : '' ) 28 | } 29 | 30 | static CommandOption of( String option, String argument = null ) { 31 | new CommandOption( option, argument ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/fat-jar-tests/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.athaydes.ceylon' 2 | 3 | group 'com.athaydes.gradle.ceylon' 4 | version '1.0' 5 | 6 | repositories { 7 | mavenLocal() 8 | } 9 | 10 | ceylon { 11 | moduleName = "com.athaydes.fatJar" 12 | } 13 | 14 | task test( type: Exec, dependsOn: 'fatJar', group: 'verification', 15 | description: 'Runs the Ceylon fatJar using Java and asserts the process output is as expected' ) { 16 | commandLine( System.getProperty( 'java.home' ) + '/bin/java', '-jar', 17 | new File( buildDir, 'com.athaydes.fatJar-1.0.0.jar' ).absolutePath ) 18 | 19 | standardOutput = new ByteArrayOutputStream() 20 | 21 | ext.output = { 22 | return standardOutput.toString() 23 | } 24 | 25 | doLast { 26 | String javaOutput = output() 27 | print javaOutput 28 | assert javaOutput.endsWith( ' INFO com.athaydes.fatJar.MyTestClass - Hello from Ceylon fatJAR!\n' ) 29 | println "Ceylon FatJar was created successfully!" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CleanTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.MavenSettingsFileCreator 5 | import groovy.transform.CompileStatic 6 | import org.gradle.api.Project 7 | import org.gradle.api.tasks.Delete 8 | import org.gradle.api.tasks.TaskAction 9 | 10 | @CompileStatic 11 | class CleanTask extends Delete { 12 | 13 | static List filesToDelete( Project project, CeylonConfig config ) { 14 | def tasks = { Class... types -> types.collect { Class type -> project.tasks.withType( type ) } } 15 | [ project.buildDir, 16 | MavenSettingsFileCreator.mavenSettingsFile( project, config ), 17 | project.files( tasks( 18 | CompileCeylonTask, GenerateOverridesFileTask, CreateMavenRepoTask, 19 | CompileCeylonTestTask, CreateDependenciesPomsTask, TestCeylonTask, 20 | CreateJavaRuntimeTask, CreateModuleDescriptorsTask ) ) ] 21 | } 22 | 23 | @TaskAction 24 | @Override 25 | void clean() { 26 | final config = project.extensions.getByType( CeylonConfig ) 27 | delete filesToDelete( project, config ) 28 | super.clean() 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/groovy/com/athaydes/gradle/ceylon/CeylonPluginTest.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.testfixtures.ProjectBuilder 5 | import org.junit.Test 6 | 7 | class CeylonPluginTest { 8 | 9 | @Test 10 | void "All tasks added to project"() { 11 | Project project = ProjectBuilder.builder() 12 | .withName( 'test-project' ) 13 | .build() 14 | 15 | project.apply plugin: 'com.athaydes.ceylon' 16 | 17 | assert project.tasks.cleanCeylon 18 | assert project.tasks.compileCeylon 19 | assert project.tasks.runCeylon 20 | assert project.tasks.testCeylon 21 | assert project.tasks.resolveCeylonDependencies 22 | assert project.tasks.generateOverridesFile 23 | assert project.tasks.importJars 24 | assert project.tasks.fatJar 25 | assert project.extensions.ceylon instanceof CeylonConfig 26 | 27 | assert project.configurations.ceylonCompile 28 | assert project.configurations.ceylonRuntime 29 | } 30 | 31 | @Test 32 | void "Can apply Java plugin, then Ceylon plugin"() { 33 | Project project = ProjectBuilder.builder() 34 | .withName( 'test-project' ) 35 | .build() 36 | 37 | project.apply plugin: 'java' 38 | project.apply plugin: 'com.athaydes.ceylon' 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CompileCeylonTestTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.Project 9 | import org.gradle.api.tasks.InputFiles 10 | import org.gradle.api.tasks.OutputDirectory 11 | import org.gradle.api.tasks.TaskAction 12 | 13 | /** 14 | * Compiles ceylon tests. 15 | */ 16 | @CompileStatic 17 | class CompileCeylonTestTask extends DefaultTask { 18 | 19 | static List inputFiles( Project project, CeylonConfig config ) { 20 | [ project.buildFile, project.files( config.testRoots, config.testResourceRoots ) ] 21 | } 22 | 23 | static File outputDir( Project project, CeylonConfig config ) { 24 | project.file( config.output ) 25 | } 26 | 27 | @InputFiles 28 | List getInputFiles() { 29 | final config = project.extensions.getByType( CeylonConfig ) 30 | inputFiles( project, config ) 31 | } 32 | 33 | @OutputDirectory 34 | File getOutputDir() { 35 | final config = project.extensions.getByType( CeylonConfig ) 36 | outputDir( project, config ) 37 | } 38 | 39 | @TaskAction 40 | void run() { 41 | final config = project.extensions.getByType( CeylonConfig ) 42 | 43 | CeylonRunner.run 'compile', config.testModule, project, config, 44 | CeylonCommandOptions.getTestCompileOptions( project, config ) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CompileCeylonTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.Project 9 | import org.gradle.api.tasks.InputFiles 10 | import org.gradle.api.tasks.OutputDirectory 11 | import org.gradle.api.tasks.TaskAction 12 | 13 | @CompileStatic 14 | class CompileCeylonTask extends DefaultTask { 15 | 16 | static List inputFiles( Project project, CeylonConfig config ) { 17 | [ project.buildFile, 18 | project.files( config.sourceRoots, config.resourceRoots ), 19 | project.tasks.withType( GenerateOverridesFileTask ) ] 20 | } 21 | 22 | static File outputDir( Project project, CeylonConfig config ) { 23 | project.file( config.output ) 24 | } 25 | 26 | @InputFiles 27 | List getInputFiles() { 28 | final config = project.extensions.getByType( CeylonConfig ) 29 | inputFiles( project, config ) 30 | } 31 | 32 | @OutputDirectory 33 | File getOutputDir() { 34 | final config = project.extensions.getByType( CeylonConfig ) 35 | outputDir( project, config ) 36 | } 37 | 38 | @TaskAction 39 | void run() { 40 | final config = project.extensions.getByType( CeylonConfig ) 41 | 42 | CeylonRunner.run 'compile', config.module, project, config, 43 | CeylonCommandOptions.getCompileOptions( project, config ) 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/MavenPomCreator.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import groovy.xml.MarkupBuilder 4 | import org.gradle.api.artifacts.ResolvedDependency 5 | 6 | class MavenPomCreator { 7 | 8 | static void createPomFor( ResolvedDependency dependency, Writer writer ) { 9 | new MarkupBuilder( writer ).with { xml -> 10 | xml.mkp.xmlDeclaration( version: "1.0", encoding: "UTF-8" ) 11 | 12 | xml.project( 13 | 'xsi:schemaLocation': 'http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd', 14 | 'xmlns': 'http://maven.apache.org/POM/4.0.0', 15 | 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance' ) { 16 | modelVersion '4.0.0' 17 | groupId dependency.moduleGroup 18 | artifactId dependency.moduleName 19 | version dependency.moduleVersion 20 | 21 | def dependencies = DependencyTree.directDependenciesOf( dependency ) 22 | 23 | if ( dependencies ) { 24 | xml.dependencies { 25 | writeDependencies xml, dependencies 26 | } 27 | } 28 | 29 | } 30 | } 31 | } 32 | 33 | private static void writeDependencies( MarkupBuilder xml, 34 | Collection dependencies ) { 35 | for ( dependency in dependencies ) { 36 | xml.dependency { 37 | groupId dependency.moduleGroup 38 | artifactId dependency.moduleName 39 | version dependency.moduleVersion 40 | } 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/MavenSettingsFileCreator.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.task.CreateMavenRepoTask 5 | import org.gradle.api.Project 6 | import org.gradle.api.logging.Logger 7 | import org.gradle.api.logging.Logging 8 | 9 | class MavenSettingsFileCreator { 10 | 11 | static final Logger log = Logging.getLogger( MavenSettingsFileCreator ) 12 | 13 | static File mavenSettingsFile( Project project, CeylonConfig config ) { 14 | config.mavenSettings ? 15 | project.file( config.mavenSettings ) : 16 | new File( project.buildDir, 'maven-settings.xml' ) 17 | } 18 | 19 | static File createMavenSettingsFile( Project project, CeylonConfig config ) { 20 | def settingsFile = mavenSettingsFile project, config 21 | 22 | // do not overwrite file if already there 23 | if ( settingsFile.exists() ) { 24 | log.debug( "Maven settings file already exists. Will not overwrite it." ) 25 | return settingsFile 26 | } 27 | 28 | log.info( "Creating Maven settings file for Ceylon" ) 29 | 30 | def mavenRepo = CreateMavenRepoTask.rootDir( project, config ) 31 | 32 | settingsFile.parentFile.mkdirs() 33 | 34 | settingsFile << """\ 35 | | 39 | | ${mavenRepo.absolutePath} 40 | | true 41 | | 42 | |""".stripMargin() 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /ceylon-gradle-plugin-tests/spring-boot-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Ceylon SpringBoot Demo 2 | 3 | This is a [Spring Boot](http://projects.spring.io/spring-boot/) Demo written in Ceylon. 4 | 5 | The code is at [run.ceylon](source/com/athaydes/springboot/run.ceylon). 6 | 7 | To run it: 8 | 9 | ``` 10 | gradle runCeylon 11 | ``` 12 | 13 | Then hit `http://localhost:8080` with your browser. You should see the `Hello World!` message. 14 | 15 | > Due to the large number of dependencies Spring Boot requires, running this for the first time will take a long time 16 | while Gradle downloads all these dependencies and install them into the Ceylon repository. 17 | Running again later should take just a second or so! 18 | 19 | ### Logging conflict issue 20 | 21 | SpringBoot uses the Logback logging library by default... 22 | this conflicts with Ceylon's own logging library, `org.slf4j.simple`, causing SpringBoot to complain on startup. 23 | 24 | To work around this issue, the Logback framework is explicitly excluded from the dependencies in the Gradle file: 25 | 26 | ```groovy 27 | dependencies { 28 | ceylonCompile "org.springframework.boot:spring-boot-starter-web:1.3.0.RELEASE", { 29 | exclude group: "ch.qos.logback" 30 | } 31 | } 32 | ``` 33 | 34 | If you, for any reason, must use Logback, the solution is to remove `org.sfl4j.simple` from the Ceylon classpath. 35 | It's ugly but it works. 36 | 37 | Find your Ceylon repo directory and type something like this: 38 | 39 | ``` 40 | mv repo/org/slf4j/simple/ repo/org/slf4j/simple_ 41 | ``` 42 | 43 | Then run your application again... it should work now. 44 | 45 | Remember to undo it later to avoid issues with the Ceylon runtime: 46 | 47 | ``` 48 | mv repo/org/slf4j/simple_ repo/org/slf4j/simple 49 | ``` 50 | 51 | ### Killing the server 52 | 53 | Unfortunately, pressing Ctrl+C is not enough to kill the Spring Boot server (Tomcat under the hood). 54 | 55 | Follow the advices on [this StackOverflow](http://stackoverflow.com/questions/23432651/terminating-mvn-spring-bootrun-doesnt-stop-tomcat) 56 | question to kill the process. 57 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/FatJarTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import com.athaydes.gradle.ceylon.util.DependencyTree 7 | import groovy.transform.CompileStatic 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.GradleException 10 | import org.gradle.api.Project 11 | import org.gradle.api.tasks.InputFiles 12 | import org.gradle.api.tasks.OutputFile 13 | import org.gradle.api.tasks.TaskAction 14 | 15 | import static com.athaydes.gradle.ceylon.task.ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES 16 | 17 | @CompileStatic 18 | class FatJarTask extends DefaultTask { 19 | 20 | static List inputFiles( Project project ) { 21 | [ project.tasks.withType( CompileCeylonTask ) ] 22 | } 23 | 24 | static File outputJar( Project project, CeylonConfig config ) { 25 | def fatJarDestination = config.fatJarDestination ?: project.buildDir.absolutePath 26 | if ( !fatJarDestination || fatJarDestination == '/' ) { 27 | throw new GradleException( 'Ceylon fatJarDestination must not be set to empty' ) 28 | } 29 | def dependencyTree = project.extensions.getByName( CEYLON_DEPENDENCIES ) as DependencyTree 30 | def jarPath = "${fatJarDestination}/$config.module-${dependencyTree.moduleVersion}.jar" 31 | return project.file( jarPath ) 32 | } 33 | 34 | @InputFiles 35 | List getInputFiles() { 36 | inputFiles( project ) 37 | } 38 | 39 | @OutputFile 40 | File getOutputFile() { 41 | final config = project.extensions.getByType( CeylonConfig ) 42 | outputJar( project, config ) 43 | } 44 | 45 | @TaskAction 46 | void run() { 47 | final config = project.extensions.getByType( CeylonConfig ) 48 | 49 | CeylonRunner.run 'fat-jar', config.module, project, config, 50 | CeylonCommandOptions.getFatJarOptions( project, config ) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CreateDependenciesPomsTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.DependencyTree 5 | import com.athaydes.gradle.ceylon.util.MavenPomCreator 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.Project 9 | import org.gradle.api.artifacts.ResolvedDependency 10 | import org.gradle.api.tasks.InputFiles 11 | import org.gradle.api.tasks.OutputDirectory 12 | import org.gradle.api.tasks.TaskAction 13 | 14 | @CompileStatic 15 | class CreateDependenciesPomsTask extends DefaultTask { 16 | 17 | static List inputFiles( Project project, CeylonConfig config ) { 18 | ResolveCeylonDependenciesTask.inputFiles( project, config ) 19 | } 20 | 21 | static File outputDir( Project project, CeylonConfig config ) { 22 | rootDir( project ) 23 | } 24 | 25 | @InputFiles 26 | List getInputFiles() { 27 | final config = project.extensions.getByType( CeylonConfig ) 28 | inputFiles( project, config ) 29 | } 30 | 31 | @OutputDirectory 32 | File getOutputDir() { 33 | final config = project.extensions.getByType( CeylonConfig ) 34 | outputDir( project, config ) 35 | } 36 | 37 | @TaskAction 38 | void run() { 39 | def dependencyTree = project.extensions 40 | .getByName( ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES ) as DependencyTree 41 | 42 | for ( dependency in dependencyTree.jarDependencies ) { 43 | def pom = pomTempLocation dependency, project 44 | if ( !pom.parentFile.exists() ) { 45 | pom.parentFile.mkdirs() 46 | } 47 | pom.withWriter { writer -> 48 | MavenPomCreator.createPomFor( dependency, writer ) 49 | } 50 | } 51 | } 52 | 53 | static File rootDir( Project project ) { 54 | new File( project.buildDir, 'dependency-poms' ) 55 | } 56 | 57 | static File pomTempLocation( ResolvedDependency dependency, Project project ) { 58 | def destinationDir = rootDir project 59 | new File( destinationDir, "${dependency.moduleName}-${dependency.moduleVersion}.pom" ) 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CreateModuleDescriptorsTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.DependencyTree 5 | import com.athaydes.gradle.ceylon.util.ModuleDescriptorCreator 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.Project 9 | import org.gradle.api.artifacts.ResolvedDependency 10 | import org.gradle.api.tasks.InputFiles 11 | import org.gradle.api.tasks.OutputDirectory 12 | import org.gradle.api.tasks.TaskAction 13 | 14 | @CompileStatic 15 | class CreateModuleDescriptorsTask extends DefaultTask { 16 | 17 | static List inputFiles( Project project, CeylonConfig config ) { 18 | ResolveCeylonDependenciesTask.inputFiles( project, config ) 19 | } 20 | 21 | static File outputDir( Project project, CeylonConfig config ) { 22 | rootDir( project ) 23 | } 24 | 25 | @InputFiles 26 | List getInputFiles() { 27 | final config = project.extensions.getByType( CeylonConfig ) 28 | inputFiles( project, config ) 29 | } 30 | 31 | @OutputDirectory 32 | File getOutputDir() { 33 | final config = project.extensions.getByType( CeylonConfig ) 34 | outputDir( project, config ) 35 | } 36 | 37 | @TaskAction 38 | void run() { 39 | def dependencyTree = project.extensions 40 | .getByName( ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES ) as DependencyTree 41 | 42 | for ( dependency in dependencyTree.jarDependencies ) { 43 | def descriptor = descriptorTempLocation dependency, project 44 | if ( !descriptor.parentFile.exists() ) { 45 | descriptor.parentFile.mkdirs() 46 | } 47 | descriptor.withWriter { writer -> 48 | ModuleDescriptorCreator.createModuleDescriptorFor dependency, writer 49 | } 50 | } 51 | } 52 | 53 | static File rootDir( Project project ) { 54 | new File( project.buildDir, 'module-descriptors' ) 55 | } 56 | 57 | static File descriptorTempLocation( ResolvedDependency dependency, Project project ) { 58 | def destinationDir = rootDir project 59 | def fileName = "${dependency.moduleName}-${dependency.moduleVersion}.properties" 60 | .replace( '-', '_' ) 61 | new File( destinationDir, fileName ) 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/CeylonConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon 2 | 3 | import com.redhat.ceylon.common.Backend 4 | import com.redhat.ceylon.common.config.CeylonConfig as CeylonToolConfig 5 | import com.redhat.ceylon.common.config.DefaultToolOptions 6 | import groovy.transform.ToString 7 | 8 | @ToString( includeNames = true ) 9 | class CeylonConfig { 10 | def ceylonLocation = null 11 | List sourceRoots 12 | List resourceRoots 13 | List testResourceRoots = [ 'test-resource' ] 14 | List testRoots 15 | String output 16 | String fatJarDestination 17 | String module = '' 18 | List moduleExclusions = [ ] 19 | String overrides 20 | String mavenSettings 21 | Boolean flatClasspath = true 22 | Boolean importJars = false 23 | Boolean forceImports = false 24 | Boolean verbose = false 25 | String javaRuntimeDestination 26 | String entryPoint 27 | String testModule = '' 28 | boolean generateTestReport = true 29 | String testReportDestination 30 | 31 | String getTestModule() { 32 | this.@testModule ?: module 33 | } 34 | 35 | void setModuleName( String name ) { 36 | this.module = name 37 | } 38 | 39 | /** 40 | * Set the default values from the Ceylon config file, if it is present. 41 | */ 42 | CeylonConfig() { 43 | final config = CeylonToolConfig.get() 44 | 45 | sourceRoots = new ArrayList( DefaultToolOptions.compilerSourceDirs ) 46 | resourceRoots = new ArrayList( DefaultToolOptions.compilerResourceDirs ) 47 | testRoots = new ArrayList( DefaultToolOptions.compilerSourceDirs ) 48 | output = DefaultToolOptions.compilerOutputRepo 49 | 50 | // TODO split comma-separated modules when passing option to Ceylon 51 | def configFileDefinesModule = ( config.getOption( DefaultToolOptions.COMPILER_MODULES ) != null ) 52 | if ( configFileDefinesModule ) { 53 | module = DefaultToolOptions.getCompilerModules( Backend.Header ).join( ',' ) 54 | } 55 | 56 | // This plugin differs from the Ceylon default regarding the flatClasspath option 57 | def configFileDefinesFlatClasspath = ( config.getBoolOption( DefaultToolOptions.DEFAULTS_FLAT_CLASSPATH ) != null ) 58 | if ( configFileDefinesFlatClasspath ) { 59 | flatClasspath = DefaultToolOptions.defaultFlatClasspath 60 | } 61 | 62 | entryPoint = DefaultToolOptions.getRunToolRun( Backend.Java ) 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /release-notes.md: -------------------------------------------------------------------------------- 1 | 1.3.1 - 2017 February 19 2 | 3 | * issue #18: added support for fatJar Ceylon task. 4 | * improved Ceylon tasks groups to fit Gradle standards. 5 | * issue #15: use Ceylon tool config file if available. 6 | * allow providing arguments directly to the Ceylon tool. 7 | * allow providing arguments to the Ceylon process with the `runCeylon` task. 8 | * issue #22: paths containing whitespaces can now be used anywhere. 9 | 10 | 1.3.0 - 2016 October 01 11 | 12 | * pull request #14: consume the output of the Ceylon process to avoid causing it to hang in Windows 13 | * issue #13: added support for importing modules with a namespace (feature added in Ceylon 1.3.0). 14 | * redesigned the plugin tasks to use Gradle annotations rather than the runtime API. 15 | * improved declarations of tasks inputs and outputs. 16 | * added @CompileStatic Groovy annotation to all tasks. Fixed small issues that were revealed by that. 17 | * added "moduleName" alias for the "module" property to allow users to avoid Gradle warning as "module" is a known property. 18 | * added generateTestReport and testReportDestination to Ceylon config - call ceylon test with --report flag by default. 19 | 20 | 1.2.0 - 2016 June 19 21 | 22 | * issue #9: tap into Gradle lifecycle tasks such as assemble, build and check 23 | * issue #11: validate Ceylon Location before accepting it 24 | * issue #12: Ceylon module may include literal String for docs 25 | 26 | 1.1.2 - 2016 Mar 06 27 | 28 | * new task: compileCeylonTest makes managing tests compilation and running much better. 29 | * new properties to configure Ceylon test sources/resources locations independently from main resources. 30 | * new task: createJavaRuntime which builds the runtime and bash/bat scripts to run Ceylon modules with the java command. 31 | * new property to allow the declaration of a module entry point, ie. the main runnable function. 32 | * documented Eclipse integration. 33 | 34 | 1.1.1 - 2016 Feb 28 35 | 36 | * ceylon.bat is found automatically in Windows 37 | * run ceylon process with the current environment rather than an empty environment 38 | 39 | 1.1 - 2016 Feb 08 40 | 41 | * added support for multi-modules Gradle projects 42 | * Ceylon projects may depend on Gradle modules written in any JVM language 43 | * made it possible to use Jars from a locally created standard Maven repository instead of importing the Jar into Ceylon. 44 | * use Java flat classpath by default. Do not try to import Jars into Ceylon repo by default. 45 | * renamed 'flatClassPath' to 'flatClasspath'. 46 | * moved location of all output files to under the project buildDirectory, except Ceylon modules 47 | (to keep the Ceylon default location). 48 | * added property to allow printing Ceylon commands instead of running them 49 | 50 | 1.0 - 2015 Nov 21 51 | 52 | * First Ceylon Gradle Plugin release. -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/TestCeylonTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.DefaultTask 8 | import org.gradle.api.Project 9 | import org.gradle.api.tasks.InputFiles 10 | import org.gradle.api.tasks.OutputDirectories 11 | import org.gradle.api.tasks.TaskAction 12 | 13 | @CompileStatic 14 | class TestCeylonTask extends DefaultTask { 15 | 16 | static List inputFiles( Project project, CeylonConfig config ) { 17 | def tasks = { Class... types -> types.collect { Class type -> project.tasks.withType( type ) } } 18 | 19 | [ project.buildFile, project.files( tasks( CompileCeylonTask, CompileCeylonTestTask ) ) ] 20 | } 21 | 22 | static List outputDirectories( Project project, CeylonConfig config ) { 23 | if ( config.generateTestReport ) [ project.file( reportsDir( project, config ) ) ] 24 | else [ ] 25 | } 26 | 27 | @InputFiles 28 | List getInputFiles() { 29 | final config = project.extensions.getByType( CeylonConfig ) 30 | inputFiles( project, config ) 31 | } 32 | 33 | @OutputDirectories 34 | List getOutputDirs() { 35 | final config = project.extensions.getByType( CeylonConfig ) 36 | outputDirectories( project, config ) 37 | } 38 | 39 | @TaskAction 40 | void run() { 41 | final config = project.extensions.getByType( CeylonConfig ) 42 | 43 | try { 44 | CeylonRunner.run 'test', config.testModule, project, config, 45 | CeylonCommandOptions.getTestOptions( project, config ) 46 | } finally { 47 | if ( config.generateTestReport ) { 48 | moveTestReports( project, config ) 49 | } 50 | } 51 | } 52 | 53 | private void moveTestReports( Project project, CeylonConfig config ) { 54 | // Ceylon currently hard-codes the location of test reports to the reports/ directory 55 | def ceylonReportDir = project.file( 'reports' ) 56 | 57 | if ( ceylonReportDir.isDirectory() ) { 58 | def destination = project.mkdir( reportsDir( project, config ) ) 59 | if ( ceylonReportDir != destination ) { 60 | logger.info( "Moving Ceylon test reports from {} to {}", ceylonReportDir, destination ) 61 | ceylonReportDir.renameTo destination 62 | } else { 63 | logger.debug( "Ceylon test reports are already in the expected location: {}", destination ) 64 | } 65 | } else { 66 | logger.warn( 'Could not find the Ceylon test reports at the expected location: {}', ceylonReportDir ) 67 | } 68 | } 69 | 70 | private static reportsDir( Project project, CeylonConfig config ) { 71 | config.testReportDestination ?: new File( project.buildDir, 'reports' ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CreateMavenRepoTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.DependencyTree 5 | import com.athaydes.gradle.ceylon.util.MavenSettingsFileCreator 6 | import groovy.transform.CompileDynamic 7 | import groovy.transform.CompileStatic 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.Project 10 | import org.gradle.api.artifacts.ResolvedDependency 11 | import org.gradle.api.tasks.InputFiles 12 | import org.gradle.api.tasks.OutputDirectory 13 | import org.gradle.api.tasks.OutputFiles 14 | import org.gradle.api.tasks.TaskAction 15 | 16 | @CompileStatic 17 | class CreateMavenRepoTask extends DefaultTask { 18 | 19 | static List inputs( Project project, CeylonConfig config ) { 20 | ResolveCeylonDependenciesTask.inputFiles( project, config ) 21 | } 22 | 23 | static List outputFiles( Project project, CeylonConfig config ) { 24 | [ MavenSettingsFileCreator.mavenSettingsFile( project, config ) ] 25 | } 26 | 27 | static File outputDir( Project project, CeylonConfig config ) { 28 | rootDir( project, config ) 29 | } 30 | 31 | @InputFiles 32 | List getInputFiles() { 33 | final config = project.extensions.getByType( CeylonConfig ) 34 | inputs( project, config ) 35 | } 36 | 37 | @OutputDirectory 38 | File getOutDir() { 39 | final config = project.extensions.getByType( CeylonConfig ) 40 | outputDir( project, config ) 41 | } 42 | 43 | @OutputFiles 44 | List getOutputFiles() { 45 | final config = project.extensions.getByType( CeylonConfig ) 46 | outputFiles( project, config ) 47 | } 48 | 49 | @TaskAction 50 | void run() { 51 | final config = project.extensions.getByType( CeylonConfig ) 52 | 53 | def rootDir = rootDir project, config 54 | 55 | MavenSettingsFileCreator.createMavenSettingsFile project, config 56 | 57 | def dependencyTree = project.extensions 58 | .getByName( ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES ) as DependencyTree 59 | 60 | dependencyTree.jarDependencies.each { ResolvedDependency dependency -> 61 | def destinationDir = destinationFor dependency, rootDir 62 | copyDependency dependency, project, destinationDir 63 | copyPom dependency, project, destinationDir 64 | } 65 | } 66 | 67 | static File rootDir( Project project, CeylonConfig config ) { 68 | new File( project.buildDir, 'maven-repository' ) 69 | } 70 | 71 | private static File destinationFor( ResolvedDependency dependency, File rootDir ) { 72 | def groupPath = dependency.moduleGroup.replace( '.', '/' ) 73 | new File( rootDir, "$groupPath/" + 74 | "${dependency.moduleName}/" + 75 | "${dependency.moduleVersion}" ) 76 | } 77 | 78 | @CompileDynamic 79 | private static void copyDependency( ResolvedDependency dependency, Project project, File destinationDir ) { 80 | project.copy { 81 | from dependency.moduleArtifacts.collect { it.file } 82 | into destinationDir 83 | } 84 | } 85 | 86 | @CompileDynamic 87 | private static void copyPom( ResolvedDependency dependency, Project project, File destinationDir ) { 88 | def pom = CreateDependenciesPomsTask.pomTempLocation( dependency, project ) 89 | project.copy { 90 | from pom 91 | into destinationDir 92 | } 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/CeylonRunner.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import groovy.transform.CompileStatic 5 | import org.gradle.api.GradleException 6 | import org.gradle.api.Project 7 | import org.gradle.api.logging.Logger 8 | import org.gradle.api.logging.Logging 9 | 10 | @CompileStatic 11 | class CeylonRunner { 12 | 13 | static final Logger log = Logging.getLogger( CeylonRunner ) 14 | 15 | static void withCeylon( Project project, CeylonConfig config, Closure ceylonConsumer ) { 16 | String ceylon = CeylonToolLocator.findCeylon( project, config.ceylonLocation ) 17 | log.debug "Running Ceylon executable: ${ceylon}" 18 | try { 19 | ceylonConsumer ceylon 20 | } catch ( GradleException e ) { 21 | throw e 22 | } catch ( e ) { 23 | throw new GradleException( 24 | 'Problem running the ceylon command. Run with --stacktrace for the cause.', e ) 25 | } 26 | } 27 | 28 | static void run( String ceylonDirective, String module, Project project, CeylonConfig config, 29 | List options, List finalArgs = [ ] ) { 30 | log.info "Executing ceylon '$ceylonDirective' in project ${project.name}" 31 | 32 | List ceylonArgs = [ ] 33 | 34 | if ( project.hasProperty( 'ceylon-args' ) ) { 35 | ceylonArgs << project.property( 'ceylon-args' )?.toString() 36 | } 37 | 38 | withCeylon( project, config ) { String ceylon -> 39 | 40 | if ( project.hasProperty( 'get-ceylon-command' ) ) { 41 | def textFor = { List list -> if ( list.empty ) '' else ' ' + list.join( ' ' ) } 42 | 43 | def optionsText = textFor( options.collect { it.withQuotedArgument() } ) 44 | def ceylonArgsText = textFor( ceylonArgs ) 45 | def finalArgsText = textFor( finalArgs ) 46 | 47 | def commandText = "${ceylon} ${ceylonDirective}${optionsText}${ceylonArgsText} ${module}${finalArgsText}" 48 | println commandText 49 | } else { 50 | def commandList = [ ceylon, ceylonDirective ] + 51 | options.collect { it.toString() } + 52 | ceylonArgs + 53 | [ module ] + 54 | finalArgs 55 | 56 | log.info( "Running command: $commandList" ) 57 | def process = commandList.execute( ( List ) null, project.file( '.' ) ) 58 | 59 | consumeOutputOf process 60 | 61 | log.debug( "Ceylon process completed." ) 62 | } 63 | } 64 | } 65 | 66 | static void consumeOutputOf( Process process, PrintStream out = System.out, PrintStream err = System.err ) { 67 | consume process.in, out 68 | consume process.err, err 69 | 70 | def exitCode = -1 71 | try { 72 | exitCode = process.waitFor() 73 | log.debug "Ceylon process finished with code $exitCode" 74 | } catch ( e ) { 75 | log.warn "Ceylon process did not die gracefully. $e" 76 | } 77 | 78 | if ( exitCode != 0 ) { 79 | throw new GradleException( "Ceylon process exited with code $exitCode. " + 80 | "See output for details." ) 81 | } 82 | } 83 | 84 | private static void consume( InputStream stream, PrintStream writer ) { 85 | Thread.startDaemon { 86 | byte[] bytes = new byte[64] 87 | while ( true ) { 88 | def len = stream.read( bytes ) 89 | if ( len > 0 ) writer.write bytes, 0, len 90 | else break 91 | } 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/DependencyTree.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.Project 5 | import org.gradle.api.artifacts.ProjectDependency 6 | import org.gradle.api.artifacts.ResolvedArtifact 7 | import org.gradle.api.artifacts.ResolvedDependency 8 | 9 | /** 10 | * Tree of dependencies. The root of the tree will contain all project dependencies. 11 | */ 12 | @CompileStatic 13 | class DependencyTree { 14 | 15 | private final Collection imports 16 | 17 | final String moduleName 18 | final String moduleVersion 19 | final Collection jarDependencies 20 | final Collection ceylonDependencies 21 | 22 | DependencyTree( Project project, Map moduleDeclaration ) { 23 | this.imports = moduleDeclaration.imports.findAll { Map imp -> imp.namespace == 'maven' } 24 | this.moduleName = moduleDeclaration.moduleName 25 | this.moduleVersion = moduleDeclaration.version 26 | 27 | jarDependencies = collectDependenciesOf project 28 | ceylonDependencies = directCeylonDependenciesOf project 29 | } 30 | 31 | private Collection collectDependenciesOf( Project project ) { 32 | def depsById = [ : ] as Map 33 | for ( dependency in directJarDependenciesOf( project ) ) { 34 | collectDependencies( dependency, depsById ) 35 | } 36 | imports.each { 37 | def id = "${it.name}:${it.version}".toString() 38 | if ( depsById.containsKey( id ) ) { 39 | it.resolvedDependency = depsById[ id ] 40 | } 41 | } 42 | onlyJars depsById.values() 43 | } 44 | 45 | private static void collectDependencies( ResolvedDependency dependency, 46 | Map depById ) { 47 | depById[ dependency.name ] = dependency 48 | for ( child in dependency.children ) collectDependencies( child, depById ) 49 | } 50 | 51 | static Collection transitiveDependenciesOf( ResolvedDependency dependency ) { 52 | def depsById = [ : ] as Map 53 | for ( child in dependency.children ) collectDependencies( child, depsById ) 54 | onlyJars depsById.values() 55 | } 56 | 57 | Collection getModuleDeclaredDependencies() { 58 | onlyJars imports.findAll { it.resolvedDependency }.collect { it.resolvedDependency } 59 | } 60 | 61 | boolean isShared( ResolvedDependency dependency ) { 62 | def module = moduleDeclaration( dependency ) 63 | return module?.shared 64 | } 65 | 66 | private Map moduleDeclaration( ResolvedDependency dependency ) { 67 | imports.find { 68 | it.name == "${dependency.moduleGroup}:${dependency.moduleName}" && 69 | it.version == dependency.moduleVersion 70 | } 71 | } 72 | 73 | static Collection directJarDependenciesOf( Project project ) { 74 | onlyJars directDependenciesOf( project ) 75 | } 76 | 77 | static Collection directCeylonDependenciesOf( Project project ) { 78 | if ( !project.configurations.findByName( 'ceylonRuntime' ) ) return [ ] 79 | final deps = project.configurations.getByName( 'ceylonRuntime' ) 80 | .allDependencies.withType( ProjectDependency ) 81 | deps.collect { ProjectDependency p -> p.dependencyProject } as Collection 82 | } 83 | 84 | static Collection directDependenciesOf( Project project ) { 85 | if ( !project.configurations.findByName( 'ceylonRuntime' ) ) return [ ] 86 | project.configurations.getByName( 'ceylonRuntime' ) 87 | .resolvedConfiguration.firstLevelModuleDependencies.collectEntries { 88 | [ it.name, it ] 89 | }.values() 90 | } 91 | 92 | static Collection directDependenciesOf( ResolvedDependency dependency ) { 93 | onlyJars dependency.children.collectEntries { 94 | [ it.name, it ] 95 | }.values() 96 | } 97 | 98 | private static Collection onlyJars( 99 | Collection dependencies ) { 100 | dependencies.findAll { dep -> 101 | dep instanceof ResolvedDependency && 102 | ( dep as ResolvedDependency ).moduleArtifacts 103 | .any { ResolvedArtifact artifact -> artifact.type == 'jar' } 104 | } as Collection 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/CeylonCommandOptions.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.task.FatJarTask 5 | import com.athaydes.gradle.ceylon.task.GenerateOverridesFileTask 6 | import groovy.transform.CompileStatic 7 | import org.gradle.api.Project 8 | import org.gradle.api.logging.Logger 9 | import org.gradle.api.logging.Logging 10 | 11 | @CompileStatic 12 | class CeylonCommandOptions { 13 | 14 | static final Logger log = Logging.getLogger( CeylonCommandOptions ) 15 | 16 | static List getCommonOptions( Project project, CeylonConfig config, boolean includeFlatClasspath = true ) { 17 | List options = [ ] 18 | def overrides = GenerateOverridesFileTask.overridesFile( project, config ) 19 | if ( overrides.exists() ) { 20 | options << CommandOption.of( '--overrides', overrides.absolutePath ) 21 | } else { 22 | log.warn( 'The overrides.xml file could not be located: {}', overrides.absolutePath ) 23 | } 24 | 25 | if ( includeFlatClasspath && config.flatClasspath ) { 26 | options << CommandOption.of( '--flat-classpath' ) 27 | } 28 | 29 | return options + getRepositoryOptions( project, config ) 30 | } 31 | 32 | private static List getRepositoryOptions( Project project, CeylonConfig config ) { 33 | def mavenSettings = MavenSettingsFileCreator.mavenSettingsFile( project, config ).absolutePath 34 | [ CommandOption.of( '--rep', /aether:$mavenSettings/ ), 35 | CommandOption.of( '--rep', project.file( config.output ).absolutePath ) ] 36 | } 37 | 38 | private static File getOut( Project project, CeylonConfig config ) { 39 | project.file( config.output ) 40 | } 41 | 42 | static List getTestCompileOptions( Project project, CeylonConfig config ) { 43 | List options = [ ] 44 | 45 | options << CommandOption.of( '--out', getOut( project, config ).absolutePath ) 46 | 47 | config.testRoots.each { options << CommandOption.of( '--source', it?.toString() ) } 48 | config.testResourceRoots.each { options << CommandOption.of( '--resource', it?.toString() ) } 49 | 50 | return getCommonOptions( project, config ) + options 51 | } 52 | 53 | static List getCompileOptions( Project project, CeylonConfig config ) { 54 | List options = [ ] 55 | 56 | options << CommandOption.of( '--out', getOut( project, config ).absolutePath ) 57 | 58 | config.sourceRoots.each { options << CommandOption.of( '--source', it?.toString() ) } 59 | config.resourceRoots.each { options << CommandOption.of( '--resource', it?.toString() ) } 60 | 61 | return getCommonOptions( project, config ) + options 62 | } 63 | 64 | static List getFatJarOptions( Project project, CeylonConfig config ) { 65 | List options = [ ] 66 | def out = FatJarTask.outputJar( project, config ) 67 | log.info "Creating fat-jar at: '$out.absolutePath'" 68 | 69 | options << CommandOption.of( '--out', out.absolutePath ) 70 | 71 | if ( config.entryPoint ) { 72 | options << CommandOption.of( '--run', config.entryPoint ) 73 | } 74 | 75 | return getCommonOptions( project, config, false ) + options 76 | } 77 | 78 | static List getRunOptions( Project project, CeylonConfig config ) { 79 | List options = [ ] 80 | 81 | if ( config.entryPoint ) { 82 | options << CommandOption.of( '--run', config.entryPoint ) 83 | } 84 | 85 | getCommonOptions( project, config ) + options 86 | } 87 | 88 | static List getTestOptions( Project project, CeylonConfig config ) { 89 | List options = [ ] 90 | 91 | if ( config.generateTestReport ) { 92 | options << CommandOption.of( '--report' ) 93 | } 94 | 95 | getCommonOptions( project, config ) + options 96 | } 97 | 98 | static List getImportJarsOptions( Project project, CeylonConfig config, File moduleDescriptor ) { 99 | List options = [ ] 100 | if ( config.verbose ) { 101 | options << CommandOption.of( '--verbose' ) 102 | } 103 | if ( config.forceImports ) { 104 | options << CommandOption.of( '--force' ) 105 | } 106 | 107 | options << 108 | CommandOption.of( '--descriptor', moduleDescriptor.absolutePath ) << 109 | CommandOption.of( '--out', getOut( project, config ).absolutePath ) 110 | 111 | return options + getRepositoryOptions( project, config ) 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/util/CeylonToolLocator.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.util 2 | 3 | import org.apache.tools.ant.taskdefs.condition.Os 4 | import org.gradle.api.GradleException 5 | 6 | import java.util.concurrent.Callable 7 | 8 | class CeylonToolLocator { 9 | 10 | static String findCeylon( project, configLocation ) { 11 | def ceylon = findCeylonLocation( project, configLocation ) 12 | try { 13 | def process = ceylon.execute() 14 | process.consumeProcessOutput() 15 | process.waitFor() 16 | return ceylon 17 | } catch ( IOException e ) { 18 | println error() 19 | throw new GradleException( 'Ceylon could not be found! See suggestions above to fix the problem.', e ) 20 | } catch ( e ) { 21 | throw new GradleException( 'A problem has occurred while trying to run the Ceylon tool at: ' + ceylon, e ) 22 | } 23 | } 24 | 25 | private static String findCeylonLocation( project, configLocation ) { 26 | if ( configLocation ) { 27 | return provided( configLocation ) 28 | } 29 | List options = ceylonBootstrapOptions( project ) + ceylonHomeOptions() + sdkManOptions() + osOptions() 30 | def ext = Os.isFamily( Os.FAMILY_WINDOWS ) ? ".bat" : "" 31 | def ceylon = options.collect { new File( it + ext ) }.find { it.file } 32 | 33 | if ( ceylon ) { 34 | return ceylon 35 | } else { 36 | return 'ceylon' 37 | } 38 | } 39 | 40 | private static String provided( configLocation ) { 41 | switch ( configLocation ) { 42 | case String: return configLocation 43 | case File: return configLocation.absolutePath 44 | case Callable: return provided( configLocation.call() ) 45 | default: throw new GradleException( 'ceylonLocation must be a String | File | Callable' ) 46 | } 47 | } 48 | 49 | private static List ceylonBootstrapOptions( project ) { 50 | return [ "${project.projectDir.toPath().resolve( 'ceylonb' )}" ] 51 | } 52 | 53 | private static List ceylonHomeOptions() { 54 | def envVar = System.getenv( 'CEYLON_HOME' ) 55 | if ( envVar ) { 56 | [ "$envVar/bin/ceylon", "$envVar/ceylon" ] 57 | } else { 58 | [ ] 59 | } 60 | } 61 | 62 | private static List osOptions() { 63 | if ( Os.isFamily( Os.FAMILY_UNIX ) ) { 64 | [ '/usr/bin/ceylon', '/usr/local/bin/ceylon' ] 65 | } else if ( Os.isFamily( Os.FAMILY_MAC ) ) { 66 | [ '/usr/bin/ceylon', '/usr/local/bin/ceylon' ] 67 | } else if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) { 68 | [ /C:\Program Files\Ceylon\bin\ceylon/, 69 | /C:\Program Files (x86)\Ceylon\bin\ceylon/ ] 70 | } else { 71 | [ ] 72 | } 73 | } 74 | 75 | private static List sdkManOptions() { 76 | List result = [ ] 77 | def sdkmanHome = System.getenv( 'SDKMAN_DIR' ) 78 | if ( sdkmanHome ) { 79 | result << "$sdkmanHome/candidates/ceylon/current/bin/ceylon" 80 | } 81 | def userHome = System.getProperty( 'user.home' ) 82 | if ( userHome ) { 83 | result << "$userHome/.sdkman/candidates/ceylon/current/bin/ceylon" 84 | } 85 | return result 86 | } 87 | 88 | static String error() { 89 | def markers = '=' * 50 90 | """ 91 | |$markers 92 | | 93 | |The Ceylon-Gradle Plugin could not find Ceylon. 94 | | 95 | |Please try one of these suggestions to fix the problem: 96 | | 97 | |* Use the ceylon bootstrap tool (follows the same concept as the 98 | | Gradle wrapper) which then will be autodetected. 99 | | In your project home run 100 | | 101 | | ceylon bootstrap \$VERSION 102 | | 103 | | The \$VERSION is optional. After this you'll find the ceylonb wrappers 104 | | in your project home. Of course you still need a local ceylon 105 | | installation once for this method to work. 106 | | 107 | |* Explicitly declare the Ceylon location using your build file: 108 | | 109 | | ceylon { 110 | | ceylonLocation = "/usr/bin/ceylon" // path to Ceylon 111 | | } 112 | | 113 | |* Set the CEYLON_HOME environment variable to the Ceylon home directory 114 | | (will look for ceylon at \$CEYLON_HOME/bin/ceylon). 115 | | 116 | |* Install Ceylon using SDKMAN! (http://sdkman.io/) by typing the following 117 | | in the Terminal: 118 | | 119 | | curl -s get.sdkman.io | bash 120 | | source "\$HOME/.sdkman/bin/sdkman-init.sh" 121 | | sdk install ceylon 122 | | 123 | |$markers 124 | |""".stripMargin() 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/ResolveCeylonDependenciesTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.parse.CeylonModuleParser 5 | import com.athaydes.gradle.ceylon.util.DependencyTree 6 | import groovy.transform.CompileStatic 7 | import groovy.transform.CompileDynamic 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.GradleException 10 | import org.gradle.api.Project 11 | import org.gradle.api.artifacts.Configuration 12 | import org.gradle.api.artifacts.Dependency 13 | import org.gradle.api.logging.Logger 14 | import org.gradle.api.logging.Logging 15 | import org.gradle.api.tasks.InputFiles 16 | import org.gradle.api.tasks.TaskAction 17 | 18 | @CompileStatic 19 | class ResolveCeylonDependenciesTask extends DefaultTask { 20 | 21 | static final Logger log = Logging.getLogger( ResolveCeylonDependenciesTask ) 22 | public static final String CEYLON_DEPENDENCIES = 'CeylonDependencies' 23 | 24 | static List inputFiles( Project project, CeylonConfig config ) { 25 | [ moduleFile( project, config ), project.allprojects.collect { Project p -> p.buildFile } ].flatten() 26 | } 27 | 28 | @InputFiles 29 | List getFileInputs() { 30 | final config = project.extensions.getByType( CeylonConfig ) 31 | inputFiles( project, config ) 32 | } 33 | 34 | @TaskAction 35 | void run() { 36 | final config = project.extensions.getByType( CeylonConfig ) 37 | File module = moduleFile( project, config ) 38 | log.info( "Parsing Ceylon module file at ${module.path}" ) 39 | 40 | if ( !module.file ) { 41 | throw new GradleException( 'Ceylon module file does not exist.' + 42 | ' Please make sure that you set "sourceRoot" and "module"' + 43 | ' correctly in the "ceylon" configuration.' ) 44 | } 45 | 46 | def moduleDeclaration = parse module.path, module.text 47 | 48 | def mavenDependencies = moduleDeclaration.imports.findAll { Map imp -> imp.namespace == 'maven' } as List 49 | 50 | def existingDependencies = project.configurations.getByName( 'ceylonCompile' ).dependencies.collect { 51 | Dependency dep -> "${dep.group}:${dep.name}:${dep.version}" 52 | } 53 | 54 | log.debug "Project existing dependencies: {}", existingDependencies 55 | 56 | mavenDependencies.each { Map dependency -> 57 | if ( !existingDependencies.contains( 58 | "${dependency.name}:${dependency.version}" ) ) { 59 | addMavenDependency dependency, project 60 | } else { 61 | log.info "Not adding transitive dependencies of module " + 62 | "$dependency as it already existed in the project" 63 | } 64 | } 65 | 66 | project.configurations.findAll { canBeResolved( (Configuration) it ) }*.resolve() 67 | 68 | def dependencyTree = dependencyTreeOf( project, moduleDeclaration ) 69 | 70 | log.info( 'No dependency problems found!' ) 71 | 72 | project.extensions.add( CEYLON_DEPENDENCIES, dependencyTree ) 73 | } 74 | 75 | /** 76 | * Checks whether a configuration can actually be resolved. Since Gradle 3.4 this is not the case 77 | * anymore for all configurations and must be explicitely checked to avoid an exception. 78 | * 79 | * @param configuration the configuration to check 80 | * @return {@code true} if the configuration can be resolved (this is always the case for Gradle < 3.4) 81 | */ 82 | @CompileDynamic 83 | static boolean canBeResolved( Configuration configuration ) { 84 | if ( configuration.metaClass.respondsTo( configuration, "isCanBeResolved" ) ) { 85 | return configuration.isCanBeResolved() 86 | } 87 | return true 88 | } 89 | 90 | static File moduleFile( Project project, CeylonConfig config ) { 91 | if ( !config.module ) { 92 | log.error( '''|The Ceylon module has not been specified. 93 | |To specify the name of your Ceylon module, add a declaration like 94 | |the following to your build.gradle file: 95 | | 96 | |ceylon { 97 | | module = 'name.of.ceylon.module' 98 | |} 99 | | 100 | |If you prefer, you can set the default module in the Ceylon config file instead, 101 | |and that will be used by Gradle.'''.stripMargin() ) 102 | 103 | throw new GradleException( "The Ceylon module must be specified" ) 104 | } 105 | 106 | def moduleNameParts = config.module.split( /\./ ).toList() 107 | 108 | List locations = [ ] 109 | for ( root in config.sourceRoots ) { 110 | def rootPath = project.file( root ).absolutePath 111 | def modulePath = ( [ rootPath ] + 112 | moduleNameParts + 113 | [ 'module.ceylon' ] ).join( '/' ) 114 | 115 | locations << modulePath 116 | def module = project.file( modulePath ) 117 | if ( module.exists() ) return module 118 | } 119 | 120 | throw new GradleException( "Module file cannot be located. " + 121 | "Looked at the following locations: $locations" ) 122 | } 123 | 124 | static DependencyTree dependencyTreeOf( Project project, Map moduleDeclaration ) { 125 | new DependencyTree( project, moduleDeclaration ) 126 | } 127 | 128 | private static void addMavenDependency( Map dependency, Project project ) { 129 | log.info "Adding dependency: ${dependency.name}:${dependency.version}" 130 | project.dependencies.add( 'ceylonCompile', "${dependency.name}:${dependency.version}" ) 131 | } 132 | 133 | private static Map parse( String name, String moduleText ) { 134 | new CeylonModuleParser().parse( name, moduleText ) 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/GenerateOverridesFileTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.DependencyTree 5 | import groovy.transform.CompileDynamic 6 | import groovy.transform.CompileStatic 7 | import groovy.xml.MarkupBuilder 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.GradleException 10 | import org.gradle.api.Project 11 | import org.gradle.api.artifacts.ResolvedDependency 12 | import org.gradle.api.logging.Logger 13 | import org.gradle.api.logging.Logging 14 | import org.gradle.api.tasks.InputFiles 15 | import org.gradle.api.tasks.OutputFiles 16 | import org.gradle.api.tasks.TaskAction 17 | 18 | @CompileStatic 19 | class GenerateOverridesFileTask extends DefaultTask { 20 | 21 | static final Logger log = Logging.getLogger( GenerateOverridesFileTask ) 22 | 23 | static List inputFiles( Project project, CeylonConfig config ) { 24 | // this task's inputs are exactly the same as the resolve task 25 | ResolveCeylonDependenciesTask.inputFiles( project, config ) 26 | } 27 | 28 | static List outputFiles( Project project, CeylonConfig config ) { 29 | [ overridesFile( project, config ) ] 30 | } 31 | 32 | @InputFiles 33 | List getInputFiles() { 34 | final config = project.extensions.getByType( CeylonConfig ) 35 | inputFiles( project, config ) 36 | } 37 | 38 | @OutputFiles 39 | List getOutputFiles() { 40 | final config = project.extensions.getByType( CeylonConfig ) 41 | outputFiles( project, config ) 42 | } 43 | 44 | @TaskAction 45 | void run() { 46 | final config = project.extensions.getByType( CeylonConfig ) 47 | 48 | def overridesFile = overridesFile( project, config ) 49 | def moduleExclusions = processedModuleExclusions config.moduleExclusions 50 | generateOverridesFile( project, overridesFile, moduleExclusions ) 51 | } 52 | 53 | static File overridesFile( Project project, CeylonConfig config ) { 54 | config.overrides ? 55 | project.file( config.overrides ) : 56 | new File( project.buildDir, "overrides.xml" ) 57 | } 58 | 59 | static List processedModuleExclusions( List moduleExclusions ) { 60 | moduleExclusions.collect { item -> 61 | switch ( item ) { 62 | case String: return [ module: item ] 63 | case Map: return item 64 | default: return [ module: item?.toString() ] 65 | } 66 | } as List 67 | } 68 | 69 | private static void generateOverridesFile( Project project, 70 | File overridesFile, 71 | List moduleExclusions ) { 72 | if ( overridesFile.exists() ) overridesFile.delete() 73 | overridesFile.parentFile.mkdirs() 74 | 75 | if ( !overridesFile.parentFile.directory ) { 76 | throw new GradleException( "Directory of overrides.xml file does not exist " + 77 | "and could not be created. Check access rights to this location: " + 78 | "${overridesFile.parentFile.absolutePath}" ) 79 | } 80 | 81 | log.info( "Generating Ceylon overrides.xml file at {}", overridesFile ) 82 | 83 | def dependencyTree = project.extensions 84 | .getByName( ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES ) as DependencyTree 85 | 86 | writeOverridesFile overridesFile, dependencyTree, moduleExclusions 87 | } 88 | 89 | @CompileDynamic 90 | private static writeOverridesFile( File overridesFile, 91 | DependencyTree dependencyTree, 92 | List moduleExclusions ) { 93 | overridesFile.withWriter { writer -> 94 | def xml = new MarkupBuilder( writer ) 95 | 96 | xml.overrides { 97 | writeExclusions moduleExclusions, xml 98 | dependencyTree.moduleDeclaredDependencies.each { ResolvedDependency dep -> 99 | def name = "${dep.moduleGroup}:${dep.moduleName}" 100 | if ( moduleExclusions.find { Map exc -> exc.module == name } ) { 101 | log.info "Skipping transitive dependencies of module {} because it is excluded", name 102 | } else { 103 | def shared = dependencyTree.isShared( dep ) 104 | def transitiveDeps = DependencyTree.transitiveDependenciesOf( dep ) 105 | if ( transitiveDeps ) { 106 | writeDependency( dep, name, shared, transitiveDeps, xml ) 107 | } 108 | } 109 | } 110 | } 111 | } 112 | } 113 | 114 | @CompileDynamic 115 | private static void writeDependency( ResolvedDependency dep, String name, boolean shared, 116 | Collection transitiveDeps, 117 | MarkupBuilder xml ) { 118 | def id = "$name/${dep.moduleVersion}" 119 | xml.artifact( coordinatesOf( dep, shared ) ) { 120 | log.info "Writing overrides with transitive dependencies for {} - shared? {}", id, shared 121 | for ( transitiveDep in transitiveDeps ) { 122 | add( coordinatesOf( transitiveDep, true ) ) 123 | } 124 | } 125 | } 126 | 127 | @CompileDynamic 128 | protected static void writeExclusions( List moduleExclusions, MarkupBuilder xml ) { 129 | moduleExclusions.each { item -> 130 | xml.remove( item ) 131 | } 132 | } 133 | 134 | protected static Map coordinatesOf( ResolvedDependency dep, boolean shared ) { 135 | def result = [ 136 | groupId : dep.moduleGroup, 137 | artifactId: dep.moduleName, 138 | version : dep.moduleVersion ] 139 | if ( shared ) result.shared = true 140 | result 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/ImportJarsTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import com.athaydes.gradle.ceylon.util.DependencyTree 7 | import groovy.transform.CompileDynamic 8 | import groovy.transform.CompileStatic 9 | import org.gradle.api.DefaultTask 10 | import org.gradle.api.GradleException 11 | import org.gradle.api.Nullable 12 | import org.gradle.api.Project 13 | import org.gradle.api.artifacts.ResolvedArtifact 14 | import org.gradle.api.artifacts.ResolvedDependency 15 | import org.gradle.api.logging.Logger 16 | import org.gradle.api.logging.Logging 17 | import org.gradle.api.tasks.InputFiles 18 | import org.gradle.api.tasks.OutputDirectory 19 | import org.gradle.api.tasks.TaskAction 20 | 21 | @CompileStatic 22 | class ImportJarsTask extends DefaultTask { 23 | 24 | static final Logger log = Logging.getLogger( ImportJarsTask ) 25 | 26 | static List inputFiles( Project project, CeylonConfig config ) { 27 | // TODO jars from other projects should be added here 28 | ResolveCeylonDependenciesTask.inputFiles( project, config ) 29 | } 30 | 31 | static File outputDir( Project project, CeylonConfig config ) { 32 | ceylonRepo( project, config ) 33 | } 34 | 35 | @InputFiles 36 | List getInputFiles() { 37 | final config = project.extensions.getByType( CeylonConfig ) 38 | inputFiles( project, config ) 39 | } 40 | 41 | @OutputDirectory 42 | File getOutputDir() { 43 | final config = project.extensions.getByType( CeylonConfig ) 44 | outputDir( project, config ) 45 | } 46 | 47 | @TaskAction 48 | void run() { 49 | log.debug "Importing artifact jars" 50 | 51 | final config = project.extensions.getByType( CeylonConfig ) 52 | 53 | def repo = ceylonRepo( project, config ) 54 | 55 | if ( !repo.directory && !repo.mkdirs() ) { 56 | throw new GradleException( "Output repository does not exist and cannot be created ${repo.absolutePath}." ) 57 | } 58 | 59 | def dependencyTree = project.extensions 60 | .getByName( ResolveCeylonDependenciesTask.CEYLON_DEPENDENCIES ) as DependencyTree 61 | 62 | if ( config.importJars ) { 63 | log.info "Importing Jar dependencies" 64 | for ( jarDependency in dependencyTree.jarDependencies ) { 65 | importDependency project, jarDependency, config 66 | } 67 | } else { 68 | log.info( "Skipping Jar imports" ) 69 | } 70 | 71 | log.info "Importing Ceylon dependencies" 72 | for ( ceylonDependency in dependencyTree.ceylonDependencies ) { 73 | importCeylonProject project, repo, ceylonDependency 74 | } 75 | } 76 | 77 | private static File ceylonRepo( Project project, CeylonConfig config ) { 78 | project.file( config.output ) 79 | } 80 | 81 | @CompileDynamic 82 | private static void importCeylonProject( Project project, File repo, Project dependency ) { 83 | log.info( 'Trying to import dependency {} as a Ceylon project', dependency.name ) 84 | 85 | def dependencyOutput = projectDependencyOutputDir( dependency ) 86 | 87 | if ( dependencyOutput?.directory ) { 88 | log.info( "Copying output from {} to {}", dependencyOutput, repo ) 89 | project.copy { 90 | into repo 91 | from dependencyOutput 92 | } 93 | } else { 94 | log.info( "Dependency {} is not a Ceylon project", dependency.name ) 95 | } 96 | } 97 | 98 | private static void importDependency( Project project, 99 | ResolvedDependency dependency, 100 | CeylonConfig config ) { 101 | def artifact = dependency.allModuleArtifacts.find { it.type == 'jar' } 102 | if ( artifact ) { 103 | if ( artifact.name == dependency.moduleName ) { 104 | importArtifact project, dependency, artifact, config 105 | } else { 106 | log.warn( "Unable to install dependency. Module name '{}' != Artifact name '{}", 107 | dependency.moduleName, artifact.name ) 108 | } 109 | } else { 110 | log.info( "Dependency {} will not be installed as it has no jar artifacts.", artifact.name ) 111 | } 112 | } 113 | 114 | private static void importArtifact( Project project, ResolvedDependency dependency, 115 | ResolvedArtifact artifact, CeylonConfig config ) { 116 | log.info( "Will try to install {} into the Ceylon repository", artifact.name ) 117 | def jarFile = artifact.file 118 | 119 | def module = "${dependency.moduleGroup}.${dependency.moduleName}/${dependency.moduleVersion}".toString() 120 | 121 | if ( module.contains( '-' ) ) { 122 | log.warn( "Importing module with illegal character '-' in name: $module. Will replace '-' with '_'." ) 123 | module = module.replace( '-', '_' ) 124 | } 125 | 126 | def moduleDescriptor = CreateModuleDescriptorsTask.descriptorTempLocation( dependency, project ) 127 | 128 | if ( jarFile?.exists() ) { 129 | importJar jarFile, module, project, moduleDescriptor, config 130 | } else { 131 | throw new GradleException( "Dependency ${module} could not be installed in the Ceylon Repository" + 132 | " because its jarFile could not be located: ${jarFile}" ) 133 | } 134 | } 135 | 136 | @Nullable 137 | private static File projectDependencyOutputDir( Project dependency ) { 138 | def ceylonConfig = dependency.extensions.findByName( 'ceylon' ) 139 | 140 | if ( ceylonConfig instanceof CeylonConfig ) { 141 | return dependency.file( ( ceylonConfig as CeylonConfig ).output ) 142 | } else { 143 | return null 144 | } 145 | } 146 | 147 | private static void importJar( File jarFile, String module, Project project, File moduleDescriptor, 148 | CeylonConfig config ) { 149 | log.debug( "Jar: {}, Module Name: {}", jarFile.name, module ) 150 | 151 | CeylonRunner.run( 'import-jar', module, project, config, 152 | CeylonCommandOptions.getImportJarsOptions( project, config, moduleDescriptor ), 153 | [ jarFile.absolutePath ] ) 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/task/CreateJavaRuntimeTask.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.task 2 | 3 | import com.athaydes.gradle.ceylon.CeylonConfig 4 | import com.athaydes.gradle.ceylon.util.CeylonCommandOptions 5 | import com.athaydes.gradle.ceylon.util.CeylonRunner 6 | import groovy.transform.CompileDynamic 7 | import groovy.transform.CompileStatic 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.GradleException 10 | import org.gradle.api.Project 11 | import org.gradle.api.logging.Logger 12 | import org.gradle.api.logging.Logging 13 | import org.gradle.api.tasks.InputDirectory 14 | import org.gradle.api.tasks.InputFiles 15 | import org.gradle.api.tasks.OutputDirectory 16 | import org.gradle.api.tasks.TaskAction 17 | 18 | import java.util.regex.Pattern 19 | 20 | /** 21 | * Task to create a Java runtime that can be run without Ceylon, using only the JVM. 22 | */ 23 | @CompileStatic 24 | class CreateJavaRuntimeTask extends DefaultTask { 25 | 26 | static final Logger log = Logging.getLogger( CreateJavaRuntimeTask ) 27 | 28 | private static def javaRuntimeDir( Project project, CeylonConfig config ) { 29 | config.javaRuntimeDestination ?: new File( project.buildDir, 'java-runtime' ) 30 | } 31 | 32 | static List inputFiles( Project project, CeylonConfig config ) { 33 | [ project.buildFile, 34 | GenerateOverridesFileTask.outputFiles( project, config ), 35 | CreateMavenRepoTask.outputFiles( project, config ), 36 | ].flatten() 37 | } 38 | 39 | static File inputDir( Project project, CeylonConfig config ) { 40 | CompileCeylonTask.outputDir( project, config ) 41 | } 42 | 43 | static File outputDir( Project project, CeylonConfig config ) { 44 | project.file( javaRuntimeDir( project, config ) ) 45 | } 46 | 47 | @InputDirectory 48 | File getInputDir() { 49 | final config = project.extensions.getByType( CeylonConfig ) 50 | inputDir( project, config ) 51 | } 52 | 53 | @InputFiles 54 | List getInputFiles() { 55 | final config = project.extensions.getByType( CeylonConfig ) 56 | inputFiles( project, config ) 57 | } 58 | 59 | @OutputDirectory 60 | File getOutputDir() { 61 | final config = project.extensions.getByType( CeylonConfig ) 62 | outputDir( project, config ) 63 | } 64 | 65 | @TaskAction 66 | void run() { 67 | final config = project.extensions.getByType( CeylonConfig ) 68 | 69 | def destination = project.file( javaRuntimeDir( project, config ) ) 70 | 71 | log.debug( "Destination of JVM runtime: ${destination.absolutePath}" ) 72 | 73 | destination.mkdirs() 74 | if ( !destination.directory ) { 75 | throw new GradleException( "Unable to create Java runtime as directory can't be created: ${destination}" ) 76 | } 77 | 78 | CeylonRunner.withCeylon( project, config ) { String ceylon -> 79 | def options = CeylonCommandOptions.getCommonOptions( project, config, false ) 80 | 81 | if ( project.hasProperty( 'get-ceylon-command' ) ) { 82 | def command = "${ceylon} classpath " + 83 | "${options.collect { it.withQuotedArgument() }.join( ' ' )} ${config.module}" 84 | println command 85 | } else { 86 | def commandList = [ ceylon, 'classpath' ] + 87 | options.collect { it.toString() } + 88 | [ config.module ] 89 | 90 | log.info( "Running command: $commandList" ) 91 | def process = commandList.execute( ( List ) null, project.file( '.' ) ) 92 | 93 | ByteArrayOutputStream processConsumer = new ByteArrayOutputStream( 2048 ) 94 | CeylonRunner.consumeOutputOf process, new PrintStream( processConsumer ) 95 | 96 | def classpath = processConsumer.toString( 'UTF-8' ) 97 | 98 | log.debug( "Got the classpath:\n$classpath" ) 99 | 100 | def fileNames = moveFilesToDestination project, classpath, destination 101 | 102 | def main = findMain config 103 | 104 | createUnixScript( main, fileNames, destination ) 105 | createWindowsScript( main, fileNames, destination ) 106 | } 107 | } 108 | } 109 | 110 | private static String findMain( CeylonConfig config ) { 111 | def main = ( config.entryPoint ?: "${config.module}::run" ).toString() 112 | def startNameIndex = main.indexOf( '::' ) + 2 113 | if ( startNameIndex < 2 ) { 114 | throw new GradleException( "Invalid entry point: '$main'. Must be of form pkg.name::functionName or pkg.name::ClassName" ) 115 | } 116 | 117 | if ( Character.isLowerCase( main[ startNameIndex ] as char ) ) { 118 | // ceylon function name ends with '_' in the JVM 119 | main += '_' 120 | } 121 | 122 | // turn main name into the equivalent JVM name 123 | return main.replace( '::', '.' ) 124 | } 125 | 126 | @CompileDynamic 127 | private static List moveFilesToDestination( Project project, String classpath, File destination ) { 128 | def separator = System.getProperty( 'path.separator' ) 129 | def paths = classpath.split( Pattern.quote( separator ) ) 130 | def fileNames = [ ] 131 | for ( path in paths ) { 132 | def file = new File( path ) 133 | fileNames << file.name 134 | if ( !file.exists() ) { 135 | throw new GradleException( "Expected file to be in classpath, but file does not exist: $file" ) 136 | } 137 | 138 | log.debug( "Copying file '{}' to '{}'", file, destination ) 139 | 140 | project.copy { 141 | from file 142 | into destination 143 | } 144 | } 145 | 146 | return fileNames 147 | } 148 | 149 | private static void createUnixScript( String main, 150 | List fileNames, 151 | File destination ) { 152 | def unixScriptFile = new File( destination, 'run.sh' ) 153 | def unixClasspath = fileNames.join( ':' ) 154 | 155 | def unixScript = """|#!/bin/sh 156 | | 157 | |cd "\$( dirname "\${BASH_SOURCE[ 0 ]}" )" 158 | | 159 | |JAVA="java" 160 | | 161 | |# if JAVA_HOME exists, use it 162 | |if [ -x "\$JAVA_HOME/bin/java" ] 163 | |then 164 | | JAVA="\$JAVA_HOME/bin/java" 165 | |else 166 | | if [ -x "\$JAVA_HOME/jre/bin/java" ] 167 | | then 168 | | JAVA="\$JAVA_HOME/jre/bin/java" 169 | | fi 170 | |fi 171 | | 172 | |"\$JAVA" -cp ${unixClasspath} ${main} "\$@" 173 | |""".stripMargin().replaceAll( Pattern.quote( '\r\n' ), '\n' ) 174 | 175 | unixScriptFile.write unixScript, 'UTF-8' 176 | 177 | log.info( 'Saved Unix/Mac run script at {}', unixScriptFile.absolutePath ) 178 | } 179 | 180 | private static void createWindowsScript( String main, 181 | List fileNames, 182 | File destination ) { 183 | def windowsScriptFile = new File( destination, 'run.bat' ) 184 | def windowsClasspath = fileNames.join( ';' ) 185 | 186 | def windowsScript = """\ 187 | |@ECHO OFF 188 | | 189 | |cd /d %~dp0 190 | | 191 | |set JAVA="java" 192 | | 193 | |REM if JAVA_HOME exists, use it 194 | |if exist "%JAVA_HOME%/bin/java" ( 195 | | set JAVA="%JAVA_HOME%/bin/java" 196 | |) else ( 197 | | if exist "%JAVA_HOME%/jre/bin/java" ( 198 | | set JAVA="%JAVA_HOME%/jre/bin/java" 199 | | ) 200 | |) 201 | | 202 | |%JAVA% -cp ${windowsClasspath} ${main} %* 203 | |""".stripMargin().replaceAll( Pattern.quote( '\r\n' ), '\n' ) 204 | 205 | windowsScriptFile.write windowsScript, 'UTF-8' 206 | 207 | log.info( 'Saved Windows run script at {}', windowsScriptFile.absolutePath ) 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/CeylonPlugin.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon 2 | 3 | import com.athaydes.gradle.ceylon.task.CleanTask 4 | import com.athaydes.gradle.ceylon.task.CompileCeylonTask 5 | import com.athaydes.gradle.ceylon.task.CompileCeylonTestTask 6 | import com.athaydes.gradle.ceylon.task.CreateDependenciesPomsTask 7 | import com.athaydes.gradle.ceylon.task.CreateJavaRuntimeTask 8 | import com.athaydes.gradle.ceylon.task.CreateMavenRepoTask 9 | import com.athaydes.gradle.ceylon.task.CreateModuleDescriptorsTask 10 | import com.athaydes.gradle.ceylon.task.FatJarTask 11 | import com.athaydes.gradle.ceylon.task.GenerateOverridesFileTask 12 | import com.athaydes.gradle.ceylon.task.ImportJarsTask 13 | import com.athaydes.gradle.ceylon.task.ResolveCeylonDependenciesTask 14 | import com.athaydes.gradle.ceylon.task.RunCeylonTask 15 | import com.athaydes.gradle.ceylon.task.TestCeylonTask 16 | import groovy.transform.CompileStatic 17 | import org.gradle.api.Plugin 18 | import org.gradle.api.Project 19 | import org.gradle.api.Task 20 | import org.gradle.api.internal.plugins.PluginApplicationException 21 | import org.gradle.api.logging.Logger 22 | import org.gradle.api.logging.Logging 23 | import org.gradle.api.tasks.Delete 24 | import org.gradle.language.base.plugins.LanguageBasePlugin 25 | 26 | @CompileStatic 27 | class CeylonPlugin implements Plugin { 28 | 29 | static final Logger log = Logging.getLogger( CeylonPlugin ) 30 | 31 | @Override 32 | void apply( Project project ) { 33 | try { 34 | project.pluginManager.apply( LanguageBasePlugin ) 35 | } catch ( PluginApplicationException e ) { 36 | log.debug( "Failed to apply LanguageBasePlugin - it had already been applied", e ) 37 | } 38 | 39 | log.debug( "CeylonPlugin being applied to project: ${project.name}" ) 40 | 41 | final config = project.extensions 42 | .create( 'ceylon', CeylonConfig ) as CeylonConfig 43 | 44 | createConfigs project, config 45 | createTasks project, config 46 | } 47 | 48 | private static createConfigs( Project project, CeylonConfig config ) { 49 | // there must be a default configuration or other projects cannot depend on this one 50 | project.configurations.maybeCreate( 'default' ) 51 | 52 | def compileConfig = project.configurations.create 'ceylonCompile' 53 | project.configurations.create( 'ceylonRuntime' ).extendsFrom compileConfig 54 | } 55 | 56 | private static createTasks( Project project, CeylonConfig config ) { 57 | Task resolveDepsTask = project.task( 58 | type: ResolveCeylonDependenciesTask, 59 | group: 'Build', 60 | description: 'Resolves all legacy dependencies declared in the Ceylon' + 61 | ' module file as well as directly in the Gradle build file.', 62 | 'resolveCeylonDependencies' ) 63 | 64 | project.task( 65 | type: GenerateOverridesFileTask, 66 | group: 'Build', 67 | dependsOn: 'resolveCeylonDependencies', 68 | description: 'Generates the overrides.xml file based on the Gradle project dependencies.\n' + 69 | ' All Java legacy dependencies declared in the Ceylon module file are checked so' + 70 | ' that if they require transitive dependencies, they are added to the auto-generated' + 71 | ' overrides file.', 72 | 'generateOverridesFile' ) 73 | 74 | project.task( 75 | type: CreateDependenciesPomsTask, 76 | group: 'Build', 77 | dependsOn: 'resolveCeylonDependencies', 78 | description: 'Creates Maven pom files for all transitive dependencies.\n' + 79 | 'The transitive dependencies are resolved by Gradle, then for each dependency, a pom ' + 80 | 'is created containing only its direct dependencies as reported by Gradle.\n' + 81 | 'This allows Ceylon to import jars without considering optional Maven dependencies, ' + 82 | 'for example, as Gradle does not resolve optional dependencies by default.', 83 | 'createDependenciesPoms' ) 84 | 85 | project.task( 86 | type: CreateModuleDescriptorsTask, 87 | group: 'Build', 88 | dependsOn: 'resolveCeylonDependencies', 89 | description: 'Creates module descriptors (properties files) for all transitive dependencies.\n' + 90 | 'The transitive dependencies are resolved by Gradle, then for each dependency, a module ' + 91 | 'descriptor is created containing all its own transitive dependencies. The module descriptors ' + 92 | 'are used when, and if, the dependencies Jar files get imported into the Ceylon repository.', 93 | 'createModuleDescriptors' ) 94 | 95 | Task createMavenRepoTask = project.task( 96 | type: CreateMavenRepoTask, 97 | group: 'Build', 98 | dependsOn: 'createDependenciesPoms', 99 | description: 'Creates a local Maven repository containing all transitive dependencies.\n' + 100 | 'The repository uses the default Maven repository format and is used by all Ceylon commands ' + 101 | 'so that Ceylon is not required to search for any Maven dependency in a remote repository, ' + 102 | 'ensuring that Gradle is used as the main Maven dependency resolver.', 103 | 'createMavenRepo' ) 104 | 105 | project.rootProject.getTasksByName( 'jar', true ).each { jar -> 106 | createMavenRepoTask.dependsOn jar 107 | } 108 | 109 | project.task( 110 | type: ImportJarsTask, 111 | group: 'Build', 112 | dependsOn: [ 'resolveCeylonDependencies', 'createMavenRepo', 'createModuleDescriptors' ], 113 | description: 'Import transitive Maven dependencies and copies the output from dependent Ceylon ' + 114 | 'projects into the local Ceylon repository .\n' + 115 | 'To enable importing Maven dependencies, the Ceylon config property "importJars" must ' + 116 | 'be set to true.', 117 | 'importJars' ) 118 | 119 | Task compileTask = project.task( 120 | type: CompileCeylonTask, 121 | group: 'Build', 122 | dependsOn: [ 'generateOverridesFile', 'importJars', 'createMavenRepo' ], 123 | description: 'Compiles Ceylon and Java source code and directly' + 124 | ' produces module and source archives in a module repository.', 125 | 'compileCeylon' ) 126 | 127 | project.task( 128 | type: RunCeylonTask, 129 | group: 'Verification', 130 | dependsOn: 'compileCeylon', 131 | description: 'Runs a Ceylon module.', 132 | 'runCeylon' ) 133 | 134 | project.task( 135 | type: CompileCeylonTestTask, 136 | group: 'Build', 137 | dependsOn: [ 'compileCeylon' ], 138 | description: 'Compiles Ceylon and Java test code and directly' + 139 | ' produces module and source archives in a module repository.', 140 | 'compileCeylonTest' ) 141 | 142 | Task testTask = project.task( 143 | type: TestCeylonTask, 144 | group: 'Verification', 145 | dependsOn: [ 'compileCeylonTest' ], 146 | description: 'Runs all tests in a Ceylon module.', 147 | 'testCeylon' ) 148 | 149 | project.task( 150 | type: CreateJavaRuntimeTask, 151 | group: 'Build', 152 | dependsOn: [ 'compileCeylon' ], 153 | description: 'Creates a Java runtime containing the full classpath' + 154 | ' as well as bash and bat scripts that can be used to invoke Java to run the Ceylon module' + 155 | ' in a JVM without any Ceylon tool.', 156 | 'createJavaRuntime' ) 157 | 158 | project.task( 159 | type: FatJarTask, 160 | group: 'Build', 161 | dependsOn: [ 'compileCeylon' ], 162 | description: 'Creates a fat jar that can be used to deploy the Ceylon project more easily as a Java application.', 163 | 'fatJar' ) 164 | 165 | def cleanTask = project.task( 166 | type: CleanTask, 167 | description: 'Removes the output of all tasks of the Ceylon plugin.', 168 | 'cleanCeylon' ) 169 | 170 | project.tasks.withType( Delete ) { Delete clean -> 171 | if ( clean != cleanTask ) { 172 | clean.dependsOn cleanTask 173 | } 174 | } 175 | 176 | project.getTasksByName( 'dependencies', false )*.dependsOn resolveDepsTask 177 | project.getTasksByName( 'assemble', false )*.dependsOn compileTask 178 | project.getTasksByName( 'check', false )*.dependsOn testTask 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/test/groovy/com/athaydes/gradle/ceylon/parse/CeylonModuleParserTest.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.parse 2 | 3 | import org.junit.Test 4 | 5 | class CeylonModuleParserTest { 6 | 7 | def parser = new CeylonModuleParser() 8 | 9 | @Test 10 | void "Can parse module with multi-line block comment"() { 11 | def result = parser.parse( 'example.ceylon', """ 12 | /* a comment 13 | spanning several lines 14 | Some [[Example]] markup. 15 | And even some code: 16 | shared function() { 17 | print("Hello world!"); 18 | } 19 | 20 | */ 21 | module my.test.module "2.0" { 22 | // this is an import 23 | import other.module "1.0"; 24 | } 25 | """ ) 26 | 27 | assert result 28 | assert result.moduleName == 'my.test.module' 29 | assert result.version == '2.0' 30 | assert result.imports == [ [ name: 'other.module', version: '1.0' ] ] 31 | } 32 | 33 | @Test 34 | void "Can parse module with multi-line doc comment with block comment inside it"() { 35 | def result = parser.parse( 'example.ceylon', """ 36 | "A comment 37 | spanning several lines 38 | Some [[Example]] markup. 39 | And even some code: 40 | shared function() { 41 | print(\\"Hello world!\\"); 42 | } 43 | 44 | /* block comments 45 | are acceptable inside doc comments. 46 | */ 47 | " 48 | module my.test.module "0" { 49 | "This import is required. 50 | The \\"1.0\\" is the version! 51 | " 52 | import other.module "1.0"; 53 | } 54 | """ ) 55 | 56 | assert result 57 | assert result.moduleName == 'my.test.module' 58 | assert result.version == '0' 59 | assert result.imports == [ [ name: 'other.module', version: '1.0' ] ] 60 | } 61 | 62 | @Test 63 | void "Can parse module with literal String comment with block comment inside it"() { 64 | def result = parser.parse( 'example.ceylon', """ 65 | |\"\"\"A comment 66 | |spanning several lines 67 | |Some [[Example]] markup. 68 | |And even some code: 69 | | shared function() { 70 | | print(\"Hello world!\"); 71 | | } 72 | | 73 | |/* block comments 74 | | are acceptable inside doc comments. 75 | | */ 76 | |\"\"\" 77 | |module my.test.module "0" { 78 | | \"\"\"This import is required. 79 | | The \"1.0\" is the version! 80 | | \"\"\" 81 | | import other.module "1.0"; 82 | |} 83 | |""".stripMargin() ) 84 | 85 | assert result 86 | assert result.moduleName == 'my.test.module' 87 | assert result.version == '0' 88 | assert result.imports == [ [ name: 'other.module', version: '1.0' ] ] 89 | } 90 | 91 | @Test 92 | void "Can parse a simple module file"() { 93 | def result = parser.parse 'myfile.ceylon', """ 94 | // some module 95 | module com.hello.world "1.0.0" { 96 | import java.lang.base "7"; 97 | } 98 | """ 99 | 100 | assert result 101 | assert result.moduleName == 'com.hello.world' 102 | assert result.version == '1.0.0' 103 | assert result.imports == [ 104 | [ name: 'java.lang.base', version: '7' ] 105 | ] 106 | } 107 | 108 | @Test 109 | void "Can parse a simple module file without any imports"() { 110 | def result = parser.parse 'myfile.ceylon', 'module com.hello.world "1.0" {}' 111 | 112 | assert result 113 | assert result.moduleName == 'com.hello.world' 114 | assert result.version == '1.0' 115 | assert result.imports == null 116 | } 117 | 118 | @Test 119 | void "Can parse a module file with many imports"() { 120 | def result = parser.parse 'myfile.ceylon', """ 121 | // some module 122 | module com.hello.world2 "2.3" { 123 | import java.lang.base "7"; 124 | import ceylon.collection "1.2"; 125 | // comment 126 | import "com.maven:module" "2.3"; // another comment 127 | import one.more.ceylon.module "4.3"; 128 | /* that's it! 129 | */ 130 | } 131 | """ 132 | 133 | assert result 134 | assert result.moduleName == 'com.hello.world2' 135 | assert result.version == '2.3' 136 | assert result.imports == [ 137 | [ name: 'java.lang.base', version: '7' ], 138 | [ name: 'ceylon.collection', version: '1.2' ], 139 | [ name: 'com.maven:module', version: '2.3', namespace: 'maven' ], 140 | [ name: 'one.more.ceylon.module', version: '4.3' ], 141 | ] 142 | } 143 | 144 | @Test 145 | void "Can parse a module file with doc Strings"() { 146 | def result = parser.parse 'myfile.ceylon', """ 147 | "This module is very \\"cool\\". 148 | It lets you do lots of things with [[MyType]]. 149 | 150 | Example: 151 | 152 | value something = MyType(\\"Hello there!\\"); 153 | 154 | Enjoy!!!" 155 | module com.hello.world "1.0.0" { 156 | import java.lang.base "7"; 157 | } 158 | """ 159 | 160 | assert result 161 | assert result.moduleName == 'com.hello.world' 162 | assert result.version == '1.0.0' 163 | assert result.imports == [ 164 | [ name: 'java.lang.base', version: '7' ] 165 | ] 166 | } 167 | 168 | @Test 169 | void "Can parse a module file with Maven imports"() { 170 | def result = parser.parse 'myfile.ceylon', """ 171 | module com.hello.world "1.0" { 172 | import "org.apache.logging.log4j:log4j-core" "2.4.1"; 173 | import "org.apache.logging.log4j:log4j-api" "2.4.1"; 174 | import "org.junit:junit" "4.12"; 175 | import ceylon.collection "1.2"; 176 | } 177 | """ 178 | 179 | assert result 180 | assert result.moduleName == 'com.hello.world' 181 | assert result.version == '1.0' 182 | assert result.imports == [ 183 | [ name: 'org.apache.logging.log4j:log4j-core', version: '2.4.1', namespace: 'maven' ], 184 | [ name: 'org.apache.logging.log4j:log4j-api', version: '2.4.1', namespace: 'maven' ], 185 | [ name: 'org.junit:junit', version: '4.12', namespace: 'maven' ], 186 | [ name: 'ceylon.collection', version: '1.2' ] 187 | ] 188 | } 189 | 190 | @Test 191 | void "Can parse a module file with annotated imports and module"() { 192 | def result = parser.parse 'myfile.ceylon', """ 193 | "An example module 194 | with \\"lots\\" of annotations" 195 | shared("jvm") 196 | module com.hello.world "1.0.0" { 197 | shared import java.lang.base "7"; 198 | shared("js") import org.jquery "2.5"; 199 | // normal import 200 | import ceylon.promise "1.2"; 201 | } 202 | """ 203 | 204 | assert result 205 | assert result.moduleName == 'com.hello.world' 206 | assert result.version == '1.0.0' 207 | assert result.shared == true 208 | assert result.imports == [ 209 | [ name: 'java.lang.base', version: '7', shared: true ], 210 | [ name: 'org.jquery', version: '2.5', shared: true ], 211 | [ name: 'ceylon.promise', version: '1.2' ], 212 | ] 213 | } 214 | 215 | @Test 216 | void "Can parse module file used in Ceylon Specification"() { 217 | def result = parser.parse 'myfile.ceylon', """ 218 | |"The best-ever ORM solution!" 219 | |license ("http://www.gnu.org/licenses/lgpl.html") 220 | |module org.hibernate "3.0.0.beta" { 221 | | shared import ceylon.language "1.0.1"; 222 | | import javax.sql "4.0"; 223 | |} 224 | |""".stripMargin() 225 | 226 | assert result 227 | assert result.moduleName == 'org.hibernate' 228 | assert result.version == '3.0.0.beta' 229 | assert result.imports == [ 230 | [ name: 'ceylon.language', version: '1.0.1', shared: true ], 231 | [ name: 'javax.sql', version: '4.0' ] 232 | ] 233 | } 234 | 235 | @Test 236 | void "Can parse a module file with comments everywhere"() { 237 | def result = parser.parse 'myfile.ceylon', """ 238 | // some module 239 | module // comment 240 | com.hello.world /* not code */ "1.0.0" 241 | {// comment 242 | import /* 243 | crazy but possible 244 | */ 245 | java.lang.base "7" /* ?? */; 246 | } // done 247 | 248 | /* 249 | comment 250 | */ 251 | //END 252 | """ 253 | 254 | assert result 255 | assert result.moduleName == 'com.hello.world' 256 | assert result.version == '1.0.0' 257 | assert result.imports == [ 258 | [ name: 'java.lang.base', version: '7' ] 259 | ] 260 | } 261 | 262 | @Test 263 | void "Can parse a realistic module file with tabs indentation"() { 264 | def result = parser.parse 'module.ceylon', """\ 265 | |native("jvm") 266 | |module com.athaydes.maven "1.0.0" { 267 | |\t\timport java.base "8"; 268 | |\t\t//import "org.apache.logging.log4j:log4j-api" "2.4.1"; 269 | |\t\tshared import "org.apache.logging.log4j:log4j-core" "2.4.1"; 270 | |\t\timport "org.spockframework:spock-core" "1.0-groovy-2.4"; 271 | |}""".stripMargin() 272 | 273 | assert result 274 | assert result.moduleName == 'com.athaydes.maven' 275 | assert result.version == '1.0.0' 276 | assert result.imports == [ 277 | [ name: 'java.base', version: '8' ], 278 | [ name: 'org.apache.logging.log4j:log4j-core', version: '2.4.1', shared: true, namespace: 'maven' ], 279 | [ name: 'org.spockframework:spock-core', version: '1.0-groovy-2.4', namespace: 'maven' ], 280 | ] 281 | } 282 | 283 | @Test 284 | void "Can parse name-spaced module imports"() { 285 | def result = parser.parse 'module.ceylon', """\ 286 | |native("jvm") 287 | |module flight "1.0.0" { 288 | | import ceylon.interop.java "1.2.3"; 289 | | 290 | | import "org.springframework.boot:spring-boot-starter-web" "1.3.3.RELEASE"; 291 | | import "org.springframework.boot:spring-boot-starter-undertow" "1.3.3.RELEASE"; 292 | | import "org.springframework.cloud:spring-cloud-starter-eureka" "1.1.0.RC1"; 293 | | 294 | | shared import "org.springframework.boot:spring-boot-starter-data-jpa" "1.3.3.RELEASE"; 295 | | 296 | | import maven:"postgresql:postgresql" "9.1-901-1.jdbc4"; //Using new prefix here 297 | | shared import my_repo:org.liquibase.core "3.4.2"; 298 | | import maven:"junit:junit" "4.12"; 299 | |}""".stripMargin() 300 | 301 | assert result 302 | assert result.moduleName == 'flight' 303 | assert result.version == '1.0.0' 304 | assert result.imports == [ 305 | [ name: 'ceylon.interop.java', version: '1.2.3' ], 306 | [ name: 'org.springframework.boot:spring-boot-starter-web', version: '1.3.3.RELEASE', namespace: 'maven' ], 307 | [ name: 'org.springframework.boot:spring-boot-starter-undertow', version: '1.3.3.RELEASE', namespace: 'maven' ], 308 | [ name: 'org.springframework.cloud:spring-cloud-starter-eureka', version: '1.1.0.RC1', namespace: 'maven' ], 309 | [ name: 'org.springframework.boot:spring-boot-starter-data-jpa', version: '1.3.3.RELEASE', shared: true, namespace: 'maven' ], 310 | [ name: 'postgresql:postgresql', version: '9.1-901-1.jdbc4', namespace: 'maven' ], 311 | [ name: 'org.liquibase.core', version: '3.4.2', shared: true, namespace: 'my_repo' ], 312 | [ name: 'junit:junit', version: '4.12', namespace: 'maven' ] 313 | ] 314 | } 315 | 316 | } 317 | -------------------------------------------------------------------------------- /src/main/groovy/com/athaydes/gradle/ceylon/parse/CeylonModuleParser.groovy: -------------------------------------------------------------------------------- 1 | package com.athaydes.gradle.ceylon.parse 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.Immutable 5 | import groovy.transform.ToString 6 | 7 | import java.util.regex.Matcher 8 | 9 | @ToString( includeNames = true, includePackage = false ) 10 | class AnnotationState { 11 | boolean parsingName = false 12 | boolean parsingOpenBracket = false 13 | boolean afterOpenBracket = false // could be close bracket or argument 14 | boolean parsingArgument = false 15 | boolean parsingCloseBracket = false 16 | } 17 | 18 | @Immutable 19 | class ParsingDocs { 20 | boolean on 21 | boolean isTripleQuote 22 | } 23 | 24 | abstract class BaseState { 25 | ParsingDocs parsingDocs = new ParsingDocs( false, false ) 26 | AnnotationState parsingAnnotationState = null 27 | boolean parsingName = false 28 | boolean parsingVersion = false 29 | } 30 | 31 | @ToString( includeFields = true, includePackage = false, includeSuperProperties = true ) 32 | class ModuleDeclarationState extends BaseState { 33 | boolean parsingStartModule = false 34 | } 35 | 36 | @ToString( includeFields = true, includePackage = false, includeSuperProperties = true ) 37 | class ModuleImportsState extends BaseState { 38 | boolean parsingSemiColon = false 39 | } 40 | 41 | @ToString( includeFields = true, includePackage = false ) 42 | class DoneState {} 43 | 44 | /** 45 | * Parser of Ceylon module files. 46 | */ 47 | @CompileStatic 48 | class CeylonModuleParser { 49 | 50 | static final moduleNamespaceRegex = /^[a-z_][a-zA-Z_0-9]*/ 51 | static final moduleIdentifierRegex = /[a-z][a-zA-Z_0-9\.]*[a-zA-Z_0-9]/ 52 | static final mavenModuleIdentifierRegex = /"[a-z][a-zA-Z_0-9\.:\-]*[a-zA-Z_0-9]"/ 53 | static final annotationNameRegex = /^[a-z_][a-zA-Z_0-9]*/ 54 | static final versionRegex = /^\"[a-zA-Z_0-9][a-zA-Z_0-9\.\-\+]*\"/ 55 | static final String nonEscapedTripleQuoteRegex = /.*(? words = [ ] 63 | private boolean lineComment = false 64 | private boolean blockComment = false 65 | 66 | Map parse( String name, String text ) { 67 | fileName = name 68 | final result = [ : ] 69 | final lines = text.readLines() as LinkedList 70 | 71 | lineLoop: 72 | while ( lines ) { 73 | words = lines.removeFirst().split( /\s/ ) 74 | .findAll { !it.empty } as LinkedList 75 | 76 | currentLine++ 77 | lineComment = false 78 | 79 | while ( words && !lineComment ) { 80 | def word = words.removeFirst() 81 | 82 | final state = this.state 83 | if ( state instanceof ModuleDeclarationState ) { 84 | parseModuleDeclaration( word, state, result ) 85 | } else if ( state instanceof ModuleImportsState ) { 86 | parseModuleImports( word, state as ModuleImportsState, result ) 87 | } else if ( state instanceof DoneState ) { 88 | break lineLoop 89 | } else { 90 | throw error( "internal state not recognized: $state" ) 91 | } 92 | } 93 | } 94 | 95 | return result 96 | } 97 | 98 | private static List getImports( Map result ) { 99 | result.get( 'imports', [ ] ) as List 100 | } 101 | 102 | private void parseModuleDeclaration( String word, 103 | ModuleDeclarationState state, 104 | Map result ) { 105 | if ( blockComment ) { 106 | def endBlockMatcher = ( word =~ endBlockCommentRegex ) 107 | if ( endBlockMatcher.find() ) { 108 | blockComment = false 109 | def lastIndex = endBlockMatcher.end() 110 | consumeChars lastIndex, word, result 111 | } 112 | } else if ( word.startsWith( '/*' ) && !state.parsingDocs.on ) { 113 | blockComment = true 114 | consumeChars 2, word, result 115 | } else if ( word.startsWith( '//' ) ) { 116 | lineComment = true 117 | } else if ( state.parsingAnnotationState ) { 118 | AnnotationState aState = state.parsingAnnotationState 119 | parseAnnotation word, state, aState, result 120 | } else if ( state.parsingName ) { 121 | def moduleNameMatcher = ( word =~ moduleIdentifierRegex ) 122 | if ( moduleNameMatcher.find() ) { 123 | def lastIndex = moduleNameMatcher.end() 124 | result.moduleName = word[ 0.. 1 ) { 144 | words.addFirst( word[ 1..-1 ] ) 145 | } 146 | } 147 | } else if ( state.parsingDocs.on ) { 148 | Matcher unescapedDelimiterMatcher = matcherFor( state.parsingDocs, word ) 149 | if ( unescapedDelimiterMatcher.find() ) { 150 | def lastIndex = unescapedDelimiterMatcher.end() 151 | result.hasDocs = true 152 | this.state = new ModuleDeclarationState() 153 | consumeChars lastIndex, word, result 154 | } 155 | } else { // begin 156 | if ( word == 'module' ) { 157 | this.state = new ModuleDeclarationState( parsingName: true ) 158 | } else if ( word.startsWith( '"' ) ) { 159 | if ( result.hasDocs ) { 160 | throw error( 'more than one doc String is not allowed' ) 161 | } 162 | def isTripleQuote = word.startsWith( '"""' ) 163 | this.state = new ModuleDeclarationState( parsingDocs: new ParsingDocs( true, isTripleQuote ) ) 164 | consumeChars 1, word, result 165 | } else { 166 | this.state = new ModuleDeclarationState( 167 | parsingAnnotationState: new AnnotationState( parsingName: true ) ) 168 | words.addFirst( word ) 169 | } 170 | } 171 | } 172 | 173 | private void parseModuleImports( String word, ModuleImportsState state, Map result ) { 174 | if ( blockComment ) { 175 | def endBlockMatcher = ( word =~ endBlockCommentRegex ) 176 | if ( endBlockMatcher.find() ) { 177 | blockComment = false 178 | def lastIndex = endBlockMatcher.end() 179 | consumeChars lastIndex, word, result 180 | } 181 | } else if ( state.parsingDocs.on ) { 182 | Matcher unescapedDelimiterMatcher = matcherFor( state.parsingDocs, word ) 183 | if ( unescapedDelimiterMatcher.find() ) { 184 | def lastIndex = unescapedDelimiterMatcher.end() 185 | this.state = new ModuleImportsState() 186 | consumeChars lastIndex, word, result 187 | } 188 | } else if ( word.startsWith( '/*' ) ) { 189 | blockComment = true 190 | consumeChars 2, word, result 191 | } else if ( word.startsWith( '//' ) ) { 192 | lineComment = true 193 | } else if ( state.parsingAnnotationState ) { 194 | parseAnnotation( word, state, state.parsingAnnotationState, result ) 195 | } else if ( state.parsingName ) { 196 | def nameMatcher = ( word =~ "($moduleNamespaceRegex:)?($moduleIdentifierRegex)" ) 197 | def mavenNameMatcher = ( word =~ "($moduleNamespaceRegex:)?($mavenModuleIdentifierRegex)" ) 198 | def matcher = nameMatcher.matches() ? nameMatcher : 199 | mavenNameMatcher.matches() ? mavenNameMatcher : null 200 | if ( matcher != null ) { 201 | def namespace = matcher.group( 1 ) ?: '' 202 | if ( namespace.endsWith( ':' ) ) namespace -= ':' 203 | def name = matcher.group( 2 ) 204 | 205 | if ( mavenNameMatcher.is( matcher ) ) { 206 | // remove the quotes if it's a Maven match 207 | name = name[ 1..-2 ] 208 | 209 | if ( !namespace ) namespace = 'maven' 210 | } 211 | 212 | def imports = getImports( result ) 213 | 214 | def importEntry = [ name: name ] 215 | if ( namespace ) importEntry.namespace = namespace 216 | 217 | if ( !imports.empty && !imports.last().name ) { // newest entry has no name yet 218 | assert imports.last().containsKey( 'shared' ) 219 | imports.last().putAll( importEntry ) 220 | } else { 221 | imports << importEntry 222 | } 223 | this.state = new ModuleImportsState( parsingVersion: true ) 224 | } else { 225 | throw error( "expected imported module name, found '$word'" ) 226 | } 227 | } else if ( state.parsingVersion ) { 228 | def versionMatcher = ( word =~ versionRegex ) 229 | if ( versionMatcher.find() ) { 230 | def imports = getImports( result ) 231 | def lastIndex = versionMatcher.end() 232 | imports.last().version = word[ 1..( lastIndex - 2 ) ] 233 | this.state = new ModuleImportsState( parsingSemiColon: true ) 234 | consumeChars lastIndex, word, result 235 | } else { 236 | throw error( "expected module version, found '$word'" ) 237 | } 238 | } else if ( state.parsingSemiColon ) { 239 | if ( word.startsWith( ';' ) ) { 240 | this.state = new ModuleImportsState() 241 | consumeChars 1, word, result 242 | } else { 243 | throw error( "expected semi-colon, found '$word'" ) 244 | } 245 | } else { // begin or end 246 | if ( word == 'import' ) { 247 | this.state = new ModuleImportsState( parsingName: true ) 248 | } else if ( word.startsWith( '"' ) ) { 249 | def isTripleQuote = word.startsWith( '"""' ) 250 | this.state = new ModuleImportsState( parsingDocs: new ParsingDocs( true, isTripleQuote ) ) 251 | consumeChars 1, word, result 252 | } else if ( word == '}' ) { 253 | this.state = new DoneState() 254 | } else { 255 | this.state = new ModuleImportsState( 256 | parsingAnnotationState: new AnnotationState( parsingName: true ) ) 257 | // put word back in the queue as we don't know what it is 258 | words.addFirst( word ) 259 | } 260 | } 261 | } 262 | 263 | private void parseAnnotation( String word, 264 | BaseState state, 265 | AnnotationState aState, 266 | Map result ) { 267 | if ( blockComment ) { 268 | def endBlockMatcher = ( word =~ endBlockCommentRegex ) 269 | if ( endBlockMatcher.find() ) { 270 | blockComment = false 271 | def lastIndex = endBlockMatcher.end() 272 | consumeChars lastIndex, word, result 273 | } 274 | } else if ( aState.parsingArgument ) { 275 | Matcher unescapedDelimiterMatcher = ( word =~ nonEscapedQuoteRegex ) 276 | if ( unescapedDelimiterMatcher.find() ) { 277 | state.parsingAnnotationState = new AnnotationState( parsingCloseBracket: true ) 278 | def lastIndex = unescapedDelimiterMatcher.end() 279 | consumeChars lastIndex, word, result 280 | } 281 | } else if ( word.startsWith( '/*' ) ) { 282 | blockComment = true 283 | consumeChars 2, word, result 284 | } else if ( word.startsWith( '//' ) ) { 285 | lineComment = true 286 | } else if ( aState.parsingName ) { 287 | if ( state instanceof ModuleImportsState && word == 'import' ) { 288 | this.state = new ModuleImportsState( parsingName: true ) 289 | } else if ( state instanceof ModuleDeclarationState && word == 'module' ) { 290 | this.state = new ModuleDeclarationState( parsingName: true ) 291 | } else { 292 | Matcher nameMatcher = ( word =~ annotationNameRegex ) 293 | if ( nameMatcher.find() ) { 294 | int lastIndex = nameMatcher.end() 295 | def annotation = word[ 0.. 1 ) { 338 | word = word[ 1..-1 ] 339 | if ( state instanceof ModuleDeclarationState ) { 340 | parseModuleDeclaration( word, state, result ) 341 | } else if ( state instanceof ModuleImportsState ) { 342 | parseModuleImports( word, state, result ) 343 | } 344 | } 345 | } else { 346 | throw error( "expected annotation ')', found '$word'" ) 347 | } 348 | } else { // start over 349 | state.parsingAnnotationState = new AnnotationState( parsingName: true ) 350 | } 351 | } 352 | 353 | private consumeChars( int count, String word, Map result ) { 354 | if ( count < word.size() ) { 355 | word = word[ count..-1 ] 356 | final state = this.state 357 | if ( state instanceof ModuleImportsState ) { 358 | parseModuleImports( word, state, result ) 359 | } else if ( state instanceof ModuleDeclarationState ) { 360 | parseModuleDeclaration( word, state, result ) 361 | } 362 | } 363 | } 364 | 365 | private RuntimeException error( String message ) { 366 | new RuntimeException( "Cannot parse module [$fileName]. " + 367 | "Error on line $currentLine: $message" ) 368 | } 369 | 370 | private static Matcher matcherFor( ParsingDocs state, String word ) { 371 | state.isTripleQuote ? 372 | word =~ nonEscapedTripleQuoteRegex : 373 | word =~ nonEscapedQuoteRegex 374 | } 375 | 376 | } 377 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ceylon Gradle Plugin 2 | 3 | [![Build Status](https://travis-ci.org/renatoathaydes/ceylon-gradle-plugin.svg?branch=master)](https://travis-ci.org/renatoathaydes/ceylon-gradle-plugin) 4 | [ ![Download](https://api.bintray.com/packages/renatoathaydes/maven/com.athaydes.ceylon/images/download.svg) ](https://bintray.com/renatoathaydes/maven/com.athaydes.ceylon/_latestVersion) 5 | 6 | This is a Gradle Plugin to make it easy to handle Ceylon projects with Gradle. 7 | 8 | Because Ceylon itself manages Ceylon dependencies, this plugin focuses on 9 | managing legacy Java dependencies so that you can get transitive dependencies 10 | resolved by Gradle. 11 | 12 | This plugin can be a real lifesaver while the Ceylon ecosystem is still developing and you need 13 | to rely on Java (and Scala, Groovy, Kotlin)'s libraries! 14 | 15 | Check out my [blog post](https://sites.google.com/a/athaydes.com/renato-athaydes/posts/theceylongradleplugin) 16 | about this plugin to understand more about the motivations behind this project. 17 | 18 | ## Using this plugin 19 | 20 | To use this plugin, simply add a Gradle build file to the root of your project 21 | and apply this plugin as shown below: 22 | 23 | * Gradle 2.1+ and 3.0+ 24 | 25 | ```groovy 26 | plugins { 27 | id 'com.athaydes.ceylon' version '1.3.1' 28 | } 29 | ``` 30 | 31 | * Old style Gradle plugin declaration 32 | 33 | *build.gradle* 34 | ```groovy 35 | buildscript { 36 | repositories { 37 | jcenter() 38 | } 39 | 40 | dependencies { 41 | classpath "com.athaydes.gradle.ceylon:ceylon-gradle-plugin:1.3.1" 42 | } 43 | } 44 | 45 | apply plugin: 'com.athaydes.ceylon' 46 | ``` 47 | 48 | You can configure the behaviour of the plugin in the `ceylon` block. 49 | 50 | For example: 51 | 52 | ```groovy 53 | ceylon { 54 | module = "com.athaydes.maven" 55 | } 56 | ``` 57 | 58 | Many settings are read from the [Ceylon config file](https://ceylon-lang.org/documentation/1.3/reference/tool/config/), 59 | if available... however, all supported settings can be overridden in the Gradle file if specified explicitly. 60 | 61 | The only mandatory field (if no Ceylon config file is present) is `module`, 62 | which you should set to the name of the Ceylon module. 63 | 64 | Other properties are explained in the next sections. 65 | 66 | ### Notes on default properties 67 | 68 | The default properties of this Gradle Plugin make your Ceylon project use the default Java flat classpath 69 | (ie. no Ceylon module isolation) because that makes it much easier to make use of several popular Java frameworks, 70 | as well as other JVM languages, which assume free access to everything in the classpath. 71 | 72 | The problem with that is that the default Ceylon module isolation is lost. 73 | 74 | To use Ceylon defaults rather than Java's, add the following options to the `ceylon` block in your build file: 75 | 76 | ```groovy 77 | ceylon { 78 | ... 79 | flatClasspath = false 80 | importJars = true 81 | } 82 | ``` 83 | 84 | ### Tasks 85 | 86 | The Ceylon-Gradle Plugin adds the following tasks to your project: 87 | 88 | * `cleanCeylon` - removes output created by the other tasks of this plugin. 89 | * `resolveCeylonDependencies` - resolves the project's dependencies. 90 | * `createDependenciesPoms` - creates Maven pom files for all transitive dependencies. 91 | * `createMavenRepo` - creates a local Maven repository containing all transitive dependencies. 92 | * `createModuleDescriptors` - creates module descriptors for all transitive dependencies. 93 | * `generateOverridesFile` - generates the overrides.xml file. 94 | * `importJars` - imports transitive dependencies into the `output` Ceylon repository. 95 | * `compileCeylon` - compiles the Ceylon module. 96 | * `compileCeylonTest` - compiles the Ceylon test module. 97 | * `runCeylon` - runs the Ceylon module (see the `entryPoint` config property). 98 | * `testCeylon` - runs the tests in the test module. 99 | * `createJavaRuntime` - creates a directory with all resources required to run the Ceylon application with only the JVM. 100 | * `fatJar` - creates a fat jar that can be used to deploy the Ceylon project more easily as a Java application. 101 | 102 | > Lifecycle tasks such as `build` and `check` also work with the Ceylon Plugin. 103 | 104 | Examples: 105 | 106 | #### Running the Ceylon module with a clean environment 107 | 108 | ``` 109 | gradle cleanCeylon runCeylon 110 | ``` 111 | 112 | #### Compile the Ceylon module and show all INFO log messages 113 | 114 | ``` 115 | gradle compileCeylon --info 116 | ``` 117 | 118 | For even more output, use `--debug`. 119 | 120 | > Another useful task that Gradle itself adds by default is `dependencies`, which prints the whole 121 | dependency tree of your project. 122 | 123 | ### Properties 124 | 125 | * `get-ceylon-command`: if the project has this property, any Ceylon commands that would have been called by this plugin 126 | are simply printed to stdout instead of actually being called. 127 | * `ceylon-args`: allows arguments to be provided directly to the Ceylon tool. 128 | * `app-args`: allows arguments to be provided to the Ceylon application (only used by the `runCeylon` task). 129 | 130 | Example usage: 131 | 132 | ``` 133 | gradle -P get-ceylon-command runCeylon 134 | ``` 135 | 136 | ``` 137 | # this can be used to activate Ceylon tool options that are not supported by the Gradle Plugin 138 | gradle compileCeylon -Pceylon-args="--fully-export-maven-dependencies" 139 | ``` 140 | 141 | >> Notice that you can also set properties in Gradle build files, so the above could be achieved by adding 142 | this line to your build file: `project.ext.'ceylon-args' = '--fully-export-maven-dependencies'` 143 | 144 | ``` 145 | gradle runCeylon -Papp-args="--my-command-options other-option" 146 | ``` 147 | 148 | ## Configuring the Ceylon build 149 | 150 | Most of the configuration of this plugin is done inside the `ceylon` block. 151 | 152 | The following properties can be set in the `ceylon` block: 153 | 154 | * `module` or `moduleName`: (**mandatory** if no Ceylon config file exists) name of the Ceylon module. 155 | * `ceylonLocation`: (optional) path to the ceylon executable. Set the `CEYLON_HOME` environment variable instead 156 | to make the build more portable, or do nothing if you use [SDKMAN!](http://sdkman.io/) 157 | as in that case, the Ceylon location will be found automatically. 158 | * `sourceRoots`: (default: `['source']`) List of directories where the Ceylon source code is located. 159 | * `resourceRoots`: (default: `['resource']`) List of directories where resources are located. 160 | * `testRoots`: (default `['source']`) List of directories where Ceylon test code is located. 161 | * `testResourceRoots`: (default `['test-resource']`) List of directories where test resources are located. 162 | * `generateTestReport`: (default `true`) whether to ask Ceylon test to generate test reports after running tests. 163 | * `testReportDestination`: (default `${project.buildDir}/reports`) directory to save test reports into. 164 | * `output`: (default: `modules`) specifies the output module repository. 165 | * `testModule`: (default: same value as `module`): name of the Ceylon test module. 166 | * `moduleExclusions`: (default: `[]`) name of the modules to remove from the compilation and runtime. 167 | * `overrides`: (default: `'${project.buildDir}/overrides.xml'`) location to store the automatically-generated overrides.xml file. 168 | * `mavenSettings`: (default: `'${project.buildDir}/maven-settings.xml'`) location of Maven settings file. 169 | If the file already exists, it is not overwritten, otherwise an appropriate file is generated (recommended). 170 | * `flatClasspath`: (default: `true`) use a flat classpath (like in standard Java), bypassing Ceylon's default module isolation. 171 | * `importJars`: (default: `false`) import dependencies' jar files into the Ceylon repository. 172 | * `forceImports`: (default: `false`) use the `--force` option when importing dependencies' jar files into the 173 | Ceylon repository. 174 | * `verbose`: (default: `false`) use the `--verbose` option when invoking Ceylon commands. 175 | * `javaRuntimeDestination`: (default: `${project.buildDir}/java-runtime`) directory to save JVM resources created 176 | by the `createJavaRuntime` task. 177 | * `fatJarDestination`: (default `${project.buildDir}`) directory to save the fat jar created by the `fatJar` task. 178 | * `entryPoint`: (default: `${moduleName}::run`) top-level element to run when calling the `runCeylon` task 179 | or the bash scripts created by the `createJavaRuntime` task. 180 | 181 | An example configuration (using most options above) might look like this: 182 | 183 | ```groovy 184 | ceylon { 185 | module = "com.acme.awesome" 186 | testModule = "test.com.acme.awesome" 187 | flatClasspath = false 188 | importJars = true 189 | sourceRoots = ['source', 'src/main/ceylon'] 190 | resourceRoots = ['resource', 'src/main/resources'] 191 | output = 'dist' 192 | verbose = true 193 | javaRuntimeDestination = file('target/jvm') 194 | entryPoint = "com.acme.awesome::start" 195 | } 196 | ``` 197 | 198 | **See the [project samples](ceylon-gradle-plugin-tests) for working examples.** 199 | 200 | ## Integration with Eclipse 201 | 202 | When you use both this plugin and Eclipse, you need to let Eclipse know about the resources created by this 203 | plugin. That's very easy: 204 | 205 | * open the `Project Properties` in Eclipse. 206 | * go to the `Ceylon Build > Module repositories` section. 207 | * in `Module overrides file`, enter the path to the `overrides.xml` file created by this plugin. 208 | * if you configured this plugin to use a `flatClasspath`, check the equivalent box just below the overrides file. 209 | * click on the `Add Maven Repository...` button. 210 | * enter the path to the Maven `settings.xml` file created by this plugin. 211 | * done! Just hit `OK` a few times and build the project again. 212 | 213 | Notes: 214 | 215 | * by default, the overrides file is saved at `build/overrides.xml`. 216 | * by default, the Maven settings file is saved at `build/maven-settings.xml`. 217 | 218 | ## Handling transitive dependencies 219 | 220 | All direct dependencies of your project must be declared in Ceylon `module.ceylon` file. 221 | 222 | However, as Ceylon does not automatically resolve transitive Maven dependencies (note: this has changed in Ceylon 1.2.3 with the [`--fully-export-maven-dependencies`](https://ceylon-lang.org/documentation/current/reference/tool/ceylon/subcommands/ceylon-compile.html#option--fully-export-maven-dependencies) flag), the Ceylon-Gradle Plugin reads 223 | the `module.ceylon` file and creates an 224 | [overrides.xml](http://ceylon-lang.org/documentation/1.2/reference/repository/overrides/) 225 | file that informs Ceylon what those transitive dependencies are. 226 | 227 | The dependencies are resolved using Gradle's standard mechanism, so you can use any repository supported by Gradle. 228 | 229 | Notice that you can exclude some particular dependency easily using Gradle. For example, to exclude dependencies with group `ch.qos.logback` (and all its transtive dependencies as well) add this to your Gradle file: 230 | 231 | ```groovy 232 | configurations { 233 | all*.exclude group: "ch.qos.logback" 234 | } 235 | ``` 236 | 237 | ### Using a flat classpath VS Ceylon module system 238 | 239 | **It is important to notice that there are 2 different ways to use the Ceylon Gradle Plugin:** 240 | 241 | * **Flat classpath**: Java's default flat classpath, with JVM dependencies used as plain jars. This is the default. 242 | * **Ceylon module system**: Using Ceylon's standard JBoss module system, which isolates modules' classpaths and verifies the runtime is 243 | consistent and not missing anything that's needed. JVM dependencies may be imported into the Ceylon repository. 244 | 245 | Which one you should use depends on your application requirements. 246 | 247 | * To use Java's flat classpath: 248 | 249 | ```groovy 250 | ceylon { 251 | ... 252 | flatClasspath = true 253 | importJars = false 254 | } 255 | ``` 256 | 257 | > The above is the default, so you might as well omit these parameters. 258 | 259 | * To use the Ceylon module system: 260 | 261 | ```groovy 262 | ceylon { 263 | ... 264 | flatClasspath = false 265 | importJars = true 266 | } 267 | ``` 268 | 269 | If Ceylon complains about packages missing, this probably means the jar you are importing refers to optional Maven 270 | dependencies' packages which Ceylon cannot guarantee will work at runtime! 271 | 272 | To force Ceylon to accept the imports anyway, set `forceImports` to `true`: 273 | 274 | ```groovy 275 | ceylon { 276 | ... 277 | flatClasspath = false 278 | importJars = true 279 | forceImports = true 280 | } 281 | ``` 282 | 283 | Here's some differences between the two so you can decide which to use: 284 | 285 | #### Flat classpath 286 | 287 | * only one version of each module may be available to all modules at runtime. 288 | * Java libraries may load any classpath resource and instantiate classes from other modules. Popular Java libraries such 289 | as Hibernate, Jersey and Guice, for example, require this behaviour. 290 | * all packages of every module are *shared* at runtime, just like in Java. At compile-time, however, the Ceylon compiler 291 | can still enforce the module boundaries between different modules. 292 | * no need to generate extra metadata to import Jars into a local Ceylon repository. 293 | 294 | Example of importing a Maven module with coordinates `com.athaydes.groupId:module-name:1.0.0` in a Ceylon module file: 295 | 296 | ```ceylon 297 | import "com.athaydes.groupId:module-name" "1.0.0"; 298 | ``` 299 | 300 | > Notice that the module name consists of the `groupId` and the `artifactId` appended with a `:` in the middle. 301 | 302 | #### Ceylon module system 303 | 304 | * many versions of the same module may be used (not currently supported by this plugin's dependency resolution). 305 | * modules boundaries are strictly enforced by Ceylon, so non-shared imports and internals of a module are completely 306 | invisible to other modules. 307 | * Jars are imported into the local Ceylon repository together with a module descriptor (generated automatically by this 308 | plugin. Currently all dependencies are shared and non-optional). 309 | 310 | Example of importing the same module as in the previous section, but using the Ceylon module syntax: 311 | 312 | ```ceylon 313 | import com.athaydes.groupId.module_name "1.0.0"; 314 | ``` 315 | 316 | > The module is imported into the Ceylon repository, so it must use Ceylon module name syntax: its name does not need 317 | to be quoted, the name is separated from the groupId with just a `.`, and the illegal character `-` is replaced 318 | with `_`. 319 | 320 | ### Using a Java library with many transitive dependencies 321 | 322 | Suppose you want to use a Java library, say [SparkJava](http://sparkjava.com/), 323 | in your Ceylon project, and you are content with using a flat classpath... 324 | you would have a `module.ceylon` file similar to this: 325 | 326 | ```ceylon 327 | native("jvm") 328 | module com.athaydes.sparkweb "1.0.0" { 329 | import java.base "8"; 330 | shared import "com.sparkjava:spark-core" "2.3"; 331 | } 332 | ``` 333 | 334 | Even though Spark has a lot of dependencies itself, you don't need to worry about that as Gradle will figure out 335 | all the transitive dependencies for you. 336 | 337 | You can see them if you want, with the `dependencies` task: 338 | 339 | ``` 340 | gradle dependencies 341 | ``` 342 | 343 | Which will print this: 344 | 345 | ``` 346 | ceylonCompile 347 | \--- com.sparkjava:spark-core:2.3 348 | +--- org.slf4j:slf4j-api:1.7.12 349 | +--- org.slf4j:slf4j-simple:1.7.12 350 | | \--- org.slf4j:slf4j-api:1.7.12 351 | +--- org.eclipse.jetty:jetty-server:9.3.2.v20150730 352 | | +--- javax.servlet:javax.servlet-api:3.1.0 353 | | +--- org.eclipse.jetty:jetty-http:9.3.2.v20150730 354 | | | \--- org.eclipse.jetty:jetty-util:9.3.2.v20150730 355 | | \--- org.eclipse.jetty:jetty-io:9.3.2.v20150730 356 | | \--- org.eclipse.jetty:jetty-util:9.3.2.v20150730 357 | +--- org.eclipse.jetty:jetty-webapp:9.3.2.v20150730 358 | | +--- org.eclipse.jetty:jetty-xml:9.3.2.v20150730 359 | | | \--- org.eclipse.jetty:jetty-util:9.3.2.v20150730 360 | | \--- org.eclipse.jetty:jetty-servlet:9.3.2.v20150730 361 | | \--- org.eclipse.jetty:jetty-security:9.3.2.v20150730 362 | | \--- org.eclipse.jetty:jetty-server:9.3.2.v20150730 (*) 363 | +--- org.eclipse.jetty.websocket:websocket-server:9.3.2.v20150730 364 | | +--- org.eclipse.jetty.websocket:websocket-common:9.3.2.v20150730 365 | | | +--- org.eclipse.jetty.websocket:websocket-api:9.3.2.v20150730 366 | | | +--- org.eclipse.jetty:jetty-util:9.3.2.v20150730 367 | | | \--- org.eclipse.jetty:jetty-io:9.3.2.v20150730 (*) 368 | | +--- org.eclipse.jetty.websocket:websocket-client:9.3.2.v20150730 369 | | | +--- org.eclipse.jetty:jetty-util:9.3.2.v20150730 370 | | | +--- org.eclipse.jetty:jetty-io:9.3.2.v20150730 (*) 371 | | | \--- org.eclipse.jetty.websocket:websocket-common:9.3.2.v2015073 (*) 372 | | +--- org.eclipse.jetty.websocket:websocket-servlet:9.3.2.v20150730 373 | | | +--- org.eclipse.jetty.websocket:websocket-api:9.3.2.v20150730 374 | | | \--- javax.servlet:javax.servlet-api:3.1.0 375 | | +--- org.eclipse.jetty:jetty-servlet:9.3.2.v20150730 (*) 376 | | \--- org.eclipse.jetty:jetty-http:9.3.2.v20150730 (*) 377 | \--- org.eclipse.jetty.websocket:websocket-servlet:9.3.2.v20150730 (*) 378 | 379 | ceylonRuntime 380 | No dependencies 381 | ``` 382 | 383 | Luckily, you don't need to figure out all these dependencies yourself! 384 | 385 | The auto-generated overrides.xml file for this example will be this one: 386 | 387 | ```xml 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | ``` 423 | 424 | ### Excluding transitive dependencies 425 | 426 | If you don't want all of transitive dependencies to be added to your project, you can remove them by specifying them 427 | as usual with Gradle and adding exclusions. 428 | 429 | For example, continuing the example above, supposing that you don't want the websocket dependencies 430 | of Jetty because you're not going to use websockets, you can declare the dependency on Spark **also** in the Gradle file, 431 | as follows: 432 | 433 | ```groovy 434 | dependencies { 435 | ceylonCompile "com.sparkjava:spark-core:2.3", { 436 | exclude group: 'org.eclipse.jetty.websocket' 437 | } 438 | } 439 | ``` 440 | 441 | > Notice that you still must declare a dependency on `spark-core` in the `module.ceylon` file even if you add that 442 | dependency on the Gradle build file. 443 | 444 | It's important to understand that direct dependencies should be declared in `module.ceylon`, as with any Ceylon project. 445 | The Gradle `dependencies` should be used only to add more information to how you want transitive dependencies to be 446 | handled, as in this example. This avoids tightly coupling your project to Gradle (once you have the overrides.xml file 447 | generated by Gradle, your project does not need anything else from Gradle and can be run by `ceylon` as usual) 448 | and confusion regarding where dependencies should be declared! 449 | 450 | ### Depending on other Gradle modules in the same project 451 | 452 | You can add a dependency to another module of your Gradle project, be it a Java (or even Scala, Groovy or Kotlin) 453 | module or another Ceylon module, using this syntax in the Gradle build file: 454 | 455 | ```groovy 456 | dependencies { 457 | ceylonCompile project( ':multi-modules-project:another-module' ) 458 | } 459 | ``` 460 | 461 | Where the name of the project is `multi-modules-project`. 462 | 463 | In the Ceylon module file, you simply refer to the name of the module (which depends on whether you're using a flat 464 | classpath or not, as explained above). 465 | 466 | For example, if the other module has these declarations in its Gradle build file: 467 | 468 | ```groovy 469 | group = 'com.athaydes.gradle' 470 | version = '4.2' 471 | ``` 472 | 473 | > notice that, with Gradle, the module name, by default, is the name of the module root directory. To change that, 474 | use a Gradle [`settings.gradle` file](https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:settings_file). 475 | 476 | If using a flat classpath, you would import this module in the Ceylon module file using this statement: 477 | 478 | ```ceylon 479 | import "com.athaydes.gradle:another-module" "4.2"; 480 | ``` 481 | 482 | If NOT using a flat classpath: 483 | 484 | ```ceylon 485 | import com.athaydes.gradle.another_module "4.2"; 486 | ``` 487 | 488 | ## Running Ceylon code without the ceylon tool in the JVM 489 | 490 | The `createJavaRuntime` task creates a directory containing all jars required to run your Ceylon module without using 491 | `ceylon run`, as well as bash/bat scripts to make it trivial to start the `java` process with the Ceylon module. 492 | 493 | It is extremely easy to do it. From the root directory of your Ceylon project, run the following commands: 494 | 495 | #### In Linux/Mac systems 496 | 497 | ``` 498 | ./gradlew clean createJavaRuntime 499 | bash build/java-runtime/run.sh 500 | ``` 501 | 502 | #### In Windows 503 | 504 | ``` 505 | gradlew clean createJavaRuntime 506 | build\java-runtime\run.bat 507 | ``` 508 | 509 | ### Why run your Ceylon code with java instead of ceylon run? 510 | 511 | Because you can get a 10x startup time improvement just by doing this. 512 | 513 | Check this out (you can run the same from the [module-with-tests-sample](ceylon-gradle-plugin-tests/module-with-tests-sample) 514 | directory): 515 | 516 | ``` 517 | # clean, compile and create the Java runtime 518 | $ ./gradlew clean createJavaRuntime 519 | ... 520 | 521 | # run the module directly with the ceylon command 522 | # to print the full command, run 523 | # ./gradlew -P get-ceylon-command runCeylon 524 | $ time ceylon run \ 525 | --overrides build/overrides.xml \ 526 | --rep=aether:build/maven-settings.xml \ 527 | --rep=modules \ 528 | --run=com.athaydes.simple::addArgs \ 529 | com.athaydes.simple 2 5.3 6 530 | 531 | The sum of { 2.0, 5.3, 6.0 } is: 13.3 532 | 533 | real 0m1.033s 534 | user 0m2.459s 535 | sys 0m0.189s 536 | 537 | # invoke java with the run.sh created by the Gradle Plugin 538 | $ time bash target/jvm/run.sh 2 5.3 6 539 | 540 | The sum of { 2.0, 5.3, 6.0 } is: 13.3 541 | 542 | real 0m0.160s 543 | user 0m0.173s 544 | sys 0m0.031s 545 | ``` 546 | 547 | ## Gradle project examples 548 | 549 | For working examples of Gradle projects using the Ceylon Gradle Plugin, refer to the 550 | [test samples directory](ceylon-gradle-plugin-tests). 551 | 552 | 553 | --------------------------------------------------------------------------------