emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] javaimp_devel 5e69ed1: javaimp: Rewrite Maven output parsing code


From: Filipp Gunbin
Subject: [elpa] javaimp_devel 5e69ed1: javaimp: Rewrite Maven output parsing code
Date: Fri, 18 Mar 2016 19:59:05 +0000

branch: javaimp_devel
commit 5e69ed13eec3fa055e86cf91f789ca167360b6ac
Author: Filipp Gunbin <address@hidden>
Commit: Filipp Gunbin <address@hidden>

    javaimp: Rewrite Maven output parsing code
---
 packages/javaimp/javaimp.el |  350 ++++++++++++++++++++++++-------------------
 1 files changed, 193 insertions(+), 157 deletions(-)

diff --git a/packages/javaimp/javaimp.el b/packages/javaimp/javaimp.el
index df402ce..f05629a 100644
--- a/packages/javaimp/javaimp.el
+++ b/packages/javaimp/javaimp.el
@@ -1,6 +1,6 @@
 ;;; javaimp.el --- Add and reorder Java import statements in Maven projects  
-*- lexical-binding: t; -*-
 
-;; Copyright (C) 2014, 2015  Free Software Foundation, Inc.
+;; Copyright (C) 2014, 2015, 2016  Free Software Foundation, Inc.
 
 ;; Author: Filipp Gunbin <address@hidden>
 ;; Maintainer: Filipp Gunbin <address@hidden>
