-
Notifications
You must be signed in to change notification settings - Fork 1
/
build.gradle
263 lines (223 loc) · 10.7 KB
/
build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules
apply from: '../../config/gradle/common.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.json')
// The module file should always exist if the module was correctly created or cloned using Gradle
if (!moduleFile.exists()) {
println "module.json does not exist!"
throw new GradleException("Failed to find module.json for " + project.name)
}
//println "Scanning for dependencies in module.json 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.destinationsol.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')
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 '+'
Project dependencyProject = findProject(':modules:' + dependency)
// Note: It is possible for a module to have assets but no code in DestinationSol, so we must check if the module project exists
if (dependencyProject != null) {
compile dependencyProject
}
} 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.destinationsol.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.destinationsol.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.destinationsol.engine', name: 'engine', 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.destinationsol.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.destinationsol')) {
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/music')
mkdir('assets/sounds')
mkdir('assets/textures')
mkdir('assets/configs')
mkdir('assets/asteroids')
mkdir('assets/schemas')
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.json and all the assets into the output
doFirst {
copy {
from 'module.json'
into 'build/classes'
}
}
}
jar.finalizedBy cleanReflections
// Prep an IntelliJ module for the DestinationSol 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')
}
}