branch: scratch/javaimp-gradle commit d9913c908adb152410e7885d9ec71a7ab7a0c8be Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
More fixes for gradle --- packages/javaimp/javaimp-gradle.el | 102 ++++++++++++++++++++++++++----------- packages/javaimp/javaimp-maven.el | 13 +++-- packages/javaimp/javaimp.el | 47 +++++++++-------- 3 files changed, 107 insertions(+), 55 deletions(-) diff --git a/packages/javaimp/javaimp-gradle.el b/packages/javaimp/javaimp-gradle.el index 908067a..d0ff6b3 100644 --- a/packages/javaimp/javaimp-gradle.el +++ b/packages/javaimp/javaimp-gradle.el @@ -21,8 +21,6 @@ (require 'javaimp-util) -;; TODO support Groovy build files (build.gradle) - (defcustom javaimp-gradle-program "gradle" "Path to the `gradle' program. Customize it if the program is not on `exec-path'." @@ -36,15 +34,14 @@ Passes specially crafted init file as -I argument to gradle and invokes task contained in it. This task returns all needed information." (message "Visiting Gradle build file %s..." file) - (let* ((init-file (make-temp-file "javaimp" nil ".kts" - javaimp--gradle-init-file-contents)) - (modules - (javaimp--call-build-tool javaimp-gradle-program - #'javaimp--gradle-handler - "-q" - "-b" (javaimp-cygpath-convert-maybe file) - "-I" (javaimp-cygpath-convert-maybe init-file) - "javaimpTask"))) + (let* ((alists (javaimp--gradle-call file + javaimp--gradle-init-script + javaimp--gradle-init-script-kotlin + #'javaimp--gradle-handler + "javaimpTask")) + (modules (mapcar (lambda (alist) + (javaimp--gradle-module-from-alist alist file)) + alists))) (prog1 ;; first module is always root (javaimp--build-tree (car modules) nil modules) @@ -52,7 +49,7 @@ information." (defun javaimp--gradle-handler () (goto-char (point-min)) - (let (modules alist parts sym val) + (let (alist res parts sym val) (while (not (eobp)) (setq parts (split-string (thing-at-point 'line) "[=\n]+" t)) (setq sym (intern (or (nth 0 parts) @@ -60,19 +57,20 @@ information." (thing-at-point 'line)))) val (nth 1 parts)) (when (and (eq sym 'id) alist) ;start of next module - (push (javaimp--gradle-module-from-alist alist) modules) + (push alist res) (setq alist nil)) (push (cons sym val) alist) (forward-line 1)) (when alist ;last module - (push (javaimp--gradle-module-from-alist alist) modules)) - (nreverse modules))) + (push alist res)) + (nreverse res))) -(defun javaimp--gradle-module-from-alist (alist) +(defun javaimp--gradle-module-from-alist (alist file-orig) (make-javaimp-module :id (javaimp--gradle-id-from-colon-separated (cdr (assq 'id alist))) :parent-id (javaimp--gradle-id-from-colon-separated (cdr (assq 'parent-id alist))) :file (cdr (assq 'file alist)) + :file-orig file-orig :final-name (cdr (assq 'final-name alist)) :packaging "jar" ;TODO :source-dir (file-name-as-directory @@ -95,25 +93,69 @@ information." (error "Invalid maven id: %s" str)) (make-javaimp-id :group (nth 0 parts) :artifact (nth 1 parts) :version (nth 2 parts))))) - -(defun javaimp--gradle-fetch-dep-jars-path (file) - (let ((init-file (make-temp-file "javaimp" nil ".kts" - javaimp--gradle-init-file-contents-dep-jars-only))) - (javaimp--call-build-tool javaimp-gradle-program - (lambda () - ;; expect just a single line - (thing-at-point 'line)) +(defun javaimp--gradle-fetch-dep-jars-path (module) + ;; always invoke on originating file becase module's file may not + ;; exist (even if reported as project.buildFile property); also, + ;; local gradlew which needs to be invoked will usually reside + ;; alongside top-level build file + (javaimp--gradle-call (javaimp-module-file-orig module) + javaimp--gradle-init-script-dep-jars-only + javaimp--gradle-init-script-dep-jars-only-kotlin + (lambda () + ;; expect just a single line + (thing-at-point 'line)) + (format ":%s:javaimpTask" ;TODO what if root? + (javaimp-id-artifact (javaimp-module-id module))))) + + +(defun javaimp--gradle-call (file init-script init-script-kotlin handler task) + (let* ((is-kotlin (equal (file-name-extension file) "kts")) + (init-file (make-temp-file "javaimp" nil + (if is-kotlin ".kts") + (if is-kotlin init-script-kotlin init-script))) + (local-gradlew (concat (file-name-directory file) "gradlew"))) + (javaimp--call-build-tool (if (file-exists-p local-gradlew) + local-gradlew + javaimp-gradle-program) + handler "-q" "-b" (javaimp-cygpath-convert-maybe file) "-I" (javaimp-cygpath-convert-maybe init-file) - "javaimpTask"))) + task))) + + +(defconst javaimp--gradle-init-script + "allprojects { + task javaimpTask { + doLast { + println \"id=${project.group}:${project.name}:${project.version}\" + if (project.parent != null) { + println \"parent-id=${project.parent.group}:${project.parent.name}:${project.parent.version}\" + } + println \"file=${project.buildFile}\" + println \"final-name=${project.archivesBaseName}\" + println 'source-dir=' + sourceSets.main.java.srcDirs.collect { it.path }.join(':') + println 'test-source-dir=' + sourceSets.test.java.srcDirs.collect { it.path }.join(':') + println \"build-dir=${project.buildDir}\" + println \"dep-jars=${configurations.testCompile.asPath}\" + } + } +}") +(defconst javaimp--gradle-init-script-dep-jars-only + "allprojects { + task javaimpTask { + doLast { + println \"${configurations.testCompile.asPath}\" + } + } +}") -(defconst javaimp--gradle-init-file-contents +(defconst javaimp--gradle-init-script-kotlin "allprojects { tasks.register(\"javaimpTask\") { doLast { - println(\"id=$project.group:$project.name:$project.version\") + println(\"id=${project.group}:${project.name}:${project.version}\") if (project.parent != null) { println(\"parent-id=${project.parent.group}:${project.parent.name}:${project.parent.version}\") } @@ -122,16 +164,16 @@ information." println(\"source-dir=${sourceSets.main.java.sourceDirectories.asPath}\") println(\"test-source-dir=${sourceSets.test.java.sourceDirectories.asPath}\") println(\"build-dir=${project.buildDir}\") - println(\"dep-jars=${configurations.testCompileClasspath.asPath}\") + println(\"dep-jars=${configurations.testCompile.asPath}\") } } }") -(defconst javaimp--gradle-init-file-contents-dep-jars-only +(defconst javaimp--gradle-init-script-dep-jars-only-kotlin "allprojects { tasks.register(\"javaimpTask\") { doLast { - println(\"${configurations.testCompileClasspath.asPath}\") + println(\"${configurations.testCompile.asPath}\") } } }") diff --git a/packages/javaimp/javaimp-maven.el b/packages/javaimp/javaimp-maven.el index 9ceb1a9..b39d0b0 100644 --- a/packages/javaimp/javaimp-maven.el +++ b/packages/javaimp/javaimp-maven.el @@ -41,7 +41,9 @@ belong to which modules and other module information" "-f" (javaimp-cygpath-convert-maybe file) "help:effective-pom")) (projects (javaimp--maven-projects-from-xml xml-tree)) - (modules (mapcar #'javaimp--maven-module-from-xml projects)) + (modules (mapcar (lambda (proj-elt) + (javaimp--maven-module-from-xml proj-elt file)) + projects)) ;; first module is always root (tree (javaimp--build-tree (car modules) nil modules))) (when tree @@ -89,7 +91,7 @@ of <project> elements" (t (error "Neither <project> nor <projects> was found in pom"))))) -(defun javaimp--maven-module-from-xml (elt) +(defun javaimp--maven-module-from-xml (elt file-orig) (let ((build-elt (javaimp--xml-child 'build elt))) (make-javaimp-module :id (javaimp--maven-id-from-xml elt) @@ -97,6 +99,7 @@ of <project> elements" ;; <project> element does not contain pom file path, so we set this slot ;; later, see javaimp--maven-fill-modules-files :file nil + :file-orig file-orig :final-name (javaimp--xml-first-child (javaimp--xml-child 'finalName build-elt)) :packaging (javaimp--xml-first-child @@ -159,14 +162,16 @@ of <project> elements" "pom.xml") tree))))) -(defun javaimp--maven-fetch-dep-jars-path (file) +(defun javaimp--maven-fetch-dep-jars-path (module) (javaimp--call-build-tool javaimp-mvn-program (lambda () (goto-char (point-min)) (search-forward "Dependencies classpath:") (forward-line 1) (thing-at-point 'line)) - "-f" (javaimp-cygpath-convert-maybe file) + ;; always invoke for this module's pom.ml + "-f" (javaimp-cygpath-convert-maybe + (javaimp-module-file module)) "dependency:build-classpath")) (provide 'javaimp-maven) diff --git a/packages/javaimp/javaimp.el b/packages/javaimp/javaimp.el index 4f87c05..fd88b4e 100644 --- a/packages/javaimp/javaimp.el +++ b/packages/javaimp/javaimp.el @@ -28,7 +28,7 @@ ;; ;; - customize `javaimp-import-group-alist' ;; - call `javaimp-visit-project', giving it the top-level project -;; directory where pom.xml / build.gradle.kts resides +;; directory where pom.xml / build.gradle[.kts] resides ;; ;; Then in a Java buffer visiting a file under that project or one of its ;; submodules call `javaimp-organize-imports' or `javaimp-add-import'. @@ -163,6 +163,7 @@ to the completion alternatives list." (cl-defstruct javaimp-module id parent-id file + file-orig final-name packaging source-dir test-source-dir build-dir @@ -181,7 +182,7 @@ to the completion alternatives list." ;;;###autoload (defun javaimp-visit-project (dir) "Loads a project and its submodules. DIR should point to a -directory containing pom.xml / build.gradle.kts. +directory containing pom.xml / build.gradle[.kts]. After being processed by this command, the module tree becomes known to javaimp and `javaimp-add-import' may be called inside @@ -192,45 +193,49 @@ any module file." (tree (cond ((file-readable-p (setq build-file (concat exp-dir "pom.xml"))) (javaimp--maven-visit build-file)) - ((file-readable-p (setq build-file (concat exp-dir "build.gradle.kts"))) + ((or (file-readable-p (setq build-file (concat exp-dir "build.gradle"))) + (file-readable-p (setq build-file (concat exp-dir "build.gradle.kts")))) (javaimp--gradle-visit build-file)) (t (error "Could not find build file in dir %s" dir))))) (when tree - ;; delete previous loaded tree, if any + ;; delete previous tree(s) loaded from this build file, if any (setq javaimp-project-forest (seq-remove (lambda (tree) - (equal (javaimp-module-file (javaimp-node-contents tree)) + (equal (javaimp-module-file-orig (javaimp-node-contents tree)) build-file)) javaimp-project-forest)) (push tree javaimp-project-forest) (message "Loaded tree for %s" dir)))) -;; Dep jars +;; Dependency jars (defun javaimp--update-module-maybe (node) (let ((module (javaimp-node-contents node)) need-update) ;; check if deps are initialized - (or (javaimp-module-dep-jars module) - (progn (message "Loading dependencies: %s" (javaimp-module-id module)) - (setq need-update t))) - ;; check if any build-file up to the top one has changed + (unless (javaimp-module-dep-jars module) + (message "Loading dependencies: %s" (javaimp-module-id module)) + (setq need-update t)) + ;; check if this or any parent build file has changed since we + ;; loaded the module (let ((tmp node)) - (while (and tmp - (not need-update)) - (let ((checked (javaimp-node-contents tmp))) - (if (> (float-time (javaimp--get-file-ts (javaimp-module-file checked))) - (float-time (javaimp-module-load-ts module))) - (progn - (message "Reloading dependencies for %s (build-file changed)" - (javaimp-module-id checked)) - (setq need-update t)))) + (while (and tmp (not need-update)) + (let ((cur (javaimp-node-contents tmp))) + (when (> (max (if (file-exists-p (javaimp-module-file cur)) + (float-time (javaimp--get-file-ts (javaimp-module-file cur))) + -1) + (if (file-exists-p (javaimp-module-file-orig cur)) + (float-time (javaimp--get-file-ts (javaimp-module-file-orig cur))) + -1)) + (float-time (javaimp-module-load-ts module))) + (message "Reloading dependencies for %s (some build-file changed)" + (javaimp-module-id cur)) + (setq need-update t))) (setq tmp (javaimp-node-parent tmp)))) (when need-update - (let* ((path (funcall (javaimp-module-dep-jars-path-fetcher module) - (javaimp-module-file module))) + (let* ((path (funcall (javaimp-module-dep-jars-path-fetcher module) module)) (new-dep-jars (javaimp--split-native-path path)) (new-load-ts (current-time))) (setf (javaimp-module-dep-jars module) new-dep-jars)