-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathbuild.gradle
426 lines (354 loc) · 15.5 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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
apply plugin: 'java'
apply plugin: 'idea'
/*
This builds the Idea gradle plugin. This requires a copy of Idea 9 to be installed on your machine as well as at least Gradle.
It compiles against several libs and plugins that are distributed with Idea as well as the open api inside Gradle.
By default, this uses the open-api jar from the gradle doing the build, however, you can override this to use a different
one. See getOpenAPIJar().
*/
ideaDirectoryVar = null
ideaLibDirectoryVar = null
ideaBuiltInPluginsDirectoryVar = null
dependencies
{
compile files(getIdeaLibFiles( false ))
compile files(getIdeaPluginFiles( false ))
//Need to compiles against the gradle-open-api jar. This defines the version of gradle the plugin works with.
//compile 'org.codehaus.gradle:gradle-open-api:0.9' whenever gradle is put into a repo (this is probably not the correct specifier)
compile files(getOpenAPIJar( false )) //for now, we'll get it manually
}
/**
This packages the java from this project with the open api jar from gradle into a single jar.
If you update the plugin and need to resubmit it to Idea, it needs to be in this form.
*/
task packageIntoSingleJar( dependsOn: build, description: "Builds the plugin, packaging it into a single jar file suitable for uploading to Idea's plugin repository.") <<
{
ant.jar( destfile: getBuiltPluginFile() )
{
zipgroupfileset( file: jar.archivePath.getAbsolutePath() )
zipgroupfileset( file: getOpenAPIJar( true ).getAbsolutePath() )
}
}
/*
This builds and deploys the idea plugin to the current Idea installation. This is really just copying jars to a specific
directory. We get that directory from Idea's installation.
*/
task deploy(dependsOn: packageIntoSingleJar, description: 'Builds and places the Gradle GUI plugin in your Idea plugin directory') <<
{
//This is the directory for a user's Idea plugins (vs the ones that are built-in and stored with the application itself).
//Idea stores a property that defines where this is. We'll ask it.
def userPluginsDirectory = getIdeaFileProperty('idea.plugins.path')
if (userPluginsDirectory == null)
throw new RuntimeException("Could not determine the directory for user plugins. You'll have to manually deploy it.")
//delete older versions of the plugin. Idea doesn't like using two versions of the same plugin.
deleteExistingPlugin( userPluginsDirectory );
//copy the jars to the destination
ant.copy(file: getBuiltPluginFile(), toDir: userPluginsDirectory.getAbsolutePath() )
}
def getBuiltPluginFile()
{
return new File(buildDir, 'plugin/gradle_gui.jar')
}
/**
This gets all the jar files inside Idea's lib directory that we depend upon.
These are shipped with Idea.
*/
def getIdeaLibFiles( boolean verifyFiles ) {
def ideaLibDirectory = getIdeaLibDirectory()
if( ideaLibDirectory == null )
return new ArrayList();
def files = [new File(ideaLibDirectory, 'annotations.jar'),
new File(ideaLibDirectory, 'extensions.jar'),
getVersionedJar( ideaLibDirectory, "groovy-all"), //the name of the groovy jar is versioned, most of the rest are not.
new File(ideaLibDirectory, 'idea.jar'),
new File(ideaLibDirectory, 'jdom.jar'),
new File(ideaLibDirectory, 'openapi.jar'),
new File(ideaLibDirectory, 'util.jar')]
if( verifyFiles )
verifyFilesExist(files)
return files
}
/**
This gets all the jar files from Idea's built-in plugins that we depend upon.
These are shipped with Idea.
*/
def getIdeaPluginFiles( boolean verifyFiles ) {
def pluginsDirectory = getIdeaBuiltInPluginsDirectory()
if( pluginsDirectory == null )
return []
def files = [new File(pluginsDirectory, 'Groovy/lib/Groovy.jar'),
new File(pluginsDirectory, 'gradle/lib/gradle.jar')]
if( verifyFiles )
verifyFilesExist(files)
return files
}
/**
Returns the Idea directory. This is the root directory of where Idea is installed on this machine. It sets
a member variable once we've got it.
*/
def getIdeaDirectory() {
if (ideaDirectoryVar == null)
ideaDirectoryVar = determineIdeaDirectory()
return ideaDirectoryVar
}
/**
Returns Idea's 'lib' directory. This is the 'lib' directory underneath the root directory of where Idea is
installed. It sets a member variable once we've got it.
*/
def getIdeaLibDirectory() {
if (ideaLibDirectoryVar == null)
ideaLibDirectoryVar = determineIdeaLibDirectory()
return ideaLibDirectoryVar
}
/**
Returns Idea's built-in plugin directory. This is where its built-in plugins that come with Idea are placed,
NOT the directory where user plugins are installed. It sets a member variable once we've got it.
*/
def getIdeaBuiltInPluginsDirectory() {
if (ideaBuiltInPluginsDirectoryVar == null)
ideaBuiltInPluginsDirectoryVar = determineIdeaBuildInPluginDirectory()
return ideaBuiltInPluginsDirectoryVar
}
//this gets the Idea directory and validates that the version of Idea is correct
def determineIdeaDirectory() {
String ideaPath = getPropertyValue('idea.home') ?: System.getenv('IDEA_HOME')
if (ideaPath != null)
{
File ideaDirectory = new File(ideaPath)
if( ideaDirectory.exists())
return ideaDirectory;
}
return null
}
/**
* Returns a project property. If it is does not exists, return null. Project properties can be either defined on the
* command line via -P or in the gradle.properties file.
*/
def getPropertyValue(String key) {
return project.hasProperty(key) ? project."$key" : null
}
/**
This returns the major version of Idea. We're not really interested in the version itself
as much as whether its a version we support. It could also be used going forward to support
multiple versions of Idea simultaneously.
*/
def getIdeaBuildVersion(File ideaDirectory) {
File buildFile = new File(ideaDirectory, 'build.txt')
if (!buildFile.exists())
throw new RuntimeException('Path to Idea invalid (\'' + path + '\'). Expected to find \'build.txt\' in this directory.')
String version = buildFile.getText()
if (version == null || version.isEmpty())
throw new Exception("Cannot determine Idea version. Trying to find version from file: " + buildFile)
//the 9 versions changed their version strings to a 2-character code, followed by a decimal
if (version.startsWith("IU-") ||
version.startsWith("IC-")) {
//at this point, we know its at least version 9.
return 9 //could check for other versions, but we're not doing anything with that info
}
//all other versions were just an integer build number.
Integer versionNumber = Integer.parseInt(version)
//we'll just check some versions we know about.
if (versionNumber <= 9952) //8.1.4
{
if (versionNumber <= 7491) //7.0.4
return 7
return 8
}
throw new Exception("Cannot determine Idea version (" + version + "). Trying to find version from file: " + buildFile)
}
//this gets the lib directory underneath Idea
def determineIdeaLibDirectory(){ return determineSafeIdeaSubDirectory( "lib") }
def determineIdeaBuildInPluginDirectory() { return determineSafeIdeaSubDirectory( "plugins") }
/**
This returns a subdirectory of the Idea home directory. If there is no Idea home directory
defined, this returns null
*/
def determineSafeIdeaSubDirectory( String subdirectory )
{
File ideaDirectory = getIdeaDirectory()
if( ideaDirectory == null )
return null;
return new File( ideaDirectory, subdirectory );
}
/**
This returns a jar named 'prefix[version].jar'. We want to ignore the version. This is only expecting a single
version of the jar to exist and throws an exception if it finds multiples. This could be altered in the future
to get the latest version.
*/
def getVersionedJar(File libDirectory, String prefix) {
if (!libDirectory.exists()) {
return null
}
//try to get the gradle.jar. It'll be "gradle-[version].jar"
File[] files = libDirectory.listFiles().findAll { it.name.toLowerCase().startsWith(prefix) && it.name.toLowerCase().endsWith('.jar') }
if (files == null || files.length == 0) {
return null
}
//if they've given us a directory with multiple gradle jars, tell them. We won't know which one to use.
if (files.length > 1) {
throw new RuntimeException(
'multiple "' + prefix + '" jars found. Cannot determine which one to use. Found files: ' + files)
}
return files[0]
}
/**
Temporary function to get the gradle-open-api jar to compile against. This defines the version of gradle the
plugin works with. We'll try to find it based on the current gradle.home. However, you may want
to build against a different version than the gradle you're building with (building for an older or newer version),
so we also allow you to override it's expected location.
*/
def getOpenAPIJar( boolean verify ) {
def openAPIJar = getPropertyValue("open-api.home")
if (openAPIJar == null) {
def gradleHome = getPropertyValue("gradle.home") ?: gradle.gradleHomeDir as String
if (gradleHome != null)
openAPIJar = gradleHome + "/lib"
}
File jar = null
if (openAPIJar != null) {
File parentDirectory = new File(openAPIJar)
jar = getVersionedJar(parentDirectory, 'gradle-open-api-')
}
if( verify )
{
if (jar == null )
throw new RuntimeException('Could not locate gradle-open-api jar. It will be determined from the currently running gradle\'s \'gradle.home\', or you can specify it as \'open-api.home\' as a java system property or gradle property. Its the path to the directory where the open-api jar is located.')
if ( !jar.exists() )
throw new RuntimeException("gradle-open-api jar doesn't exist. Looking at '" + jar.getAbsolutePath() + "'" )
}
return jar
}
def verifyFilesExist(List files) {
Iterator iterator = files.iterator()
while (iterator.hasNext()) {
File file = (File) iterator.next()
if (!file.exists())
throw new RuntimeException("File does not exist: " + file)
}
}
/**
This returns the value of an Idea file property. This comes from a file (created by IntelliJ)
that defines several locations and properties used by Idea.
*/
def getIdeaFileProperty(String propertyName) {
String osName = System.getProperty("os.name")
if (osName.equalsIgnoreCase("mac os x")) //we have to do something different for OS X
return getIdeaFilePropertyFromInfoPlist(propertyName)
return getIdeaFilePropertyInternal(propertyName)
}
/**
This returns the value of an Idea file property. This version is used on Windows and Linux.
*/
def getIdeaFilePropertyInternal(String propertyName) {
Properties props = new Properties()
new File(ideaDirectoryVar, 'bin/idea.properties').withReader { props.load it }
String path = props[propertyName]
if (path == null)
return null
path = path.replace('${user.home}', System.getProperty('user.home'))
return new File(path)
}
/**
This returns the value of an Idea file property when running on OS X. OS X uses info.plist files
which are really just xml but made to be SAX parser friendly as the elements are ordered where
one node is the key and its following sibling is the value. Instead of using attributes, they
use the xml 'text content'.
*/
def getIdeaFilePropertyFromInfoPlist(String propertyName) {
File infoPlistFile = new File(ideaDirectoryVar, 'Contents/info.plist')
if (!infoPlistFile.exists())
throw new RuntimeException("Could not find Idea's info.plist file. Expected at '" + infoPlistFile.getAbsolutePath() + "'")
def xml = new XmlParser().parse(infoPlistFile)
//I don't like this, but we'll do a BREADTH first search and when we find the sought node, we'll
//get the next node we come to. The properties are buried multiple levels deep. I would have
//preferred to find the property then get its sibling, but that wasn't working (parent().children()
//always returned an empty list). As it is, this seems very fragile.
boolean stopNextTime;
def valueNode = xml.breadthFirst().find
{
def stopThisTime = stopNextTime //we were instructed to stop the next time around (we're now at the next time)
stopNextTime = propertyName.equals(it.text())
return stopThisTime
}
if (valueNode == null)
return null
def path = valueNode.text()
path = path.replace('~', System.getProperty('user.home'))
return new File(path)
}
task wrapper(type: Wrapper) {
gradleVersion = '0.9.1'
}
/**
This deletes an existing Gradle GUI plugin in the users plugin directory.
*/
def deleteExistingPlugin( File userPluginsDirectory )
{
userPluginsDirectory.eachFile( {
if( isGradlePlugin( it ) )
{
if( it.isFile() )
ant.delete( file: it.getAbsoluteFile() )
else
ant.delete( dir: it.getAbsoluteFile() )
}
} )
}
/**
Determines if the given file is a gradle plugin file/directory. We have to track files made
by this project (current and older versions) as well as ones modified by Idea (once submitted
to IntelliJ).
*/
boolean isGradlePlugin( File file )
{
String lowerCaseFileName = file.getName().toLowerCase()
if( file.isDirectory() )
{
//is it the first version of the plugin? It wasn't yet packaged into a single jar and was in sub directory 'gradle gui/lib'
if( lowerCaseFileName.toLowerCase().startsWith( 'gradle gui' ) )
return true
}
//at this point, we know its a file.
if( lowerCaseFileName.endsWith( '.jar' ) )
{
//If you download it inside Idea, the jar file is renamed so spaces are underscores and
//it appends a version number to it. Ex: "Gradle_GUI_7976.jar"
if( lowerCaseFileName.startsWith( 'gradle_gui_' ) )
return true
//early versions were gradle gui with a space. People complained (I guess they used command line tools frequently and the space complicated things).
if( lowerCaseFileName.startsWith( 'gradle gui') )
return true
}
//does it have the same name we're currently building?
String currentPluginName = getBuiltPluginFile().getName()
if( file.getName().equals( currentPluginName ) )
return true
return false
}
/**
This verifies that certain required files (like Idea's home directory)
are defined and throws an exception if not. This is actually intended to
provide the user with useful feedback if they attempt to execute some
code when things aren't setup properly.
Mostly, this is here so you can get a task list without an error (because
you failed to specify Idea's home), but you will then be told of an error
when you attempt to execute a task (and have failed to specify Idea's home).
*/
def assertRequiredFilesDefined()
{
//make sure Idea's home is defined properly
File ideaDirectory = determineIdeaDirectory()
if (ideaDirectory== null)
throw new RuntimeException('You must specify the path to Idea as the system property \'idea.home\'.')
if (!ideaDirectory.exists())
throw new RuntimeException('Path to Idea invalid (\'' + ideaDirectory + '\'). You must specify the path to Idea as \'idea.home\' as a java system property or gradle property.')
int version = getIdeaBuildVersion(ideaDirectory)
if (version < 9)
throw new RuntimeException("Invalid version of Idea. This requires version 9 or higher.")
//verify the lib and plugin files exist
getIdeaLibFiles( true )
getIdeaPluginFiles( true )
getOpenAPIJar( true )
}
//ensure you can't do a build unless you've verified certain things exist
compileJava.doFirst { assertRequiredFilesDefined() }