-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinstallUtils.gradle
596 lines (548 loc) · 32.7 KB
/
installUtils.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
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Gradle tasks and methods for creating installers, including the staging of exeuctables in sigma-web, s-cgi and similar directories.
// To use this add this line to the root gradle file:
// apply from: 'installUtils.gradle'
def getDebugState(Project prj) {
// May be enchanced to enable debugging for certain project names.
def rv = true//false
return rv
}
// Will create (and return) a debug or release aggregate task (e.g. legacyInstaller) in a target project,
// with the suffix 'Debug' or 'Release'.
// Then it will walk up the project tree, creating the same aggregate task if needed, and setting dependencies.
// If the target task already exists, it will just be returned.
def getOrCreateAggregateTaskForSubproject(Project prj, String taskNamePrefix, String descr, Boolean wantDebug) {
String methodName = 'gOCATFS'
def taskName = taskNamePrefix + (wantDebug ? 'Debug' : 'Release')
def groupName = wantDebug ? 'debugGroup' : 'releaseGroup'
def fullDesc = descr + (wantDebug ? ' - Debug' : ' - Release')
def stdAggTaskName = wantDebug ? 'debug' : 'release'
def debugOn = getDebugState(prj)
if(debugOn) {
println "Debug(${methodName}): getOrCreateAggregateTaskForSubproject: prj=${prj.path}, descr=${descr}, wantDebug=${wantDebug}"
}
// Loop up the path from the passed in project, creating the aggregate task as we go, making it depend on the descendant's aggregate task.
def tPrj = prj
def childTask = null
while(tPrj != null) {
// Get the aggregate task at this level, create it if it doesn't exist.
def newTask = tPrj.tasks.findByName(taskName)
if(newTask == null) {
newTask = tPrj.tasks.create(taskName)
newTask.group = getRootProject().property(groupName)
newTask.description = fullDesc
if(debugOn) { println "Debug(${methodName}): Created aggregate project task ${newTask.name} for project ${tPrj.path}, group=" + newTask.group }
}
// Make the new task at this level depend on the child task (from the previous loop iteration), if there is one.
if(childTask){
if(debugOn) { println "Debug(${methodName}): Setting aggregate project task named ${tPrj.path}:${newTask.name} to depend on child prj task ${childTask.name} for original input project ${prj.path}"}
newTask.dependsOn(childTask)
}
// Make the aggregate task at this level depend on the new task (from the previous loop iteration), if there is one.
if(debugOn) { println "Debug(${methodName}): Setting standard aggregate project task named ${tPrj.path}:${stdAggTaskName} to depend on new agg task ${newTask.name} for original input project ${prj.path}"}
tPrj.tasks.findByName(stdAggTaskName).dependsOn(newTask)
// Set up for next loop iteration.
tPrj = tPrj.parent
childTask = newTask
}
def rv = prj.tasks.findByName(taskName)
if(debugOn) {println "Debug(${methodName}): returning task ${prj.path}:${rv.name}."}
return rv
}
////////////////////////////////////////////////////////////////
// Add an addProjOutputCopyFilesTask task to any subproject that has an "extra" property with a name matching the value of projMapPropName.
// The property is a map where the key is the file name that the CppApplication is producing,
// that is the output of a LinkExecutable task.
// and the value is a File, or List of Files specifying where the executable should be copied.
//
// This code is based on this snippet from "thadhouse" on the gradle native slack channel, 2020-07-13.
// def copyToTask = tasks.register("copyToOutputsInApp", Copy) {
// into "$buildDir/outputs"
// }
// application.binaries.whenElementFinalized { binary ->
// if (binary.name.endsWith('Debug')) {
// copyToTask.configure {
// it.dependsOn binary.linkTask
// it.from binary.linkTask.get().linkedFile
// }
// }
// }
//
// TODO: This method is too big, I should at least take the code that is duplicated for debug/release and move
// it into a new method, then call it once for debug and one for release.
def addProjOutputCopyFilesTask(Project prj, Project parent, String taskPrefix, String projMapPropName, String basePath, String descr, Boolean wantTasksInParent) {
String methodName = 'aPOCFT'
def debugTasks = [:]
def releaseTasks = [:]
def tgtPrj = wantTasksInParent ? parent : prj
def debugOn = getDebugState(prj)
if(debugOn) {
println "Debug(${methodName}): Called for project ${prj.path}, parent ${parent? parent.path : 'null parent'}, taskPrefix=${taskPrefix}, projMapPropName=${projMapPropName ?: 'null'}, wantTasksInParent=${wantTasksInParent}"
}
// Create an aggregate debug task in the project, parent and root, this task will reference all the individual debug copy tasks.
if(debugOn) {
println "Debug(${methodName}): addProjOutputCopyFilesTask calling getOrCreateAggregateTaskForSubproject for prj=${prj.path}, parent=${parent.path}}"
}
def dbgAggTask = getOrCreateAggregateTaskForSubproject(tgtPrj, taskPrefix, descr, true)
def dbgCopyAllTask = tgtPrj.tasks.findByName(dbgAggTask.name + '_CopyAll')
if(dbgCopyAllTask == null) {
dbgCopyAllTask = tgtPrj.tasks.create(dbgAggTask.name + '_CopyAll')
}
// This task might have been created from a project that wasn't able to set the
// dependency, so we'll always set it, whether we created it or not.
if(debugOn) { println "Debug(${methodName}): Setting dbgAggTask task ${dbgAggTask.path} to depend on new prj task ${dbgCopyAllTask.path}."}
dbgAggTask.dependsOn(dbgCopyAllTask)
// Create an aggregate release task in the project, parent and root, this task will reference all the individual release copy tasks.
def relAggTask = getOrCreateAggregateTaskForSubproject(tgtPrj, taskPrefix, descr, false)
def relCopyAllTask = tgtPrj.tasks.findByName(relAggTask.name + '_CopyAll')
if(relCopyAllTask == null) {
relCopyAllTask = tgtPrj.tasks.create(relAggTask.name + '_CopyAll')
}
relAggTask.dependsOn(relCopyAllTask)
// The subproject contains a line like this mapping a directory key to a filename value:
// ext.projMapPropName = [ (file("c:/temp/target/dir")) : "foo" ]
// The filename could be an array of filenames:
// ext.projMapPropName = [ (file("c:/temp/target/dir")) : ["bar", "foo" ]
// Or it could be a map containing filenames and options:
// ext.projMapPropName = [ (file("c:/temp/target/dir")) : ["codeSign":true,"fileBasename":"foo" ]]
// Or even an array of maps:
// ext.projMapPropName = [ (file("c:/temp/target/dir")) : [
// ["codeSign":true,"fileBasename":"foo"],
// ["codeSign":false,"fileBasename":"bar"]
// ]
prj.property(projMapPropName).eachWithIndex { path, fileBasename, idx ->
// Resolve the passed in (optional) basepath with the path from the map.
// Handle the cases where the path from the map is a string and where it's a File.
def File targetPath
if(basePath == null) {
if(path instanceof java.io.File) {
targetPath = path
if(debugOn) {
println "Debug(${methodName}): resolved basePath:null and file path:${path.path} to : ${targetPath.path} for project ${tgtPrj.path}"
}
} else {
targetPath = file(path)
if(debugOn) {
println "Debug(${methodName}): resolved basePath:null and file string:${path} to : ${targetPath.path} for project ${tgtPrj.path}"
}
}
} else {
if(path instanceof java.io.File) {
targetPath = file(basePath + '/' + path.path)
if(debugOn) {
println "Debug(${methodName}): resolved basePath:${basePath} and file path:${path.path} to : ${targetPath.path} for project ${tgtPrj.path}"
}
} else {
targetPath = file(basePath + '/' + path)
if(debugOn) {
println "Debug(${methodName}): resolved basePath:${basePath} and file string:${path} to : ${targetPath.path} for project ${tgtPrj.path}"
}
}
}
if(debugOn) {
println "Debug(${methodName}): handling project ${prj.name}, ${projMapPropName} index ${idx}, target file name=${fileBasename}, target path=${targetPath.path} for project ${tgtPrj.path}"
}
///// Handle the target filename(s), turn them into an array, even if there's only one.
def fnameList = []
if(fileBasename instanceof java.util.ArrayList) {
// We have multiple values, so just set the array to the incoming array.
fnameList = fileBasename
} else {
// We have a single file value, so push it into the array.
fnameList.push(fileBasename)
}
fnameList.eachWithIndex { fname, idx2 ->
///// Check to see if what we think is the file name is actually a map, which may include some option settings.
Boolean shouldSign = false
Boolean addExeOrDllSuffix = true
String outputFilename = null
String src_path = prj.buildDir.path
if(fname instanceof Map) {
def targetMap = fname
fname = null
if(debugOn) {println "Debug(${methodName}): Handling map instead of file name for project ${tgtPrj.path}."}
if(targetMap.containsKey('codeSign')) {
if(isWindows) {
shouldSign = targetMap['codeSign']
} else {
println "codeSign option ignored on Linux for ${tgtPrj.path}."
}
if(debugOn) {println "Debug(${methodName}): Debug: shouldSign=${shouldSign}"}
} else {
if(debugOn) {println "Debug(${methodName}): Debug: shouldSign=false"}
}
if(targetMap.containsKey('fileBasename')) {
fname = targetMap['fileBasename']
if(debugOn) {println "Debug(${methodName}): fname=${fname} for project ${tgtPrj.path}"}
}
if(targetMap.containsKey('addExeOrDllSuffix')) {
addExeOrDllSuffix = targetMap['addExeOrDllSuffix']
if(debugOn) {println "Debug(${methodName}): addExeOrDllSuffix=${addExeOrDllSuffix} for project ${tgtPrj.path}"}
}
if(targetMap.containsKey('outputFilename')) {
outputFilename = targetMap['outputFilename']
if(debugOn) {println "Debug(${methodName}): outputFilename=${outputFilename} for project ${tgtPrj.path}"}
}
if(targetMap.containsKey('src_path')) {
src_path = targetMap['src_path']
if(debugOn) {println "Debug(${methodName}): src_path=${src_path} for project ${tgtPrj.path}"}
}
} else if (fname instanceof String) {
if(debugOn) { println "Debug(${methodName}): fname=${fname} for project ${tgtPrj.path}"}
}
if(outputFilename == null) {
outputFilename = fname
}
if(debugOn) {println "Debug(${methodName}): fname after resolution is ${fname}"}
def targetFilename = fname
def isWindows = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem.isWindows()
if(addExeOrDllSuffix) {
// Sanity check, the file names in ext.${projMapPropName} should not contain ".exe" or ".dll", as we will add that
// below if we're running on windows.
if(fname.endsWith('.exe')) {
throw new GradleException("Stopping build because the ext.${projMapPropName} setting for subproject ${prj.name} contains .exe as part of the filename.")
}
if(fname.endsWith('.dll')) {
throw new GradleException("Stopping build because the ext.${projMapPropName} setting for subproject ${prj.name} contains .dll as part of the filename.")
}
if(prj.hasProperty('library')) {
if(isWindows){
targetFilename += ".dll"
outputFilename += ".dll"
} else {
targetFilename += ".so"
outputFilename += ".so"
}
} else {
if(isWindows) {
targetFilename += ".exe"
outputFilename += ".exe"
}
}
}
//////////////// Debug Tasks
// Use the dynamic API for task inputs and outputs to configure a copy task that we won't execute, but it is
// used later as an input the the copy method, alowing us to execute a single task that does the copy and the
// signtool step.
// See https://docs.gradle.org/current/userguide/working_with_files.html#sec:copying_multiple_files_example
// search for Example 41. Copying files using the copy() method with up-to-date check
def dbgTaskName = "${taskPrefix}DebugCopy_${prj.name}_${idx}_${idx2}"
if(debugOn) {println "Debug(${methodName}): about to register debug copy task name ${tgtPrj.path}:${dbgTaskName} for file name ${fname}"}
// This task will be invoked via the copy method from the next task we define.
def newDebugCopyTask = tgtPrj.tasks.register(dbgTaskName + '_CopyOnly', Copy) {
rename { return outputFilename } // Name the file as specified, may not actually be a different name, but this works either way.
// This causes the exec task to have the Source directory as an input, which isn't good.
//into targetPath.path
// I don't think this is needed.
//outputs.file(targetPath.path + "/" + targetFilename)
setDescription("Copy file ${src_path}/${targetFilename} to path ${targetPath.path}.")
doLast {
if(debugOn) {
println "Debug(${methodName}): ${it.name} in copyTask, copying debug file named ${targetFilename} to ${targetPath.path}"
dumpTaskToJson(tgtPrj,it, file(tgtPrj.projectDir), "${it.name}_from_copyTask.json")
}
}
}
def newDebugTask = tgtPrj.tasks.register(dbgTaskName) {
if(addExeOrDllSuffix) {
if(debugOn) {
println "Debug(${methodName}): Registering debug task named ${tgtPrj.path}:${name} for file named ${targetFilename}, with inputs from ${newDebugCopyTask}, inputs=${inputs.files(newDebugCopyTask)}"
String ifiles = ""
it.inputs.files.each { f ->
ifiles += ",${f.path} "
}
println "Debug(${methodName}): ExecTask ${tgtPrj.path}:${name} inputs before adding inputs from copyTask: ${ifiles}"
dumpTaskToJson(tgtPrj,it, file(tgtPrj.projectDir), "${it.name}_from_generic_task_1.json")
}
inputs.files(newDebugCopyTask)
.withPropertyName("inputs")
.withPathSensitivity(PathSensitivity.RELATIVE)
} else {
// For use with a .cnf file or something like that. We don't want to depend on the link task,
// we want to depend on the file itself.
if(debugOn) {
println "Debug(${methodName}): Registering debug task named ${tgtPrj.path}:${name} for file named ${targetFilename}, with input file from project ${prj.path}:${prj.name}: ${src_path}/${targetFilename}"
}
inputs.file("${src_path}/${targetFilename}")
}
outputs.file(targetPath.path + "/" + outputFilename)
doLast {
if(debugOn) {
println "Debug(${methodName}): ${it.name} in debug copy/sign task, copying file ${targetFilename} " +
"to ${targetPath.path}/${outputFilename} using task ${newDebugCopyTask.name}."
dumpTaskToJson(tgtPrj,it, file(tgtPrj.projectDir), "${it.name}_from_generic_task_3.json")
}
copy {
from inputs.files
rename { return outputFilename } // Name the file as specified, may not actually be a different name, but this works either way.
into targetPath.path
}
if(shouldSign) {
if(debugOn) {println "Debug(${methodName}): ${it.name} in newDebugTask register call, should sign is on for file ${targetFilename} to ${targetPath.path}."}
exec { commandLine 'signtool', 'sign', '/fd', 'SHA256', '/a', '/v', '/f', getRootProject().property('codeSignCert'),
'/p', getRootProject().property('codeSignPassword'), "${targetPath.path}/${targetFilename}" }
}
}
}
// Map of the copy/sign task to a map with the code sign setting, and the copy task, which will have the input set later based on the build variant.
if(debugOn) {println "Debug: pushing debug task ${newDebugTask.name}, shouldSign=${shouldSign}, copy only task named ${newDebugCopyTask.name}, file ${targetFilename}, outputFilename ${outputFilename}, targetPath ${targetPath.path} for project=${tgtPrj.path}"}
debugTasks[newDebugTask] = [
'codeSign':shouldSign,
'copyTask':newDebugCopyTask,
'addExeOrDllSuffix':addExeOrDllSuffix
]
//////////////// Release Tasks
def relTaskName = "${taskPrefix}ReleaseCopy_${prj.name}_${idx}_${idx2}"
if(debugOn) {println "Debug(${methodName}): about to register release copy task name ${tgtPrj.path}:${relTaskName} for file name ${fname}"}
def newReleaseCopyTask = tgtPrj.tasks.register(relTaskName + '_CopyOnly', Copy) {
rename { return outputFilename } // Name the file as specified, may not actually be a different name, but this works either way.
// This causes the exec task to have the Source directory as an input, which isn't good.
//into targetPath.path
// I don't think this is needed.
//outputs.file(targetPath.path + "/" + targetFilename)
doLast {
if(debugOn) {
println "Debug(${methodName}): ${it.name} in copyTask, copying release file named ${targetFilename} to ${targetPath.path}"
dumpTaskToJson(tgtPrj,it, file(tgtPrj.projectDir), "${it.name}_from_copyTask.json")
}
}
}
def newReleaseTask = tgtPrj.tasks.register(relTaskName) {
if(addExeOrDllSuffix) {
if(debugOn) {
println "Debug(${methodName}): Registering release task named ${tgtPrj.path}:${name} for file named ${targetFilename}, with inputs from ${newReleaseCopyTask}, inputs=${inputs.files(newReleaseCopyTask)}"
}
inputs.files(newReleaseCopyTask)
.withPropertyName("inputs")
.withPathSensitivity(PathSensitivity.RELATIVE)
} else {
// For use with a .cnf file or something like that. We don't want to depend on the link task,
// we want to depend on the file itself.
if(debugOn) {
println "Debug(${methodName}): Registering release task named ${tgtPrj.path}:${name} for file named ${targetFilename}, with input file from project ${prj.path}:${prj.name}: ${src_path}/${targetFilename}"
}
inputs.file("${src_path}/${targetFilename}")
}
outputs.file(targetPath.path + "/" + outputFilename)
doLast {
if(debugOn) {
println "Debug(${methodName}): ${it.name} in release copy/sign task, copying file ${targetFilename} to ${targetPath.path} using task ${newReleaseCopyTask.name}"
dumpTaskToJson(tgtPrj,it, file(tgtPrj.projectDir), "${it.name}_from_generic_task_1.json")
}
copy {
from inputs.files
rename { return outputFilename } // Name the file as specified, may not actually be a different name, but this works either way.
into targetPath.path
}
if(shouldSign) {
if(debugOn) {println "Debug(${methodName}): ${it.name} in newReleaseTask register call, should sign is on for file ${targetFilename} to ${targetPath.path}."}
exec { commandLine 'signtool', 'sign', '/fd', 'SHA256', '/a', '/v', '/f', getRootProject().property('codeSignCert'),
'/p', getRootProject().property('codeSignPassword'), "${targetPath.path}/${targetFilename}" }
}
}
}
// Map of the copy/sign task to a map with the code sign setting, and the copy task, which will have the input set later based on the build variant.
if(debugOn) {println "Debug: pushing release task ${newReleaseTask.name}, shouldSign=${shouldSign}, copy only task named ${newReleaseCopyTask.name}, file ${targetFilename}, outputFilename ${outputFilename}, targetPath ${targetPath.path} for project=${tgtPrj.path}"}
releaseTasks[newReleaseTask] = [
'codeSign':shouldSign,
'copyTask':newReleaseCopyTask,
'addExeOrDllSuffix':addExeOrDllSuffix
]
}
}
// When each referenced task has been finalized, set the dependencies for the copy tasks that we created, we can't do it before that time.
prj.components.main.binaries.whenElementFinalized { binary ->
if (binary.name.endsWith('Debug')) {
if(debugOn) {println "Debug(${methodName}): about to configure ${debugTasks.size()} debug tasks."}
debugTasks.each { et, optionMap ->
def copyTask = optionMap['copyTask']
if(debugOn) { println "Debug: configuring debug task ${et.name}, copytask=${copyTask.name}" }
if(optionMap['addExeOrDllSuffix']) {
copyTask.configure {
if(debugOn) {
println "Debug(${methodName}): Updating debug copy task ${prj.path}:${et.name} for binary ${binary.name}, adding dependency on linker task named ${binary.linkTask.get().name}, setting from file " +
binary.linkTask.get().linkedFile.getAsFile().get().path
String ifiles = ""
it.inputs.files.each { f ->
ifiles += ",${f.path} "
}
println "Debug(${methodName}): CopyTask inputs before adding linked file: ${ifiles}"
}
inputs.file(binary.linkTask.get().linkedFile)
it.dependsOn binary.linkTask
}
et.configure {
if(debugOn) {
println "Debug(${methodName}): Updating debug exec task ${tgtPrj.path}:${et.name} for binary ${binary.name}, adding dependency on linker task named ${binary.linkTask.get().name}, inputs=${binary.linkTask.get().linkedFile}, file=" + binary.linkTask.get().linkedFile.getAsFile().get().name
}
it.dependsOn binary.linkTask
inputs.file(binary.linkTask.get().linkedFile)
}
}
if(debugOn) {
println "Debug(${methodName}): Updating debug task ${tgtPrj.path}:${dbgCopyAllTask.name} which now also dependsOn ${et.name}"
}
dbgCopyAllTask.dependsOn(et)
tgtPrj.tasks.findByName('debug').dependsOn(dbgAggTask)
}
}
if (binary.name.endsWith('Release')) {
if(debugOn) {println "Debug: about to configure ${releaseTasks.size()} debug tasks."}
releaseTasks.each { et, optionMap ->
def copyTask = optionMap['copyTask']
if(debugOn) {println "Debug: configuring release task ${et.name}, copytask=${copyTask.name}"}
if(optionMap['addExeOrDllSuffix']) {
copyTask.configure {
if(debugOn) {
println "Debug(${methodName}): Updating release copy task ${prj.path}:${et.name} for binary ${binary.name}, adding dependency on linker task named ${binary.linkTask.get().name}, setting from file " +
binary.linkTask.get().linkedFile.getAsFile().get().name
}
inputs.file(binary.linkTask.get().linkedFile)
it.dependsOn binary.linkTask
}
et.configure {
if(debugOn) {
println "Debug(${methodName}): Updating release exec task ${tgtPrj.path}:${et.name} for binary ${binary.name}, adding dependency on linker task named ${binary.linkTask.get().name}, inputs=${binary.linkTask.get().linkedFile}."
binary.linkTask.get().linkedFile.getAsFile().get().name
}
it.dependsOn binary.linkTask
inputs.file(binary.linkTask.get().linkedFile)
}
}
if(debugOn) {
println "Debug(${methodName}): Updating release task ${tgtPrj.path}:${relCopyAllTask.name} which now also dependsOn ${et.name}"
}
relCopyAllTask.dependsOn(et)
tgtPrj.tasks.findByName('release').dependsOn(relAggTask)
}
}
}
}
////////////////////////////////////////////////////////////////
// Creates a self extracting old style zip installer, returns maps with the created tasks.
def createZipInstallerTasks(Project prj,
String installerFileName, String installerFilePath,
String productName, String productDescription,
String programDescription, String defaultPath,
String serviceName, String runProgram,
Task toDependOn, String inputPath, String inputIncludeSpec,
Boolean silentInstaller
) {
def rv = [:]
def instTaskNameSuffix = 'Installer'
if(silentInstaller) {
instTaskNameSuffix = 'SilentInstaller'
}
def createParmsHeader = prj.tasks.register("createParmsHFor${instTaskNameSuffix}") {
outputs.file "${prj.projectDir}/parms.h"
file("${prj.projectDir}/parms.h").text = """
#define PROGRAM_DESCR \"${programDescription}\"
#define DEFAULT_PATH \"${defaultPath}\"
#define SERVICE_NAME \"${serviceName}\"
#define RUN_PROGRAM \"${runProgram}\"
"""
}
// TODO: Can I move the application in here too? probably not but would be nice, which means I need to pass in the path, or just assume it's here.
def ZNST = file("${prj.buildDir}/${installerFileName}").path
def BDRY = file("${TopProjDir}/zsfx_inst/zsfx_base/boundary.txt").path
def ZSFX = file("${TopProjDir}/zsfx_inst/zsfx_base/unzipsfx.exe").path
def CSETUP = file("${buildDir}/install/wintools/CSetup.exe").path
def ZPKG = file("${prj.buildDir}/pkg.zip").path
// TODO: should I move the zip in here too? have to get the dependencies right.
// For the moment I'm not doing it because (using command_center.gradle as an example),
// the CCI_stage task then wouldn't have anything to use as an output, so gradle
// would always run the task, which isn't desireable.
// Task to create the installer itself - debug
def debugInstallerTask = prj.tasks.register("createDebug${instTaskNameSuffix}") {
dependsOn(createParmsHeader)
dependsOn(toDependOn)
// The installer tasks need to also depend upon the installer stage/copy task, at least with the way things are set up now.
// TODO Someday, really this should depend on the link task and we should know to use the debug exe,
// but the calling project is currently telling us to take the .exe from the top of the Build directory.
// So this is a bit of a hack, but I'm hoping to do much better when we can move to Nokee.
dependsOn(prj.tasks.findByName('stageDebug_CopyAll'))
inputs.files(
ZNST,
BDRY,
ZSFX,
fileTree(dir:inputPath, include: inputIncludeSpec)
)
outputs.files(installerFilePath)
doLast {
def instFile = file(installerFilePath)
def instFileDir = instFile.getAbsoluteFile().getParent()
if(!file(ZNST).exists()) {
throw new GradleException("Unable to find ZNST file ${ZNST}.");
}
if(!file(BDRY).exists()) {
throw new GradleException("Unable to find BDRY file ${BDRY}.");
}
if(!file(ZSFX).exists()) {
throw new GradleException("Unable to find ZFSX file ${ZSFX}.");
}
if(!file(ZPKG).exists()) {
throw new GradleException("Unable to find ZPKG file ${ZPKG}.");
}
exec {
workingDir "${inputPath}"
if(silentInstaller) {
commandLine "cmd", "/C", "copy", "/b", "${ZNST}+${BDRY}+${ZSFX}+${ZPKG}", instFile.getPath()
} else {
logger.info("Executing command: cmd /C copy /b ${ZNST}+${BDRY}+${ZSFX}+${ZPKG}, ${instFile.getPath()}")
commandLine "cmd", "/C", "copy", "/b", "${ZNST}+${BDRY}+${ZSFX}+${ZPKG}", instFile.getPath()
}
}
exec {
workingDir instFile.getParentFile()
commandLine 'signtool', 'sign', '/fd', 'SHA256', '/a', '/v', '/f', getRootProject().property('codeSignCert'),
'/p', getRootProject().property('codeSignPassword'), instFile.name
}
}
}
tasks.findByName('debug').dependsOn(debugInstallerTask)
rv['debugInstallerTask'] = debugInstallerTask
// Task to create the installer itself - release
def releaseInstallerTask = prj.tasks.create("createRelease${instTaskNameSuffix}") {
dependsOn(createParmsHeader)
dependsOn(toDependOn)
def relCopy = prj.tasks.findByName('stageRelease_CopyAll')
if(relCopy) {
dependsOn(relCopy)
}
inputs.files(
ZNST,
BDRY,
ZSFX,
fileTree(dir:inputPath, include: inputIncludeSpec)
)
outputs.files(installerFilePath)
doLast {
def instFile = file(installerFilePath)
def instFileDir = instFile.getAbsoluteFile().getParent()
exec {
workingDir "${inputPath}"
commandLine "cmd", "/C", "copy", "/b", "${ZNST}+${BDRY}+${ZSFX}+${ZPKG}", instFile.getPath()
}
exec {
workingDir instFile.getParentFile()
commandLine 'signtool', 'sign', '/fd', 'SHA256', '/a', '/v', '/f', getRootProject().property('codeSignCert'),
'/p', getRootProject().property('codeSignPassword'), instFile.name
}
}
}
tasks.findByName('release').dependsOn(releaseInstallerTask)
rv['releaseInstallerTask'] = releaseInstallerTask
return rv
}
// We need to "convert" our groovy method(s) to Closures, otherwise they won't be visible in
// other Gradle files.
// We wouldn't have to do this if these methods were in the root Gradle file, but this way
// we can refactor things to keep the root Gradle file cleaner.
// See https://stackoverflow.com/questions/18715137/extract-common-methods-from-gradle-build-script
ext {
getOrCreateAggregateTaskForSubproject = this.&getOrCreateAggregateTaskForSubproject
addProjOutputCopyFilesTask = this.&addProjOutputCopyFilesTask
createZipInstallerTasks = this.&createZipInstallerTasks
}