Re: pom 0.4 -- Utility functions for dealing with maven project.xml files

Lukáš Benda <[email protected]> Sun, 28 Jan 2007 08:45:32 +0100
Newsgroups gmane.emacs.jdee
Organization AP Netsoft
Message-ID <[email protected]>
Is this pom usable for maven2 projects?

Because of, when I tri it I get "POM: Invalid attribute list" error (it's 
error on bottom of pom.el).

Where shell be problem?

Lukas "benzin" Benda
 

Dne středa 03 srpen 2005 21:51 Ole Arndt napsal(a):
> ;;; pom --- Utility functions for dealing with maven project.xml files
>
> ;; Copyright (C) 2005 Ole Arndt
>
> ;; Author: Ole Arndt <ole at sugarshark dot com>
> ;; Maintainer: Ole Arndt <ole at sugarshark dot com>
> ;; Keywords: development, java, jdee, maven
> ;; Time-stamp: Wed Aug  3 21:41:05 2005
> ;; Version: 0.4
> ;; X-URL: http://sugarshark.com/elisp/mylisp/pom.el
>
> ;; This file is *NOT* part of GNU Emacs.
>
> ;; This program is free software; you can redistribute it and/or modify it
> ;; under the terms of the GNU General Public License as published by the
> Free ;; Software Foundation; either version 2, or (at your option) any
> later ;; version.
>
> ;; This program is distributed in the hope that it will be useful, but
> WITHOUT ;; ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or ;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> General Public License for ;; more details.
>
> ;; You should have received a copy of the GNU General Public License along
> with ;; GNU Emacs; see the file COPYING.  If not, write to the Free
> Software ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
> 02111-1307, USA.
>
> ;;; Commentary:
>
> ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;
> ;; Introduction
> ;; ------------
> ;;
> ;; This package holds some functions to deal with maven POMs
> ;;
> ;; It lets you set up you JDE variables from a maven project.xml file.
> ;; It supports project file inheritance and property substitution from the
> ;; `project.properties' and `build.properties' files.
> ;;
> ;; My typical prj.el for the JDEE looks like this:
> ;;
> ;;   (require 'pom)
> ;;   (let ((pom (pom-read-pom)))
> ;;     (jde-project-file-version "1.0")
> ;;     (jde-set-variables
> ;;      '(jde-javadoc-gen-destination-directory "./target/docs/apidocs")
> ;;      '(jde-project-name (pom-get-project-id pom))
> ;;      '(jde-global-classpath (pom-get-classpath pom))))
> ;;
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;; ;;; Options
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;;
>
> (defgroup pom nil
>   "Options controlling the maven POM parser
> See `pom-read-pom' for more information."
>
>   :group 'tools)
>
> (defcustom pom-maven-local-repository "~/.maven/repository"
>   "*Default maven repository directory."
>
>   :type 'directory
>   :group 'pom)
>
> (defcustom pom-project-file-name "project.xml"
>   "*Default name of a project file."
>
>   :type 'string
>   :group 'pom)
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;; ;;; POM handling
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;;
>
> (defun pom-get-dependency-list (pom)
>   "Get dependencies from a POM in the form of a list
> of (groupId artifactId version jar type) quintuples."
>   (let ((deps (pom-get-tag pom 'dependencies)) (result ()))
>     (dolist (a (and (listp deps) deps))
>       (if a
> 	  (let* ((id (pom-substitute-properties pom (cadr (assoc 'id a))))
> 		 (groupId (or (pom-substitute-properties
> 			       pom (cadr (assoc 'groupId a)))
> 			      (and id (car (string-split ":" id)))))
> 		 (artifactId (or (pom-substitute-properties
> 				  pom (cadr (assoc 'artifactId a)))
> 				 (and id (or (cadr (string-split ":" id)) id))))
> 		 (version (pom-substitute-properties
> 			   pom (cadr (assoc 'version a))))
> 		 (type (or (pom-substitute-properties
> 			    pom (cadr (assoc 'type a))) "jar"))
> 		 (jar (or (pom-substitute-properties pom (cadr (assoc 'jar a)))
> 			  (concat artifactId "-" version "."
> 				  (if (string= type "plugin") "jar" type)))))
> 	    (push (list groupId artifactId version jar type) result))))
>     (nreverse result)))
>
> (defun pom-get-tag (pom tag-name)
>   "Get the contents of a tag. Returns either a string or a list of
> children." (let ((pp pom) (tag nil) (res nil))
>     (while (car pp)
>       (set 'tag (assoc tag-name (car pp)))
>       (if (and tag (nth 1 tag))
> 	  (if (or (not res) (stringp (car res)))
> 	      (setq res (cdr tag))
> 	    (if (not (stringp (nth 1 tag)))
> 		(setq res (append res (cdr tag))))))
>       (set 'pp (cdr pp)))
>     (if (stringp (car res))
> 	(pom-substitute-properties pom (car res)) res)))
>
> (defun pom-substitute-properties (pom string)
>   "Substitute all occurances of \\${pom.\\(name\\)} with the result of
> `(pom-get-tag pom (quote name))'"
>   (and string
>        (replace-regexp-in-string
> 	"\\${\\(pom\\.\\)*\\([^}]+\\)}"
> 	(lambda (str)
> 	  (let ((prop (match-string 2 str)))
> 	    (or (pom-get-tag pom (intern prop)) prop))) string)))
>
> (defun pom-find-pom (&optional pom-file)
>   "Find the next project.xml file. Search up the directory tree."
>   (interactive)
>   (let ((pom (expand-file-name (or pom-file pom-project-file-name))))
>     (while (not (file-exists-p pom))
>       (if (string= (file-name-directory pom) "/")
> 	  (error "%s does not exist" (file-name-nondirectory pom))
> 	(setq pom (expand-file-name (concat "../" (file-name-nondirectory pom))
> 				    (file-name-directory pom)))))
>     pom))
>
> (defun pom-read-pom (&optional file)
>   "Read a project.xml file  and its parents into a list of lisp structures.
> The properties defined in the project.properties and build.properties
> files will be parsed as well.
> Properities referenced with a ${property} syntax will be substituted in
> both the POM and the propertiy files. This also works for POM values.
> Example:
>      With ${pom.version} you get the value of the version tag.
>      With ${pom.dependencies} you get a sublist of the POM representation.
> "
>   (let* ((pom-file (expand-file-name (or file (pom-find-pom))))
> 	 (pom-dir (expand-file-name (file-name-directory pom-file)))
> 	 (builtin-props `((properties (basedir ,pom-dir))))
> 	 (build-props (pom-read-properties
> 		       (expand-file-name "build.properties" pom-dir)))
> 	 (project-props (pom-read-properties
> 			 (expand-file-name "project.properties" pom-dir)))
> 	 (pom (append builtin-props project-props
> 		      build-props (pom-parse-pom pom-file)))
> 	 (extend (pom-get-tag pom 'extend)))
>     (append (and (stringp extend) (pom-read-pom extend)) pom)))
>
>
> (defun pom-get-project-id (&optional pom)
>   "Get the project id. If the optional `pom' parameter is nil,
> the project.xml file will be read and parsed."
>   (pom-get-tag (or pom (pom-read-pom)) 'id))
>
> (defun pom-get-dependencies (&optional pom repository)
>   "Get a list of artifacts this project depends on."
>   (interactive)
>   (let ((pp (or pom (pom-read-pom)))
> 	(repo (expand-file-name (or repository pom-maven-local-repository))))
>     (mapcar (lambda (a) (concat repo "/"
> 				(nth 0 a) "/" (nth 4 a) "s/" (nth 3 a)))
> 	    (pom-get-dependency-list pp))))
>
> (defun pom-get-dependent-jars (&optional pom repository)
>   "Get a list of jars this project depends on."
>   (interactive)
>   (let ((pp (or pom (pom-read-pom)))
> 	(repo (expand-file-name (or repository pom-maven-local-repository)))
> 	(result ()))
>     (dolist (a (pom-get-dependency-list pp))
>       (if (string= (nth 4 a) "jar")
> 	  (push (concat repo "/" (nth 0 a) "/"
> 			(nth 4 a) "s/" (nth 3 a)) result)))
>     (nreverse result)))
>
> (defun pom-get-classpath (&optional pom repository)
>   "Get the classpath for the project."
>   (let* ((pp (or pom (pom-read-pom)))
> 	 (basedir (pom-get-tag pp 'basedir)))
>     (append (list (expand-file-name "target/classes" basedir)
> 		  (expand-file-name "target/test-classes" basedir))
> 	    (pom-get-dependent-jars pp repository))))
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;; ;;; Reading and parsing property files
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;;
>
> (defun pom-read-properties (file)
>   "Read java property files."
>   (let ((keep))
>     (if (get-file-buffer file)
> 	(progn
> 	  (set-buffer (get-file-buffer file))
> 	  (setq keep (point)))
>       (let (auto-mode-alist)
> 	(set-buffer (find-file-noselect file))))
>     (let ((props (pom-parse-properties (point-min) (point-max))))
>       (if keep
> 	  (goto-char keep)
> 	(kill-buffer (current-buffer)))
>       props)))
>
> (defun pom-parse-properties (beg end)
>   "Parse java properties in region"
>   (let ((props nil))
>     (save-excursion
>       (goto-char beg)
>       (while (search-forward-regexp
> 	      "^\\s *\\([0-9A-Za-z_\\-\\.]+\\)\\s *=\\s *\\(.*\\)\\s *$"
> 	      end t)
> 	(push (list (intern (match-string 1)) (match-string 2)) props)))
>     (and props (list (append (list 'properties) (nreverse props))))))
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;; ;;; A simple xml parser for the POM.
> ;;  Taken and simplified from an older verison of xml.el
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;;
>
> (defun pom-parse-pom (file)
>   "Parse the well-formed POM FILE.
> If FILE is already edited, this will keep the buffer alive.
> Returns the top node with all its children."
>   (let ((keep))
>     (if (get-file-buffer file)
> 	(progn
> 	  (set-buffer (get-file-buffer file))
> 	  (setq keep (point)))
>       (let (auto-mode-alist)
> 	(set-buffer (find-file-noselect file))))
>     (let ((pom (pom-parse-region (point-min) (point-max))))
>       (if keep
> 	  (goto-char keep)
> 	(kill-buffer (current-buffer)))
>       pom)))
>
> (defun pom-parse-region (beg end)
>   "Parse the region from BEG to END in BUFFER."
>   (let (pom result)
>     (save-excursion
>       (goto-char beg)
>       (while (< (point) end)
> 	(if (search-forward "<" end t)
> 	    (progn
> 	      (forward-char -1)
> 	      (if (null pom)
> 		  (progn
> 		    (set 'result (pom-parse-tag end))
> 		    (cond
> 		     ((listp (car result))
> 		      (add-to-list 'pom (cdr result)))
> 		     (t
> 		      (add-to-list 'pom result))))
> 		(error "POM files can have only one toplevel tag.")))
> 	  (goto-char end)))
>       (reverse pom))))
>
>
> (defun pom-parse-tag (end)
>   "Parse the tag that is just in front of point.
> The end tag must be found before the position END in the current buffer.
> Returns one of:
>    - a list : the matching node
>    - nil    : the point is not looking at a tag."
>   (cond
>    ;; Processing instructions (like the <?xml version="1.0"?> tag at the
>    ;; beginning of a document)
>    ((looking-at "<\\?")
>     (search-forward "?>" end)
>     (skip-chars-forward " \t\n")
>     (pom-parse-tag end))
>    ;;  Character data (CDATA) sections, in which no tag should be
> interpreted ((looking-at "<!\\[CDATA\\[")
>     (let ((pos (match-end 0)))
>       (unless (search-forward "]]>" end t)
> 	(error "CDATA section does not end anywhere in the document"))
>       (buffer-substring-no-properties pos (match-beginning 0))))
>    ;;  skip DTD for the document
>    ((looking-at "<!DOCTYPE")
>     (search-forward ">" end)
>     (skip-chars-forward " \t\n")
>     (pom-parse-tag end))
>    ;;  skip comments
>    ((looking-at "<!--")
>     (search-forward "-->" end)
>     (skip-chars-forward " \t\n")
>     (pom-parse-tag end))
>    ;;  end tag
>    ((looking-at "</")
>     '())
>    ;;  opening tag
>    ((looking-at "<\\([^/> \t\n]+\\)")
>     (let* ((node-name (match-string 1))
> 	   (children (list (intern node-name)))
> 	   (case-fold-search nil) ;; XML is case-sensitive
> 	   pos)
>       (goto-char (match-end 1))
>
>       ;; ignore the attribute list; not needed for POMs
>
>       ;; is this an empty element ?
>       (if (looking-at "[ \t\n]*/>")
> 	  (progn
> 	    (skip-chars-forward " \t\n")
> 	    (forward-char 2)
> 	    (skip-chars-forward " \t\n")
> 	    (append children '("")))
>
> 	;; is this a valid start tag ?
> 	(if (= (char-after) ?>)
> 	    (progn
> 	      (forward-char 1)
> 	      (skip-chars-forward " \t\n")
> 	      ;;  Now check that we have the right end-tag. Note that this one
> 	      ;; might contain spaces after the tag name
> 	      (while (not (looking-at (concat "</" node-name "[ \t\n]*>")))
> 		(cond
> 		 ((looking-at "</")
> 		  (error (concat
> 			  "POM: invalid syntax -- invalid end tag (expecting "
> 			  node-name
> 			  ") at pos " (number-to-string (point)))))
> 		 ((= (char-after) ?<)
> 		  (set 'children (append children (list (pom-parse-tag end)))))
> 		 (t
> 		  (set 'pos (point))
> 		  (search-forward "<" end)
> 		  (forward-char -1)
> 		  (let ((string (buffer-substring-no-properties pos (point)))
> 			(pos 0))
> 		    (set 'children (append children
> 					   (list string)))))))
> 	      (goto-char (match-end 0))
> 	      (skip-chars-forward " \t\n")
> 	      (if (> (point) end)
> 		  (error "POM: End tag for %s not found before end of region."
> 			 node-name))
> 	      children
> 	      )
>
> 	  ;;  This was an invalid start tag
> 	  (error "POM: Invalid attribute list")))))))
>
> (provide 'pom)
>
> ;;; EOF