From f9b305f228298cc8461ab3018c141512296278f0 Mon Sep 17 00:00:00 2001 From: oniatus Date: Mon, 2 Jan 2017 16:17:37 +0100 Subject: [PATCH 01/20] Auto-include build.gradle from Core module --- modules/subprojects.gradle | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/subprojects.gradle b/modules/subprojects.gradle index 9d372ea39da..a3d30cd5b3b 100644 --- a/modules/subprojects.gradle +++ b/modules/subprojects.gradle @@ -3,13 +3,16 @@ new File(rootDir, 'modules').eachDir { possibleSubprojectDir -> def subprojectName = 'modules:' + possibleSubprojectDir.name //println "Gradle is reviewing module $subprojectName for inclusion as a sub-project" File buildFile = new File(possibleSubprojectDir, "build.gradle") - if (buildFile.exists()) { - println "Module $subprojectName has a build file so counting it complete and including it" - include subprojectName - def subprojectPath = ':' + subprojectName - def subproject = project(subprojectPath) - subproject.projectDir = possibleSubprojectDir + if (!buildFile.exists()) { + println "Module $subprojectName has no build file, adding build.gradle file from core and including it" + File replacementGradle = new File(rootDir, 'modules/Core/build.gradle') + File targetFile = new File(possibleSubprojectDir, "build.gradle") + targetFile << replacementGradle.text } else { - println "***** WARNING: Found a module without a build.gradle, corrupt dir? NOT including $subprojectName *****" + println "Module $subprojectName has a build file so counting it complete and including it" } + include subprojectName + def subprojectPath = ':' + subprojectName + def subproject = project(subprojectPath) + subproject.projectDir = possibleSubprojectDir } From 2a7a16ca134273fc3fa29dd6f238031ca6e2e286 Mon Sep 17 00:00:00 2001 From: oniatus Date: Mon, 2 Jan 2017 16:25:56 +0100 Subject: [PATCH 02/20] Small cleanup --- modules/subprojects.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/subprojects.gradle b/modules/subprojects.gradle index a3d30cd5b3b..fdd81a95a6b 100644 --- a/modules/subprojects.gradle +++ b/modules/subprojects.gradle @@ -6,8 +6,7 @@ new File(rootDir, 'modules').eachDir { possibleSubprojectDir -> if (!buildFile.exists()) { println "Module $subprojectName has no build file, adding build.gradle file from core and including it" File replacementGradle = new File(rootDir, 'modules/Core/build.gradle') - File targetFile = new File(possibleSubprojectDir, "build.gradle") - targetFile << replacementGradle.text + buildFile << replacementGradle.text } else { println "Module $subprojectName has a build file so counting it complete and including it" } From 9ce582c0a7c7090959ab48ff73c7e818b1c0b4f9 Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 26 Jan 2017 02:04:36 -0500 Subject: [PATCH 03/20] Major Gradle overhaul - bunch of stuff done, stable again but more to do. - Upgrades to Gradle 3.3 from 2.10 - Removes the need for module directories to have a build.gradle - Related cleanup / simplification of scripts - Bakes in support for alternative module languages into new /modules Gradle scripts via new "language" property in module.txt --- .gitignore | 2 +- build.gradle | 21 +- engine/build.gradle | 4 - facades/PC/build.gradle | 18 +- facades/TeraEd/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 54208 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 68 ++-- gradlew.bat | 14 +- modules/Core/build.gradle | 301 ------------------ modules/CoreSampleGameplay/build.gradle | 301 ------------------ modules/build.gradle | 43 +++ modules/java.gradle | 82 +++++ modules/kotlin.gradle | 86 +++++ .../build.gradle => module.gradle} | 144 ++------- modules/scala.gradle | 82 +++++ modules/subprojects.gradle | 18 +- 17 files changed, 389 insertions(+), 801 deletions(-) delete mode 100644 modules/Core/build.gradle delete mode 100644 modules/CoreSampleGameplay/build.gradle create mode 100644 modules/build.gradle create mode 100644 modules/java.gradle create mode 100644 modules/kotlin.gradle rename modules/{BuilderSampleGameplay/build.gradle => module.gradle} (73%) create mode 100644 modules/scala.gradle diff --git a/.gitignore b/.gitignore index 10904360e31..35c2fa19eba 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ extensions !/modules/Core !/modules/CoreSampleGameplay !/modules/BuilderSampleGameplay -!/modules/subprojects.gradle +!/modules/*.gradle /meta/* !/meta/subprojects.gradle /libs/* diff --git a/build.gradle b/build.gradle index 7a8fd99b57d..b7b325476fc 100644 --- a/build.gradle +++ b/build.gradle @@ -135,22 +135,10 @@ def terasologyModules() { subprojects.findAll {it.parent.name == 'modules'} } -// Helper that replaces the build.gradle under every module with a fresh copy from the Core module -task refreshModuleGradle << { - File replacementGradle = new File(rootDir, 'modules/Core/build.gradle') - terasologyModules().each { - if (it.name != 'Core') { - File targetFile = new File(rootDir, "modules/" + it.name + "/build.gradle") - targetFile.delete() - targetFile << replacementGradle.text - } - } -} - // Helpers that do magic things after having dependencies attached below -task moduleClasses -task moduleJars - +//task moduleClasses +//task moduleJars +/* // This magically makes everything work - without this the desired module projects returned have no tasks :-( gradle.projectsEvaluated { // Note how "classes" may indirectly trigger "jar" for module dependencies of modules (module compile dependency) @@ -159,9 +147,10 @@ gradle.projectsEvaluated { // This makes it work for a full jar task moduleJars.dependsOn(terasologyModules().jar) } - +*/ // This is a TEMPORARY tweak to make "changing" dependencies always ('0') check for newer snapshots available // TODO: Remove this when versioning and promotion works fully, then we shouldn't care about snapshots normally anyway +// For some reason this can stay here, yet had to be removed from everywhere else for Gradle 3.3 configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } diff --git a/engine/build.gradle b/engine/build.gradle index d0ae86290c3..6fa29302d28 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -80,10 +80,6 @@ configurations { devCompile.extendsFrom compile } -// TODO: Remove when we don't need to rely on snapshots. Wonder why modules respected this set in root project, engine not so much -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} // Primary dependencies definition dependencies { diff --git a/facades/PC/build.gradle b/facades/PC/build.gradle index 07f216f5787..048baa896b9 100644 --- a/facades/PC/build.gradle +++ b/facades/PC/build.gradle @@ -83,7 +83,7 @@ task game(type:JavaExec) { // Dependencies: natives + all modules & the PC facade itself (which will trigger the engine) dependsOn rootProject.extractNatives - dependsOn rootProject.moduleClasses + // dependsOn rootProject.moduleClasses // TODO: Review? dependsOn classes // Run arguments @@ -104,7 +104,7 @@ task debug(type:JavaExec) { // Dependencies: natives + all modules & the PC facade itself (which will trigger the engine) dependsOn rootProject.extractNatives - dependsOn rootProject.moduleClasses + // dependsOn rootProject.moduleClasses // TODO: Review? dependsOn classes // Run arguments @@ -182,7 +182,7 @@ task server(type:JavaExec) { // Dependencies: natives + all modules & the PC facade itself (which will trigger the engine) dependsOn rootProject.extractNatives - dependsOn rootProject.moduleClasses + // dependsOn rootProject.moduleClasses // TODO: Review? dependsOn classes dependsOn setupServerConfig dependsOn setupServerModules @@ -251,26 +251,20 @@ task distApp (type: Sync) { } } -// This is a TEMPORARY tweak to make "changing" dependencies always ('0') check for newer snapshots available -// TODO: Remove this when versioning and promotion works fully, then we shouldn't care about snapshots normally anyway -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - // Distribute modules - only grabs Core in Jenkins but locally will grab any present. "Distros" now handle Jenkins packs task distModules (type: Sync) { description = "Prepares local modules for distribution" dependsOn distApp - dependsOn rootProject.moduleJars - + // dependsOn rootProject.moduleJars // TODO: Review. Doesn't seem to work anymore anyway +/* // So this is probably a hack, but it works ;-) It does not work if it is in distApp, default "into" quirk ? into("$distsDir/app/modules") rootProject.terasologyModules().each { from "$rootDir/modules/${it.name}/build/libs" include "*.jar" } + */ } - task distPCZip (type: Zip) { dependsOn distApp dependsOn distModules diff --git a/facades/TeraEd/build.gradle b/facades/TeraEd/build.gradle index c7e0e5e99c5..71e59bbbcb5 100644 --- a/facades/TeraEd/build.gradle +++ b/facades/TeraEd/build.gradle @@ -19,7 +19,7 @@ task editor(type:JavaExec) { // Dependencies: natives + all modules & the PC facade itself (which will trigger the engine) dependsOn rootProject.extractNatives - dependsOn rootProject.moduleClasses + // dependsOn rootProject.moduleClasses // TODO: Review? dependsOn classes // Run arguments diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 941144813d241db74e1bf25b6804c679fbe7f0a3..31b06f23403669dc26a4725a3c21c01da34b0091 100644 GIT binary patch delta 24979 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 wfIy~h)^_Gx&K71C){d^+j?T{?_CR%EWq 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa68..f9553162f12 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/modules/Core/build.gradle b/modules/Core/build.gradle deleted file mode 100644 index db7ab6bcf3d..00000000000 --- a/modules/Core/build.gradle +++ /dev/null @@ -1,301 +0,0 @@ -// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules - -// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic -apply from: "$rootDir/config/gradle/artifactory.gradle" - -import groovy.json.JsonSlurper -import java.text.SimpleDateFormat; - -// Git plugin details at https://github.com/ajoberstar/gradle-git -import org.ajoberstar.gradle.git.tasks.* -import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; -import org.reflections.scanners.TypeAnnotationsScanner; -import org.reflections.util.ConfigurationBuilder; - -// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( -buildscript { - repositories { - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case - jcenter() - mavenCentral() - } - - dependencies { - // Artifactory plugin - classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') - - // Git plugin for Gradle - classpath 'org.ajoberstar:gradle-git:0.6.3' - - // Needed for caching reflected data during builds - classpath 'org.reflections:reflections:0.9.10' - classpath 'dom4j:dom4j:1.6.1' - } -} - -ext { - // Read environment variables, including variables passed by jenkins continuous integration server - env = System.getenv() -} - -def moduleDepends = []; -def moduleFile = file('module.txt') - -// The module file should always exist if the module was correctly created or cloned using Gradle -if (!moduleFile.exists()) { - println "Y U NO EXIST MODULE.TXT!" - throw new GradleException("Failed to find module.txt for " + project.name) -} - -//println "Scanning for dependencies in module.txt for " + project.name -def slurper = new JsonSlurper() -def moduleConfig = slurper.parseText(moduleFile.text) -for (dependency in moduleConfig.dependencies) { - if (dependency.id != 'engine') { - moduleDepends += dependency.id - } -} - -// Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess) -version = moduleConfig.version - -// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor -group = 'org.terasology.modules' - -println "Version for $project.name loaded as $version for group $group" - -// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - -// Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules -dependencies { - // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace - if (project.name != project(':').name) { - println "\nProcessing module '$project.name' in a multi-project workspace" - - // Dependency on the engine itself (actually its built jar file) - compile project(':engine') - - // Engine unit tests contain classes that module unit tests can extend, so need to be compile, not testCompile - compile project(':engine-tests') - - if (moduleDepends.size() > 0) { - println "* $project.name has extra dependencies:" - moduleDepends.each { - println "** $it" - } - } else { - println "* No extra dependencies" - } - - // If the module has dependencies on other modules we look for either a source version or a remote binary - for (dependency in moduleDepends) { - File wouldBeSrcPath = new File(rootDir, 'modules/' + dependency) - //println "Scanning for source module at: " + wouldBeSrcPath.getAbsolutePath() - - // First see if we have an actual source module project in the Gradle project tree (user fetchModule'ed it) - if (wouldBeSrcPath.exists()) { - //TODO: This could hit problems with corrupt module directories? - - println "*** Identified source: " + dependency - // Note: if artifactoryPublish is used in a multi-project workspace including modules the .pom gets hard version refs - // Normally they're expected to run in Jenkins standalone where they'll instead match the else and get version '+' - compile project(':modules:' + dependency) - } else { - println "*** Seeking as binary: " + dependency - // The '+' is satisfied by any version. "changing" triggers better checking for updated snapshots - // TODO: When version handling and promotion is in then we can probably ignore snapshots in normal cases - compile(group: 'org.terasology.modules', name: dependency, version: '+', changing: true) - } - } - - // This step resolves artifacts early, after which project config CANNOT be altered again! - configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> - def id = artifact.moduleVersion.id - - // Check for any needed module dependencies on other modules that we need at runtime - if (id.group == 'org.terasology.modules' && id.name != "Core") { - File moduleSrcPath = new File(rootDir, 'modules/' + id.name) - File moduleJarPath = new File(rootDir, 'modules/' + id.name + '-' + id.version + '.jar') - - if (moduleSrcPath.exists()) { - println "*** Found module dependency $id.name in source form, not copying a runtime jar from Gradle" - } else { - println "$project.name resolved binary $id.group - $id.name at version $id.version" - - // This copies the jar from the Gradle cache to the game's module dir for runtime usage, if needed - if (!moduleJarPath.exists()) { - println "* Writing a runtime jar to /modules: " + moduleJarPath.name - moduleJarPath.createNewFile() - moduleJarPath << artifact.file.bytes - } - } - } - } - } else { - println "We're in a single-project non-Core module workspace (Jenkins) so will look elsewhere for dependencies" - - // TODO: While this is easy it would prevent modules declaring an engine dependency of a specific version - // TODO: Look for a provided engine jar in the workspace and use that if present - // TODO: Only use engine, engine-tests, and maybe core for compilation, but remove when publishing? - compile(group: 'org.terasology.engine', name: 'engine', version: '+', changing: true) - compile(group: 'org.terasology.engine', name: 'engine-tests', version: '+', changing: true) - - // To get Terasology module dependencies we simply declare them against Artifactory - moduleDepends.each { - println "*** Attempting to fetch dependency module from Artifactory for " + project.name + ": " + it - // The '+' is satisfied by any version - compile(group: 'org.terasology.modules', name: it, version: '+', changing: true) - - } - - // TODO: parse and apply external lib dependencies if any are present - // TODO: Consider / keep an eye on whether resolving artifacts early at this point causes any trouble (is only for logging) - // This step resolves artifacts (both compile & testCompile) and prints out some interesting versions - configurations.testCompile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> - def id = artifact.moduleVersion.id - // Print out module (and engine stuff) dependencies and the exact versions they resolved at - if (id.group.startsWith('org.terasology')) { - println "*** $project.name remotely resolved $id.group - $id.name - version $id.version" - } - } - } -} - -// Change the output dir of each module -sourceSets { - main { - java { - output.classesDir 'build/classes' - } - } -} - -// Generate the module directory structure if missing -task createSkeleton() { - mkdir('assets') - mkdir('assets/animations') - mkdir('assets/atlas') - mkdir('assets/behaviors') - mkdir('assets/blocks') - mkdir('assets/blockSounds') - mkdir('assets/blockTiles') - mkdir('assets/fonts') - mkdir('assets/materials') - mkdir('assets/mesh') - mkdir('assets/music') - mkdir('assets/prefabs') - mkdir('assets/shaders') - mkdir('assets/shapes') - mkdir('assets/skeletalMesh') - mkdir('assets/skins') - mkdir('assets/sounds') - mkdir('assets/textures') - mkdir('assets/ui') - mkdir('overrides') - mkdir('deltas') - mkdir('src/main/java') - mkdir('src/test/java') -} - -task cacheReflections { - description = 'Caches reflection output to make regular startup faster. May go stale and need cleanup at times.' - // TODO: The extra "org" qualifier excludes test classes otherwise sucked up in Jenkins, causing issues. Redo later - File dirToReflect = new File(sourceSets.main.output.classesDir, "org") - inputs.files dirToReflect - outputs.file file(sourceSets.main.output.classesDir.toString() + "/reflections.cache") - dependsOn classes - doFirst { - // Without the .mkdirs() we might hit a scenario where the classes dir doesn't exist yet - dirToReflect.mkdirs() - Reflections reflections = new Reflections(new ConfigurationBuilder() - .addUrls(dirToReflect.toURI().toURL()) - .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner())) - reflections.save(sourceSets.main.output.classesDir.toString() + "/reflections.cache") - } -} - -task cleanReflections(type: Delete) { - description = 'Cleans the reflection cache. Useful in cases where it has gone stale and needs regeneration.' - delete sourceSets.main.output.classesDir.toString() + "/reflections.cache" -} - -// This task syncs everything in the assets dir into the output dir, used when jarring the module -task syncAssets(type: Sync) { - from 'assets' - into 'build/classes/assets' -} - -task syncOverrides(type: Sync) { - from 'overrides' - into 'build/classes/overrides' -} - -task syncDeltas(type: Sync) { - from 'deltas' - into 'build/classes/deltas' -} - -// Instructions for packaging a jar file - is a manifest even needed for modules? -jar { - // Make sure the assets directory is included - dependsOn cacheReflections - dependsOn syncAssets - dependsOn syncOverrides - dependsOn syncDeltas - - // Jarring needs to copy module.txt and all the assets into the output - doFirst { - copy { - from 'module.txt' - into 'build/classes' - } - } -} - -jar.finalizedBy cleanReflections - -// Prep an IntelliJ module for the Terasology module - yes, might want to read that twice :D -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - downloadSources = true - } -} - -// For Eclipse just make sure the classpath is right -eclipse { - classpath { - defaultOutputDir = file('build/classes') - } -} - -// Utility task to update the module (except Core) via Git - not tested with local changes present, may cause trouble -task (updateModule, type: GitPull) { - description = 'Updates source for the module from its home (most likely GitHub)' - - // Base whether the task executes on two things - // 1 - we actually asked for it ("gradlew updateModule") - otherwise we don't want it to run TODO: Test for abbreviations? - // 2 - this is not the Core module, which lives with the engine and needs no updates - boolean enabled = "updateModule" in project.gradle.startParameter.taskNames && !project.name.equals("Core") - // TODO: Used to cheat with declaring tasks using << but that defers everything (including config) to execution phase - // Some tasks do not work that way, this one would ALWAYS go with default (root git repo) in that case - // Probably should go through other stuff and use this strategy instead of << - - // Only if we asked for it (and not Core) do we actually configure the repo path and log that we're updating - if (enabled) { - - // This is the Git repo we're actually using - projectDir is specific to the executing project, a.k.a. module whatever - // If not enabled the default is the root project's Git dir, which is a valid Git dir - // However in the case of Core we'd be setting ain invalid Git dir which causes fail - so this avoids that - repoPath = projectDir - - println "Pulling updates via Git to " + getRepoDir() + ", if dependencies change run Gradle again (like 'gradlew idea')" - } -} diff --git a/modules/CoreSampleGameplay/build.gradle b/modules/CoreSampleGameplay/build.gradle deleted file mode 100644 index db7ab6bcf3d..00000000000 --- a/modules/CoreSampleGameplay/build.gradle +++ /dev/null @@ -1,301 +0,0 @@ -// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules - -// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic -apply from: "$rootDir/config/gradle/artifactory.gradle" - -import groovy.json.JsonSlurper -import java.text.SimpleDateFormat; - -// Git plugin details at https://github.com/ajoberstar/gradle-git -import org.ajoberstar.gradle.git.tasks.* -import org.reflections.Reflections; -import org.reflections.scanners.SubTypesScanner; -import org.reflections.scanners.TypeAnnotationsScanner; -import org.reflections.util.ConfigurationBuilder; - -// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( -buildscript { - repositories { - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case - jcenter() - mavenCentral() - } - - dependencies { - // Artifactory plugin - classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') - - // Git plugin for Gradle - classpath 'org.ajoberstar:gradle-git:0.6.3' - - // Needed for caching reflected data during builds - classpath 'org.reflections:reflections:0.9.10' - classpath 'dom4j:dom4j:1.6.1' - } -} - -ext { - // Read environment variables, including variables passed by jenkins continuous integration server - env = System.getenv() -} - -def moduleDepends = []; -def moduleFile = file('module.txt') - -// The module file should always exist if the module was correctly created or cloned using Gradle -if (!moduleFile.exists()) { - println "Y U NO EXIST MODULE.TXT!" - throw new GradleException("Failed to find module.txt for " + project.name) -} - -//println "Scanning for dependencies in module.txt for " + project.name -def slurper = new JsonSlurper() -def moduleConfig = slurper.parseText(moduleFile.text) -for (dependency in moduleConfig.dependencies) { - if (dependency.id != 'engine') { - moduleDepends += dependency.id - } -} - -// Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess) -version = moduleConfig.version - -// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor -group = 'org.terasology.modules' - -println "Version for $project.name loaded as $version for group $group" - -// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - -// Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules -dependencies { - // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace - if (project.name != project(':').name) { - println "\nProcessing module '$project.name' in a multi-project workspace" - - // Dependency on the engine itself (actually its built jar file) - compile project(':engine') - - // Engine unit tests contain classes that module unit tests can extend, so need to be compile, not testCompile - compile project(':engine-tests') - - if (moduleDepends.size() > 0) { - println "* $project.name has extra dependencies:" - moduleDepends.each { - println "** $it" - } - } else { - println "* No extra dependencies" - } - - // If the module has dependencies on other modules we look for either a source version or a remote binary - for (dependency in moduleDepends) { - File wouldBeSrcPath = new File(rootDir, 'modules/' + dependency) - //println "Scanning for source module at: " + wouldBeSrcPath.getAbsolutePath() - - // First see if we have an actual source module project in the Gradle project tree (user fetchModule'ed it) - if (wouldBeSrcPath.exists()) { - //TODO: This could hit problems with corrupt module directories? - - println "*** Identified source: " + dependency - // Note: if artifactoryPublish is used in a multi-project workspace including modules the .pom gets hard version refs - // Normally they're expected to run in Jenkins standalone where they'll instead match the else and get version '+' - compile project(':modules:' + dependency) - } else { - println "*** Seeking as binary: " + dependency - // The '+' is satisfied by any version. "changing" triggers better checking for updated snapshots - // TODO: When version handling and promotion is in then we can probably ignore snapshots in normal cases - compile(group: 'org.terasology.modules', name: dependency, version: '+', changing: true) - } - } - - // This step resolves artifacts early, after which project config CANNOT be altered again! - configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> - def id = artifact.moduleVersion.id - - // Check for any needed module dependencies on other modules that we need at runtime - if (id.group == 'org.terasology.modules' && id.name != "Core") { - File moduleSrcPath = new File(rootDir, 'modules/' + id.name) - File moduleJarPath = new File(rootDir, 'modules/' + id.name + '-' + id.version + '.jar') - - if (moduleSrcPath.exists()) { - println "*** Found module dependency $id.name in source form, not copying a runtime jar from Gradle" - } else { - println "$project.name resolved binary $id.group - $id.name at version $id.version" - - // This copies the jar from the Gradle cache to the game's module dir for runtime usage, if needed - if (!moduleJarPath.exists()) { - println "* Writing a runtime jar to /modules: " + moduleJarPath.name - moduleJarPath.createNewFile() - moduleJarPath << artifact.file.bytes - } - } - } - } - } else { - println "We're in a single-project non-Core module workspace (Jenkins) so will look elsewhere for dependencies" - - // TODO: While this is easy it would prevent modules declaring an engine dependency of a specific version - // TODO: Look for a provided engine jar in the workspace and use that if present - // TODO: Only use engine, engine-tests, and maybe core for compilation, but remove when publishing? - compile(group: 'org.terasology.engine', name: 'engine', version: '+', changing: true) - compile(group: 'org.terasology.engine', name: 'engine-tests', version: '+', changing: true) - - // To get Terasology module dependencies we simply declare them against Artifactory - moduleDepends.each { - println "*** Attempting to fetch dependency module from Artifactory for " + project.name + ": " + it - // The '+' is satisfied by any version - compile(group: 'org.terasology.modules', name: it, version: '+', changing: true) - - } - - // TODO: parse and apply external lib dependencies if any are present - // TODO: Consider / keep an eye on whether resolving artifacts early at this point causes any trouble (is only for logging) - // This step resolves artifacts (both compile & testCompile) and prints out some interesting versions - configurations.testCompile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> - def id = artifact.moduleVersion.id - // Print out module (and engine stuff) dependencies and the exact versions they resolved at - if (id.group.startsWith('org.terasology')) { - println "*** $project.name remotely resolved $id.group - $id.name - version $id.version" - } - } - } -} - -// Change the output dir of each module -sourceSets { - main { - java { - output.classesDir 'build/classes' - } - } -} - -// Generate the module directory structure if missing -task createSkeleton() { - mkdir('assets') - mkdir('assets/animations') - mkdir('assets/atlas') - mkdir('assets/behaviors') - mkdir('assets/blocks') - mkdir('assets/blockSounds') - mkdir('assets/blockTiles') - mkdir('assets/fonts') - mkdir('assets/materials') - mkdir('assets/mesh') - mkdir('assets/music') - mkdir('assets/prefabs') - mkdir('assets/shaders') - mkdir('assets/shapes') - mkdir('assets/skeletalMesh') - mkdir('assets/skins') - mkdir('assets/sounds') - mkdir('assets/textures') - mkdir('assets/ui') - mkdir('overrides') - mkdir('deltas') - mkdir('src/main/java') - mkdir('src/test/java') -} - -task cacheReflections { - description = 'Caches reflection output to make regular startup faster. May go stale and need cleanup at times.' - // TODO: The extra "org" qualifier excludes test classes otherwise sucked up in Jenkins, causing issues. Redo later - File dirToReflect = new File(sourceSets.main.output.classesDir, "org") - inputs.files dirToReflect - outputs.file file(sourceSets.main.output.classesDir.toString() + "/reflections.cache") - dependsOn classes - doFirst { - // Without the .mkdirs() we might hit a scenario where the classes dir doesn't exist yet - dirToReflect.mkdirs() - Reflections reflections = new Reflections(new ConfigurationBuilder() - .addUrls(dirToReflect.toURI().toURL()) - .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner())) - reflections.save(sourceSets.main.output.classesDir.toString() + "/reflections.cache") - } -} - -task cleanReflections(type: Delete) { - description = 'Cleans the reflection cache. Useful in cases where it has gone stale and needs regeneration.' - delete sourceSets.main.output.classesDir.toString() + "/reflections.cache" -} - -// This task syncs everything in the assets dir into the output dir, used when jarring the module -task syncAssets(type: Sync) { - from 'assets' - into 'build/classes/assets' -} - -task syncOverrides(type: Sync) { - from 'overrides' - into 'build/classes/overrides' -} - -task syncDeltas(type: Sync) { - from 'deltas' - into 'build/classes/deltas' -} - -// Instructions for packaging a jar file - is a manifest even needed for modules? -jar { - // Make sure the assets directory is included - dependsOn cacheReflections - dependsOn syncAssets - dependsOn syncOverrides - dependsOn syncDeltas - - // Jarring needs to copy module.txt and all the assets into the output - doFirst { - copy { - from 'module.txt' - into 'build/classes' - } - } -} - -jar.finalizedBy cleanReflections - -// Prep an IntelliJ module for the Terasology module - yes, might want to read that twice :D -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - downloadSources = true - } -} - -// For Eclipse just make sure the classpath is right -eclipse { - classpath { - defaultOutputDir = file('build/classes') - } -} - -// Utility task to update the module (except Core) via Git - not tested with local changes present, may cause trouble -task (updateModule, type: GitPull) { - description = 'Updates source for the module from its home (most likely GitHub)' - - // Base whether the task executes on two things - // 1 - we actually asked for it ("gradlew updateModule") - otherwise we don't want it to run TODO: Test for abbreviations? - // 2 - this is not the Core module, which lives with the engine and needs no updates - boolean enabled = "updateModule" in project.gradle.startParameter.taskNames && !project.name.equals("Core") - // TODO: Used to cheat with declaring tasks using << but that defers everything (including config) to execution phase - // Some tasks do not work that way, this one would ALWAYS go with default (root git repo) in that case - // Probably should go through other stuff and use this strategy instead of << - - // Only if we asked for it (and not Core) do we actually configure the repo path and log that we're updating - if (enabled) { - - // This is the Git repo we're actually using - projectDir is specific to the executing project, a.k.a. module whatever - // If not enabled the default is the root project's Git dir, which is a valid Git dir - // However in the case of Core we'd be setting ain invalid Git dir which causes fail - so this avoids that - repoPath = projectDir - - println "Pulling updates via Git to " + getRepoDir() + ", if dependencies change run Gradle again (like 'gradlew idea')" - } -} diff --git a/modules/build.gradle b/modules/build.gradle new file mode 100644 index 00000000000..a325c2ba0b0 --- /dev/null +++ b/modules/build.gradle @@ -0,0 +1,43 @@ +// This file is the entry point for Gradle's build logic for modules (subprojects.gradle just sets up project structure) + +// This buildscript block is needed for some plugins to work, even if they are applied deeper in via apply from: blocks +// TODO: Switch to the new Gradle plugin approach when it works in subproject blocks (beyond Gradle 3.3 sometime) + +buildscript { + repositories { + jcenter() + } + dependencies { + // Needed at this level for modules in Kotlin + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6" + + // Needed for our deep dark Java wizardry + //classpath 'org.reflections:reflections:0.9.10' + //classpath 'dom4j:dom4j:1.6.1' + } +} + +import groovy.json.JsonSlurper + +// We need to prepare the build logic for each module so we use a subprojects block to make this execute for each +subprojects { + + // Parse out the language selection from module.txt + def moduleFile = file('module.txt') + JsonSlurper slurper = new JsonSlurper() + def moduleConfig = slurper.parseText(moduleFile.text) + + // When we know the language we apply the appropriate language-specific wrapper for build logic + if (moduleConfig.language == "scala") { + println "Oh hey, a Scala module. Using its build" + apply from: '../scala.gradle' + } else if (moduleConfig.language == "kotlin") { + println "Oh hey, a Kotlin module. Using its build" + // TODO: This satisfies Kotlin compilation in a module using it. Still need to guarantee a dependency on KotlinLib to get the runtime jar (I think?) + // So during Gradling for a language specific module insert condition: If KotlinLib then include the jar. If not then validate KotlinLib dep in module.txt + apply from: '../kotlin.gradle' + } else { + println "Boring old Java module" + apply from: '../java.gradle' + } +} diff --git a/modules/java.gradle b/modules/java.gradle new file mode 100644 index 00000000000..3f1dd8252e7 --- /dev/null +++ b/modules/java.gradle @@ -0,0 +1,82 @@ +// This Gradle file is an include file for modules wanting to run in plain old Java + +// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic +apply from: "$rootDir/config/gradle/artifactory.gradle" + +// Grab the common stuff specific to modules builds (allows it to live in a module specific but language agnostic file) +apply from: "../module.gradle" + +// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( +buildscript { + repositories { + // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case + jcenter() + } + + dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + + // Git plugin for Gradle + classpath 'org.ajoberstar:gradle-git:0.6.3' + + // Needed for caching reflected data during builds + classpath 'org.reflections:reflections:0.9.10' + classpath 'dom4j:dom4j:1.6.1' + } +} + +ext { + // For the Java modules we add these two additional dirs to the module directory structure + moduleSkeletonDirs << 'src/main/java' << 'src/test/java' +} + +sourceSets { + main { + java { + output.classesDir 'build/classes' + } + } +} + +// Generate the module directory structure if missing (by declaring the task here we also get the language specific extras) +task createSkeleton() { + moduleSkeletonDirs.each { + mkdir it + } +} + +jar { + // Make sure the assets directory is included + dependsOn cacheReflections + dependsOn syncAssets + dependsOn syncOverrides + dependsOn syncDeltas + + // Jarring needs to copy module.txt and all the assets into the output + doFirst { + copy { + from 'module.txt' + into 'build/classes' + } + } +} +jar.finalizedBy cleanReflections + +// Prep an IntelliJ module for the Terasology module - yes, might want to read that twice :D +idea { + module { + // Change around the output a bit + inheritOutputDirs = false + outputDir = file('build/classes') + testOutputDir = file('build/testClasses') + downloadSources = true + } +} + +// For Eclipse just make sure the classpath is right +eclipse { + classpath { + defaultOutputDir = file('build/classes') + } +} diff --git a/modules/kotlin.gradle b/modules/kotlin.gradle new file mode 100644 index 00000000000..7e5613eb8b7 --- /dev/null +++ b/modules/kotlin.gradle @@ -0,0 +1,86 @@ +// This Gradle file is an include file for modules wanting to run in Kotlin +apply plugin: "kotlin" + +// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc +apply from: "$rootDir/config/gradle/artifactory.gradle" + +// Grab the module specific build logic that's language agnostic +apply from: "../module.gradle" + +// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( +buildscript { + repositories { + jcenter() + } + + dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + + // Needed for caching reflected data during builds + classpath 'org.reflections:reflections:0.9.10' + classpath 'dom4j:dom4j:1.6.1' + + // Needed for modules in Kotlin + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6" + } +} + +ext { + // For the Kotlin modules we add these two additional dirs to the module directory structure + moduleSkeletonDirs << 'src/main/kotlin' << 'src/test/kotlin' +} + +sourceSets { + main { + kotlin { + output.classesDir 'build/classes' + } + } +} + +configurations { + kotlinConf.extendsFrom compile + kotlinTestConf.extendsFrom testCompile + kotlinEmbedded +} + +dependencies { + // Since the main compile and compileTest configs are defined in the generic module.gradle we can't modify them here - so extend instead + kotlinConf group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.0.6' + kotlinConf group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.0.6' + + kotlinTestConf group: 'org.jetbrains.kotlin', name: 'kotlin-test:1.0.6' + kotlinTestConf group: 'org.jetbrains.kotlin', name: 'kotlin-test-junit:1.0.6' + + // To make this module bundle Kotlin's runtime jar we put it in a separate config by itself + kotlinEmbedded group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: '1.0.6' +} + + + +// Generate the module directory structure if missing (by declaring the task here we also get the language specific extras) +task createSkeleton() { + moduleSkeletonDirs.each { + mkdir it + } +} + +// TODO: Only embed Kotlin for the KotlinLib module - otherwise rely on a dependency declared on KotlinLib +jar { + // Make sure the assets directory is included + dependsOn cacheReflections + dependsOn syncAssets + dependsOn syncOverrides + dependsOn syncDeltas + + // Jarring needs to copy module.txt and all the assets into the output + doFirst { + copy { + from 'module.txt' + from configurations.kotlinEmbedded + into 'build/classes' + } + } +} +jar.finalizedBy cleanReflections diff --git a/modules/BuilderSampleGameplay/build.gradle b/modules/module.gradle similarity index 73% rename from modules/BuilderSampleGameplay/build.gradle rename to modules/module.gradle index db7ab6bcf3d..96dbbc8f2e7 100644 --- a/modules/BuilderSampleGameplay/build.gradle +++ b/modules/module.gradle @@ -1,54 +1,19 @@ -// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules - -// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic -apply from: "$rootDir/config/gradle/artifactory.gradle" +// This file holds language-generic Gradle stuff for modules. It is meant to be included by the language specific Gradle files import groovy.json.JsonSlurper -import java.text.SimpleDateFormat; // Git plugin details at https://github.com/ajoberstar/gradle-git import org.ajoberstar.gradle.git.tasks.* + import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ConfigurationBuilder; -// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( -buildscript { - repositories { - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case - jcenter() - mavenCentral() - } - - dependencies { - // Artifactory plugin - classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') - - // Git plugin for Gradle - classpath 'org.ajoberstar:gradle-git:0.6.3' - - // Needed for caching reflected data during builds - classpath 'org.reflections:reflections:0.9.10' - classpath 'dom4j:dom4j:1.6.1' - } -} - -ext { - // Read environment variables, including variables passed by jenkins continuous integration server - env = System.getenv() -} - def moduleDepends = []; def moduleFile = file('module.txt') -// The module file should always exist if the module was correctly created or cloned using Gradle -if (!moduleFile.exists()) { - println "Y U NO EXIST MODULE.TXT!" - throw new GradleException("Failed to find module.txt for " + project.name) -} - -//println "Scanning for dependencies in module.txt for " + project.name +println "Scanning for dependencies in module.txt for " + project.name def slurper = new JsonSlurper() def moduleConfig = slurper.parseText(moduleFile.text) for (dependency in moduleConfig.dependencies) { @@ -56,6 +21,7 @@ for (dependency in moduleConfig.dependencies) { moduleDepends += dependency.id } } +println "Dependencies: $moduleDepends" // Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess) version = moduleConfig.version @@ -65,9 +31,29 @@ group = 'org.terasology.modules' println "Version for $project.name loaded as $version for group $group" -// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' +ext { + // The base set of directories potentially needed in a module. Language Gradle files add their unique extras + moduleSkeletonDirs = ['assets', + 'assets/animations', + 'assets/atlas', + 'assets/behaviors', + 'assets/blocks', + 'assets/blockSounds', + 'assets/blockTiles', + 'assets/fonts', + 'assets/materials', + 'assets/mesh', + 'assets/music', + 'assets/prefabs', + 'assets/shaders', + 'assets/shapes', + 'assets/skeletalMesh', + 'assets/skins', + 'assets/sounds', + 'assets/textures', + 'assets/ui', + 'overrides', + 'deltas'] } // Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules @@ -165,42 +151,6 @@ dependencies { } } -// Change the output dir of each module -sourceSets { - main { - java { - output.classesDir 'build/classes' - } - } -} - -// Generate the module directory structure if missing -task createSkeleton() { - mkdir('assets') - mkdir('assets/animations') - mkdir('assets/atlas') - mkdir('assets/behaviors') - mkdir('assets/blocks') - mkdir('assets/blockSounds') - mkdir('assets/blockTiles') - mkdir('assets/fonts') - mkdir('assets/materials') - mkdir('assets/mesh') - mkdir('assets/music') - mkdir('assets/prefabs') - mkdir('assets/shaders') - mkdir('assets/shapes') - mkdir('assets/skeletalMesh') - mkdir('assets/skins') - mkdir('assets/sounds') - mkdir('assets/textures') - mkdir('assets/ui') - mkdir('overrides') - mkdir('deltas') - mkdir('src/main/java') - mkdir('src/test/java') -} - task cacheReflections { description = 'Caches reflection output to make regular startup faster. May go stale and need cleanup at times.' // TODO: The extra "org" qualifier excludes test classes otherwise sucked up in Jenkins, causing issues. Redo later @@ -239,43 +189,8 @@ task syncDeltas(type: Sync) { into 'build/classes/deltas' } -// Instructions for packaging a jar file - is a manifest even needed for modules? -jar { - // Make sure the assets directory is included - dependsOn cacheReflections - dependsOn syncAssets - dependsOn syncOverrides - dependsOn syncDeltas - - // Jarring needs to copy module.txt and all the assets into the output - doFirst { - copy { - from 'module.txt' - into 'build/classes' - } - } -} - -jar.finalizedBy cleanReflections - -// Prep an IntelliJ module for the Terasology module - yes, might want to read that twice :D -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - downloadSources = true - } -} - -// For Eclipse just make sure the classpath is right -eclipse { - classpath { - defaultOutputDir = file('build/classes') - } -} - +/* +TODO: Review - not sure if working well. Maybe a better way to do it via standalone Groovy utility script // Utility task to update the module (except Core) via Git - not tested with local changes present, may cause trouble task (updateModule, type: GitPull) { description = 'Updates source for the module from its home (most likely GitHub)' @@ -299,3 +214,4 @@ task (updateModule, type: GitPull) { println "Pulling updates via Git to " + getRepoDir() + ", if dependencies change run Gradle again (like 'gradlew idea')" } } +*/ \ No newline at end of file diff --git a/modules/scala.gradle b/modules/scala.gradle new file mode 100644 index 00000000000..1f77ccbd9b9 --- /dev/null +++ b/modules/scala.gradle @@ -0,0 +1,82 @@ +// This Gradle file is an include file for modules wanting to run in Scala +apply plugin: "scala" + +// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc +apply from: "$rootDir/config/gradle/artifactory.gradle" + +// Grab the module specific build logic that's language agnostic +apply from: "../module.gradle" + +// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( +buildscript { + repositories { + jcenter() + } + + dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + + // Needed for caching reflected data during builds + classpath 'org.reflections:reflections:0.9.10' + classpath 'dom4j:dom4j:1.6.1' + } +} + +ext { + // For the Scala modules we add these two additional dirs to the module directory structure + moduleSkeletonDirs << 'src/main/scala' << 'src/test/scala' +} + +sourceSets { + main { + scala { + output.classesDir 'build/classes' + } + } +} + +configurations { + scalaConf.extendsFrom compile + scalaEmbedded +} + +dependencies { + // Since the main compile and compileTest configs are defined in the generic module.gradle we can't modify them here - so extend instead + scalaConf group: 'org.scala-lang', name: 'scala-reflect', version: '2.11.7' + scalaConf group: 'org.scala-lang', name: 'scala-compiler', version: '2.11.7' + + // To make this module bundle Kotlin's runtime jar we put it in a separate config by itself + scalaEmbedded group: 'org.scala-lang', name: 'scala-library', version: '2.11.7' +} + +// Generate the module directory structure if missing (by declaring the task here we also get the language specific extras) +task createSkeleton() { + moduleSkeletonDirs.each { + mkdir it + } +} + +// TODO: Only embed Scala for the ScalaLib module - otherwise rely on a dependency declared on ScalaLib +jar { + // Make sure the assets directory is included + dependsOn cacheReflections + dependsOn syncAssets + dependsOn syncOverrides + dependsOn syncDeltas + + // Jarring needs to copy module.txt and all the assets into the output + doFirst { + copy { + from 'module.txt' + from configurations.scalaEmbedded + into 'build/classes' + } + } +} +jar.finalizedBy cleanReflections + +// Needed for Scala for some reason - Kotlin seems to pick up on the custom configurations on its own but here we have to be explicit +tasks.withType(ScalaCompile) { + scalaClasspath = configurations.scalaConf +} \ No newline at end of file diff --git a/modules/subprojects.gradle b/modules/subprojects.gradle index fdd81a95a6b..39d3b839747 100644 --- a/modules/subprojects.gradle +++ b/modules/subprojects.gradle @@ -1,17 +1,13 @@ // This magically allows subdirs in this subproject to themselves become sub-subprojects in a proper tree structure new File(rootDir, 'modules').eachDir { possibleSubprojectDir -> + def subprojectName = 'modules:' + possibleSubprojectDir.name - //println "Gradle is reviewing module $subprojectName for inclusion as a sub-project" - File buildFile = new File(possibleSubprojectDir, "build.gradle") - if (!buildFile.exists()) { - println "Module $subprojectName has no build file, adding build.gradle file from core and including it" - File replacementGradle = new File(rootDir, 'modules/Core/build.gradle') - buildFile << replacementGradle.text + println "Gradle is reviewing module $subprojectName for inclusion as a sub-project" + + File moduleFile = new File(possibleSubprojectDir, "module.txt") + if (!moduleFile.exists()) { + println "***WARNING*** Module $subprojectName has no module file, expecting corrupt directory, please fix!" } else { - println "Module $subprojectName has a build file so counting it complete and including it" + include subprojectName } - include subprojectName - def subprojectPath = ':' + subprojectName - def subproject = project(subprojectPath) - subproject.projectDir = possibleSubprojectDir } From 0defbe307a6b54145d4286457af2dfef1b00c415 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 27 Jan 2017 23:58:57 -0500 Subject: [PATCH 04/20] Minor cleanup. --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- modules/build.gradle | 4 ---- modules/java.gradle | 3 --- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 64edf4cd05b..1afe91ff27f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jan 25 19:21:42 EST 2017 +#Fri Jan 27 18:22:28 EST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/modules/build.gradle b/modules/build.gradle index a325c2ba0b0..de6f6fac69e 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -10,10 +10,6 @@ buildscript { dependencies { // Needed at this level for modules in Kotlin classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6" - - // Needed for our deep dark Java wizardry - //classpath 'org.reflections:reflections:0.9.10' - //classpath 'dom4j:dom4j:1.6.1' } } diff --git a/modules/java.gradle b/modules/java.gradle index 3f1dd8252e7..7ef4a41b5e7 100644 --- a/modules/java.gradle +++ b/modules/java.gradle @@ -17,9 +17,6 @@ buildscript { // Artifactory plugin classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') - // Git plugin for Gradle - classpath 'org.ajoberstar:gradle-git:0.6.3' - // Needed for caching reflected data during builds classpath 'org.reflections:reflections:0.9.10' classpath 'dom4j:dom4j:1.6.1' From 4ea0ddcf173a282855daa9f26dae8dd3f880fcb3 Mon Sep 17 00:00:00 2001 From: Cervator Date: Sun, 29 Oct 2017 22:10:16 -0400 Subject: [PATCH 05/20] Changes I forgot to commit back when I remembered what they were! I think it was something like ... - removes the IDE configurations :-( - tries to find a hook for a prep task (to extract natives, code analysis config, and copy templates) - fixes a Gradle structure / resolution performance issue - adds the Groovy Wrapper that I since added to the main project so this one is already out of date --- build.gradle | 108 +++--------- config/gradle/common.gradle | 2 - engine/build.gradle | 16 +- facades/PC/build.gradle | 25 --- facades/TeraEd/build.gradle | 10 -- gradle/wrapper/groovy-wrapper.jar | Bin 0 -> 5142 bytes groovyw | 172 +++++++++++++++++++ groovyw.bat | 84 ++++++++++ module.groovy | 267 ++++++++++++++++++++++++++++++ modules/build.gradle | 2 +- modules/java.gradle | 18 -- modules/kotlin.gradle | 5 +- modules/module.gradle | 44 ++--- templates/module.txt | 6 +- 14 files changed, 563 insertions(+), 196 deletions(-) create mode 100644 gradle/wrapper/groovy-wrapper.jar create mode 100644 groovyw create mode 100644 groovyw.bat create mode 100644 module.groovy diff --git a/build.gradle b/build.gradle index b7b325476fc..0bd2d982e86 100644 --- a/build.gradle +++ b/build.gradle @@ -1,19 +1,9 @@ // Separate build file for structure heavy stuff like using Git to fetch other repos to embed within the project apply from: 'config/gradle/utility.gradle' -apply from: 'config/gradle/ide.gradle' // Needed for extending the "clean" task to also delete custom stuff defined here like natives apply plugin: 'base' -// For generating IntelliJ project files -apply plugin: 'idea' - -// The root project should not be an eclipse project. It keeps eclipse (4.2) from finding the sub-projects. -//apply plugin: 'eclipse' - -// Git plugin details at https://github.com/ajoberstar/gradle-git -import org.ajoberstar.gradle.git.tasks.* - // Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( buildscript { repositories { @@ -130,24 +120,6 @@ task extractConfig (type: Copy) { into "$rootDir/$dirConfigMetrics" } -// Helper that returns a list of all local Terasology module projects -def terasologyModules() { - subprojects.findAll {it.parent.name == 'modules'} -} - -// Helpers that do magic things after having dependencies attached below -//task moduleClasses -//task moduleJars -/* -// This magically makes everything work - without this the desired module projects returned have no tasks :-( -gradle.projectsEvaluated { - // Note how "classes" may indirectly trigger "jar" for module dependencies of modules (module compile dependency) - moduleClasses.dependsOn(terasologyModules().classes) - - // This makes it work for a full jar task - moduleJars.dependsOn(terasologyModules().jar) -} -*/ // This is a TEMPORARY tweak to make "changing" dependencies always ('0') check for newer snapshots available // TODO: Remove this when versioning and promotion works fully, then we shouldn't care about snapshots normally anyway // For some reason this can stay here, yet had to be removed from everywhere else for Gradle 3.3 @@ -172,10 +144,15 @@ task protobufCompileLinux(type:Exec) { commandLine 'protobuf/compiler/protoc', '--proto_path=engine/src/main/protobuf', '--java_out', 'engine/src/main/java', "engine/src/main/protobuf/EntityData.proto", "engine/src/main/protobuf/NetMessage.proto" } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// General IDE customization // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// These tasks are written in a way that makes them execute always, outside Gradle's regular workflow of calculating what needs to be done // +// If they were written as Copy tasks and such they'd only work during the execution phase for a run that included them on the task graph // +// That's how it was done in the frequent 'gradlew idea' days where any change impacting project structure needed a rerun + IDE restart // +// With Gradle import / linking enabled instead we can use IDE integration to avoid a restart but don't have an explicit task to chain to // +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// TODO: Convert the natives, config, and IDE setup to be tasks like this one task copyInMissingTemplates { description = "Copies in placeholders from the /templates dir to project root if not present yet" File gradlePropsFile = new File(rootDir, 'gradle.properties') @@ -188,64 +165,19 @@ task copyInMissingTemplates { } } -// Make sure the IDE prep includes extraction of natives -ideaModule.dependsOn extractNatives -ideaModule.dependsOn copyInMissingTemplates - -// For IntelliJ add a bunch of excluded directories -idea { - - // Exclude Eclipse dirs - // TODO: Update this as Eclipse bin dirs now generate in several deeper spots rather than at top-level - module.excludeDirs += file('bin') - module.excludeDirs += file('.settings') - // TODO: Add a single file exclude for facades/PC/Terasology.launch ? - - // Exclude special dirs - module.excludeDirs += file('natives') - module.excludeDirs += file('protobuf') - - // Exclude output dirs - module.excludeDirs += file('logs') - module.excludeDirs += file('saves') - module.excludeDirs += file('screenshots') - module.excludeDirs += file('terasology-server') - module.excludeDirs += file('terasology-2ndclient') - - module.downloadSources = true - - project { - // Set JDK - jdkName = '1.8' - wildcards -= '!?*.groovy' - - ipr { - withXml { xmlProvider -> - // Apply a bunch of tweaks to IntelliJ config - all defined in ide.gradle - // Part reason for separate file was in case a module needs to define something it cannot do so in a project block - def iprNode = xmlProvider.asNode() - ideaActivateCheckstyle(iprNode) - ideaActivateCopyright(iprNode) - ideaActivateAnnotations(iprNode) - ideaActivateGit(iprNode) - ideaActivateGradle(iprNode) - } - - // Sets sourceCompatibility within IntelliJ (without this root build having the Java plugin applied) - whenMerged {project -> - project.jdk.languageLevel = 'JDK_1_8' - } - } - } +task prepareStuff { + dependsOn extractNatives + dependsOn extractConfig +} - // Tweaks to the .iws - workspace.iws.withXml { xmlProvider -> - def iwsNode = xmlProvider.asNode() - ideaMakeAutomatically(iwsNode) - ideaRunConfig(iwsNode) - } +afterEvaluate { + // This pops up way too early - after this particular file has been evaluated? Module config logging follows + // Really need a hook to trigger a task's execution phase on any project evaluation + // Difficulty: IntelliJ uses a special entry point (likely Eclipse as well) that just evaluates somehow + println 'After evaluate (TODO: Trying to find a good point to hook in a prep task)' } -cleanIdea.doLast { - new File('Terasology.iws').delete() +gradle.afterProject { + // This triggers *a lot* - after every project is evaluated. So similar to allProjects.afterEvaluate? + println 'After project (TODO: Trying to find a good point to hook in a prep task)' } \ No newline at end of file diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index a20cb1e06c7..12ea62362b9 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -1,8 +1,6 @@ // This include file is meant for each Java project/module and contains setup for artifact repos, code analysis, etc apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'project-report' apply plugin: 'checkstyle' apply plugin: 'pmd' diff --git a/engine/build.gradle b/engine/build.gradle index 6fa29302d28..8b41508235a 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -149,6 +149,7 @@ task cacheReflections { doLast { // Without the .mkdirs() we might hit a scenario where the classes dir doesn't exist yet + // TODO: This could be Gradlefied further by declaring inputs/outputs better, maybe a plugin? file(sourceSets.main.output.classesDir.toString()).mkdirs() Reflections reflections = new org.reflections.Reflections(new org.reflections.util.ConfigurationBuilder() .addUrls(configurations.compile.collect { it.toURI().toURL()} + sourceSets.main.output.classesDir.toURI().toURL()) @@ -216,20 +217,5 @@ jar.finalizedBy cleanReflections // General IDE customization // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -idea { - module { - // Add development "dev" dir - sourceDirs += sourceSets.dev.allJava.srcDirs - - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - downloadSources = true - } -} - // Make sure our config file for code analytics get extracted (vulnerability: non-IDE execution of single analytic) -ideaModule.dependsOn rootProject.extractConfig -tasks.eclipse.dependsOn rootProject.extractConfig check.dependsOn rootProject.extractConfig diff --git a/facades/PC/build.gradle b/facades/PC/build.gradle index 048baa896b9..0f54a3f3ce9 100644 --- a/facades/PC/build.gradle +++ b/facades/PC/build.gradle @@ -283,28 +283,3 @@ task distForLauncher (type: Sync) { } } } - -// Prep an IntelliJ module for the facade -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - } -} - -task copyEclipseLauncher(type: Copy) { - from "$rootDir/config/eclipse" - into projectDir - include("Terasology.launch") -} - -tasks.eclipse { - dependsOn copyEclipseLauncher - dependsOn rootProject.extractNatives -} - -cleanEclipse.doLast { - new File(projectDir, "Terasology.launch").delete() -} diff --git a/facades/TeraEd/build.gradle b/facades/TeraEd/build.gradle index 71e59bbbcb5..53b9269b641 100644 --- a/facades/TeraEd/build.gradle +++ b/facades/TeraEd/build.gradle @@ -34,13 +34,3 @@ task editor(type:JavaExec) { classpath project(':engine').sourceSets.main.output.classesDir classpath project(':engine').configurations.runtime } - -// Prep an IntelliJ module for the facade -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - } -} diff --git a/gradle/wrapper/groovy-wrapper.jar b/gradle/wrapper/groovy-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..dc694676103d5d1e836fb9a36d4804c3a1279cf9 GIT binary patch literal 5142 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 literal 0 HcmV?d00001 diff --git a/groovyw b/groovyw new file mode 100644 index 00000000000..757080f7b48 --- /dev/null +++ b/groovyw @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar:$APP_HOME/gradle/wrapper/groovy-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GroovyWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/groovyw.bat b/groovyw.bat new file mode 100644 index 00000000000..c437ccabc53 --- /dev/null +++ b/groovyw.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Groovy Wrapper version of the Gradle Wrapper +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar;%APP_HOME%\gradle\wrapper\groovy-wrapper.jar; + +@rem Execute Groovy via the Gradle Wrapper +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GroovyWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/module.groovy b/module.groovy new file mode 100644 index 00000000000..23f91c494de --- /dev/null +++ b/module.groovy @@ -0,0 +1,267 @@ +// TODO: Credit original authors (MaxBorsch PR #2634 and smsunarto PR #2657 +// TODO: Also separately credit #2727 by oniatus as inspiration to get going with Gradle/Groovy + +/* +// Interactive Dynamic task definition for creating a new module (from scratch, rather than cloning from GitHub) +// Sample command: gradlew createModuleMyStuff +tasks.addRule("Pattern: createModule,,,") { String taskName -> + if (taskName.startsWith("createModule")) { + + // Split arguments by comma + def args = (taskName - 'createModule').tokenize (',') + + // Use provided argument or request from the user + def createModule_repo = args[0] ?: getUserString ('Enter module name:') + def createModule_version = args[1] ?: getUserString ('Enter initial module version:') + def createModule_author = args[2] ?: getUserString ('Enter author name:') + def createModule_description = args[3] ?: getUserString ('Enter module description:') + + // Here's the actual task definition for each dynamically created task of name taskName + task (taskName, type: GitInit) { + description = 'Creates template source for a given module to the local project and preps a local Git repo' + + if (!createModule_repo){ + throw new GradleException ("Aborted createModule! No module name.") + } + + // Repo name is the dynamic part of the task name + def repo = createModule_repo + def parentDir = 'modules' + + // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties + def githubHome = 'Terasology' + + // Command line parameter has precedence - if it is set we do not check gradle.properties + if (project.hasProperty('githubAccount')) { + githubHome = githubAccount + } else if (project.hasProperty('alternativeGithubHome')) { + githubHome =alternativeGithubHome + } + + def destination = file("$parentDir/$repo") + + // Don't create this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) + enabled = !destination.exists() + println "createModule requested for $repo linked to $githubHome on GitHub - exists already? " + !enabled + + // Do the actual creation if we don't have the directory already + if (enabled) { + + println "Creating $repo locally" + destination.mkdir() + destinationPath = destination + + // TODO: Add in the local mapping to a remote ref definition. Needs support in the Gradle-Git plugin + //uri = "https://github.com/$githubAccount/" + repo + ".git" + bare = false + + // Copy in some template stuff for the new module + doLast { + new File(destination, 'build.gradle') << new File(rootDir, 'modules/Core/build.gradle').text + // TODO : Add in the logback.groovy from engine\src\test\resources\logback.groovy ? Local dev only, Jenkins will use the one inside engine-tests.jar. Also add to .gitignore + def moduleManifest = new File (destination, 'module.txt') + def moduleText = new File(templatesDir, 'module.txt').text + moduleText = moduleText + .replaceAll('MODULENAME', createModule_repo) + .replaceAll('VERSION', createModule_version) + .replaceAll('AUTHOR', createModule_author) + .replaceAll('DESCRIPTION', createModule_description) + + moduleManifest << moduleText + new File(destination, '.gitignore') << new File(templatesDir, '.gitignore').text + } + } + } + } +} +*/ + +// We use GrGit for interacting with Git. This gets a hold of it as a dependency like Gradle would +// TODO: Consider if we should do something to fix/suppress the SLF4J warning that gets logged on first usage? +@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') +@Grab(group='org.ajoberstar', module='grgit', version='1.9.3') +import org.ajoberstar.grgit.Grgit + +import groovy.json.JsonSlurper + +// Grab override properties from the gradle.properties file (shared with various Gradle commands) +Properties properties = new Properties() +new File("gradle.properties").withInputStream { + properties.load(it) +} +//println "Properties: " + properties + +// Groovy Elvis operator woo! Defaults to "Terasology" if an override isn't set +githubHome = properties.alternativeGithubHome ?: "Terasology" + +//println "githubHome is: $githubHome" + +// For keeping a list of modules retrieved so far +modulesRetrieved = [] + +// Module dependencies we don't want to retrieve as they live in the main Terasology repo +excludedDependencies = ["engine", "Core", "CoreSampleGameplay", "BuilderSampleGameplay"] + +/** + * Primary entry point for retrieving modules, kicks off recursively if needed. + * @param modules the modules we want to retrieve + * @param recurse whether to also retrieve dependencies of the desired modules + */ +def retrieve(String[] modules, boolean recurse) { + println "Now inside retrieve, user (recursively? $recurse) wants: $modules" + for (String module : modules) { + println "Starting loop for module $module, are we recursing? $recurse" + println "Modules retrieved so far: $modulesRetrieved" + retrieveModule(module, recurse) + //println "Modules retrieved after recent addition(s): modulesRetrieved" + } +} + +/** + * Retrieves a single module via Git Clone. Considers whether it exists locally first or if it has already been retrieved this execution. + * @param module the target module to retrieve + * @param recurse whether to also retrieve its dependencies (if so then recurse back into retrieve) + */ +def retrieveModule(String module, boolean recurse) { + File targetDir = new File("modulesTEST/$module") //TODO: Adjust after testing - moduleTEST + println "Request to retrieve module $module would store it at $targetDir - exists? " + targetDir.exists() + + if (targetDir.exists()) { + println "That module already had an existing directory locally. If something is wrong with it please delete and try again" + modulesRetrieved << module + } else if (modulesRetrieved.contains(module)) { + println "We already retrieved $module - skipping" + } else { + println "Retrieving module $module - if it doesn't appear to exist (typo for instance) you'll get an auth prompt (in case it is private)" + //noinspection GroovyAssignabilityCheck - GrGit has its own .clone but a warning gets issued for Object.clone + Grgit.clone dir: targetDir, uri: "https://github.com/$githubHome/${module}.git" + modulesRetrieved << module + + // TODO: Temporary until build.gradle gets removed from module directories (pending Cervator work) + File targetBuildGradle = new File(targetDir, 'build.gradle') + targetBuildGradle.delete() + targetBuildGradle << new File('modulesTEST/Core/build.gradle').text //TODO: Adjust after testing - moduleTEST + + File moduleManifest = new File(targetDir, 'module.txt') + if (!moduleManifest.exists()) { + def moduleText = new File("templates/module.txt").text + moduleManifest << moduleText.replaceAll('MODULENAME', module) + println "WARNING: Module $module did not have a module.txt! One was created, please review and submit to GitHub" + } + + // Recurse deeper if we are retrieving dependencies as well + if (recurse) { + def foundDependencies = readModuleDependencies(new File(targetDir, "module.txt")) + if (foundDependencies.length == 0) { + println "Module $module did not appear to have any dependencies we need to worry about" + } else { + println "Module $module has the following module dependencies we care about: $foundDependencies" + String[] uniqueDependencies = foundDependencies - modulesRetrieved + println "After removing dupes already retrieved we have the remaining dependencies left: $uniqueDependencies" + if (uniqueDependencies.length > 0) { + retrieve(uniqueDependencies, true) + } + } + } + } +} + +/** + * Reads a given module info file to figure out which if any dependencies it has. Filters out any already retrieved. + * @param targetModuleInfo the target file to check (a module.txt file or similar) + * @return a String[] containing the next level of dependencies, if any + */ +String[] readModuleDependencies(File targetModuleInfo) { + def qualifiedDependencies = [] + if (!targetModuleInfo.exists()) { + println "The module info file did not appear to exist - can't calculate dependencies" + return qualifiedDependencies + } + + def slurper = new JsonSlurper() + def moduleConfig = slurper.parseText(targetModuleInfo.text) + for (dependency in moduleConfig.dependencies) { + if (excludedDependencies.contains(dependency.id)) { + println "Skipping listed dependency $dependency as it is in the exclude list (shipped with primary project)" + } else { + println "Accepting listed dependency $dependency" + qualifiedDependencies << dependency.id + } + } + return qualifiedDependencies +} + +/** + * Accepts input from the user, showing a descriptive prompt. + * @param prompt the prompt to show the user + */ +def getUserString (String prompt) { + println ('\n*** ' + prompt + '\n') + + def reader = new BufferedReader(new InputStreamReader(System.in)) // Note: Do not close reader, it will close System.in (Big no-no) + + return reader.readLine() +} + +/** + * Simply prints usage information. + */ +def printUsage() { + println "" + println "Utility script for interacting with modules. Available sub commands:" + println "- 'get' - retrieves one or more modules in source form (separate with spaces)" + println "- 'recurse' - retrieves the given module(s) *and* their dependencies in source form" + println "" + println "Example: 'groovyw module recurse GooeysQuests Sample' - would retrieve those modules plus their dependencies" + println "*NOTE*: Module names are case sensitive" + println "" + println "If you omit further arguments beyond the sub command you'll be prompted for details" + println "After changing modules available in your workspace rerun 'gradlew idea' and/or refresh your IDE" + println "" + println "For advanced usage see project documentation. For instance you can provide an alternative GitHub home" + println "A gradle.properties file (one exists under '/templates' in an engine workspace) can provide such overrides" + println "" +} + +// Main bit of logic handling the entry points to this script - defers actual work to dedicated methods +//println "Args: $args" +if (args.length == 0) { + printUsage() +} else { + def recurse = false + switch (args[0]) { + case 'usage': + printUsage() + break + case "recurse": + recurse = true + println "We're retrieving recursively (all the things depended on too)" + // We just fall through here to the get logic after setting a boolean + //noinspection GroovyFallthrough + case "get": + println "Preparing to get one or more modules" + if (args.length == 1) { + // User hasn't supplied any module names, so ask + def moduleString = getUserString('Enter Module Name(s - separate multiple with spaces, CapiTaliZation MatterS): ') + println "User wants: $moduleString" + // Split it on whitespace + String[] moduleList = moduleString.split("\\s+") + println "Now in an array: $moduleList" + retrieve moduleList, recurse + } else { + // User has supplied one or more module names, so pass them forward (skipping the "get" arg) + def adjustedArgs = args.drop(1) + println "Adjusted args: $adjustedArgs" + retrieve adjustedArgs, recurse + } + println "All done retrieving requested modules: $modulesRetrieved" + break + case "create": + println "We're doing a create" + String someParam = getUserString("Please enter a thing") + println "User return was: $someParam" + break + default: + println "UNRECOGNIZED COMMAND - please try again or use 'groovyw module usage' for help" + } +} diff --git a/modules/build.gradle b/modules/build.gradle index de6f6fac69e..38f5e3afa46 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -8,7 +8,7 @@ buildscript { jcenter() } dependencies { - // Needed at this level for modules in Kotlin + // Needed at this level to support modules in Kotlin classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6" } } diff --git a/modules/java.gradle b/modules/java.gradle index 7ef4a41b5e7..3f22d38569b 100644 --- a/modules/java.gradle +++ b/modules/java.gradle @@ -59,21 +59,3 @@ jar { } } jar.finalizedBy cleanReflections - -// Prep an IntelliJ module for the Terasology module - yes, might want to read that twice :D -idea { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file('build/classes') - testOutputDir = file('build/testClasses') - downloadSources = true - } -} - -// For Eclipse just make sure the classpath is right -eclipse { - classpath { - defaultOutputDir = file('build/classes') - } -} diff --git a/modules/kotlin.gradle b/modules/kotlin.gradle index 7e5613eb8b7..c0a5cf72a3e 100644 --- a/modules/kotlin.gradle +++ b/modules/kotlin.gradle @@ -54,11 +54,12 @@ dependencies { kotlinTestConf group: 'org.jetbrains.kotlin', name: 'kotlin-test-junit:1.0.6' // To make this module bundle Kotlin's runtime jar we put it in a separate config by itself + // TODO: As noted below as well this could for space reasons only be done for the KotlinLib module + // Could also consider skipping the KotlinLib dependency set in module.txt for others (the lang field forces it) + // In that case we may need to keep in mind the versioning of Kotlin - should modules be allowed to pick? kotlinEmbedded group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: '1.0.6' } - - // Generate the module directory structure if missing (by declaring the task here we also get the language specific extras) task createSkeleton() { moduleSkeletonDirs.each { diff --git a/modules/module.gradle b/modules/module.gradle index 96dbbc8f2e7..8e0fce4cbe1 100644 --- a/modules/module.gradle +++ b/modules/module.gradle @@ -2,9 +2,6 @@ import groovy.json.JsonSlurper -// Git plugin details at https://github.com/ajoberstar/gradle-git -import org.ajoberstar.gradle.git.tasks.* - import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; @@ -41,6 +38,7 @@ ext { 'assets/blockSounds', 'assets/blockTiles', 'assets/fonts', + 'assets/i18n', 'assets/materials', 'assets/mesh', 'assets/music', @@ -58,6 +56,10 @@ ext { // Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules dependencies { + // TODO: Add a new Gradle plugin that itself is responsible for scanning module.txt (actually module.info.json or so) + // It should contain a method that can be triggered here that will apply the appropriate dependencies for the given module + // Ideally it could also handle the source vs binary plus outputting nice build info + // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace if (project.name != project(':').name) { println "\nProcessing module '$project.name' in a multi-project workspace" @@ -99,7 +101,10 @@ dependencies { } // This step resolves artifacts early, after which project config CANNOT be altered again! - configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + //TODO: This is what causes the nested task slowdown, due to the resolve at config time issue + //configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + // TODO: This updated version seems to do the trick without a slowdown! Hunt down any other usage like the old one + configurations.compile.incoming.afterResolve { ResolvedArtifact artifact -> def id = artifact.moduleVersion.id // Check for any needed module dependencies on other modules that we need at runtime @@ -141,7 +146,9 @@ dependencies { // TODO: parse and apply external lib dependencies if any are present // TODO: Consider / keep an eye on whether resolving artifacts early at this point causes any trouble (is only for logging) // This step resolves artifacts (both compile & testCompile) and prints out some interesting versions - configurations.testCompile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + + //configurations.testCompile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + configurations.testCompile.incoming.afterResolve { ResolvedArtifact artifact -> // Fixed version def id = artifact.moduleVersion.id // Print out module (and engine stuff) dependencies and the exact versions they resolved at if (id.group.startsWith('org.terasology')) { @@ -188,30 +195,3 @@ task syncDeltas(type: Sync) { from 'deltas' into 'build/classes/deltas' } - -/* -TODO: Review - not sure if working well. Maybe a better way to do it via standalone Groovy utility script -// Utility task to update the module (except Core) via Git - not tested with local changes present, may cause trouble -task (updateModule, type: GitPull) { - description = 'Updates source for the module from its home (most likely GitHub)' - - // Base whether the task executes on two things - // 1 - we actually asked for it ("gradlew updateModule") - otherwise we don't want it to run TODO: Test for abbreviations? - // 2 - this is not the Core module, which lives with the engine and needs no updates - boolean enabled = "updateModule" in project.gradle.startParameter.taskNames && !project.name.equals("Core") - // TODO: Used to cheat with declaring tasks using << but that defers everything (including config) to execution phase - // Some tasks do not work that way, this one would ALWAYS go with default (root git repo) in that case - // Probably should go through other stuff and use this strategy instead of << - - // Only if we asked for it (and not Core) do we actually configure the repo path and log that we're updating - if (enabled) { - - // This is the Git repo we're actually using - projectDir is specific to the executing project, a.k.a. module whatever - // If not enabled the default is the root project's Git dir, which is a valid Git dir - // However in the case of Core we'd be setting ain invalid Git dir which causes fail - so this avoids that - repoPath = projectDir - - println "Pulling updates via Git to " + getRepoDir() + ", if dependencies change run Gradle again (like 'gradlew idea')" - } -} -*/ \ No newline at end of file diff --git a/templates/module.txt b/templates/module.txt index 29d2f183f1c..18b2de98bdd 100644 --- a/templates/module.txt +++ b/templates/module.txt @@ -1,9 +1,9 @@ { "id" : "MODULENAME", - "version" : "0.1.0-SNAPSHOT", - "author" : "", + "version" : "VERSION", + "author" : "AUTHOR", "displayName" : "MODULENAME", - "description" : "", + "description" : "DESCRIPTION", "dependencies" : [], "serverSideOnly" : false } \ No newline at end of file From 7fca9da3df54e6163c0d5a43240d37dc7ddf220c Mon Sep 17 00:00:00 2001 From: Cervator Date: Sun, 29 Oct 2017 22:19:38 -0400 Subject: [PATCH 06/20] Ooooone more thing. Or two more things. Prep the prepareStuff task better and bring in the latest module utility --- build.gradle | 1 + module.groovy | 193 ++++++++++++++++++++++++++++---------------------- 2 files changed, 110 insertions(+), 84 deletions(-) diff --git a/build.gradle b/build.gradle index 0bd2d982e86..e8cd3e7714f 100644 --- a/build.gradle +++ b/build.gradle @@ -168,6 +168,7 @@ task copyInMissingTemplates { task prepareStuff { dependsOn extractNatives dependsOn extractConfig + dependsOn copyInMissingTemplates } afterEvaluate { diff --git a/module.groovy b/module.groovy index 23f91c494de..3cf34e23f1e 100644 --- a/module.groovy +++ b/module.groovy @@ -1,81 +1,3 @@ -// TODO: Credit original authors (MaxBorsch PR #2634 and smsunarto PR #2657 -// TODO: Also separately credit #2727 by oniatus as inspiration to get going with Gradle/Groovy - -/* -// Interactive Dynamic task definition for creating a new module (from scratch, rather than cloning from GitHub) -// Sample command: gradlew createModuleMyStuff -tasks.addRule("Pattern: createModule,,,") { String taskName -> - if (taskName.startsWith("createModule")) { - - // Split arguments by comma - def args = (taskName - 'createModule').tokenize (',') - - // Use provided argument or request from the user - def createModule_repo = args[0] ?: getUserString ('Enter module name:') - def createModule_version = args[1] ?: getUserString ('Enter initial module version:') - def createModule_author = args[2] ?: getUserString ('Enter author name:') - def createModule_description = args[3] ?: getUserString ('Enter module description:') - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitInit) { - description = 'Creates template source for a given module to the local project and preps a local Git repo' - - if (!createModule_repo){ - throw new GradleException ("Aborted createModule! No module name.") - } - - // Repo name is the dynamic part of the task name - def repo = createModule_repo - def parentDir = 'modules' - - // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties - def githubHome = 'Terasology' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$repo") - - // Don't create this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "createModule requested for $repo linked to $githubHome on GitHub - exists already? " + !enabled - - // Do the actual creation if we don't have the directory already - if (enabled) { - - println "Creating $repo locally" - destination.mkdir() - destinationPath = destination - - // TODO: Add in the local mapping to a remote ref definition. Needs support in the Gradle-Git plugin - //uri = "https://github.com/$githubAccount/" + repo + ".git" - bare = false - - // Copy in some template stuff for the new module - doLast { - new File(destination, 'build.gradle') << new File(rootDir, 'modules/Core/build.gradle').text - // TODO : Add in the logback.groovy from engine\src\test\resources\logback.groovy ? Local dev only, Jenkins will use the one inside engine-tests.jar. Also add to .gitignore - def moduleManifest = new File (destination, 'module.txt') - def moduleText = new File(templatesDir, 'module.txt').text - moduleText = moduleText - .replaceAll('MODULENAME', createModule_repo) - .replaceAll('VERSION', createModule_version) - .replaceAll('AUTHOR', createModule_author) - .replaceAll('DESCRIPTION', createModule_description) - - moduleManifest << moduleText - new File(destination, '.gitignore') << new File(templatesDir, '.gitignore').text - } - } - } - } -} -*/ - // We use GrGit for interacting with Git. This gets a hold of it as a dependency like Gradle would // TODO: Consider if we should do something to fix/suppress the SLF4J warning that gets logged on first usage? @GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/') @@ -123,7 +45,7 @@ def retrieve(String[] modules, boolean recurse) { * @param recurse whether to also retrieve its dependencies (if so then recurse back into retrieve) */ def retrieveModule(String module, boolean recurse) { - File targetDir = new File("modulesTEST/$module") //TODO: Adjust after testing - moduleTEST + File targetDir = new File("modules/$module") println "Request to retrieve module $module would store it at $targetDir - exists? " + targetDir.exists() if (targetDir.exists()) { @@ -140,7 +62,7 @@ def retrieveModule(String module, boolean recurse) { // TODO: Temporary until build.gradle gets removed from module directories (pending Cervator work) File targetBuildGradle = new File(targetDir, 'build.gradle') targetBuildGradle.delete() - targetBuildGradle << new File('modulesTEST/Core/build.gradle').text //TODO: Adjust after testing - moduleTEST + targetBuildGradle << new File('templates/build.gradle').text File moduleManifest = new File(targetDir, 'module.txt') if (!moduleManifest.exists()) { @@ -191,6 +113,67 @@ String[] readModuleDependencies(File targetModuleInfo) { return qualifiedDependencies } +/** + * Creates a new module with the given name and adds the necessary .gitignore, + * build.gradle and module.txt files. + * @param name the name of the module to be created + */ +def createModule(String name) { + // Check if the module already exists. If not, create the module directory + File targetDir = new File("modules/$name") + if (targetDir.exists()) { + println "Target directory already exists. Aborting." + return + } + println "Creating target directory" + targetDir.mkdir() + + // Add gitignore + println "Creating .gitignore" + File gitignore = new File(targetDir, ".gitignore") + def gitignoreText = new File("templates/.gitignore").text + gitignore << gitignoreText + + // Add build.gradle (temporary until it gets removed) + println "Creating build.gradle" + File buildGradle = new File(targetDir, "build.gradle") + def buildGradleText = new File("templates/build.gradle").text + buildGradle << buildGradleText + + // Add module.txt + println "Creating module.txt" + File moduleManifest = new File(targetDir, "module.txt") + def moduleText = new File("templates/module.txt").text + moduleManifest << moduleText.replaceAll('MODULENAME', name) + + // Initialize git + Grgit.init dir: targetDir, bare: false +} + +/** + * Update a given module. + * @param name the name of the module to update + */ +def updateModule(String name) { + println "Attempting to update module $name" + File targetDir = new File("modules/$name") + if (!targetDir.exists()) { + println "Module \"$name\" not found" + return + } + + def moduleGit = Grgit.open(dir: targetDir) + def clean = moduleGit.status().clean + println "Is \"$name\" clean? $clean" + if (!clean) { + println "Module has uncommitted changes. Aborting." + return + } + + println "Updating module $name" + moduleGit.pull remote: "origin" +} + /** * Accepts input from the user, showing a descriptive prompt. * @param prompt the prompt to show the user @@ -211,6 +194,7 @@ def printUsage() { println "Utility script for interacting with modules. Available sub commands:" println "- 'get' - retrieves one or more modules in source form (separate with spaces)" println "- 'recurse' - retrieves the given module(s) *and* their dependencies in source form" + println "- 'create' - creates a new module" println "" println "Example: 'groovyw module recurse GooeysQuests Sample' - would retrieve those modules plus their dependencies" println "*NOTE*: Module names are case sensitive" @@ -236,8 +220,8 @@ if (args.length == 0) { case "recurse": recurse = true println "We're retrieving recursively (all the things depended on too)" - // We just fall through here to the get logic after setting a boolean - //noinspection GroovyFallthrough + // We just fall through here to the get logic after setting a boolean + //noinspection GroovyFallthrough case "get": println "Preparing to get one or more modules" if (args.length == 1) { @@ -258,8 +242,49 @@ if (args.length == 0) { break case "create": println "We're doing a create" - String someParam = getUserString("Please enter a thing") - println "User return was: $someParam" + String name = "" + + // Get new module's name + if (args.length > 2) { + println "Received more than one argument. Aborting." + break + } else if (args.length == 2) { + name = args[1] + } else { + name = getUserString("Enter module name: ") + } + println "User wants to create a module named: $name" + + createModule(name) + + println "Created module named $name" + break + case "update": + println "We're updating modules" + String[] moduleList = [] + if (args.length == 1) { + // User hasn't supplied any module names, so ask + def moduleString = getUserString('Enter Module Name(s - separate multiple with spaces, CapiTaliZation MatterS): ') + // Split it on whitespace + moduleList = moduleString.split("\\s+") + } else { + // User has supplied one or more module names, so pass them forward (skipping the "get" arg) + moduleList = args.drop(1) + } + println "List of modules to update: $moduleList" + for (String module: moduleList) { + updateModule(module) + } + break + case "update-all": + println "We're updating all modules" + println "List of modules:" + new File("modules").eachDir() { dir -> + String moduleName = dir.getPath().substring(8) + if (!excludedDependencies.contains(moduleName)) { + updateModule(moduleName) + } + } break default: println "UNRECOGNIZED COMMAND - please try again or use 'groovyw module usage' for help" From 95109133aafafc4d41b8d5baa9160cd2a68f1893 Mon Sep 17 00:00:00 2001 From: bbarker Date: Sun, 29 Oct 2017 22:45:43 -0400 Subject: [PATCH 07/20] minor version bump for scala --- modules/scala.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/scala.gradle b/modules/scala.gradle index 1f77ccbd9b9..1e0625720e4 100644 --- a/modules/scala.gradle +++ b/modules/scala.gradle @@ -43,11 +43,11 @@ configurations { dependencies { // Since the main compile and compileTest configs are defined in the generic module.gradle we can't modify them here - so extend instead - scalaConf group: 'org.scala-lang', name: 'scala-reflect', version: '2.11.7' - scalaConf group: 'org.scala-lang', name: 'scala-compiler', version: '2.11.7' + scalaConf group: 'org.scala-lang', name: 'scala-reflect', version: '2.11.11' + scalaConf group: 'org.scala-lang', name: 'scala-compiler', version: '2.11.11' - // To make this module bundle Kotlin's runtime jar we put it in a separate config by itself - scalaEmbedded group: 'org.scala-lang', name: 'scala-library', version: '2.11.7' + // To make this module bundle Scala's runtime jar we put it in a separate config by itself + scalaEmbedded group: 'org.scala-lang', name: 'scala-library', version: '2.11.11' } // Generate the module directory structure if missing (by declaring the task here we also get the language specific extras) From 329a749c0a3621c2a570857e8b6971bb89fbf041 Mon Sep 17 00:00:00 2001 From: Cervator Date: Mon, 30 Oct 2017 22:49:45 -0400 Subject: [PATCH 08/20] Remove build.gradle stuff for modules from the utility script --- module.groovy | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/module.groovy b/module.groovy index 3cf34e23f1e..583530b6d31 100644 --- a/module.groovy +++ b/module.groovy @@ -59,11 +59,6 @@ def retrieveModule(String module, boolean recurse) { Grgit.clone dir: targetDir, uri: "https://github.com/$githubHome/${module}.git" modulesRetrieved << module - // TODO: Temporary until build.gradle gets removed from module directories (pending Cervator work) - File targetBuildGradle = new File(targetDir, 'build.gradle') - targetBuildGradle.delete() - targetBuildGradle << new File('templates/build.gradle').text - File moduleManifest = new File(targetDir, 'module.txt') if (!moduleManifest.exists()) { def moduleText = new File("templates/module.txt").text @@ -114,8 +109,7 @@ String[] readModuleDependencies(File targetModuleInfo) { } /** - * Creates a new module with the given name and adds the necessary .gitignore, - * build.gradle and module.txt files. + * Creates a new module with the given name and adds the necessary .gitignore and module.txt files. * @param name the name of the module to be created */ def createModule(String name) { @@ -134,12 +128,6 @@ def createModule(String name) { def gitignoreText = new File("templates/.gitignore").text gitignore << gitignoreText - // Add build.gradle (temporary until it gets removed) - println "Creating build.gradle" - File buildGradle = new File(targetDir, "build.gradle") - def buildGradleText = new File("templates/build.gradle").text - buildGradle << buildGradleText - // Add module.txt println "Creating module.txt" File moduleManifest = new File(targetDir, "module.txt") From 7b0e30ab666cab03a42374995782264a41d0dd1e Mon Sep 17 00:00:00 2001 From: Cervator Date: Mon, 30 Oct 2017 23:11:18 -0400 Subject: [PATCH 09/20] Add the telemetry dependency stuff completed during GSOC - that code isn't present here but there is still a dependency quirk that causes modules to end up depending on a snapshot of the engine rather than local engine src, so Gradle included the telemetry dependency from the jar and then couldn't find it (as it exists in a separate artifact repository) --- config/gradle/common.gradle | 5 +++++ engine/build.gradle | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index 12ea62362b9..95add413e3a 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -37,6 +37,11 @@ repositories { url "http://artifactory.terasology.org/artifactory/virtual-repo-live" } } + + // snowplow for telemetry + maven { + url "http://maven.snplow.com/releases" + } } dependencies { diff --git a/engine/build.gradle b/engine/build.gradle index 8b41508235a..f2f227bd549 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -114,6 +114,12 @@ dependencies { compile group: 'ec.util', name: 'MersenneTwister', version: '20' compile group: 'org.eaxy', name: 'eaxy', version: '0.1' + // telemetry + compile (group: 'com.snowplowanalytics', name: 'snowplow-java-tracker', version :'0.8.0'){ + exclude group:'org.slf4j',module:'slf4j-simple' + } + compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '4.10' + // Our developed libs compile group: 'org.terasology', name: 'gestalt-module', version: '5.1.2' compile group: 'org.terasology', name: 'gestalt-asset-core', version: '5.1.2' From 9499a0df67d140f9031683cddc24e9abc65fcf32 Mon Sep 17 00:00:00 2001 From: Cervator Date: Mon, 30 Oct 2017 23:12:31 -0400 Subject: [PATCH 10/20] More remembered things: while the new & faster resolution stuff works in pure Gradle, it makes IntelliJ barf with an unintelligible error on a Gradle refresh. However, oddly, the same exact thing on a testCompile instead of a regular compile source set works fine. --- modules/module.gradle | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/module.gradle b/modules/module.gradle index 8e0fce4cbe1..550fc86c92d 100644 --- a/modules/module.gradle +++ b/modules/module.gradle @@ -101,10 +101,12 @@ dependencies { } // This step resolves artifacts early, after which project config CANNOT be altered again! - //TODO: This is what causes the nested task slowdown, due to the resolve at config time issue - //configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> - // TODO: This updated version seems to do the trick without a slowdown! Hunt down any other usage like the old one - configurations.compile.incoming.afterResolve { ResolvedArtifact artifact -> + //TODO: This is what causes the nested task slowdown, due to the resolve at config time issue + configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + // TODO: This updated version seems to do the trick without a slowdown! + // However, this exact variant causes an error on Gradle refresh within IntelliJ ... the testCompile doesn't? IntelliJ bug? + //configurations.compile.incoming.afterResolve { ResolvedArtifact artifact -> + def id = artifact.moduleVersion.id // Check for any needed module dependencies on other modules that we need at runtime @@ -146,7 +148,6 @@ dependencies { // TODO: parse and apply external lib dependencies if any are present // TODO: Consider / keep an eye on whether resolving artifacts early at this point causes any trouble (is only for logging) // This step resolves artifacts (both compile & testCompile) and prints out some interesting versions - //configurations.testCompile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> configurations.testCompile.incoming.afterResolve { ResolvedArtifact artifact -> // Fixed version def id = artifact.moduleVersion.id From 56a744f5aa469f1f1f3137bfa595cf50f8610244 Mon Sep 17 00:00:00 2001 From: Cervator Date: Tue, 31 Oct 2017 01:00:06 -0400 Subject: [PATCH 11/20] Actually don't depend on the telemetry stuff yet, just make sure Gradle knows where to find it if needed via module->engine snapshot quirk --- engine/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engine/build.gradle b/engine/build.gradle index f2f227bd549..944b5185577 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -114,11 +114,16 @@ dependencies { compile group: 'ec.util', name: 'MersenneTwister', version: '20' compile group: 'org.eaxy', name: 'eaxy', version: '0.1' + /* Gradle / project structure quirk: modules sometimes will hook on to an engine snapshot rather than local source + off in the Nanoware fork GSOC happened in parallel, but was merged and published to Artifactory + a Nanoware workspace would then have a module catch on to the upstream engine, lacking telemetry (diff repo) + adding said repo here resolves the resolution issue, but having the actual dependencies clashes with the code // telemetry compile (group: 'com.snowplowanalytics', name: 'snowplow-java-tracker', version :'0.8.0'){ exclude group:'org.slf4j',module:'slf4j-simple' } compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '4.10' + */ // Our developed libs compile group: 'org.terasology', name: 'gestalt-module', version: '5.1.2' From 5544f86ab4eec3d3045058890a3d996a3e624502 Mon Sep 17 00:00:00 2001 From: Cervator Date: Wed, 1 Nov 2017 19:53:50 -0400 Subject: [PATCH 12/20] Assortment of tweaks to make things work better, committed before I manage to erase them accidentally again. Includes Gradle 4 and some related changes. --- .gitignore | 2 +- build.gradle | 15 +++-- config/gradle/common.gradle | 4 +- facades/PC/build.gradle | 70 +++++++++++++----------- gradle/wrapper/gradle-wrapper.properties | 2 +- modules/build.gradle | 2 + modules/module.gradle | 25 ++++++++- modules/subprojects.gradle | 1 + templates/facades.gradle | 1 + 9 files changed, 80 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index 35c2fa19eba..c2986225678 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ build/ /override.cfg # Ignore IntelliJ - could use "/**/*.iml" to catch all .iml files, but that requires a somewhat recent Git version -/out/ +out/ modules/Core/Core.iml modules/CoreSampleGameplay/CoreSampleGameplay.iml modules/BuilderSampleGameplay/BuilderSampleGameplay.iml diff --git a/build.gradle b/build.gradle index e8cd3e7714f..752cdec0c37 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,8 @@ apply from: 'config/gradle/utility.gradle' // Needed for extending the "clean" task to also delete custom stuff defined here like natives apply plugin: 'base' +apply plugin: 'project-report' + // Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( buildscript { repositories { @@ -48,7 +50,12 @@ repositories { // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs maven { - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + if (rootProject.hasProperty("artifactoryResolveRepo")) { + url "http://artifactory.terasology.org/artifactory/$artifactoryResolveRepo" + println "Changing root RESOLVE repo to $artifactoryResolveRepo" + } else { + url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + } } } @@ -175,10 +182,10 @@ afterEvaluate { // This pops up way too early - after this particular file has been evaluated? Module config logging follows // Really need a hook to trigger a task's execution phase on any project evaluation // Difficulty: IntelliJ uses a special entry point (likely Eclipse as well) that just evaluates somehow - println 'After evaluate (TODO: Trying to find a good point to hook in a prep task)' + //println 'After evaluate (TODO: Trying to find a good point to hook in a prep task)' } gradle.afterProject { // This triggers *a lot* - after every project is evaluated. So similar to allProjects.afterEvaluate? - println 'After project (TODO: Trying to find a good point to hook in a prep task)' -} \ No newline at end of file + //println 'After project (TODO: Trying to find a good point to hook in a prep task)' +} diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index 95add413e3a..7bf6889e460 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -32,9 +32,11 @@ repositories { if (rootProject.hasProperty("alternativeResolutionRepo")) { // If the user supplies an alternative repo via gradle.properties then use that url alternativeResolutionRepo + println "common.gradle picked up a custom resolution repo: $alternativeResolutionRepo" } else { // Our default is the main virtual repo containing everything except repos for testing Artifactory itself url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + println "common.gradle is set to use the standard resolution (virtual-repo-live)" } } @@ -125,4 +127,4 @@ findbugs { // TODO: Temporary until javadoc has been fixed for Java 8 everywhere javadoc { failOnError = false -} \ No newline at end of file +} diff --git a/facades/PC/build.gradle b/facades/PC/build.gradle index 0f54a3f3ce9..89a5fcedd4a 100644 --- a/facades/PC/build.gradle +++ b/facades/PC/build.gradle @@ -121,59 +121,63 @@ task debug(type:JavaExec) { classpath project(':engine').configurations.runtime } -// By delaying this task to doLast (the << bit) we don't get the headless server dir set up unless actually wanting it + // TODO: This is not the Gradle Way. Needs more declared output-fu to determine up-to-date instead of the if -task setupServerConfig() << { +task setupServerConfig() { description "Parses parameters passed via Gradle and writes them to the local run-from-source server dir's config.cfg" - def json = new JsonBuilder() + doLast { + def json = new JsonBuilder() - def serverRoot = rootProject.file(localServerDataPath); - def config = new File(serverRoot, 'config.cfg') + def serverRoot = rootProject.file(localServerDataPath); + def config = new File(serverRoot, 'config.cfg') - if (!config.exists()) { + if (!config.exists()) { - serverRoot.mkdir() - logger.lifecycle("Creating config file $config") + serverRoot.mkdir() + logger.lifecycle("Creating config file $config") - json { - worldGeneration { - if (project.hasProperty('seed')) { - logger.lifecycle(" Seed value: $seed"); - defaultSeed seed - } - if (project.hasProperty('worldGen')) { - logger.lifecycle(" World Generator: $worldGen"); - defaultGenerator worldGen + json { + worldGeneration { + if (project.hasProperty('seed')) { + logger.lifecycle(" Seed value: $seed"); + defaultSeed seed + } + if (project.hasProperty('worldGen')) { + logger.lifecycle(" World Generator: $worldGen"); + defaultGenerator worldGen + } } - } - defaultModSelection { - if (project.hasProperty('extraModules')) { - logger.lifecycle(" Enabling modules: $extraModules"); - modules extraModules.tokenize(" ,") + defaultModSelection { + if (project.hasProperty('extraModules')) { + logger.lifecycle(" Enabling modules: $extraModules"); + modules extraModules.tokenize(" ,") + } } } + config.text = json.toPrettyString() } - config.text = json.toPrettyString() } } // TODO: Seems to always be up to date so no modules get copied -task setupServerModules(type: Sync) << { +task setupServerModules(type: Sync) { description 'Parses "extraModules" - a comma-separated list of modules and puts them into ' + localServerDataPath - if (project.hasProperty('extraModules')) { - // Grab modules from Artifactory - cheats by declaring them as dependencies - extraModules.tokenize(' ,').each { String module -> - println "Extra module: " + module - dependencies { - modules group: 'org.terasology.modules', name: module, version: '+', changing: 'true' + doLast { + if (project.hasProperty('extraModules')) { + // Grab modules from Artifactory - cheats by declaring them as dependencies + extraModules.tokenize(' ,').each { String module -> + println "Extra module: " + module + dependencies { + modules group: 'org.terasology.modules', name: module, version: '+', changing: 'true' + } } } - } - from(configurations.modules) - into(new File(rootProject.file(localServerDataPath), "modules")) + from(configurations.modules) + into(new File(rootProject.file(localServerDataPath), "modules")) + } } // TODO: Make a task to reset server / game data diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1afe91ff27f..001744d9136 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip diff --git a/modules/build.gradle b/modules/build.gradle index 38f5e3afa46..9e982bb0f59 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -15,6 +15,8 @@ buildscript { import groovy.json.JsonSlurper +println "The build.gradle from /modules says hi" + // We need to prepare the build logic for each module so we use a subprojects block to make this execute for each subprojects { diff --git a/modules/module.gradle b/modules/module.gradle index 550fc86c92d..bce0ffd7966 100644 --- a/modules/module.gradle +++ b/modules/module.gradle @@ -2,6 +2,22 @@ import groovy.json.JsonSlurper +buildscript { + repositories { + // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case + jcenter() + } + + dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + + // Needed for caching reflected data during builds + classpath 'org.reflections:reflections:0.9.10' + classpath 'dom4j:dom4j:1.6.1' + } +} + import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; @@ -100,12 +116,13 @@ dependencies { } } + // This step resolves artifacts early, after which project config CANNOT be altered again! //TODO: This is what causes the nested task slowdown, due to the resolve at config time issue - configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> + //configurations.compile.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact -> // TODO: This updated version seems to do the trick without a slowdown! // However, this exact variant causes an error on Gradle refresh within IntelliJ ... the testCompile doesn't? IntelliJ bug? - //configurations.compile.incoming.afterResolve { ResolvedArtifact artifact -> + configurations.compile.incoming.afterResolve { ResolvedArtifact artifact -> def id = artifact.moduleVersion.id @@ -128,6 +145,9 @@ dependencies { } } } + + + } else { println "We're in a single-project non-Core module workspace (Jenkins) so will look elsewhere for dependencies" @@ -156,6 +176,7 @@ dependencies { println "*** $project.name remotely resolved $id.group - $id.name - version $id.version" } } + } } diff --git a/modules/subprojects.gradle b/modules/subprojects.gradle index 39d3b839747..28f3b5c1d5f 100644 --- a/modules/subprojects.gradle +++ b/modules/subprojects.gradle @@ -9,5 +9,6 @@ new File(rootDir, 'modules').eachDir { possibleSubprojectDir -> println "***WARNING*** Module $subprojectName has no module file, expecting corrupt directory, please fix!" } else { include subprojectName + println "Including $subprojectName as a valid module" } } diff --git a/templates/facades.gradle b/templates/facades.gradle index a3bc72d6206..37d6e53753e 100644 --- a/templates/facades.gradle +++ b/templates/facades.gradle @@ -13,6 +13,7 @@ repositories { // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs maven { url "http://artifactory.terasology.org/artifactory/repo" + println "facades.gradle (the template? huh) was reached with standard 'repo' for resolution" } } From 78bd1c9dfc8493cc726efdcc6dbca9b3ec87f903 Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 2 Nov 2017 16:26:03 -0400 Subject: [PATCH 13/20] Collapse the old config dir into the existing Gradle dir - no changes in moved files yet. --- .gitignore | 2 +- build.gradle | 2 +- {config/gradle => gradle}/artifactory.gradle | 0 {config/gradle => gradle}/common.gradle | 0 {config => gradle}/eclipse/.importorder | 0 {config => gradle}/eclipse/Terasology.launch | 0 {config => gradle}/eclipse/TerasologyAWT.launch | 0 {config => gradle}/eclipse/codetemplates.xml | 0 {config => gradle}/eclipse/formatting.xml | 0 {config => gradle}/eclipse/templates.xml | 0 {config/gradle => gradle}/ide.gradle | 0 {config/gradle => gradle}/jenkins.groovy | 0 {config/gradle => gradle}/utility.gradle | 0 13 files changed, 2 insertions(+), 2 deletions(-) rename {config/gradle => gradle}/artifactory.gradle (100%) rename {config/gradle => gradle}/common.gradle (100%) rename {config => gradle}/eclipse/.importorder (100%) rename {config => gradle}/eclipse/Terasology.launch (100%) rename {config => gradle}/eclipse/TerasologyAWT.launch (100%) rename {config => gradle}/eclipse/codetemplates.xml (100%) rename {config => gradle}/eclipse/formatting.xml (100%) rename {config => gradle}/eclipse/templates.xml (100%) rename {config/gradle => gradle}/ide.gradle (100%) rename {config/gradle => gradle}/jenkins.groovy (100%) rename {config/gradle => gradle}/utility.gradle (100%) diff --git a/.gitignore b/.gitignore index c2986225678..cf92697ab36 100644 --- a/.gitignore +++ b/.gitignore @@ -90,7 +90,7 @@ entityDump.txt # Ignore stuff we extract for use with Terasology /natives/ -config/metrics/ +gradle/metrics/ # Ignore weird stuff that might be obsolete diff --git a/build.gradle b/build.gradle index 752cdec0c37..3bfc1331724 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ assert org.gradle.api.JavaVersion.current().isJava8Compatible() // Declare "extra properties" (variables) for the project (and subs) - a Gradle thing that makes them special. ext { dirNatives = 'natives' - dirConfigMetrics = 'config/metrics' + dirConfigMetrics = 'gradle/metrics' templatesDir = 'templates' // Lib dir for use in manifest entries etc (like in :engine). A separate "libsDir" exists, auto-created by Gradle diff --git a/config/gradle/artifactory.gradle b/gradle/artifactory.gradle similarity index 100% rename from config/gradle/artifactory.gradle rename to gradle/artifactory.gradle diff --git a/config/gradle/common.gradle b/gradle/common.gradle similarity index 100% rename from config/gradle/common.gradle rename to gradle/common.gradle diff --git a/config/eclipse/.importorder b/gradle/eclipse/.importorder similarity index 100% rename from config/eclipse/.importorder rename to gradle/eclipse/.importorder diff --git a/config/eclipse/Terasology.launch b/gradle/eclipse/Terasology.launch similarity index 100% rename from config/eclipse/Terasology.launch rename to gradle/eclipse/Terasology.launch diff --git a/config/eclipse/TerasologyAWT.launch b/gradle/eclipse/TerasologyAWT.launch similarity index 100% rename from config/eclipse/TerasologyAWT.launch rename to gradle/eclipse/TerasologyAWT.launch diff --git a/config/eclipse/codetemplates.xml b/gradle/eclipse/codetemplates.xml similarity index 100% rename from config/eclipse/codetemplates.xml rename to gradle/eclipse/codetemplates.xml diff --git a/config/eclipse/formatting.xml b/gradle/eclipse/formatting.xml similarity index 100% rename from config/eclipse/formatting.xml rename to gradle/eclipse/formatting.xml diff --git a/config/eclipse/templates.xml b/gradle/eclipse/templates.xml similarity index 100% rename from config/eclipse/templates.xml rename to gradle/eclipse/templates.xml diff --git a/config/gradle/ide.gradle b/gradle/ide.gradle similarity index 100% rename from config/gradle/ide.gradle rename to gradle/ide.gradle diff --git a/config/gradle/jenkins.groovy b/gradle/jenkins.groovy similarity index 100% rename from config/gradle/jenkins.groovy rename to gradle/jenkins.groovy diff --git a/config/gradle/utility.gradle b/gradle/utility.gradle similarity index 100% rename from config/gradle/utility.gradle rename to gradle/utility.gradle From 3945d8956bd3f5b6979c7e0ac76669bbf793243b Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 2 Nov 2017 16:40:07 -0400 Subject: [PATCH 14/20] Adjustments for the demise of the config dir --- build.gradle | 2 +- engine-tests/build.gradle | 3 +-- engine/build.gradle | 6 +++--- facades/PC/build.gradle | 2 +- facades/TeraEd/build.gradle | 2 +- gradle/artifactory.gradle | 4 ++-- gradle/common.gradle | 6 +++--- gradle/ide.gradle | 6 +++--- modules/java.gradle | 2 +- modules/kotlin.gradle | 2 +- modules/scala.gradle | 4 ++-- 11 files changed, 19 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 3bfc1331724..c5967253407 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ // Separate build file for structure heavy stuff like using Git to fetch other repos to embed within the project -apply from: 'config/gradle/utility.gradle' +apply from: 'gradle/utility.gradle' // Needed for extending the "clean" task to also delete custom stuff defined here like natives apply plugin: 'base' diff --git a/engine-tests/build.gradle b/engine-tests/build.gradle index 9672e2305d0..f2ddacbd75a 100644 --- a/engine-tests/build.gradle +++ b/engine-tests/build.gradle @@ -1,7 +1,7 @@ // Engine tests are split out due to otherwise quirky project dependency issues with module tests extending engine tests // Grab all the common stuff like plugins to use, artifact repositories, code analysis config -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" import groovy.json.JsonSlurper @@ -50,4 +50,3 @@ dependencies { compile group: 'org.mockito', name: 'mockito-all', version: '1.10.19' compile group: 'org.jboss.shrinkwrap', name: 'shrinkwrap-depchain-java7', version: '1.1.3' } - diff --git a/engine/build.gradle b/engine/build.gradle index 944b5185577..c189f6df153 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -6,7 +6,7 @@ plugins { } // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" import groovy.json.JsonSlurper import org.reflections.Reflections; @@ -157,7 +157,7 @@ task cacheReflections { description = 'Caches reflection output to make regular startup faster. May go stale and need cleanup at times.' inputs.files project.classes.outputs.files dependsOn classes - + doLast { // Without the .mkdirs() we might hit a scenario where the classes dir doesn't exist yet // TODO: This could be Gradlefied further by declaring inputs/outputs better, maybe a plugin? @@ -167,7 +167,7 @@ task cacheReflections { .setScanners(new TypeAnnotationsScanner(), new SubTypesScanner())) reflections.save(sourceSets.main.output.classesDir.toString() + "/reflections.cache") } - + } task cleanReflections(type: Delete) { diff --git a/facades/PC/build.gradle b/facades/PC/build.gradle index 89a5fcedd4a..46018208db9 100644 --- a/facades/PC/build.gradle +++ b/facades/PC/build.gradle @@ -1,7 +1,7 @@ // The PC facade is responsible for the primary distribution - a plain Java application runnable on PCs // Grab all the common stuff like plugins to use, artifact repositories, code analysis config -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" import org.apache.tools.ant.filters.FixCrLfFilter import java.text.SimpleDateFormat; diff --git a/facades/TeraEd/build.gradle b/facades/TeraEd/build.gradle index 53b9269b641..04ec4fcd61d 100644 --- a/facades/TeraEd/build.gradle +++ b/facades/TeraEd/build.gradle @@ -1,7 +1,7 @@ // The Editor facade is responsible for the (shader) editor - a plain Java application runnable on PCs // Grab all the common stuff like plugins to use, artifact repositories, code analysis config -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" // Base the engine tests on the same version number as the engine version = project(':engine').version diff --git a/gradle/artifactory.gradle b/gradle/artifactory.gradle index 66e5d1f6354..5308b172fbf 100644 --- a/gradle/artifactory.gradle +++ b/gradle/artifactory.gradle @@ -1,6 +1,6 @@ // This include file applies our Artifactory related settings to places that need them (root project + modules) // It is a superset of the the stuff common to Java sub projects so we include the common.gradle here -apply from: "$rootDir/config/gradle/common.gradle" +apply from: "$rootDir/gradle/common.gradle" // Artifactory publishing requires these (without maven we'd get no .pom with dependency info published) apply plugin: 'maven' @@ -90,4 +90,4 @@ artifactoryPublish { dependsOn jar, sourceJar, javadocJar // TODO: After Gradle 2.3 to 2.10 upgrade have to use `gradlew generatePomFileForMavenJavaPublication artifactoryPublish` // The generation task doesn't happen on its own yet can't be set as a dependsOn as it isn't available yet? -} \ No newline at end of file +} diff --git a/gradle/common.gradle b/gradle/common.gradle index 7bf6889e460..4be54ff63c1 100644 --- a/gradle/common.gradle +++ b/gradle/common.gradle @@ -107,13 +107,13 @@ jacocoTestReport { // TODO: Maybe update other projects like modules to pull the zipped dependency so fewer quirks are needed in Jenkins checkstyle { ignoreFailures = true - configFile = new File(rootDir, 'config/metrics/checkstyle/checkstyle.xml') + configFile = new File(rootDir, 'gradle/metrics/checkstyle/checkstyle.xml') configProperties.samedir = checkstyle.configFile.parentFile } pmd { ignoreFailures = true - ruleSetFiles = files("$rootDir/config/metrics/pmd/pmd.xml") + ruleSetFiles = files("$rootDir/gradle/metrics/pmd/pmd.xml") // By default, gradle uses both ruleset file AND the rulesets. Override the ruleSets to use only those from the file ruleSets = [] } @@ -121,7 +121,7 @@ pmd { findbugs { ignoreFailures = true toolVersion = '3.0.1' - excludeFilter = new File(rootDir, "config/metrics/findbugs/findbugs-exclude.xml") + excludeFilter = new File(rootDir, "gradle/metrics/findbugs/findbugs-exclude.xml") } // TODO: Temporary until javadoc has been fixed for Java 8 everywhere diff --git a/gradle/ide.gradle b/gradle/ide.gradle index 31032e9db72..7c94357e869 100644 --- a/gradle/ide.gradle +++ b/gradle/ide.gradle @@ -12,14 +12,14 @@ ext { def option = builder.option(name: 'configuration') { map { entry(key: 'active-configuration', - value: 'PROJECT_RELATIVE:$PROJECT_DIR$/config/metrics/checkstyle/checkstyle.xml:Terasology CheckStyle') + value: 'PROJECT_RELATIVE:$PROJECT_DIR$/gradle/metrics/checkstyle/checkstyle.xml:Terasology CheckStyle') entry(key: 'check-nonjava-files', value: false) entry(key: 'check-test-classes', value: true) entry(key: 'location-0', value: 'CLASSPATH:/sun_checks.xml:The default CheckStyle rules') entry(key: 'location-1', - value: 'PROJECT_RELATIVE:$PROJECT_DIR$/config/metrics/checkstyle/checkstyle.xml:Terasology CheckStyle') - entry(key: 'property-1.samedir', value: 'config/metrics/checkstyle') + value: 'PROJECT_RELATIVE:$PROJECT_DIR$/gradle/metrics/checkstyle/checkstyle.xml:Terasology CheckStyle') + entry(key: 'property-1.samedir', value: 'gradle/metrics/checkstyle') entry(key: 'suppress-errors', value: false) entry(key: 'thirdparty-classpath', value: '') } diff --git a/modules/java.gradle b/modules/java.gradle index 3f22d38569b..5eaebdb8cf9 100644 --- a/modules/java.gradle +++ b/modules/java.gradle @@ -1,7 +1,7 @@ // This Gradle file is an include file for modules wanting to run in plain old Java // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" // Grab the common stuff specific to modules builds (allows it to live in a module specific but language agnostic file) apply from: "../module.gradle" diff --git a/modules/kotlin.gradle b/modules/kotlin.gradle index c0a5cf72a3e..ae34141d942 100644 --- a/modules/kotlin.gradle +++ b/modules/kotlin.gradle @@ -2,7 +2,7 @@ apply plugin: "kotlin" // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" // Grab the module specific build logic that's language agnostic apply from: "../module.gradle" diff --git a/modules/scala.gradle b/modules/scala.gradle index 1e0625720e4..689f93532f0 100644 --- a/modules/scala.gradle +++ b/modules/scala.gradle @@ -2,7 +2,7 @@ apply plugin: "scala" // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc -apply from: "$rootDir/config/gradle/artifactory.gradle" +apply from: "$rootDir/gradle/artifactory.gradle" // Grab the module specific build logic that's language agnostic apply from: "../module.gradle" @@ -79,4 +79,4 @@ jar.finalizedBy cleanReflections // Needed for Scala for some reason - Kotlin seems to pick up on the custom configurations on its own but here we have to be explicit tasks.withType(ScalaCompile) { scalaClasspath = configurations.scalaConf -} \ No newline at end of file +} From a1bc52b7395b00421922306f3655aeb69aa94d79 Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 2 Nov 2017 17:47:50 -0400 Subject: [PATCH 15/20] Move templates into the gradle dir too --- {templates => gradle/templates}/.gitignore | 0 {templates => gradle/templates}/VERSION | 0 {templates => gradle/templates}/facades.gradle | 0 {templates => gradle/templates}/gradle.properties | 0 {templates => gradle/templates}/metaREADME.markdown | 0 {templates => gradle/templates}/module.txt | 0 {templates => gradle/templates}/override.cfg | 0 {templates => gradle/templates}/version.txt | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename {templates => gradle/templates}/.gitignore (100%) rename {templates => gradle/templates}/VERSION (100%) rename {templates => gradle/templates}/facades.gradle (100%) rename {templates => gradle/templates}/gradle.properties (100%) rename {templates => gradle/templates}/metaREADME.markdown (100%) rename {templates => gradle/templates}/module.txt (100%) rename {templates => gradle/templates}/override.cfg (100%) rename {templates => gradle/templates}/version.txt (100%) diff --git a/templates/.gitignore b/gradle/templates/.gitignore similarity index 100% rename from templates/.gitignore rename to gradle/templates/.gitignore diff --git a/templates/VERSION b/gradle/templates/VERSION similarity index 100% rename from templates/VERSION rename to gradle/templates/VERSION diff --git a/templates/facades.gradle b/gradle/templates/facades.gradle similarity index 100% rename from templates/facades.gradle rename to gradle/templates/facades.gradle diff --git a/templates/gradle.properties b/gradle/templates/gradle.properties similarity index 100% rename from templates/gradle.properties rename to gradle/templates/gradle.properties diff --git a/templates/metaREADME.markdown b/gradle/templates/metaREADME.markdown similarity index 100% rename from templates/metaREADME.markdown rename to gradle/templates/metaREADME.markdown diff --git a/templates/module.txt b/gradle/templates/module.txt similarity index 100% rename from templates/module.txt rename to gradle/templates/module.txt diff --git a/templates/override.cfg b/gradle/templates/override.cfg similarity index 100% rename from templates/override.cfg rename to gradle/templates/override.cfg diff --git a/templates/version.txt b/gradle/templates/version.txt similarity index 100% rename from templates/version.txt rename to gradle/templates/version.txt From 23ca1e85066d9d96c7c03beacb715c67596c0b0c Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 3 Nov 2017 16:16:16 -0400 Subject: [PATCH 16/20] Checkpoint - more moving stuff around plus start on the harness. --- .gitignore | 2 +- build.gradle | 35 ++- engine/build.gradle | 3 +- facades/PC/build.gradle | 3 +- gradle/templates/.gitignore | 6 +- gradle/templates/facades.gradle | 4 +- gradle/templates/gradle.properties | 8 +- gradle/utility.gradle | 381 ----------------------------- module.groovy | 8 +- modules/build.gradle | 8 +- modules/module.gradle | 2 +- 11 files changed, 55 insertions(+), 405 deletions(-) delete mode 100644 gradle/utility.gradle diff --git a/.gitignore b/.gitignore index cf92697ab36..4105e5171cd 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ extensions /libs/* !/libs/subprojects.gradle -# Ignore Gradle and some transient project config files (template versions available under /templates) +# Ignore Gradle and some transient project config files (template versions available under /gradle/templates) build/ /gradle.properties /override.cfg diff --git a/build.gradle b/build.gradle index c5967253407..7a2566071f3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,3 @@ -// Separate build file for structure heavy stuff like using Git to fetch other repos to embed within the project -apply from: 'gradle/utility.gradle' - // Needed for extending the "clean" task to also delete custom stuff defined here like natives apply plugin: 'base' @@ -34,7 +31,7 @@ assert org.gradle.api.JavaVersion.current().isJava8Compatible() ext { dirNatives = 'natives' dirConfigMetrics = 'gradle/metrics' - templatesDir = 'templates' + templatesDir = 'gradle/templates' // Lib dir for use in manifest entries etc (like in :engine). A separate "libsDir" exists, auto-created by Gradle subDirLibs = 'libs' @@ -161,7 +158,7 @@ task protobufCompileLinux(type:Exec) { // TODO: Convert the natives, config, and IDE setup to be tasks like this one task copyInMissingTemplates { - description = "Copies in placeholders from the /templates dir to project root if not present yet" + description = "Copies in placeholders from the /gradle/templates dir to project root if not present yet" File gradlePropsFile = new File(rootDir, 'gradle.properties') File OverrideCfgFile = new File(rootDir, 'override.cfg') if (!gradlePropsFile.exists()) { @@ -172,12 +169,40 @@ task copyInMissingTemplates { } } +// TODO: Consider making this stuff excluded from clean, then offer a fullClean for the rare time that may be needed +// That would allow a `gradlew clean` without having to rerun this at all, everything would still work fine (with rebuild) task prepareStuff { dependsOn extractNatives dependsOn extractConfig dependsOn copyInMissingTemplates } +task harnessTheBuild (type: Zip) { + description = "Prepares all build files and supporting stuff needed to build modules solo" + dependsOn extractNatives + dependsOn extractConfig + + from ('modules') { + include '*.gradle' + } + + from ('gradle') { + include '*.gradle' + include 'wrapper/**/*' + include 'metrics/**/*' + include 'templates/**/*' + into 'gradle' + } + + from 'gradlew' + from 'gradlew.bat' + from 'groovyw' + from 'groovyw.bat' + from 'module.groovy' + + archiveName = "TerasologyHarness.zip" +} + afterEvaluate { // This pops up way too early - after this particular file has been evaluated? Module config logging follows // Really need a hook to trigger a task's execution phase on any project evaluation diff --git a/engine/build.gradle b/engine/build.gradle index c189f6df153..6bde7de8f6c 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -23,7 +23,8 @@ ext { // Read environment variables, including variables passed by jenkins continuous integration server env = System.getenv() - templatesDir = new File(rootDir, 'templates') + // TODO: Use project.file() instead? Good practice / warning. Can be used as plain file(). But may need one-arg approach? + templatesDir = new File(rootDir, 'gradle/templates') // Stuff for our automatic version file setup startDateTimeString = dateTimeFormat.format(new Date()) diff --git a/facades/PC/build.gradle b/facades/PC/build.gradle index 46018208db9..11d57535184 100644 --- a/facades/PC/build.gradle +++ b/facades/PC/build.gradle @@ -17,7 +17,7 @@ ext { // General props mainClassName = 'org.terasology.engine.Terasology' subDirLibs = 'libs' - templatesDir = new File(rootDir, 'templates') + templatesDir = new File("$rootDir/gradle/templates") rootDirDist = new File(rootDir, 'build/distributions') // Read environment variables, including variables passed by jenkins continuous integration server @@ -269,6 +269,7 @@ task distModules (type: Sync) { } */ } + task distPCZip (type: Zip) { dependsOn distApp dependsOn distModules diff --git a/gradle/templates/.gitignore b/gradle/templates/.gitignore index 25e5ed21447..d9bd3a40c52 100644 --- a/gradle/templates/.gitignore +++ b/gradle/templates/.gitignore @@ -1,4 +1,4 @@ -# Modules get a copy of build.gradle as they are not allowed to have their own (for build security / sandboxing) +# Modules do not need and are not allowed a build file build.gradle # IntelliJ @@ -10,4 +10,6 @@ build.gradle .project .settings bin/ -build/ \ No newline at end of file +build/ + +#TODO: Add new entries expected when the build harness has been added to a module dir diff --git a/gradle/templates/facades.gradle b/gradle/templates/facades.gradle index 37d6e53753e..1d92a1bef84 100644 --- a/gradle/templates/facades.gradle +++ b/gradle/templates/facades.gradle @@ -23,11 +23,11 @@ dependencies { checkstyle { ignoreFailures = true - configFile = new File(rootDir, 'config/checkstyle/checkstyle.xml') + configFile = new File(rootDir, 'gradle/metrics/checkstyle/checkstyle.xml') configProperties.samedir = checkstyle.configFile.parentFile } pmd { ignoreFailures = true - ruleSetFiles = files("$rootDir/config/pmd/pmd.xml") + ruleSetFiles = files("$rootDir/gradle/metrics/pmd/pmd.xml") } diff --git a/gradle/templates/gradle.properties b/gradle/templates/gradle.properties index ecfaed08739..3cfb08eb3a1 100644 --- a/gradle/templates/gradle.properties +++ b/gradle/templates/gradle.properties @@ -1,7 +1,9 @@ # These settings can speed up the execution of Gradle (and some may be on by default anyway in newer Gradle versions) org.gradle.daemon=true -org.gradle.parallel = true -org.gradle.configureondemand=true +org.gradle.parallel = false +org.gradle.configureondemand=false +org.gradle.console=verbose + # Alternative resolution repo to use in general (not an Artifactory setting, but a more general Maven repo definition) # alternativeResolutionRepo=http://artifactory.terasology.org/artifactory/virtual-nanoware-and-remote @@ -34,4 +36,4 @@ org.gradle.configureondemand=true # If you want to work under a different GitHub account/org you can set it here # There are two properties split out as modules & meta modules have the same name, so they can't share user/org # alternativeGithubHome=Nanoware -# alternativeGithubMetaHome=Nanoware \ No newline at end of file +# alternativeGithubMetaHome=Nanoware diff --git a/gradle/utility.gradle b/gradle/utility.gradle deleted file mode 100644 index 5fff457c4c4..00000000000 --- a/gradle/utility.gradle +++ /dev/null @@ -1,381 +0,0 @@ -// This extra build file is mainly for structural setup of the project using Git to import other repos from GitHub - -// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( -buildscript { - repositories { - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case - jcenter() - mavenCentral() - } - - dependencies { - // Git plugin for Gradle - classpath 'org.ajoberstar:gradle-git:0.6.3' - } -} - -// Git plugin details at https://github.com/ajoberstar/gradle-git -import org.ajoberstar.gradle.git.tasks.* - -ext { - // TODO: Huh, why can't this be resolved from the main build.gradle anymore? It used to be accessible - templatesDir = 'templates' -} - -// Dynamic task definition for cloning an existing module (with the module name embedded in the task name as ) -// Sample command: gradlew fetchModulePortals -tasks.addRule("Pattern: fetchModule") { String taskName -> - if (taskName.startsWith("fetchModule")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitClone) { - // TODO: This task description does not get listed under the "Rules" section on "gradlew tasks" :-( - description = 'Fetches source for a given module to the local project, cloned from GitHub' - - // Repo name is the dynamic part of the task name - def repo = (taskName - 'fetchModule') - def parentDir = 'modules' - - // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties - def githubHome = 'Terasology' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$repo") - - // Don't clone this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "fetchModule requested for $repo from Github under $githubHome - exists already? " + !enabled - - // Do the actual clone if we don't have the directory already - if (enabled) { - uri = "https://github.com/$githubHome/" + repo + ".git" - println "Fetching $repo from $uri" - destinationPath = destination - bare = false - } - - // Copy in (replace if existing for some reason) a build.gradle from template, plus module.txt if missing - doLast { - File targetBuildGradle = new File(destination, 'build.gradle') - targetBuildGradle.delete() - targetBuildGradle << new File(rootDir, 'modules/Core/build.gradle').text - - File moduleManifest = new File (destination, 'module.txt') - if (!moduleManifest.exists()) { - def moduleText = new File(templatesDir, 'module.txt').text - moduleManifest << moduleText.replaceAll('MODULENAME', repo) - println "WARNING: Module $repo did not have a module.txt! One was created, please review and submit to GitHub" - } - } - } - } -} - -// Dynamic task definition for creating a new module (from scratch, rather than cloning from GitHub) -// Sample command: gradlew createModuleMyStuff -tasks.addRule("Pattern: createModule") { String taskName -> - if (taskName.startsWith("createModule")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitInit) { - description = 'Creates template source for a given module to the local project and preps a local Git repo' - - // Repo name is the dynamic part of the task name - def repo = (taskName - 'createModule') - def parentDir = 'modules' - - // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties - def githubHome = 'Terasology' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$repo") - - // Don't create this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "createModule requested for $repo linked to $githubHome on GitHub - exists already? " + !enabled - - // Do the actual creation if we don't have the directory already - if (enabled) { - - println "Creating $repo locally" - destination.mkdir() - destinationPath = destination - - // TODO: Add in the local mapping to a remote ref definition. Needs support in the Gradle-Git plugin - //uri = "https://github.com/$githubAccount/" + repo + ".git" - bare = false - - // Copy in some template stuff for the new module - doLast { - new File(destination, 'build.gradle') << new File(rootDir, 'modules/Core/build.gradle').text - // TODO : Add in the logback.groovy from engine\src\test\resources\logback.groovy ? Local dev only, Jenkins will use the one inside engine-tests.jar. Also add to .gitignore - def moduleManifest = new File (destination, 'module.txt') - def moduleText = new File(templatesDir, 'module.txt').text - moduleManifest << moduleText.replaceAll('MODULENAME', repo) - new File(destination, '.gitignore') << new File(templatesDir, '.gitignore').text - } - } - } - } -} - -// Dynamic task definition for cloning an existing meta-module (with the meta-module name embedded in the task name as ) -// Note how this one uses a different override name - modules & meta modules share names, so cannot co-exist in same Org -// Sample command: gradlew fetchMetaStructuralResources -tasks.addRule("Pattern: fetchMeta") { String taskName -> - if (taskName.startsWith("fetchMeta")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitClone) { - // TODO: This task description does not get listed under the "Rules" section on "gradlew tasks" :-( - description = 'Fetches source for a given meta-module to the local project, cloned from GitHub' - - // Repo name is the dynamic part of the task name - def repo = (taskName - 'fetchMeta') - def parentDir = 'meta' - - // Default GitHub account to use. Supply with -PgithubMetaAccount="TargetAccountName" or via gradle.properties - def githubHome = 'MetaTerasology' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubMetaAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubMetaHome')) { - githubHome =alternativeGithubHome - } - - // Since meta-modules only accompany normal modules they need a unique name - def destination = file("$parentDir/$repo" + "Meta") - - // Don't clone this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "fetchMeta requested for $repo from Github under $githubHome - exists already? " + !enabled - - // Do the actual clone if we don't have the directory already - if (enabled) { - uri = "https://github.com/$githubHome/" + repo + ".git" - println "Fetching $repo from $uri" - destinationPath = destination - bare = false - } - } - } -} - -// Dynamic task definition for creating a new meta-module (from scratch, rather than cloning from GitHub) -// Sample command: gradlew createMetaStructuralResources -tasks.addRule("Pattern: createMeta") { String taskName -> - if (taskName.startsWith("createMeta")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitInit) { - description = 'Creates template source for a given meta-module to the local project and preps a local Git repo' - - // Repo name is the dynamic part of the task name + "Meta" appended in the case of meta-modules - def repo = (taskName - 'createMeta') - def parentDir = 'meta' - - // Default GitHub account to use. Supply with -PgithubMetaAccount="TargetAccountName" or via gradle.properties - def githubHome = 'MetaTerasology' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubMetaAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubMetaHome')) { - githubHome =alternativeGithubHome - } - - // Since meta-modules only accompany normal modules they need a unique name - def destination = file("$parentDir/$repo" + "Meta") - - // Don't create this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "createMeta requested for $repo linked to $githubHome on GitHub - exists already? " + !enabled - - // Do the actual creation if we don't have the directory already - if (enabled) { - - println "Creating $repo locally" - destination.mkdir() - destinationPath = destination - - // TODO: Add in the local mapping to a remote ref definition. Needs support in the Gradle-Git plugin - //uri = "https://github.com/$githubAccount/" + repo + ".git" - bare = false - - // Copy in some template stuff for the new meta-module - doLast { - new File(destination, 'README.markdown') << new File(templatesDir, 'metaREADME.markdown').text.replaceAll('MODULENAME', repo) - new File(destination, '.gitignore') << new File(templatesDir, '.gitignore').text - } - } - } - } -} - -// Dynamic task definition for cloning an existing facade (with the facade name embedded in the task name as ) -// Sample command: gradlew fetchFacadeAndroid -tasks.addRule("Pattern: fetchFacade") { String taskName -> - if (taskName.startsWith("fetchFacade")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitClone) { - description = 'Fetches source for a given facade to the local project, cloned from GitHub' - - // Repo name is the dynamic part of the task name. Facade repos are prefixed with "Facade" so we do "math" - def repo = (taskName - 'fetch') - def localName = (repo - 'Facade') - def parentDir = 'facades' - - println "Repo is $repo - localName is $localName" - - // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties - def githubHome = 'MovingBlocks' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$localName") - - // Don't clone this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "fetchFacade requested for $localName from Github under $githubHome - exists already? " + !enabled - - // Do the actual clone if we don't have the directory already - if (enabled) { - uri = "https://github.com/$githubHome/" + repo + ".git" - println "Fetching $repo from $uri" - destinationPath = destination - bare = false - } - } - } -} - -// Dynamic task definition for creating a new facade (with the facade name embedded in the task name as ) -// Sample command: gradlew createFacadeConsoleX -tasks.addRule("Pattern: createFacade") { String taskName -> - if (taskName.startsWith("createFacade")) { - - // Here's the actual task definition for each dynamically created task of name taskName - task (taskName, type: GitInit) { - description = 'Creates template source for a given facade to the local project and preps a local Git repo' - - // Repo name is the dynamic part of the task name. Facade repos are prefixed with "Facade" so we do "math" - def repo = (taskName - 'create') - def localName = (repo - 'Facade') - def parentDir = 'facades' - - println "Repo is $repo - localName is $localName" - - // Default GitHub account to use. Supply with -PgithubAccount="TargetAccountName" or via gradle.properties - def githubHome = 'MovingBlocks' - - // Command line parameter has precedence - if it is set we do not check gradle.properties - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$localName") - - // Don't create this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "createFacade requested for $localName linked to Github under $githubHome - exists already? " + !enabled - - // Do the actual creation if we don't have the directory already TODO: Doesn't enable the GitHub mapping yet - if (enabled) { - //uri = "https://github.com/$githubHome/" + repo + ".git" - println "Creating $repo locally" // pointed at $uri" - destination.mkdir() - destinationPath = destination - bare = false - - // Copy in some template stuff for the new facade. TODO: This doesn't do a whole lot yet... - doLast { - new File(destination, 'build.gradle') << new File(templatesDir, 'facades.gradle').text - def moduleManifest = new File (destination, 'module.txt') - def moduleText = new File(templatesDir, 'module.txt').text - moduleManifest << moduleText.replaceAll('MODULENAME', repo) - new File(destination, '.gitignore') << '*.iml' - println "*** New facade created but this template is pretty raw! Please review well before using" - } - } - } - } -} - -// Dynamic task for fetching project-related libs -// Sample command: gradlew fetchLibCrashReporter -tasks.addRule("Pattern: fetchLib") { String taskName -> - if (taskName.startsWith("fetchLib")) { - - // Task for fetching our various library projects like TeraBullet - task (taskName, type: GitClone) { - description = 'Fetches source for a given Terasology-related library to the local project, pulled from GitHub' - - // Repo name is the dynamic part of the task name - def repo = (taskName - 'fetchLib') - def parentDir = 'libs' - - // Default to MovingBlocks but set some stuff for known libs - def githubHome = 'MovingBlocks' - - switch (repo) { - case 'TeraBullet' : - // TeraBullet currently uses the "develop" branch - branch = 'develop' - break; - - // Hmm, what to do with casing issues. Camel case gradlew fetchLibJitter is so pretty! But .. jitter - case 'Jitter' : - case 'jitter' : - // Jitter is hosted in the "openleap" org and everything is in lower case, whoops - githubHome = 'openleap' - repo = 'jitter' - break; - case 'Index' : - githubHome = 'Terasology' - break; - } - - // Allow user to override the GitHub account to pull from. Supply with -PgithubAccount="TargetAccountName" - if (project.hasProperty('githubAccount')) { - githubHome = githubAccount - } else if (project.hasProperty('alternativeGithubHome')) { - githubHome =alternativeGithubHome - } - - def destination = file("$parentDir/$repo") - - // Don't clone this repo if we already have a directory by that name (also determines Gradle UP-TO-DATE) - enabled = !destination.exists() - println "fetchLib requested for $repo from Github under $githubHome - exists already? " + !enabled - - // Do the actual clone if we don't have the directory already - if (enabled) { - uri = "https://github.com/$githubHome/" + repo + ".git" - println "Fetching $repo from $uri" - destinationPath = destination - bare = false - } - } - } -} diff --git a/module.groovy b/module.groovy index 583530b6d31..8423cd966fd 100644 --- a/module.groovy +++ b/module.groovy @@ -61,7 +61,7 @@ def retrieveModule(String module, boolean recurse) { File moduleManifest = new File(targetDir, 'module.txt') if (!moduleManifest.exists()) { - def moduleText = new File("templates/module.txt").text + def moduleText = new File("gradle/templates/module.txt").text moduleManifest << moduleText.replaceAll('MODULENAME', module) println "WARNING: Module $module did not have a module.txt! One was created, please review and submit to GitHub" } @@ -125,13 +125,13 @@ def createModule(String name) { // Add gitignore println "Creating .gitignore" File gitignore = new File(targetDir, ".gitignore") - def gitignoreText = new File("templates/.gitignore").text + def gitignoreText = new File("gradle/templates/.gitignore").text gitignore << gitignoreText // Add module.txt println "Creating module.txt" File moduleManifest = new File(targetDir, "module.txt") - def moduleText = new File("templates/module.txt").text + def moduleText = new File("gradle/templates/module.txt").text moduleManifest << moduleText.replaceAll('MODULENAME', name) // Initialize git @@ -191,7 +191,7 @@ def printUsage() { println "After changing modules available in your workspace rerun 'gradlew idea' and/or refresh your IDE" println "" println "For advanced usage see project documentation. For instance you can provide an alternative GitHub home" - println "A gradle.properties file (one exists under '/templates' in an engine workspace) can provide such overrides" + println "A gradle.properties file (one exists under '/gradle/templates' in an engine workspace) can provide such overrides" println "" } diff --git a/modules/build.gradle b/modules/build.gradle index 9e982bb0f59..23e48b37c51 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -15,7 +15,7 @@ buildscript { import groovy.json.JsonSlurper -println "The build.gradle from /modules says hi" +println "The build.gradle from /modules says hi. We're going to review some potential modules!" // We need to prepare the build logic for each module so we use a subprojects block to make this execute for each subprojects { @@ -27,15 +27,15 @@ subprojects { // When we know the language we apply the appropriate language-specific wrapper for build logic if (moduleConfig.language == "scala") { - println "Oh hey, a Scala module. Using its build" + println "\nFound a Scala module: * $project.name *" apply from: '../scala.gradle' } else if (moduleConfig.language == "kotlin") { - println "Oh hey, a Kotlin module. Using its build" + println "\nFound a Kotlin module: * $project.name *" // TODO: This satisfies Kotlin compilation in a module using it. Still need to guarantee a dependency on KotlinLib to get the runtime jar (I think?) // So during Gradling for a language specific module insert condition: If KotlinLib then include the jar. If not then validate KotlinLib dep in module.txt apply from: '../kotlin.gradle' } else { - println "Boring old Java module" + println "\nFound a Java module: * $project.name *" apply from: '../java.gradle' } } diff --git a/modules/module.gradle b/modules/module.gradle index bce0ffd7966..de8b46bc7a6 100644 --- a/modules/module.gradle +++ b/modules/module.gradle @@ -78,7 +78,7 @@ dependencies { // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace if (project.name != project(':').name) { - println "\nProcessing module '$project.name' in a multi-project workspace" + println "Processing module '$project.name' in a multi-project workspace" // Dependency on the engine itself (actually its built jar file) compile project(':engine') From eff4c371cb0d84c7d0dcbd11b46448c39aea1827 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 3 Nov 2017 16:18:24 -0400 Subject: [PATCH 17/20] Move the shared/include stuff in the new module system into /gradle as well --- {modules => gradle}/java.gradle | 0 {modules => gradle}/kotlin.gradle | 0 {modules => gradle}/module.gradle | 0 {modules => gradle}/scala.gradle | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {modules => gradle}/java.gradle (100%) rename {modules => gradle}/kotlin.gradle (100%) rename {modules => gradle}/module.gradle (100%) rename {modules => gradle}/scala.gradle (100%) diff --git a/modules/java.gradle b/gradle/java.gradle similarity index 100% rename from modules/java.gradle rename to gradle/java.gradle diff --git a/modules/kotlin.gradle b/gradle/kotlin.gradle similarity index 100% rename from modules/kotlin.gradle rename to gradle/kotlin.gradle diff --git a/modules/module.gradle b/gradle/module.gradle similarity index 100% rename from modules/module.gradle rename to gradle/module.gradle diff --git a/modules/scala.gradle b/gradle/scala.gradle similarity index 100% rename from modules/scala.gradle rename to gradle/scala.gradle From 7cabfe17499b7f032685614253b5998e199291ca Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 3 Nov 2017 16:44:54 -0400 Subject: [PATCH 18/20] Tweaks for moved files, build harness looking decent --- build.gradle | 2 +- gradle/java.gradle | 2 +- gradle/kotlin.gradle | 2 +- gradle/scala.gradle | 2 +- module.groovy | 4 ++++ modules/build.gradle | 6 +++--- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 7a2566071f3..41b941a4c4c 100644 --- a/build.gradle +++ b/build.gradle @@ -183,7 +183,7 @@ task harnessTheBuild (type: Zip) { dependsOn extractConfig from ('modules') { - include '*.gradle' + include 'build.gradle' } from ('gradle') { diff --git a/gradle/java.gradle b/gradle/java.gradle index 5eaebdb8cf9..01c05479480 100644 --- a/gradle/java.gradle +++ b/gradle/java.gradle @@ -4,7 +4,7 @@ apply from: "$rootDir/gradle/artifactory.gradle" // Grab the common stuff specific to modules builds (allows it to live in a module specific but language agnostic file) -apply from: "../module.gradle" +apply from: "$rootDir/gradle/module.gradle" // Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( buildscript { diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index ae34141d942..039a5eb6ba5 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -5,7 +5,7 @@ apply plugin: "kotlin" apply from: "$rootDir/gradle/artifactory.gradle" // Grab the module specific build logic that's language agnostic -apply from: "../module.gradle" +apply from: "$rootDir/gradle/module.gradle" // Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( buildscript { diff --git a/gradle/scala.gradle b/gradle/scala.gradle index 689f93532f0..43d739f5558 100644 --- a/gradle/scala.gradle +++ b/gradle/scala.gradle @@ -5,7 +5,7 @@ apply plugin: "scala" apply from: "$rootDir/gradle/artifactory.gradle" // Grab the module specific build logic that's language agnostic -apply from: "../module.gradle" +apply from: "$rootDir/gradle/module.gradle" // Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( buildscript { diff --git a/module.groovy b/module.groovy index 8423cd966fd..1bd94b5a7e2 100644 --- a/module.groovy +++ b/module.groovy @@ -274,6 +274,10 @@ if (args.length == 0) { } } break + case "init" + // TODO: Special case for using the build harness in a solo module workspace. + // Should work akin to create but using the workspace root, not modules/$name + break default: println "UNRECOGNIZED COMMAND - please try again or use 'groovyw module usage' for help" } diff --git a/modules/build.gradle b/modules/build.gradle index 23e48b37c51..a5bc945a329 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -28,14 +28,14 @@ subprojects { // When we know the language we apply the appropriate language-specific wrapper for build logic if (moduleConfig.language == "scala") { println "\nFound a Scala module: * $project.name *" - apply from: '../scala.gradle' + apply from: "$rootDir/gradle/scala.gradle" } else if (moduleConfig.language == "kotlin") { println "\nFound a Kotlin module: * $project.name *" // TODO: This satisfies Kotlin compilation in a module using it. Still need to guarantee a dependency on KotlinLib to get the runtime jar (I think?) // So during Gradling for a language specific module insert condition: If KotlinLib then include the jar. If not then validate KotlinLib dep in module.txt - apply from: '../kotlin.gradle' + apply from: "$rootDir/gradle/kotlin.gradle" } else { println "\nFound a Java module: * $project.name *" - apply from: '../java.gradle' + apply from: "$rootDir/gradle/java.gradle" } } From bcfb9d5839fdba743b740b0ccb0bda5b16cd77ce Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 4 Nov 2017 00:08:19 -0400 Subject: [PATCH 19/20] Quick ugly hacks that seemed to be enough to get the build harness working in a standalone module workspace. Should clean up later, the Artifactory block is all over the place now. Must be a way to shrink that down. --- gradle/artifactory.gradle | 17 +++++++++++++++++ modules/build.gradle | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/gradle/artifactory.gradle b/gradle/artifactory.gradle index 5308b172fbf..4f026f65d71 100644 --- a/gradle/artifactory.gradle +++ b/gradle/artifactory.gradle @@ -7,6 +7,23 @@ apply plugin: 'maven' apply plugin: 'com.jfrog.artifactory' apply plugin: 'maven-publish' +// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-( +buildscript { + repositories { + // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case + jcenter() + } + + dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + + // Needed for caching reflected data during builds + classpath 'org.reflections:reflections:0.9.10' + classpath 'dom4j:dom4j:1.6.1' + } +} + // This configures what we need to interact with the MovingBlocks Artifactory instance. It is primarily for local use. // In Jenkins the Artifactory plugin can supply overrides for the following values artifactory { diff --git a/modules/build.gradle b/modules/build.gradle index a5bc945a329..fa3934fa3bc 100644 --- a/modules/build.gradle +++ b/modules/build.gradle @@ -8,6 +8,9 @@ buildscript { jcenter() } dependencies { + // Artifactory plugin + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '4.0.0') + // Needed at this level to support modules in Kotlin classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6" } @@ -17,8 +20,34 @@ import groovy.json.JsonSlurper println "The build.gradle from /modules says hi. We're going to review some potential modules!" -// We need to prepare the build logic for each module so we use a subprojects block to make this execute for each -subprojects { +if (project.name != project(':').name) { + println "We're running embedded in an engine workspace" + + // We need to prepare the build logic for each module so we use a subprojects block to make this execute for each + subprojects { + + // Parse out the language selection from module.txt + def moduleFile = file('module.txt') + JsonSlurper slurper = new JsonSlurper() + def moduleConfig = slurper.parseText(moduleFile.text) + + // When we know the language we apply the appropriate language-specific wrapper for build logic + if (moduleConfig.language == "scala") { + println "\nFound a Scala module: * $project.name *" + apply from: "$rootDir/gradle/scala.gradle" + } else if (moduleConfig.language == "kotlin") { + println "\nFound a Kotlin module: * $project.name *" + // TODO: This satisfies Kotlin compilation in a module using it. Still need to guarantee a dependency on KotlinLib to get the runtime jar (I think?) + // So during Gradling for a language specific module insert condition: If KotlinLib then include the jar. If not then validate KotlinLib dep in module.txt + apply from: "$rootDir/gradle/kotlin.gradle" + } else { + println "\nFound a Java module: * $project.name *" + apply from: "$rootDir/gradle/java.gradle" + } + } + +} else { + println "Solo module build woo!" // Parse out the language selection from module.txt def moduleFile = file('module.txt') @@ -27,15 +56,15 @@ subprojects { // When we know the language we apply the appropriate language-specific wrapper for build logic if (moduleConfig.language == "scala") { - println "\nFound a Scala module: * $project.name *" + println "\nThis is a standalone Scala module workspace: * $project.name *" apply from: "$rootDir/gradle/scala.gradle" } else if (moduleConfig.language == "kotlin") { - println "\nFound a Kotlin module: * $project.name *" + println "\nThis is a standalone Kotlin module workspace: * $project.name *" // TODO: This satisfies Kotlin compilation in a module using it. Still need to guarantee a dependency on KotlinLib to get the runtime jar (I think?) // So during Gradling for a language specific module insert condition: If KotlinLib then include the jar. If not then validate KotlinLib dep in module.txt apply from: "$rootDir/gradle/kotlin.gradle" } else { - println "\nFound a Java module: * $project.name *" + println "\nThis is a standalone Java module workspace: * $project.name *" apply from: "$rootDir/gradle/java.gradle" } } From 957d8f3bfcf7b4f81012848b2d5534b6400ead3b Mon Sep 17 00:00:00 2001 From: Cervator Date: Sat, 4 Nov 2017 00:09:27 -0400 Subject: [PATCH 20/20] Experimental fix to unit testing starting out of the Gradle cache. Seems to let the unit tests in Pathfinding work out the directory, but then a module sandboxing quirk appears? --- .../java/org/terasology/engine/paths/PathManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/engine/paths/PathManager.java b/engine/src/main/java/org/terasology/engine/paths/PathManager.java index cb5b6cc6ef8..38dd8a5a8df 100644 --- a/engine/src/main/java/org/terasology/engine/paths/PathManager.java +++ b/engine/src/main/java/org/terasology/engine/paths/PathManager.java @@ -65,7 +65,15 @@ private PathManager() { URL urlToSource = PathManager.class.getProtectionDomain().getCodeSource().getLocation(); Path codeLocation = Paths.get(urlToSource.toURI()); - System.out.println("codeLocation: " + codeLocation); + System.out.println("PathManager being initialized. Initial code location is " + codeLocation.toAbsolutePath()); + + // In the case of unit testing in a module the engine jar may be somewhere totally different. We don't want that + if (codeLocation.toString().contains(".gradle") || codeLocation.toString().contains(".m2")) { + System.out.println("PathManager is being initialized out of a jar in the .gradle or .m2 cache. Need better working dir!"); + codeLocation = Paths.get(""); + System.out.println("Hopefully changed it to the right working dir: " + codeLocation.toAbsolutePath()); + } + if (Files.isRegularFile(codeLocation)) { installPath = findNativesHome(codeLocation.getParent(), 5); if (installPath == null) {