branch: javaimp_devel commit 327e1bacb65b9fc9029022454f733f27a25cde4c Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
in progress --- packages/javaimp/javaimp.el | 240 ++++++++++++++++++++++++++---------------- 1 files changed, 148 insertions(+), 92 deletions(-) diff --git a/packages/javaimp/javaimp.el b/packages/javaimp/javaimp.el index a2ab7c4..6a50e76 100644 --- a/packages/javaimp/javaimp.el +++ b/packages/javaimp/javaimp.el @@ -208,13 +208,21 @@ Only top-level classes are included.") (car (cddr el))) +;; Cygwin + +(defun javaimp-cygpath-convert-maybe (path) + (if (eq system-type 'cygwin) + (car (process-lines javaimp-cygpath-program "-u" path)) + path)) + + ;; Structs (cl-defstruct javaimp-node parent children contents) (cl-defstruct javaimp-module - id file file-ts final-name + id parent-id file file-ts final-name packaging source-dir test-source-dir build-dir dep-jars) @@ -232,9 +240,9 @@ Only top-level classes are included.") file file-ts classes) -;;; Loading Maven projects +;;; Maven -;; TODO if it's already there? +;; TODO what if it's already there? ;;;###autoload (defun javaimp-maven-visit-project (path) @@ -245,28 +253,42 @@ directory containing pom.xml." (concat (file-name-as-directory path) "pom.xml")))) (unless (file-readable-p file) (error "Cannot read file: %s" file)) - (push (javaimp-maven-load-tree file) javaimp-project-forest) + (let ((tree (javaimp--maven-load-tree file))) + (if tree + (push tree javaimp-project-forest))) (message "Loaded tree for %s" file))) -(defun javaimp-maven-load-tree (file) - ;; TODO - "Creates a tree of Maven projects starting from FILE" - (let* ((effective-pom (javaimp-parse-effective-pom pom)) - (project-elts - (cond ((assq 'projects effective-pom) ;project contains <module> tag(s) - (javaimp-xml-child-list (assq 'projects effective-pom) 'project)) - ((assq 'project effective-pom) ;single-module project - (list (assq 'project effective-pom))) - (t - (error "Cannot find projects in XML tree")))) - (modules-alist (javaimp-maven-process-projects project-elts))) - (javaimp-fill-pom-file-paths modules-alist pom) - modules-alist)) - -(defun javaimp-parse-effective-pom (pom) +(defun javaimp--maven-load-tree (file) + "Invokes `mvn help:effective-pom' on FILE and using its output +creates a tree of Maven projects starting from FILE. Children +which link to the parent via the <parent> element are inheriting +children and are also included. Subordinate modules with no +inheritance are not included." + (let ((xml-tree (javaimp--maven-read-effective-pom file))) + (cond ((assq 'project xml-tree) + ;; no real children + (let ((project-elt (assq 'project xml-tree))) + (message "Independent submodules: %s" + (mapconcat #'javaimp-xml-first-child + (javaimp--maven-get-module-elts project-elt) + ", ")) + (let ((module (javaimp--maven-parse-module project-elt))) + (javaimp--build-tree (javaimp-module-id module) nil (list module))))) + ((assq 'projects xml-tree) + ;; we have are inheriting children - they and their children, if + ;; any, are listed in a linear list + (let* ((project-elts (javaimp-xml-child-list + (assq 'projects xml-tree) 'project)) + (all-modules (mapcar #'javaimp--maven-parse-module project-elts))) + (javaimp--build-tree (javaimp-module-id (car all-modules)) nil all-modules))) + (t + ;; neither <project> nor <projects> - error + (error "Invalid `help:effective-pom' output"))))) + +(defun javaimp--maven-read-effective-pom (pom) "Calls `mvn help:effective:pom and returns XML parse tree" (message "Loading root pom %s..." pom) - (javaimp-call-mvn + (javaimp--maven-call pom "help:effective-pom" (lambda () (let ((xml-start-pos @@ -285,44 +307,45 @@ directory containing pom.xml." (match-end 0))))) (xml-parse-region xml-start-pos xml-end-pos))))) +(defun javaimp--maven-call (pom-file target handler) + "Runs Maven target TARGET on POM-FILE, then calls HANDLER in +the temporary buffer and returns its result" + (message "Calling \"mvn %s\" on pom: %s" target pom-file) + (with-temp-buffer + (let* ((pom-file (javaimp-cygpath-convert-maybe pom-file)) + (status + ;; FIXME check Maven output on Gnu/Linux + (let ((coding-system-for-read + (if (eq system-type 'cygwin) 'utf-8-dos))) + (process-file javaimp-mvn-program nil t nil "-f" pom-file target))) + (b (current-buffer))) + (with-current-buffer (get-buffer-create javaimp-debug-buf-name) + (erase-buffer) + (insert-buffer-substring b)) + (or (and (numberp status) (= status 0)) + (error "Maven target \"%s\" failed with status \"%s\"" target status)) + (goto-char (point-min)) + (funcall handler)))) +(defun javaimp--maven-get-module-elts (project-elt) + (javaimp-xml-child-list + (javaimp-xml-child 'modules project-elt) 'module)) -(defun javaimp-fill-pom-file-paths (modules pom) - "Subroutine of `javaimp-maven-load-module-tree'" - (let ((artifact-alist (javaimp-traverse-pom-tree (list pom)))) - (dolist (module modules) - (let* ((artifact (javaimp-mod-artifact module)) - (path - (cdr (or (seq-find (lambda (el) - (equal artifact (car el))) - artifact-alist) - ;; Compare just id if comparison by all fields failed - (seq-find (lambda (el) - (equal (javaimp-artifact-artifact-id artifact) - (javaimp-artifact-artifact-id (car el)))) - artifact-alist) - (error "Cannot find path for artifact: %s" artifact))))) - (javaimp-set-mod-pom-file module path))))) - -(defun javaimp-extract-artifact-info (elt) - (javaimp-make-artifact - (javaimp-xml-first-child (javaimp-xml-child 'groupId elt)) - (javaimp-xml-first-child (javaimp-xml-child 'artifactId elt)) - (javaimp-xml-first-child (javaimp-xml-child 'version elt)))) - -(defun javaimp-cygpath-convert-maybe (path) - (if (eq system-type 'cygwin) - (car (process-lines javaimp-cygpath-program "-u" path)) - path)) +(defun javaimp--maven-parse-module (elt) + ;; TODO file - instead of javaimp-fill-pom-file-paths + ;; + ;; TODO javaimp-maven-process-projects + ;; + ;; TODO set everything immediately -;; todo set everything immediately + ) (defun javaimp-maven-process-projects (projects-elts) (mapcar (lambda (project-elt) (let ((build-elt (javaimp-xml-child 'build project-elt))) (javaimp-make-mod - (javaimp-extract-artifact-info project-elt) + (javaimp--maven-extract-id project-elt) nil ;pom-file will be set later (file-name-as-directory (javaimp-cygpath-convert-maybe @@ -335,17 +358,68 @@ directory containing pom.xml." (javaimp-xml-first-child (javaimp-xml-child 'directory build-elt)))) nil ;pom-file-mod-ts will be set later nil ;jar-list will be set later - (javaimp-extract-artifact-info + (javaimp--maven-extract-id (javaimp-xml-child 'parent project-elt)) nil ;parent-ts will be set later (javaimp-xml-first-child (javaimp-xml-child 'finalName build-elt)) ))) projects-elts)) -(defun javaimp-extract-submodules-paths (project-elt) - (let* ((modules-elt (javaimp-xml-child 'modules project-elt)) - (module-elts (javaimp-xml-child-list modules-elt 'module))) - (mapcar #'javaimp-xml-first-child module-elts))) +(defun javaimp--maven-extract-id (elt) + (javaimp-make-artifact + (javaimp-xml-first-child (javaimp-xml-child 'groupId elt)) + (javaimp-xml-first-child (javaimp-xml-child 'artifactId elt)) + (javaimp-xml-first-child (javaimp-xml-child 'version elt)))) + +;; Module tree + +(defun javaimp--build-tree (id parent-node all-modules) + (let ((this (or (javaimp--find-by-id id all-modules) + (error "Cannot find module %s!" id))) + ;; although each real parent has <modules> section, better way to + ;; build hirarchy is to analyze <parent> node in each child + (children (javaimp--find-by-parent-id id all-modules))) + (if (and (null children) + (string= (javaimp-module-packaging module) "pom")) ;TODO remove mvn specifics + ;; this module is a pure aggregate module - it has neither real + ;; children nor source files, so skip it + nil + ;; otherwise, make node + (let ((this-node (make-javaimp-node parent-node nil this))) + (setf (javaimp-node-children this-node) + (mapcar (lambda (child) + (javaimp--build-tree (javaimp-module-id child) this-node all-modules)) + children)) + this-node)))) + +(defun javaimp--find-by-id (id modules) + ;; TODO seq-find + ) + +(defun javaimp--find-by-parent-id (parent-id modules) + ;; TODO seq-find + ) + + +;; pom file parsing - this will not be needed? + +(defun javaimp-fill-pom-file-paths (modules pom) + "Subroutine of `javaimp-maven-load-module-tree'" + (let ((artifact-alist (javaimp-traverse-pom-tree (list pom)))) + (dolist (module modules) + (let* ((artifact (javaimp-mod-artifact module)) + (path + (cdr (or (seq-find (lambda (el) + (equal artifact (car el))) + artifact-alist) + ;; Compare just id if comparison by all fields failed + (seq-find (lambda (el) + (equal (javaimp-artifact-artifact-id artifact) + (javaimp-artifact-artifact-id (car el)))) + artifact-alist) + (error "Cannot find path for artifact: %s" artifact))))) + (javaimp-set-mod-pom-file module path))))) + (defun javaimp-parse-pom-file (pom-file) "Subroutine of `javaimp-traverse-pom-tree'. Parses POM-FILE. @@ -361,24 +435,10 @@ relative path list." (assq 'project xml-tree)) (t (error "Cannot find <project> element in pom %s!" pom-file))))) - (cons (javaimp-extract-artifact-info project-elt) - (javaimp-extract-submodules-paths project-elt)))) + (cons (javaimp--maven-extract-id project-elt) + (mapcar #'javaimp-xml-first-child + (javaimp--maven-get-module-elts project-elt))))) -(defun javaimp-create-absolute-submodules-paths (base-pom paths) - "Subroutine of `javaimp-traverse-pom-tree'" - (mapcar - (lambda (rel-path) - (expand-file-name - (concat - ;; base path - (file-name-directory base-pom) - ;; submodule relative path - (file-name-as-directory - (javaimp-cygpath-convert-maybe rel-path)) - ;; well-known pom name - "pom.xml"))) - paths)) - (defun javaimp-traverse-pom-tree (pom-file-list) "Traverses pom tree and returns alist where each element is of the form (\"ARTIFACT\" . \"POM-FILE-PATH\"). Result paths are in @@ -398,32 +458,28 @@ platform default format." ;; rest items (javaimp-traverse-pom-tree (cdr pom-file-list))))) -(defun javaimp-call-mvn (pom-file target handler) - "Runs Maven target TARGET on POM-FILE, then calls HANDLER in -the temporary buffer and returns its result" - (message "Calling \"mvn %s\" on pom: %s" target pom-file) - (with-temp-buffer - (let* ((pom-file (javaimp-cygpath-convert-maybe pom-file)) - (status - ;; FIXME check Maven output on Gnu/Linux - (let ((coding-system-for-read - (if (eq system-type 'cygwin) 'utf-8-dos))) - (process-file javaimp-mvn-program nil t nil "-f" pom-file target))) - (b (current-buffer))) - (with-current-buffer (get-buffer-create javaimp-debug-buf-name) - (erase-buffer) - (insert-buffer-substring b)) - (or (and (numberp status) (= status 0)) - (error "Maven target \"%s\" failed with status \"%s\"" target status)) - (goto-char (point-min)) - (funcall handler)))) +(defun javaimp-create-absolute-submodules-paths (base-pom paths) + "Subroutine of `javaimp-traverse-pom-tree'" + (mapcar + (lambda (rel-path) + (expand-file-name + (concat + ;; base path + (file-name-directory base-pom) + ;; submodule relative path + (file-name-as-directory + (javaimp-cygpath-convert-maybe rel-path)) + ;; well-known pom name + "pom.xml"))) + paths)) + ;;; Working with module dependency JARs (defun javaimp-maven-fetch-module-deps (module) "Returns list of dependency jars for MODULE" - (javaimp-call-mvn + (javaimp--maven-call (javaimp-mod-pom-file module) "dependency:build-classpath" (lambda () (let (deps-line)