1. Clojuresque
  2. Untitled project
  3. base

Commits

Meikel Brandmeyer  committed 53b5f0b

Implement incremental compilation

  • Participants
  • Parent commits 6605e81
  • Branches default

Comments (0)

Files changed (3)

File build.gradle

View file
             compile "clojuresque:clojuresque-${plugin}:${version}"
         }
         compile "de.kotka.gradle:gradle-utils:0.2.2"
+        compile "org.clojure:clojure:1.5.1"
+        compile "org.clojure:tools.namespace:0.2.4"
 
         testCompile('org.spockframework:spock-core:0.7-groovy-1.8') {
             exclude group: 'org.codehaus.groovy', module: 'groovy-all'

File clojuresque-base/src/main/groovy/clojuresque/tasks/ClojureCompile.groovy

View file
 import kotka.gradle.utils.ConfigureUtil
 import kotka.gradle.utils.Delayed
 
+import clojure.lang.RT
+
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFiles
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.StopExecutionException
 import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.incremental.IncrementalTaskInputs
 
 class ClojureCompile extends ClojureSourceTask {
     @OutputDirectory
     def jvmOptions = {}
 
     @TaskAction
-    void compile() {
+    void compile(IncrementalTaskInputs inputs) {
         def destDir = getDestinationDir()
         if (destDir == null) {
             throw new StopExecutionException("destinationDir not set!")
         }
         destDir.mkdirs()
 
+        def final require = RT.var("clojure.core", "require")
+        def final symbol  = RT.var("clojure.core", "symbol")
+
+        require.invoke(symbol.invoke("clojuresque.tasks.clojure-compile-util"))
+
+        def final fileDependencies = RT.var(
+            "clojuresque.tasks.clojure-compile-util",
+            "file-dependencies"
+        )
+
+        def dependencyGraph = fileDependencies.invoke(source.files)
+
+        def outOfDateInputs = [] as Set
+        inputs.outOfDate {
+            if (it.file.path.endsWith(".clj"))
+                outOfDateInputs << it.file
+        }
+        inputs.removed   { deleteDerivedFiles(it.file) }
+
+        def toCompile = findDependentFiles(outOfDateInputs, dependencyGraph)
+
         def options = [
             compileMode:      (getAotCompile()) ? "compile" : "require",
             warnOnReflection: (getWarnOnReflection()),
-            sourceFiles:      source.files.collect { it.path }
+            sourceFiles:      toCompile.collect { it.path }
         ]
 
         project.clojureexec {
                 dirMode  = this.dirMode
                 fileMode = this.fileMode
 
-                from srcDirs
+                from(srcDirs) {
+                    include {
+                        def f = it.file
+                        f.isDirectory() || outOfDateInputs.contains(f)
+                    }
+                }
                 into destDir
             }
         }
     }
+
+    public findDependentFiles(outOfDateFiles, dependencyGraph) {
+        def toCompile = [] as Set
+        outOfDateFiles.each {
+            toCompile.add(it)
+            def dependents = dependencyGraph[it]
+            if (dependents)
+                toCompile.addAll(dependents)
+        }
+        toCompile
+    }
+
+    public deleteDerivedFiles(parent) {
+        def relativeParent = getSrcDirs().findResult {
+            Util.relativizePath(it, parent)
+        }
+        if (relativeParent == null)
+            return
+
+        def pattern = relativeParent.replaceAll("\\.clj\$", "") + "*"
+
+        project.fileTree(getDestinationDir()).include(pattern).files.each {
+            it.delete()
+        }
+    }
 }

File clojuresque-base/src/main/resources/clojuresque/tasks/clojure_compile_util.clj

View file
+(ns clojuresque.tasks.clojure-compile-util
+  (:require
+    [clojure.tools.namespace.dependency :as deps]
+    [clojure.tools.namespace.file       :as file]
+    [clojure.tools.namespace.track      :as track]))
+
+(defn invert-map
+  [m]
+  (reduce-kv #(assoc %1 %3 %2) {} m))
+
+(defn file-dependencies
+  [files]
+  (let [tracker (file/add-files (track/tracker) files)
+        graph   (::track/deps tracker)
+        nodes   (deps/nodes graph)
+        fmap    (invert-map (::file/filemap tracker))]
+    (->> nodes
+      (map #(set (map fmap (deps/immediate-dependents graph %))))
+      (zipmap (map fmap nodes)))))