@@ -34,13 +34,13 @@ import org.gradle.api.tasks.SourceSet
3434import org.gradle.api.tasks.TaskAction
3535import org.gradle.api.tasks.compile.AbstractCompile
3636import org.gradle.api.tasks.incremental.IncrementalTaskInputs
37- import org.gradle.api.tasks.incremental.InputFileDetails
3837import org.gradle.process.JavaForkOptions
3938import org.gradle.process.internal.DefaultJavaForkOptions
4039import org.gradle.process.internal.ExecException
4140import org.gradle.process.internal.JavaExecHandleBuilder
4241import org.gradle.util.ConfigureUtil
4342import java.io.File
43+ import java.io.IOException
4444import java.io.OutputStream
4545import java.util.*
4646import java.util.regex.Pattern
@@ -49,6 +49,7 @@ import javax.inject.Inject
4949/* *
5050 * @author Colin Fleming
5151 */
52+ @Suppress(" unused" )
5253class ClojurePlugin : Plugin <Project > {
5354 val logger = Logging .getLogger(this .javaClass)
5455
@@ -163,6 +164,12 @@ open class ClojureSourceSetImpl(displayName: String?, resolver: FileResolver?) :
163164
164165class ReflectionWarnings (var enabled : Boolean , var projectOnly : Boolean , var asErrors : Boolean )
165166
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+
166173open class ClojureCompile @Inject constructor(val fileResolver : FileResolver ) :
167174 AbstractCompile (),
168175 JavaForkOptions by DefaultJavaForkOptions (fileResolver) {
@@ -175,30 +182,38 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
175182 var elideMeta: Collection <String > = emptyList()
176183 var directLinking: Boolean = false
177184
185+ @Suppress(" unused" )
178186 var namespaces: Collection <String > = emptyList()
179187
188+ @Suppress(" unused" )
180189 fun reflectionWarnings (configureClosure : Closure <Any ?>? ): ReflectionWarnings {
181190 ConfigureUtil .configure(configureClosure, reflectionWarnings)
182191 return reflectionWarnings
183192 }
184193
185- override fun compile () {
186- throw UnsupportedOperationException ()
187- }
188-
194+ @Suppress(" UNUSED_PARAMETER" )
189195 @TaskAction
190196 fun compile (inputs : IncrementalTaskInputs ) {
197+ compile()
198+ }
199+
200+ override fun compile () {
191201 logger.info(" Starting ClojureCompile task" )
192202
193- destinationDir.mkdirs()
203+ val tmpDestinationDir = temporaryDir.resolve(" classes" )
204+ removeObsoleteClassFiles(destinationDir, tmpDestinationDir)
194205
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()
197211
198212 if (copySourceToOutput ? : ! aotCompile) {
199213 project.copy {
200- it.from(getSource()).into(destinationDir )
214+ it.from(getSource()).into(tmpDestinationDir )
201215 }
216+ copyToDestination(tmpDestinationDir)
202217 return
203218 }
204219
@@ -215,7 +230,7 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
215230 logger.info(" Compiling " + namespaces.joinToString(" , " ))
216231
217232 val script = listOf (" (try" ,
218- " (binding [*compile-path* \" ${destinationDir .canonicalPath} \" " ,
233+ " (binding [*compile-path* \" ${tmpDestinationDir .canonicalPath} \" " ,
219234 " *warn-on-reflection* ${reflectionWarnings.enabled} " ,
220235 " *compiler-options* {:disable-locals-clearing $disableLocalsClearing " ,
221236 " :elide-meta [${elideMeta.map { " :$it " }.joinToString(" " )} ]" ,
@@ -263,6 +278,8 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
263278
264279 executeScript(script, stdout, stderr)
265280
281+ copyToDestination(tmpDestinationDir)
282+
266283 if (libraryReflectionWarningCount > 0 ) {
267284 System .err.println (" $libraryReflectionWarningCount reflection warnings from dependencies" )
268285 }
@@ -272,28 +289,22 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
272289 }
273290 }
274291
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 )
293294 }
294295
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+ }
297308 }
298309
299310 private fun executeScript (script : String , stdout : OutputStream , stderr : OutputStream ) {
@@ -385,7 +396,6 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
385396 ' \\ ' to " _BSLASH_" ,
386397 ' ?' to " _QMARK_" )
387398
388- val CLJ_EXTENSION_REGEX = " cljc?" .toRegex()
389399 val DEMUNGE_MAP = CHAR_MAP .map { it.value to it.key }.toMap()
390400 val DEMUNGE_PATTERN = Pattern .compile(DEMUNGE_MAP .keys
391401 .sortedByDescending { it.length }
@@ -394,6 +404,7 @@ open class ClojureCompile @Inject constructor(val fileResolver: FileResolver) :
394404
395405 val REFLECTION_WARNING_PREFIX = " Reflection warning, "
396406
407+ @Suppress(" unused" )
397408 fun munge (name : String ): String {
398409 val sb = StringBuilder ()
399410 for (c in name) {
@@ -431,7 +442,9 @@ open class ClojureTestRunner @Inject constructor(val fileResolver: FileResolver)
431442 ConventionTask (),
432443 JavaForkOptions by DefaultJavaForkOptions (fileResolver) {
433444
445+ @Suppress(" unused" )
434446 var classpath: FileCollection = SimpleFileCollection ()
447+ @Suppress(" unused" )
435448 var namespaces: Collection <String > = emptyList()
436449 var junitReport: File ? = null
437450
0 commit comments