@@ -66,11 +66,12 @@
 ;; which are not matched by any regexp in that variable are assigned a
 ;; default order defined by `javaimp-import-default-order' (50 by default).
 ;;
-;; Sample setup (put this into your .emacs):
+;; Sample .emacs initialization:
 ;; 
 ;; (require 'javaimp)
 ;; 
-;; (add-to-list 'javaimp-import-group-alist 
'("\\`\\(ru\\.yota\\.\\|tv\\.okko\\.\\)" . 80))
+;; (add-to-list 'javaimp-import-group-alist
+;;   '("\\`\\(my\\.company\\.\\|my\\.company2\\.\\)" . 80))
 ;; 
 ;; (setq javaimp-jdk-home (getenv "JAVA_HOME"))
 ;; (setq javaimp-include-current-project-classes t)
@@ -82,19 +83,28 @@
 ;;         (local-set-key "\C-co" 'javaimp-organize-imports)))
 ;; 
 ;; 
-;; TODO:
+;; TODO before version 1.0:
 ;; 
-;; Support adding static imports by giving a prefix argument to
+;; - correct submodule tree for each top-level project (now top-level projects
+;; hold linear submodule list and this prevents modification checking for 
parent
+;; poms).  If a project doesn't have any children, then it should be in the 
list
+;; by itself.
+;; 
+;; - cl-defstruct for data
+;; 
+;; Other:
+;;  
+;; - support adding static imports by giving a prefix argument to
 ;; `javaimp-add-import'.
 ;;  
-;; Use functions `cygwin-convert-file-name-from-windows' and
+;; - use functions `cygwin-convert-file-name-from-windows' and
 ;; `cygwin-convert-file-name-to-windows' when they are available instead of
-;; calling `cygpath'.  See
-;; https://cygwin.com/ml/cygwin/2013-03/msg00228.html.
-
+;; calling `cygpath'.  See https://cygwin.com/ml/cygwin/2013-03/msg00228.html.
 
 ;;; Code:
 
+(require 'seq)
+
 
 ;;; User options
 
@@ -163,7 +173,7 @@ Only top-level classes are included.")
 (defconst javaimp-debug-buf-name "*javaimp-debug*")
 
 
-;;; Dealing with XML
+;;; XML routines
 
 (defun javaimp-xml-child-list (xml-tree child-name)
   "Returns list of children of XML-TREE filtered by CHILD-NAME"
@@ -182,8 +192,10 @@ Only top-level classes are included.")
   (car (cddr el)))
 
 
-;; A module is represented as a list of the form `(ARTIFACT POM-FILE
-;; SOURCE-DIR TEST-SOURCE-DIR BUILD-DIR POM-FILE-MOD-TS PARENT PARENT-TS)'.
+;; FIXME: use cl-defstruct!
+
+;; A module is represented as a list: `(ARTIFACT POM-FILE SOURCE-DIR
+;; TEST-SOURCE-DIR BUILD-DIR POM-FILE-MOD-TS PARENT PARENT-TS)'.
 
 (defsubst javaimp-make-mod (artifact pom-file source-dir
                                     test-source-dir build-dir
@@ -197,6 +209,8 @@ Only top-level classes are included.")
 
 (defsubst javaimp-get-mod-pom-file (module)
   (nth 1 module))
+(defsubst javaimp-set-mod-pom-file (module value)
+  (setcar (nthcdr 1 module) value))
 
 (defsubst javaimp-get-mod-source-dir (module)
   (nth 2 module))
@@ -230,18 +244,16 @@ Only top-level classes are included.")
 
 ;; An artifact is represented as a list: (GROUP-ID ARTIFACT-ID VERSION).
 
-;; FIXME: use cl-defstruct!
-
-(defun javaimp-make-artifact (group-id artifact-id version)
+(defsubst javaimp-make-artifact (group-id artifact-id version)
   (list group-id artifact-id version))
 
-(defun javaimp-artifact-group-id (artifact)
+(defsubst javaimp-artifact-group-id (artifact)
   (car artifact))
 
-(defun javaimp-artifact-artifact-id (artifact)
+(defsubst javaimp-artifact-artifact-id (artifact)
   (cadr artifact))
 
-(defun javaimp-artifact-version (artifact)
+(defsubst javaimp-artifact-version (artifact)
   (nth 2 artifact))
 
 (defun javaimp-artifact-to-string (artifact)
@@ -255,7 +267,7 @@ Only top-level classes are included.")
 
 
 
-;; A jar is represented as follows: `(JAR-PATH JAR-MOD-TS . CLASSES-LIST).
+;; A jar is represented as a list: `(JAR-PATH JAR-MOD-TS . CLASSES-LIST).
 
 (defsubst javaimp-make-jar (jar-path jar-mod-ts classes-list)
   (cons jar-path (cons jar-mod-ts classes-list)))
@@ -276,150 +288,168 @@ Only top-level classes are included.")
   (setcdr (cdr jar) value))
 
 
-;;; Loading maven projects tree
+;;; Loading Maven projects tree
 
 ;;;###autoload
 (defun javaimp-maven-visit-root (path)
   "Loads all modules starting from root module identified by
-PATH.  PATH should point to a directory."
+PATH.  PATH should point to a directory containing pom.xml."
   (interactive "DVisit maven root project: ")
-  (let ((root-pom (expand-file-name
-                  (concat (file-name-as-directory path) "pom.xml")))
-       modules existing-module)
-    (unless (file-readable-p root-pom)
-      (error "Cannot read root pom: %s" root-pom))
-    (setq modules (javaimp-maven-load-module-tree root-pom))
-    ;; if a root module with such path is already loaded, replace its
-    ;; modules
-    (setq existing-module (assoc root-pom javaimp-maven-root-modules))
-    (if existing-module
-       (setcdr existing-module modules)
+  (let* ((root-pom (expand-file-name
+                   (concat (file-name-as-directory path) "pom.xml")))
+        (modules (if (file-readable-p root-pom)
+                     (javaimp-maven-load-module-tree root-pom)
+                   (error "Cannot read root pom: %s" root-pom)))
+        (root-project (assoc root-pom javaimp-maven-root-modules)))
+    (if root-project
+       (setcdr root-project modules)
       (push (cons root-pom modules) javaimp-maven-root-modules))
     (message "Loaded modules for %s" path)))
 
-(defun javaimp-get-projects (xml-tree)
-  (cond ((assq 'projects xml-tree)
-        (javaimp-xml-child-list (assq 'projects xml-tree) 'project))
-       ((assq 'project xml-tree)
-        (list (assq 'project xml-tree)))
-       (t
-        (error "Cannot find projects in mvn output"))))
-
-(defun javaimp-maven-load-module-tree (pom)
-  "Returns an alist of all Maven modules in a hierarchy starting
-with POM"
+(defun javaimp-parse-effective-pom (pom)
+  "Calls `mvn help:effective:pom and returns XML parse tree"
   (message "Loading root pom %s..." pom)
   (javaimp-call-mvn
    pom "help:effective-pom"
    (lambda ()
-     (let (xml-start-pos xml-end-pos)
-       ;; find where we should start parsing XML
-       (goto-char (point-min))
-       (re-search-forward "<\\?xml\\|<projects?")
-       (setq xml-start-pos (match-beginning 0))
-       ;; determine the start tag
-       (goto-char (point-min))
-       (re-search-forward "<\\(projects?\\)")
-       ;; find closing tag which is also the end of the region to parse
-       (search-forward (concat "</" (match-string 1) ">"))
-       (setq xml-end-pos (match-end 0))
-       ;; parse
-       (let ((artifact-pomfile-alist
-             (javaimp-build-artifact-pomfile-alist (list pom)))
-            (children (javaimp-get-projects
-                       (xml-parse-region xml-start-pos xml-end-pos))))
-        (javaimp-maven-build-children children artifact-pomfile-alist))))))
-
-(defun javaimp-make-artifact-from-xml (node)
+     (let ((xml-start-pos
+           (save-excursion
+             (progn
+               (goto-char (point-min))
+               (re-search-forward "<\\?xml\\|<projects?")
+               (match-beginning 0))))
+          (xml-end-pos
+           (save-excursion
+             (progn
+               (goto-char (point-min))
+               (re-search-forward "<\\(projects?\\)")
+               ;; corresponding closing tag is the end of parse region
+               (search-forward (concat "</" (match-string 1) ">"))
+               (match-end 0)))))
+       (xml-parse-region xml-start-pos xml-end-pos)))))
+
+(defun javaimp-maven-load-module-tree (pom)
+  "Returns an alist of all Maven modules in a hierarchy starting
+with POM"
+  (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-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-alist)
+      (let* ((artifact (javaimp-get-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 node))
-   (javaimp-xml-first-child (javaimp-xml-child 'artifactId node))
-   (javaimp-xml-first-child (javaimp-xml-child 'version node))))
-
-(defun javaimp-get-pom-file-path-lax (artifact artifact-pomfile-alist)
-  (assoc-default
-   artifact artifact-pomfile-alist
-   (lambda (tested target)
-     (or (equal target tested)
-        (equal (javaimp-artifact-artifact-id target)
-               (javaimp-artifact-artifact-id tested))))))
-
-(defun javaimp-maven-build-children (projects artifact-pomfile-alist)
-  (let (result)
-    (dolist (proj projects result)
-      (let* ((artifact (javaimp-make-artifact-from-xml proj))
-            (pom-file-path (javaimp-get-pom-file-path-lax
-                            artifact artifact-pomfile-alist))
-            (build (javaimp-xml-child 'build proj))
-            (source-dir (javaimp-xml-first-child
-                         (javaimp-xml-child 'sourceDirectory build))) 
-            (test-source-dir (javaimp-xml-first-child
-                              (javaimp-xml-child 'testSourceDirectory
-                                                 build)))
-            (build-dir (javaimp-xml-first-child
-                        (javaimp-xml-child 'directory build)))
-            (parent (javaimp-make-artifact-from-xml
-                     (javaimp-xml-child 'parent proj))))
-       (push (javaimp-make-mod 
-              artifact
-              pom-file-path
-              (file-name-as-directory
-               (if (eq system-type 'cygwin) 
-                   (car (process-lines javaimp-cygpath-program "-u"
-                                       source-dir))
-                 source-dir))
-              (file-name-as-directory
-               (if (eq system-type 'cygwin) 
-                   (car (process-lines javaimp-cygpath-program "-u" 
-                                       test-source-dir))
-                 test-source-dir))
-              (file-name-as-directory
-               (if (eq system-type 'cygwin) 
-                   (car (process-lines javaimp-cygpath-program "-u" 
-                                       build-dir))
-                 build-dir))
-              nil nil parent nil)
-             result)))))
-
-(defun javaimp-build-artifact-pomfile-alist (pom-file-list)
-  "Recursively builds an alist where each element is of the
-form (\"ARTIFACT\" . \"POM-FILE-PATH\"). This is needed because
-there is no pom file path in the output of `mvn
-help:effective-pom'.  Each pom file path in POM-FILE-LIST should
-be in platform's default format."
-  (when pom-file-list
-    (let ((pom-file (car pom-file-list))
-         xml-tree project)
-      (message "Saving artifact id -> pom file mapping for %s" pom-file)
-      (with-temp-buffer
-       (insert-file-contents pom-file)
-       (setq xml-tree (xml-parse-region (point-min) (point-max))))
-      (setq project (if (assq 'top xml-tree)
-                       (assq 'project (cddr (assq 'top xml-tree)))
-                     (assq 'project xml-tree)))
-      (cons
-       ;; this pom
-       (cons (javaimp-make-artifact-from-xml project) pom-file)
-       (append
-       ;; submodules
-       (javaimp-build-artifact-pomfile-alist
-        (mapcar (lambda (submodule)
-                  (expand-file-name
-                   (concat
-                    ;; this pom's path
-                    (file-name-directory pom-file)
-                    ;; relative submodule directory
-                    (file-name-as-directory
-                     (let ((submodule-path (car (cddr submodule))))
-                       (if (eq system-type 'cygwin)
-                           (car (process-lines javaimp-cygpath-program "-u" 
-                                               submodule-path))
-                         submodule-path)))
-                    ;; well-known file name
-                    "pom.xml")))
-                (javaimp-xml-child-list (assq 'modules (cddr project)) 
'module)))
-       ;; rest items
-       (javaimp-build-artifact-pomfile-alist (cdr pom-file-list)))))))
+   (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" source-dir))
+    source-dir))
+
+(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)
+       nil                             ;pom-file will be set later
+       (file-name-as-directory
+        (javaimp-cygpath-convert-maybe
+         (javaimp-xml-first-child (javaimp-xml-child 'sourceDirectory 
build-elt))))
+       (file-name-as-directory
+        (javaimp-cygpath-convert-maybe
+         (javaimp-xml-first-child (javaimp-xml-child 'testSourceDirectory 
build-elt))))
+       (file-name-as-directory
+        (javaimp-cygpath-convert-maybe
+         (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-xml-child 'parent project-elt))
+       nil                             ;parent-ts will be set later
+       )))
+   project-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-parse-pom-file (pom-file)
+  "Subroutine of `javaimp-traverse-pom-tree'.  Parses POM-FILE.
+Car of result is artifact info.  Cdr of result is submodules
+relative path list."
+  (message "Parsing pom file mapping for %s" pom-file)
+  (let* ((xml-tree (with-temp-buffer
+                    (insert-file-contents pom-file)
+                    (xml-parse-region (point-min) (point-max))))
+        (project-elt (cond ((assq 'top xml-tree)
+                            (javaimp-xml-child 'project (assq 'top xml-tree)))
+                           ((assq 'project xml-tree)
+                            (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))))
+
+(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
+platform default format."
+  (if pom-file-list
+      (append
+       ;; this item
+       (let* ((this-pom (car pom-file-list))
+             (pom-file-data (javaimp-parse-pom-file this-pom)))
+        (append
+         ;; this pom itself
+         (list (cons (car pom-file-data) this-pom))
+         ;; children of this pom
+         (javaimp-traverse-pom-tree
+          (javaimp-create-absolute-submodules-paths
+           this-pom (cdr pom-file-data)))))
+       ;; 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
@@ -439,13 +469,14 @@ the temporary buffer and returns its result"
       (with-current-buffer (get-buffer-create javaimp-debug-buf-name)
        (erase-buffer)
        (insert-buffer-substring output-buf))
-      (unless (and (numberp status) (= status 0))
-       (error "Maven target \"%s\" failed with status \"%s\""
-              target status))
+      (or (and (numberp status) (= status 0))
+         (error "Maven target \"%s\" failed with status \"%s\""
+                target status))
+      (goto-char (point-min))
       (funcall handler))))
 
 
-;;; Reading and caching dependencies
+;;; Working with module dependency JARs
 
 (defun javaimp-maven-fetch-module-deps (module)
   "Returns list of dependency jars for MODULE"
@@ -720,25 +751,30 @@ argument is a list of additional classes to import."
            (javaimp-insert-import-groups static-import-groups t))
        (message "Nothing to organize")))))
 
-;;;###autoload
 (defun javaimp-invalidate-jar-classes-cache ()
   "Resets jar classes cache (debugging only)"
   (interactive)
   (setq javaimp-jar-classes-cache nil))
 
-;;;###autoload
 (defun javaimp-forget-all-visited-modules ()
   "Resets `javaimp-maven-root-modules' (debugging only)"
   (interactive)
   (setq javaimp-maven-root-modules nil))
 
-;;;###autoload
 (defun javaimp-reset ()
   "Resets all data (debugging only)"
   (interactive)
   (javaimp-forget-all-visited-modules)
   (javaimp-invalidate-jar-classes-cache))
 
+;; Some functions which can be used in other modules
+
+(defun javaimp-get-source-directories ()
+  (apply #'seq-concatenate 'list
+        (mapcar (lambda (root)
+                  (mapcar #'javaimp-get-mod-source-dir (cdr root)))
+                javaimp-maven-root-modules)))
+
 (provide 'javaimp)
 
 ;;; javaimp.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]