@@ -34,13 +34,13 @@ import org.gradle.api.tasks.SourceSet
34
34
import org.gradle.api.tasks.TaskAction
35
35
import org.gradle.api.tasks.compile.AbstractCompile
36
36
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
37
- import org.gradle.api.tasks.incremental.InputFileDetails
38
37
import org.gradle.process.JavaForkOptions
39
38
import org.gradle.process.internal.DefaultJavaForkOptions
40
39
import org.gradle.process.internal.ExecException
41
40
import org.gradle.process.internal.JavaExecHandleBuilder
42
41
import org.gradle.util.ConfigureUtil
43
42
import java.io.File
43
+ import java.io.IOException
44
44
import java.io.OutputStream
45
45
import java.util.*
46
46
import java.util.regex.Pattern
@@ -49,6 +49,7 @@ import javax.inject.Inject
49
49
/* *
50
50
* @author Colin Fleming
51
51
*/
52
+ @Suppress(" unused" )
52
53
class ClojurePlugin : Plugin <Project > {
53
54
val logger = Logging .getLogger(this .javaClass)
54
55
@@ -163,6 +164,12 @@ open class ClojureSourceSetImpl(displayName: String?, resolver: FileResolver?) :
163
164
164
165
class ReflectionWarnings (var enabled : Boolean , var projectOnly : Boolean , var asErrors : Boolean )
165
166
167
+ object FileCopyErrorHandler : (File , IOException ) -> OnErrorAction {
168
+ override fun invoke (file : File , exception : IOException ): OnErrorAction {
169
+ throw ExecException (" Could not copy ${file} to output directory" , exception)
170
+ }
171
+ }
172
+
166
173
open class ClojureCompile @Inject constructor(val fileResolver : FileResolver ) :
167
174
AbstractCompile (),
168
175
JavaForkOptions by DefaultJavaForkOptions (fileResolver) {
@@ -175,30 +182,38 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
175
182
var elideMeta: Collection <String > = emptyList()
176
183
var directLinking: Boolean = false
177
184
185
+ @Suppress(" unused" )
178
186
var namespaces: Collection <String > = emptyList()
179
187
188
+ @Suppress(" unused" )
180
189
fun reflectionWarnings (configureClosure : Closure <Any ?>? ): ReflectionWarnings {
181
190
ConfigureUtil .configure(configureClosure, reflectionWarnings)
182
191
return reflectionWarnings
183
192
}
184
193
185
- override fun compile () {
186
- throw UnsupportedOperationException ()
187
- }
188
-
194
+ @Suppress(" UNUSED_PARAMETER" )
189
195
@TaskAction
190
196
fun compile (inputs : IncrementalTaskInputs ) {
197
+ compile()
198
+ }
199
+
200
+ override fun compile () {
191
201
logger.info(" Starting ClojureCompile task" )
192
202
193
- destinationDir.mkdirs()
203
+ val tmpDestinationDir = temporaryDir.resolve(" classes" )
204
+ removeObsoleteClassFiles(destinationDir, tmpDestinationDir)
194
205
195
- inputs.outOfDate { removeOutputFilesDerivedFromInputFile(it, destinationDir) }
196
- inputs.removed { removeOutputFilesDerivedFromInputFile(it, destinationDir) }
206
+ if (! tmpDestinationDir.deleteRecursively()) {
207
+ throw ExecException (" Could not delete ${tmpDestinationDir} " )
208
+ }
209
+ tmpDestinationDir.mkdirs()
210
+ destinationDir.mkdirs()
197
211
198
212
if (copySourceToOutput ? : ! aotCompile) {
199
213
project.copy {
200
- it.from(getSource()).into(destinationDir )
214
+ it.from(getSource()).into(tmpDestinationDir )
201
215
}
216
+ copyToDestination(tmpDestinationDir)
202
217
return
203
218
}
204
219
@@ -215,7 +230,7 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
215
230
logger.info(" Compiling " + namespaces.joinToString(" , " ))
216
231
217
232
val script = listOf (" (try" ,
218
- " (binding [*compile-path* \" ${destinationDir .canonicalPath} \" " ,
233
+ " (binding [*compile-path* \" ${tmpDestinationDir .canonicalPath} \" " ,
219
234
" *warn-on-reflection* ${reflectionWarnings.enabled} " ,
220
235
" *compiler-options* {:disable-locals-clearing $disableLocalsClearing " ,
221
236
" :elide-meta [${elideMeta.map { " :$it " }.joinToString(" " )} ]" ,
@@ -263,6 +278,8 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
263
278
264
279
executeScript(script, stdout, stderr)
265
280
281
+ copyToDestination(tmpDestinationDir)
282
+
266
283
if (libraryReflectionWarningCount > 0 ) {
267
284
System .err.println (" $libraryReflectionWarningCount reflection warnings from dependencies" )
268
285
}
@@ -272,28 +289,22 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
272
289
}
273
290
}
274
291
275
- private fun removeOutputFilesDerivedFromInputFile (inputFileDetails : InputFileDetails , destinationDir : File ) {
276
- val sourceAbsoluteFile = inputFileDetails.file
277
- if (isClojureSource(sourceAbsoluteFile)) {
278
- logger.debug(" Removing class files for {}" , inputFileDetails.file)
279
- val sourceCanonicalFileName = sourceAbsoluteFile.canonicalPath
280
- val sourceFileRoot = getSourceRootsFiles()
281
- .find { sourceCanonicalFileName.startsWith(it.canonicalPath) }
282
- ? : throw IllegalStateException (" No source root found for source file ${sourceAbsoluteFile} " )
283
- val sourceRelativeFile = sourceAbsoluteFile.relativeTo(sourceFileRoot)
284
- val sourceRelativeDirectory = sourceRelativeFile.parentFile
285
- val sourceFileName = sourceAbsoluteFile.nameWithoutExtension
286
- destinationDir.resolve(sourceRelativeDirectory)
287
- .listFiles { file -> file.name.startsWith(sourceFileName) }
288
- ?.forEach {
289
- logger.debug(" Deleting derived file {}" , it)
290
- it.delete()
291
- }
292
- }
292
+ private fun copyToDestination (tmpDestinationDir : File ) {
293
+ tmpDestinationDir.copyRecursively(target = destinationDir, overwrite = true , onError = FileCopyErrorHandler )
293
294
}
294
295
295
- private fun isClojureSource (file : File ): Boolean {
296
- return CLJ_EXTENSION_REGEX .matches(file.extension) && getSourceRoots().any { file.canonicalPath.startsWith(it) }
296
+ private fun removeObsoleteClassFiles (destinationDir : File , tmpDestinationDir : File ) {
297
+ tmpDestinationDir.walkBottomUp().forEach {
298
+ val relativeFile = it.relativeTo(tmpDestinationDir)
299
+ val fileInDestination = destinationDir.resolve(relativeFile)
300
+ if (fileInDestination.exists()) {
301
+ if (fileInDestination.delete()) {
302
+ logger.debug(" Deleted obsolete output file {}" , fileInDestination)
303
+ } else {
304
+ logger.warn(" Couldn't delete obsolete output file {}" , fileInDestination)
305
+ }
306
+ }
307
+ }
297
308
}
298
309
299
310
private fun executeScript (script : String , stdout : OutputStream , stderr : OutputStream ) {
@@ -385,7 +396,6 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
385
396
' \\ ' to " _BSLASH_" ,
386
397
' ?' to " _QMARK_" )
387
398
388
- val CLJ_EXTENSION_REGEX = " cljc?" .toRegex()
389
399
val DEMUNGE_MAP = CHAR_MAP .map { it.value to it.key }.toMap()
390
400
val DEMUNGE_PATTERN = Pattern .compile(DEMUNGE_MAP .keys
391
401
.sortedByDescending { it.length }
@@ -394,6 +404,7 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
394
404
395
405
val REFLECTION_WARNING_PREFIX = " Reflection warning, "
396
406
407
+ @Suppress(" unused" )
397
408
fun munge (name : String ): String {
398
409
val sb = StringBuilder ()
399
410
for (c in name) {
@@ -431,7 +442,9 @@ open class ClojureTestRunner @Inject constructor(val fileResolver: FileResolver)
431
442
ConventionTask (),
432
443
JavaForkOptions by DefaultJavaForkOptions (fileResolver) {
433
444
445
+ @Suppress(" unused" )
434
446
var classpath: FileCollection = SimpleFileCollection ()
447
+ @Suppress(" unused" )
435
448
var namespaces: Collection <String > = emptyList()
436
449
var junitReport: File ? = null
437
450
0 commit comments