/
buildExtension.gradle
328 lines (266 loc) · 11.1 KB
/
buildExtension.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
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.tools.ant.filters.ReplaceTokens
defaultTasks 'buildExtension'
apply plugin: 'java-library'
/*****************************************************************************************
*
* Reads the application.properties file and sets properties for the version,
* release name, and distro prefix (ghidira_<version>)
*
*****************************************************************************************/
def ghidraInstallDir = file(buildscript.sourceFile.getAbsolutePath() + "/../..").getCanonicalFile().getAbsolutePath()
def ghidraDir = file(ghidraInstallDir + "/Ghidra").getCanonicalFile().getAbsolutePath()
def ghidraProps = new Properties()
file(ghidraDir + "/application.properties").withReader { reader ->
ghidraProps.load(reader)
project.ext.ghidra_version = ghidraProps.getProperty('application.version')
project.ext.RELEASE_NAME = ghidraProps.getProperty('application.release.name')
project.ext.DISTRO_PREFIX = "ghidra_${ghidra_version}"
project.ext.GRADLE_MINIMUM_VERSION = ghidraProps.getProperty('application.gradle.min')
}
/***************************************************************************************
* Make sure the correct version of gradle is being used
***************************************************************************************/
import org.gradle.util.GradleVersion;
final GradleVersion minimum_version = GradleVersion.version("${GRADLE_MINIMUM_VERSION}")
if (GradleVersion.current() < minimum_version) {
throw new GradleException("Requires at least $minimum_version, but was run with $gradle.gradleVersion")
}
configurations {
helpPath
}
artifacts {
helpPath jar
}
task copyDependencies(type: Copy) {
from configurations.runtimeClasspath
into "lib"
exclude { fileTreeElement ->
def fileAbsPath = fileTreeElement.getFile().getCanonicalFile().toPath()
// Avoid including Ghidra Jars in lib folder...
def isGhidraJar = fileAbsPath.startsWith(ghidraInstallDir)
// ...and jars already in the destination location
def destLibDir = project.file("lib").getCanonicalFile().toPath()
def isFromDest = fileAbsPath.startsWith(destLibDir)
return isGhidraJar || isFromDest
}
}
compileJava {
sourceCompatibility = ghidraProps.getProperty('application.java.compiler')
targetCompatibility = ghidraProps.getProperty('application.java.compiler')
dependsOn copyDependencies
}
dependencies {
api fileTree(dir: 'lib', include: "*.jar")
api fileTree(dir: ghidraDir + '/Framework', include: "**/*.jar")
api fileTree(dir: ghidraDir + '/Features', include: "**/*.jar")
api fileTree(dir: ghidraDir + '/Debug', include: "**/*.jar")
api fileTree(dir: ghidraDir + '/Processors', include: "**/*.jar")
helpPath fileTree(dir: ghidraDir + '/Features/Base', include: "**/Base.jar")
}
def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}_${getCurrentDate()}"
def DISTRIBUTION_DIR = file("dist")
def pathInZip = "${project.name}"
task zipSource (type: Zip) {
// Define some metadata about the zip (name, location, version, etc....)
it.archiveBaseName = project.name + "-src"
it.archiveExtension = 'zip'
it.destinationDirectory = file(project.projectDir.path + "/build/tmp/src")
// We MUST copy from a directory, and not just grab a list of source files.
// This is the only way to preserve the directory structure.
it.from project.projectDir
it.include 'src/**/*'
}
task buildExtension (type: Zip) {
archiveBaseName = "${ZIP_NAME_PREFIX}_${project.name}"
archiveExtension = 'zip'
destinationDirectory = DISTRIBUTION_DIR
archiveVersion = ''
// Make sure that we don't try to copy the same file with the same path into the
// zip (this can happen!)
duplicatesStrategy 'exclude'
// This filtered property file copy must appear before the general
// copy to ensure that it is prefered over the unmodified file
File propFile = new File(project.projectDir, "extension.properties")
from (propFile) {
String version = "${ghidra_version}"
String name = "${project.name}"
filter (ReplaceTokens, tokens: [extversion: version])
filter (ReplaceTokens, tokens: [extname: name])
into pathInZip
}
from (project.jar) {
into pathInZip + "/lib"
}
from (project.projectDir) {
exclude 'build/**'
exclude '*.gradle'
exclude 'certification.manifest'
exclude 'dist/**'
exclude 'bin/**'
exclude 'src/**'
exclude '.gradle/**'
exclude '.classpath'
exclude '.project'
exclude '.settings/**'
exclude 'developer_scripts'
exclude '.antProperties.xml'
exclude 'gradlew'
exclude 'gradlew.bat'
exclude 'gradle/wrapper/gradle-wrapper.jar'
exclude 'gradle/wrapper/gradle-wrapper.properties'
into pathInZip
}
/////////////////
// SOURCE
/////////////////
from (tasks["zipSource"]) {
into pathInZip + "/lib"
}.dependsOn(zipSource)
/////////////////
// GLOBALS
/////////////////
// First get a list of all files that are under 'src/global'.
FileTree fileTree = project.fileTree('src/global') {
include '**/*'
}
// Now loop over each one, copying it into the zip we're creating. Each will be placed
// at the root level, starting with the first folder AFTER 'src/global/'.
//
// eg: If the file is '/Ghidra/Extensions/Sample/src/global/docs/hello.html', then
// the file in the zip will be at /docs/hello.html
//
fileTree.each { File file ->
String filePath = stripGlobalFilePath(file)
from (file) {
into filePath
}
}
doLast {
println "\nCreated " + archiveBaseName + "." + archiveExtension + " in " + destinationDirectory
}
}
// task for calling the java help indexer
task indexHelp(type: JavaExec) {
File helpRootDir = file('src/main/help') // this the root dir for the help source
File outputFile = file("build/help/main/help/${project.name}_JavaHelpSearch")
onlyIf {helpRootDir.exists()}
dependsOn configurations.helpPath
inputs.dir helpRootDir
outputs.dir outputFile
classpath = sourceSets.main.runtimeClasspath // this modules runtime classpath (contains jhall.jar)
mainClass = 'com.sun.java.help.search.Indexer' // main class to call
// tell the indexer where send its output
args '-db', outputFile.absolutePath
// The index has a config file parameter. The only thing we use in the config file
// is a root directory path that should be stripped off all the help references to
// make them relative instead of absolute
File configFile = file('build/helpconfig') // this is the config file that we will create
// create the config file when the task runs and not during configuration.
doFirst {
configFile.parentFile.mkdirs();
configFile.write "IndexRemove ${helpRootDir.absolutePath}" + File.separator + "\n"
}
// pass the config file we created as an argument to the indexer
args '-c',"$configFile"
// gather up all the help files into a file collection
FileTree helpFiles = fileTree('src/main/help') {
include '**/*.htm'
include '**/*.html'
}
doFirst {
// for each help file that was found, add it as an argument to the indexer
helpFiles.each { File file ->
args "${file.absolutePath}"
}
}
group "private"
description "indexes the helps files for this module. [gradle/helpProject.gradle]"
}
// task for building Ghidra help files - depends on the output from the help indexer
task buildHelp(type: JavaExec, dependsOn: indexHelp) {
File helpRootDir = file('src/main/help/help') // help root where topics dir lives
File outputDir = file('build/help/main/help') // dir where we want the help files to be generated
onlyIf {helpRootDir.exists()}
inputs.dir helpRootDir
outputs.dir outputDir
classpath = sourceSets.main.runtimeClasspath // this modules runtime classpath (contains jhall.jar)
mainClass = 'help.GHelpBuilder' // program to run to build help files.
args '-n', "${project.name}" // use the modules name as the base for the help file name
args '-o', "${outputDir.absolutePath}" // set the output directory arg
doFirst {
configurations.helpPath.each {
args "-hp"
args "${it.absolutePath}"
}
args "${helpRootDir.absolutePath}" // tell the help builder what help dir to process
}
description " Builds the help for this module. [gradle/helpProject.gradle]\n"
}
// include the help into the module's jar
jar {
from "build/help/main" // include the generated help index files
from "src/main/help" // include the help source files
archiveVersion = ""
}
// build the help whenever this module's jar file is built
jar.dependsOn 'buildHelp'
/*********************************************************************************
* Takes the given file and returns a string representing the file path with everything
* up-to and including 'src/global' removed, as well as the filename.
*
* eg: If the file path is '/Ghidra/Configurations/Common/src/global/docs/hello.html',
* the returned string will be at /docs
*
* Note: We have to use 'File.separator' instead of a slash ('/') because of how
* windows/unix handle slashes ('/' vs. '\'). We only need to do this in cases where we're
* using java string manipulation libraries (eg String.replace); Gradle already
* understands how to use the proper slash.
*********************************************************************************/
String stripGlobalFilePath(File file) {
// First strip off everything before 'src/global/ in the file path.
def slashIndex = file.path.indexOf('src' + File.separator + 'global')
String filePath = file.path.substring(slashIndex);
// Now remove 'src/global/' from the string.
filePath = filePath.replace('src' + File.separator + 'global' + File.separator, "");
// Now we need to strip off the filename itself, which we do by finding the last
// instance of a slash ('/') in the string. Unfortunately, groovy doesn't give
// us a "lastIndexOf('/')" or something nice like that, so we reverse the string
// and look for the slash that way, remove the filename, then reverse it back.
//
// Note that it's possible there is no slash (all we have is a filename), meaning
// this file will be placed at the root level.
//
String reverseFilePath = filePath.reverse()
slashIndex = reverseFilePath.indexOf(File.separator)
if (slashIndex != -1) {
reverseFilePath = reverseFilePath.substring(slashIndex)
filePath = reverseFilePath.reverse()
}
else {
filePath = ""
}
return filePath
}
/*********************************************************************************
* Returns the current date formatted as yyyyMMdd.
*********************************************************************************/
def getCurrentDate() {
def date = new Date()
def formattedDate = date.format('yyyyMMdd')
return formattedDate
}