[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 195a4b8: * externals-list: Convert javaimp to :external
From: |
Stefan Monnier |
Subject: |
[elpa] master 195a4b8: * externals-list: Convert javaimp to :external |
Date: |
Tue, 1 Dec 2020 10:08:36 -0500 (EST) |
branch: master
commit 195a4b87ef3b9eeab6b05a7dca769220e91749a7
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
* externals-list: Convert javaimp to :external
---
externals-list | 1 +
packages/javaimp/gradleTaskBody.inc.kts | 27 --
packages/javaimp/javaimp-gradle.el | 153 ----------
packages/javaimp/javaimp-maven.el | 180 -----------
packages/javaimp/javaimp-tests.el | 23 --
packages/javaimp/javaimp-util.el | 165 -----------
packages/javaimp/javaimp.el | 511 --------------------------------
7 files changed, 1 insertion(+), 1059 deletions(-)
diff --git a/externals-list b/externals-list
index 7a921fe..379f6df 100644
--- a/externals-list
+++ b/externals-list
@@ -131,6 +131,7 @@
("ioccur" :external
"https://github.com/thierryvolpiatto/ioccur.git")
("ivy-explorer" :external "https://github.com/clemera/ivy-explorer")
("ivy-posframe" :external "https://github.com/tumashu/ivy-posframe")
+ ("javaimp" :external nil)
("jgraph-mode" :external nil)
("js2-mode" :external "https://github.com/mooz/js2-mode.git")
("json-mode" :external nil)
diff --git a/packages/javaimp/gradleTaskBody.inc.kts
b/packages/javaimp/gradleTaskBody.inc.kts
deleted file mode 100644
index 942814f..0000000
--- a/packages/javaimp/gradleTaskBody.inc.kts
+++ /dev/null
@@ -1,27 +0,0 @@
-// use syntax which is valid both in Groovy and in Kotlin
-doLast {
- println("id=${project.group};${project.path};${project.version}")
- if (project.parent != null) {
-
println("parent-id=${project.parent.group};${project.parent.path};${project.parent.version}")
- }
- println("file=${project.buildFile}")
- println("build-dir=${project.buildDir}")
- if (project.pluginManager.hasPlugin("java")) {
- // "archives" configuration and "sourceSets" property defined by java
plugin
- println("final-name=" +
project.configurations.getByName("archives").artifacts.stream()
- .filter { it.type.equals("jar") || it.type.equals("war") }
- .map { it.file.path }
- .findFirst()
- .orElse(""))
- println("source-dirs=" + project.sourceSets.stream()
- .flatMap { it.allJava.srcDirs.stream().map { it.path } }
- .collect(Collectors.joining(File.pathSeparator)))
- println("dep-jars=" + project.sourceSets.stream()
- .flatMap { it.compileClasspath.files.stream().filter {
it.name.endsWith("jar") }.map { it.path } }
- .collect(Collectors.joining(File.pathSeparator)))
- } else {
- println("final-name=")
- println("source-dirs=")
- println("dep-jars=")
- }
-}
diff --git a/packages/javaimp/javaimp-gradle.el
b/packages/javaimp/javaimp-gradle.el
deleted file mode 100644
index 2241da5..0000000
--- a/packages/javaimp/javaimp-gradle.el
+++ /dev/null
@@ -1,153 +0,0 @@
-;;; javaimp-gradle.el --- javaimp gradle support -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2019 Free Software Foundation, Inc.
-
-;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
-
-;; 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-(require 'javaimp-util)
-
-(defcustom javaimp-gradle-program "gradle"
- "Path to the `gradle' program. Customize it if the program is
-not on `exec-path'. If the visited project's directory contains
-gradlew program, it is used in preference."
- :group 'javaimp
- :type 'string)
-
-(defconst javaimp--gradle-task-body
- (with-temp-buffer
- (insert-file-contents (expand-file-name "gradleTaskBody.inc.kts"
javaimp--basedir))
- (buffer-string))
- "Task body, uses syntax which can be used both in Groovy and Kotlin")
-
-(defun javaimp--gradle-visit (file)
- "Calls gradle on FILE to get various project information.
-
-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* ((alists (javaimp--gradle-call file
- javaimp--gradle-task-body
- #'javaimp--gradle-handler
- "javaimpTask"))
- (modules (mapcar (lambda (alist)
- (javaimp--gradle-module-from-alist alist file))
- alists)))
- ;; first module is always root
- (javaimp--build-tree (car modules) nil modules)))
-
-(defun javaimp--gradle-handler ()
- (goto-char (point-min))
- (let (alist res sym val)
- (while (re-search-forward "^\\([[:alnum:]-]+\\)=\\(.*\\)$" nil t)
- (setq sym (intern (match-string 1))
- val (match-string 2))
- (if (string-blank-p val)
- (setq val nil))
- (when (and (eq sym 'id) alist) ;start of next module
- (push alist res)
- (setq alist nil))
- (push (cons sym val) alist))
- (when alist ;last module
- (push alist res))
- (nreverse res)))
-
-(defun javaimp--gradle-module-from-alist (alist file-orig)
- (make-javaimp-module
- :id (javaimp--gradle-id-from-semi-separated (cdr (assq 'id alist)))
- :parent-id (javaimp--gradle-id-from-semi-separated (cdr (assq 'parent-id
alist)))
- :file (cdr (assq 'file alist))
- :file-orig file-orig
- ;; jar/war supported
- :final-name (let ((final-name (javaimp-cygpath-convert-maybe
- (cdr (assq 'final-name alist)))))
- (and final-name
- (member (file-name-extension final-name) '("jar" "war"))
- final-name))
- :source-dirs (mapcar #'file-name-as-directory
- (javaimp--split-native-path
- (cdr (assq 'source-dirs alist))))
- :build-dir (file-name-as-directory
- (javaimp-cygpath-convert-maybe
- (cdr (assq 'build-dir alist))))
- :dep-jars (javaimp--split-native-path (cdr (assq 'dep-jars alist)))
- :load-ts (current-time)
- :dep-jars-path-fetcher #'javaimp--gradle-fetch-dep-jars-path))
-
-(defun javaimp--gradle-id-from-semi-separated (str)
- (when str
- (let ((parts (split-string str ";" t)) artifact)
- (unless (= (length parts) 3)
- (error "Invalid project id: %s" str))
- (setq artifact (nth 1 parts))
- (if (equal artifact ":")
- (setq artifact "<root>")
- ;; convert "[:]foo:bar:baz" into "foo.bar.baz"
- (setq artifact (replace-regexp-in-string
- ":" "." (string-remove-prefix ":" artifact))))
- (make-javaimp-id :group (nth 0 parts) :artifact artifact
- :version (nth 2 parts)))))
-
-(defun javaimp--gradle-fetch-dep-jars-path (module)
- ;; always invoke on root file becase module's file may not exist
- ;; (even if reported as project.buildFile property)
- (javaimp--gradle-call (javaimp-module-file-orig module)
- javaimp--gradle-task-body
- (lambda ()
- (re-search-forward "^dep-jars=\\(.*\\)$")
- (match-string 1))
- (concat (if (javaimp-module-parent-id module)
- (concat ":" (javaimp-id-artifact
(javaimp-module-id module))))
- ":javaimpTask")))
-
-(defun javaimp--gradle-call (file init-script-body 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
- (javaimp--gradle-init-script-kotlin
init-script-body)
- (javaimp--gradle-init-script
init-script-body))))
- (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)
- task)))
-
-
-(defun javaimp--gradle-init-script (body)
- (concat "
-import java.io.File
-import java.util.stream.Collectors
-allprojects {
- task javaimpTask {"
- body
- "} }"))
-
-(defun javaimp--gradle-init-script-kotlin (body)
- (concat "
-import java.io.File
-import java.util.stream.Collectors
-allprojects {
- tasks.register(\"javaimpTask\") {"
- body
- "} }"))
-
-(provide 'javaimp-gradle)
diff --git a/packages/javaimp/javaimp-maven.el
b/packages/javaimp/javaimp-maven.el
deleted file mode 100644
index 524aa77..0000000
--- a/packages/javaimp/javaimp-maven.el
+++ /dev/null
@@ -1,180 +0,0 @@
-;;; javaimp-maven.el --- javaimp maven support -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2019 Free Software Foundation, Inc.
-
-;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
-
-;; 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-;;; Code:
-
-(require 'javaimp-util)
-
-(defcustom javaimp-mvn-program "mvn"
- "Path to the `mvn' program. Customize it if the program is not
-on `exec-path'."
- :group 'javaimp
- :type 'string)
-
-
-(defun javaimp--maven-visit (file)
- "Calls `mvn help:effective-pom' on FILE,
-reads project structure from the output and records which files
-belong to which modules and other module information"
- (message "Visiting Maven POM file %s..." file)
- (let* ((xml-tree (javaimp--call-build-tool javaimp-mvn-program
-
#'javaimp--maven-effective-pom-handler
- "-f"
(javaimp-cygpath-convert-maybe file)
- "help:effective-pom"))
- (projects (javaimp--maven-projects-from-xml xml-tree))
- (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
- ;; Set files in a separate step after building the tree because "real"
- ;; parent of a child (given by <parent>) does not necessary contains the
- ;; child in its <modules>. This is rare, but happens.
- (javaimp--maven-fill-modules-files file tree)
- ;; check that no :file slot is empty
- (let ((modules-without-files
- (mapcar #'javaimp-node-contents
- (javaimp--select-nodes-from-tree
- tree (lambda (m)
- (null (javaimp-module-file m)))))))
- (if modules-without-files
- (error "Cannot find file for module(s): %s"
- (mapconcat #'javaimp-module-id modules-without-files
", "))))
- tree)))
-
-(defun javaimp--maven-effective-pom-handler ()
- (let ((start
- (save-excursion
- (progn
- (goto-char (point-min))
- (re-search-forward "<\\?xml\\|<projects?")
- (match-beginning 0))))
- (end
- (save-excursion
- (progn
- (goto-char (point-min))
- (re-search-forward "<\\(projects?\\)")
- ;; corresponding close tag is the end of parse region
- (search-forward (concat "</" (match-string 1) ">"))
- (match-end 0)))))
- (xml-parse-region start end)))
-
-(defun javaimp--maven-projects-from-xml (tree)
- "Analyzes result of `mvn help:effective-pom' and returns list
-of <project> elements"
- (let ((project (assq 'project tree))
- (projects (assq 'projects tree)))
- (cond (project
- (list project))
- (projects
- (javaimp--xml-children projects 'project))
- (t
- (error "Neither <project> nor <projects> was found in pom")))))
-
-(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)
- :parent-id (javaimp--maven-id-from-xml (javaimp--xml-child 'parent elt))
- ;; <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
- ;; jar/war supported
- :final-name (let ((packaging (or (javaimp--xml-first-child
- (javaimp--xml-child 'packaging
elt))
- "jar")))
- (when (member packaging '("jar" "war"))
- (concat (javaimp--xml-first-child
- (javaimp--xml-child 'finalName build-elt))
- "." packaging)))
- :source-dirs (list (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)))))
- :build-dir (file-name-as-directory
- (javaimp-cygpath-convert-maybe
- (javaimp--xml-first-child (javaimp--xml-child
'directory build-elt))))
- :dep-jars nil ; dep-jars is initialized lazily on demand
- :load-ts (current-time)
- :dep-jars-path-fetcher #'javaimp--maven-fetch-dep-jars-path)))
-
-(defun javaimp--maven-id-from-xml (elt)
- (make-javaimp-id
- :group (javaimp--xml-first-child (javaimp--xml-child 'groupId elt))
- :artifact (javaimp--xml-first-child (javaimp--xml-child 'artifactId elt))
- :version (javaimp--xml-first-child (javaimp--xml-child 'version elt))))
-
-(defun javaimp--maven-fill-modules-files (file tree)
- ;; Reads module id from FILE, looks up corresponding module in TREE, sets its
- ;; :file slot, then recurses for each submodule. A submodule file path is
- ;; constructed by appending relative path taken from <module> to FILE's
- ;; directory.
- (let* ((xml-tree (with-temp-buffer
- (insert-file-contents file)
- (xml-parse-region (point-min) (point-max))))
- (project-elt (assq 'project xml-tree))
- (this-id (javaimp--maven-id-from-xml project-elt))
- ;; seems that the only mandatory component in tested ids is
artifact, while
- ;; group and version may be inherited and thus not presented in
pom.xml
- (id-pred (if (or (null (javaimp-id-group this-id))
- (null (javaimp-id-version this-id)))
- (progn
- (message "File %s contains incomplete id,
will check artifact only" file)
- (lambda (tested-id)
- (equal (javaimp-id-artifact this-id)
- (javaimp-id-artifact
tested-id))))
- (lambda (tested-id)
- (equal this-id tested-id))))
- (module
- (javaimp-node-contents
- (or (javaimp--find-node-in-tree
- tree (lambda (m)
- (funcall id-pred (javaimp-module-id m))))
- (error "Cannot find module for id %s (taken from file %s)"
this-id file)))))
- (setf (javaimp-module-file module) file)
- (let ((rel-paths
- (mapcar #'javaimp--xml-first-child
- (javaimp--xml-children (javaimp--xml-child 'modules
project-elt) 'module))))
- (dolist (rel-path rel-paths)
- (javaimp--maven-fill-modules-files (concat (file-name-directory
file)
-
(file-name-as-directory rel-path)
-
"pom.xml")
- tree)))))
-
-(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))
- ;; 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-tests.el
b/packages/javaimp/javaimp-tests.el
deleted file mode 100644
index 0dbe86f..0000000
--- a/packages/javaimp/javaimp-tests.el
+++ /dev/null
@@ -1,23 +0,0 @@
-;;; javaimp-tests.el --- javaimp tests -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2016-2019 Free Software Foundation, Inc.
-
-;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
-
-(require 'ert)
-(require 'javaimp-maven)
-
-(ert-deftest javaimp-test--maven-projects-from-xml--project ()
- (with-temp-buffer
- (insert "<project/>")
- (let ((projects (javaimp--maven-projects-from-xml
- (xml-parse-region (point-min) (point-max)))))
- (should (eql (length projects) 1)))))
-
-(ert-deftest javaimp-test--maven-projects-from-xml--projects ()
- (with-temp-buffer
- (insert "<projects><project/><project/></projects>")
- (let ((projects (javaimp--maven-projects-from-xml
- (xml-parse-region (point-min) (point-max)))))
- (should (eql (length projects) 2)))))
diff --git a/packages/javaimp/javaimp-util.el b/packages/javaimp/javaimp-util.el
deleted file mode 100644
index c03414d..0000000
--- a/packages/javaimp/javaimp-util.el
+++ /dev/null
@@ -1,165 +0,0 @@
-;;; javaimp-util.el --- javaimp util -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2019 Free Software Foundation, Inc.
-
-;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
-
-;; 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-;;; Code:
-
-(require 'xml)
-(require 'cl-lib)
-(require 'seq)
-
-(defcustom javaimp-cygpath-program
- (if (eq system-type 'cygwin) "cygpath")
- "Path to the `cygpath' program (Cygwin only). Customize it if
-the program is not on `exec-path'."
- :group 'javaimp
- :type 'string)
-
-(defconst javaimp-debug-buf-name "*javaimp-debug*")
-
-(defconst javaimp--basedir (file-name-directory load-file-name))
-
-;; Structs
-
-(cl-defstruct javaimp-node
- parent children contents)
-
-(cl-defstruct javaimp-module
- id parent-id
- file
- file-orig
- final-name ;may be relative (to build-dir)
- source-dirs build-dir
- dep-jars
- load-ts
- dep-jars-path-fetcher)
-
-(cl-defstruct javaimp-id
- group artifact version)
-
-(cl-defstruct javaimp-cached-jar
- file read-ts classes)
-
-
-(defun javaimp--xml-children (xml-tree child-name)
- "Returns list of children of XML-TREE filtered by CHILD-NAME"
- (seq-filter (lambda (child)
- (and (consp child)
- (eq (car child) child-name)))
- (cddr xml-tree)))
-
-(defun javaimp--xml-child (name el)
- "Returns a child of EL named by symbol NAME"
- (assq name (cddr el)))
-
-(defun javaimp--xml-first-child (el)
- "Returns a first child of EL"
- (car (cddr el)))
-
-
-(defun javaimp--get-file-ts (file)
- (nth 5 (file-attributes file)))
-
-(defun javaimp-print-id (id)
- (format "%s:%s:%s"
- (javaimp-id-artifact id)
- (javaimp-id-group id)
- (javaimp-id-version id)))
-
-(defun javaimp--get-jdk-jars ()
- (and javaimp-java-home
- (file-accessible-directory-p javaimp-java-home)
- (let ((lib-dir
- (concat (file-name-as-directory javaimp-java-home)
- (file-name-as-directory "jre")
- (file-name-as-directory "lib"))))
- (directory-files lib-dir t "\\.jar\\'"))))
-
-
-;; TODO 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
-
-(defun javaimp-cygpath-convert-maybe (path &optional mode is-really-path)
- "On Cygwin, converts PATH using cygpath according to MODE and
-IS-REALLY-PATH. If MODE is `unix' (the default), adds -u switch.
-If MODE is `windows', adds -m switch. If `is-really-path' is
-non-nil, adds `-p' switch. On other systems, PATH is returned
-unchanged."
- (if (and path (eq system-type 'cygwin))
- (progn
- (unless mode (setq mode 'unix))
- (let (args)
- (push (cond ((eq mode 'unix) "-u")
- ((eq mode 'windows) "-m")
- (t (error "Invalid mode: %s" mode)))
- args)
- (and is-really-path (push "-p" args))
- (push path args)
- (car (apply #'process-lines javaimp-cygpath-program args))))
- path))
-
-
-(defun javaimp--call-build-tool (program handler &rest args)
- "Runs PROGRAM with ARGS, then calls HANDLER in the temporary
-buffer and returns its result"
- (message "Calling %s on args: %s" program args)
- (with-temp-buffer
- (let ((status (let ((coding-system-for-read
- (if (eq system-type 'cygwin) 'utf-8-dos)))
- ;; TODO check
in output on Gnu/Linux
- (apply #'process-file program nil t nil args)))
- (buf (current-buffer)))
- (with-current-buffer (get-buffer-create javaimp-debug-buf-name)
- (erase-buffer)
- (insert-buffer-substring buf))
- (or (and (numberp status) (= status 0))
- (error "\"%s\" failed with status \"%s\"" program status))
- (goto-char (point-min))
- (funcall handler))))
-
-(defun javaimp--split-native-path (path)
- (when path
- (let ((converted (javaimp-cygpath-convert-maybe path 'unix t))
- (sep-regex (concat "[" path-separator "\n" "]+")))
- (split-string converted sep-regex t))))
-
-(defun javaimp--build-tree (this parent-node all)
- (message "Building tree for module: %s" (javaimp-print-id (javaimp-module-id
this)))
- (let ((children
- ;; more or less reliable way to find children is to look for
- ;; modules with "this" as the parent
- (seq-filter (lambda (m)
- (equal (javaimp-module-parent-id m) (javaimp-module-id
this)))
- all)))
- (let* ((this-node (make-javaimp-node
- :parent parent-node
- :children nil
- :contents this))
- ;; recursively build child nodes
- (child-nodes
- (mapcar (lambda (child)
- (javaimp--build-tree child this-node all))
- children)))
- (setf (javaimp-node-children this-node) child-nodes)
- this-node)))
-
-(provide 'javaimp-util)
diff --git a/packages/javaimp/javaimp.el b/packages/javaimp/javaimp.el
deleted file mode 100644
index cd340f4..0000000
--- a/packages/javaimp/javaimp.el
+++ /dev/null
@@ -1,511 +0,0 @@
-;;; javaimp.el --- Add and reorder Java import statements in Maven/Gradle
projects -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2014-2019 Free Software Foundation, Inc.
-
-;; Author: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Maintainer: Filipp Gunbin <fgunbin@fastmail.fm>
-;; Version: 0.7.1
-;; Keywords: java, maven, gradle, programming
-
-;; 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Allows to manage Java import statements in Maven/Gradle projects.
-;;
-;; Quick start:
-;;
-;; - customize `javaimp-import-group-alist'
-;; - call `javaimp-visit-project', giving it the top-level project
-;; 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'.
-;;
-;; This module does not add all needed imports automatically! It only helps
-;; you to quickly add imports when stepping through compilation errors.
-;;
-;; Some details:
-;;
-;; If Maven/Gradle failed, you can see its output in the buffer named
-;; by `javaimp-debug-buf-name' (default is "*javaimp-debug*").
-;;
-;; Contents of jar files and Maven/Gradle project structures are
-;; cached, so usually only the first command should take a
-;; considerable amount of time to complete. If a module's build file
-;; or any of its parents' build files (within visited tree) was
-;; modified after information was loaded, dependencies are fetched
-;; from the build tool again. If a jar file was changed, its contents
-;; are re-read.
-;;
-;; Currently inner classes are filtered out from completion alternatives.
-;; You can always import top-level class and use qualified name.
-;;
-;;
-;; Example:
-;;
-;; (require 'javaimp)
-;; (add-to-list 'javaimp-import-group-alist
-;; '("\\`\\(my\\.company\\.\\|my\\.company2\\.\\)" . 80))
-;; (setq javaimp-additional-source-dirs '("generated-sources/thrift"))
-;; (add-hook 'java-mode-hook
-;; (lambda ()
-;; (local-set-key "\C-ci" 'javaimp-add-import)
-;; (local-set-key "\C-co" 'javaimp-organize-imports)))
-;; (global-set-key (kbd "C-c j v") 'javaimp-visit-project)
-;;
-
-;;; News:
-
-;; v0.7:
-;; - Added Gradle support.
-;;
-;; - Removed javaimp-maven-visit-project in favor of javaimp-visit-project.
-;;
-;; - Split into multiple files.
-
-
-;;; Code:
-
-(require 'javaimp-maven)
-(require 'javaimp-gradle)
-
-
-
-;; User options
-
-(defgroup javaimp ()
- "Add and reorder Java import statements in Maven/Gradle
-projects"
- :group 'c)
-
-(defcustom javaimp-import-group-alist '(("\\`java\\." . 10) ("\\`javax\\." .
15))
- "Specifies how to group classes and how to order resulting
-groups in the imports list.
-
-Each element should be of the form (CLASSNAME-REGEXP . ORDER)
-where CLASSNAME-REGEXP is a regexp matching the fully qualified
-class name. Lowest-order groups are placed earlier.
-
-The order of classes which were not matched is defined by
-`javaimp-import-default-order'."
- :group 'javaimp
- :type '(alist :key-type string :value-type integer))
-
-(defcustom javaimp-import-default-order 50
- "Defines the order of classes which were not matched by
-`javaimp-import-group-alist'"
- :group 'javaimp
- :type 'integer)
-
-(defcustom javaimp-java-home (getenv "JAVA_HOME")
- "Path to the JDK. Directory jre/lib underneath this path is
-searched for JDK libraries. By default, it is initialized from
-the JAVA_HOME environment variable."
- :group 'javaimp
- :type 'string)
-
-(defcustom javaimp-additional-source-dirs nil
- "List of directories where additional (e.g. generated)
-source files reside.
-
-Each directory is a relative path from ${project.build.directory} project
-property value.
-
-Typically you would check documentation for a Maven plugin, look
-at the parameter's default value there and add it to this list.
-
-E.g. \"${project.build.directory}/generated-sources/<plugin_name>\"
-becomes \"generated-sources/<plugin_name>\" (note the absence
-of the leading slash.
-
-Custom values set in plugin configuration in pom.xml are not
-supported yet."
- :group 'javaimp
- :type '(repeat (string :tag "Relative directory")))
-
-(defcustom javaimp-jar-program "jar"
- "Path to the `jar' program used to read contents of jar files.
-Customize it if the program is not on `exec-path'."
- :group 'javaimp
- :type 'string)
-
-(defcustom javaimp-include-current-module-classes t
- "If non-nil, current module's classes are included into
-completion alternatives. `javaimp-add-import' will find all java
-files in the current project and add their fully-qualified names
-to the completion alternatives list."
- :group 'javaimp
- :type 'boolean)
-
-
-;; Variables
-
-(defvar javaimp-project-forest nil
- "Visited projects")
-
-(defvar javaimp-cached-jars nil
- "Alist of cached jars. Each element is of the form (FILE
- . CACHED-JAR).")
-
-
-
-;;;###autoload
-(defun javaimp-visit-project (dir)
- "Loads a project and its submodules. DIR should point to a
-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
-any module file."
- (interactive "DVisit Maven or Gradle project in directory: ")
- (let* ((exp-dir (expand-file-name (file-name-as-directory dir)))
- build-file
- (tree (cond
- ((file-readable-p (setq build-file (concat exp-dir "pom.xml")))
- (javaimp--maven-visit build-file))
- ((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 tree(s) loaded from this build file, if any
- (setq javaimp-project-forest
- (seq-remove (lambda (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))))
-
-
-;; Dependency jars
-
-(defun javaimp--update-module-maybe (node)
- (let ((module (javaimp-node-contents node))
- need-update)
- ;; check if deps are initialized
- (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 ((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)
module))
- (new-dep-jars (javaimp--split-native-path path))
- (new-load-ts (current-time)))
- (setf (javaimp-module-dep-jars module) new-dep-jars)
- (setf (javaimp-module-load-ts module) new-load-ts)))))
-
-(defun javaimp--get-jar-classes (file)
- (let ((cached (cdr (assoc file javaimp-cached-jars))))
- (cond ((null cached)
- ;; create, load & put into cache
- (setq cached
- (make-javaimp-cached-jar
- :file file
- :read-ts (javaimp--get-file-ts file)
- :classes (javaimp--fetch-jar-classes file)))
- (push (cons file cached) javaimp-cached-jars))
- ((> (float-time (javaimp--get-file-ts (javaimp-cached-jar-file
cached)))
- (float-time (javaimp-cached-jar-read-ts cached)))
- ;; reload
- (setf (javaimp-cached-jar-classes cached)
(javaimp--fetch-jar-classes file))
- ;; update read-ts
- (setf (javaimp-cached-jar-read-ts cached) (current-time))))
- ;; return from cached
- (javaimp-cached-jar-classes cached)))
-
-(defun javaimp--fetch-jar-classes (file)
- (message "Reading classes in file: %s" file)
- (with-temp-buffer
- (let ((coding-system-for-read (and (eq system-type 'cygwin) 'utf-8-dos)))
- ;; on cygwin, "jar" is a windows program, so file path needs to be
- ;; converted appropriately.
- (process-file javaimp-jar-program nil t nil
- ;; `jar' accepts commands/options as a single string
- "tf" (javaimp-cygpath-convert-maybe file 'windows))
- (goto-char (point-min))
- (while (search-forward "/" nil t)
- (replace-match "."))
- (goto-char (point-min))
- (let (result)
- (while (re-search-forward "\\(^[[:alnum:]._]+\\)\\.class$" nil t)
- (push (match-string 1) result))
- result))))
-
-
-;; Tree search routines
-
-(defun javaimp--find-node (predicate)
- (catch 'found
- (dolist (tree javaimp-project-forest)
- (javaimp--find-node-in-tree-1 tree predicate))))
-
-(defun javaimp--select-nodes (predicate)
- (apply #'seq-concatenate 'list
- (mapcar (lambda (tree)
- (javaimp--select-nodes-from-tree tree predicate))
- javaimp-project-forest)))
-
-(defun javaimp--find-node-in-tree (tree predicate)
- (catch 'found
- (javaimp--find-node-in-tree-1 tree predicate)))
-
-(defun javaimp--find-node-in-tree-1 (tree predicate)
- (when tree
- (if (funcall predicate (javaimp-node-contents tree))
- (throw 'found tree))
- (dolist (child (javaimp-node-children tree))
- (javaimp--find-node-in-tree-1 child predicate))))
-
-(defun javaimp--select-nodes-from-tree (tree predicate)
- (when tree
- (append (if (funcall predicate (javaimp-node-contents tree))
- (list tree))
- (apply #'seq-concatenate 'list
- (mapcar (lambda (child)
- (javaimp--select-nodes-from-tree child predicate))
- (javaimp-node-children tree))))))
-
-
-;; Some API functions
-
-;; do not expose tree structure, return only modules
-
-(defun javaimp-find-module (predicate)
- (let ((node (javaimp--find-node predicate)))
- (and node
- (javaimp-node-contents node))))
-
-(defun javaimp-select-modules (predicate)
- (mapcar #'javaimp-node-contents
- (javaimp--select-nodes predicate)))
-
-
-;;; Adding imports
-
-;; TODO narrow alternatives by class local name
-
-;;;###autoload
-(defun javaimp-add-import (classname)
- "Imports classname in the current file. Interactively,
-asks for a class to import, adds import statement and calls
-`javaimp-organize-imports'. Import statements are not
-duplicated. Completion alternatives are constructed based on
-this module's dependencies' classes, JDK classes and top-level
-classes in the current module."
- (interactive
- (let* ((file (expand-file-name (or buffer-file-name
- (error "Buffer is not visiting a
file!"))))
- (node (or (javaimp--find-node
- (lambda (m)
- (seq-some (lambda (dir)
- (string-prefix-p dir file))
- (javaimp-module-source-dirs m))))
- (error "Cannot find module by file: %s" file))))
- (javaimp--update-module-maybe node)
- (let ((module (javaimp-node-contents node)))
- (list (completing-read
- "Import: "
- (append
- ;; we're not caching full list of classes coming from module
- ;; dependencies because jars may change and we need to reload
- ;; them
- (let ((jars (append (javaimp-module-dep-jars module)
- (javaimp--get-jdk-jars))))
- (apply #'seq-concatenate 'list
- (mapcar #'javaimp--get-jar-classes jars)))
- (and javaimp-include-current-module-classes
- (javaimp--get-module-classes module)))
- nil t nil nil (symbol-name (symbol-at-point)))))))
- (barf-if-buffer-read-only)
- (javaimp-organize-imports (cons classname 'ordinary)))
-
-(defun javaimp--get-module-classes (module)
- "Returns list of top-level classes in current module"
- (append
- ;; source dirs
- (seq-mapcat (lambda (dir)
- (and (file-accessible-directory-p dir)
- (javaimp--get-directory-classes dir nil)))
- (javaimp-module-source-dirs module))
- ;; additional source dirs
- (seq-mapcat (lambda (rel-dir)
- (let ((dir (concat (javaimp-module-build-dir module)
- (file-name-as-directory rel-dir))))
- (and (file-accessible-directory-p dir)
- (javaimp--get-directory-classes dir nil))))
- javaimp-additional-source-dirs)))
-
-(defun javaimp--get-directory-classes (dir prefix)
- (append
- ;; .java files in current directory
- (mapcar (lambda (file)
- (concat prefix (file-name-sans-extension (car file))))
- (seq-filter (lambda (file) (null (cadr file))) ;only files
- (directory-files-and-attributes dir nil "\\.java\\'" t)))
- ;; descend into subdirectories
- (apply #'seq-concatenate 'list
- (mapcar (lambda (subdir)
- (let ((name (car subdir)))
- (javaimp--get-directory-classes
- (concat dir (file-name-as-directory name)) (concat
prefix name "."))))
- (seq-filter (lambda (file)
- (and (eq (cadr file) t) ;only directories
- (null (member (car file) '("." "..")))))
- (directory-files-and-attributes dir nil nil
t))))))
-
-
-;; Organizing imports
-
-;;;###autoload
-(defun javaimp-organize-imports (&rest new-imports)
- "Groups import statements according to the value of
-`javaimp-import-group-alist' (which see) and prints resulting
-groups leaving one blank line between groups.
-
-If the file already contains some import statements, this command
-rewrites them, starting with the same place. Else, if the the
-file contains package directive, this command inserts one blank
-line below and then imports. Otherwise, imports are inserted at
-the beginning of buffer.
-
-Classes within a single group are ordered in a lexicographic
-order. Imports not matched by any regexp in `javaimp-import-group-alist'
-are assigned a default order defined by
-`javaimp-import-default-order'.
-
-NEW-IMPORTS is a list of additional imports; each element should
-be of the form (CLASS . TYPE), where CLASS is a string and TYPE
-is `ordinary' or `static'. Interactively, NEW-IMPORTS is nil."
- (interactive)
- (barf-if-buffer-read-only)
- (save-excursion
- (goto-char (point-min))
- (let* ((old-data (javaimp--parse-imports))
- (first (car old-data))
- (last (cadr old-data))
- (all-imports (append new-imports (cddr old-data))))
- (if all-imports
- (progn
- ;; delete old imports, if any
- (if first
- (progn
- (goto-char last)
- (forward-line)
- (delete-region first (point))))
- (javaimp--prepare-for-insertion first)
- (setq all-imports
- (cl-delete-duplicates
- all-imports
- :test (lambda (first second)
- (equal (car first) (car second)))))
- ;; assign order
- (let ((with-order
- (mapcar
- (lambda (import)
- (let ((order (or (assoc-default (car import)
- javaimp-import-group-alist
- 'string-match)
- javaimp-import-default-order)))
- (cons import order)))
- all-imports)))
- (setq with-order
- (sort with-order
- (lambda (first second)
- ;; sort by order, name
- (if (= (cdr first) (cdr second))
- (string< (caar first) (caar second))
- (< (cdr first) (cdr second))))))
- (javaimp--insert-imports with-order)))
- (message "Nothing to organize!")))))
-
-(defun javaimp--parse-imports ()
- "Returns (FIRST LAST . IMPORTS)"
- (let (first last imports)
- (while (re-search-forward
"^\\s-*import\\s-+\\(static\\s-+\\)?\\([._[:word:]]+\\)" nil t)
- (let ((type (if (match-string 1) 'static 'ordinary))
- (class (match-string 2)))
- (push (cons class type) imports))
- (setq last (line-beginning-position))
- (or first (setq first last)))
- (cons first (cons last imports))))
-
-(defun javaimp--prepare-for-insertion (start)
- (cond (start
- ;; if there were any imports, we start inserting at the same place
- (goto-char start))
- ((re-search-forward "^\\s-*package\\s-" nil t)
- ;; if there's a package directive, insert one blank line below and
- ;; leave point after it
- (end-of-line)
- (if (eobp)
- (insert ?\n)
- (forward-line))
- ;; then insert one blank line and we're done
- (insert ?\n))
- (t
- ;; otherwise, just go to bob
- (goto-char (point-min)))))
-
-(defun javaimp--insert-imports (imports)
- (let ((static (seq-filter (lambda (elt)
- (eq (cdar elt) 'static))
- imports))
- (ordinary (seq-filter (lambda (elt)
- (eq (cdar elt) 'ordinary))
- imports)))
- (javaimp--insert-import-group "import static %s;" static)
- (and static ordinary (insert ?\n))
- (javaimp--insert-import-group "import %s;" ordinary)))
-
-(defun javaimp--insert-import-group (pattern imports)
- (let (last-order)
- (dolist (import imports)
- ;; if adjacent imports have different order value, insert a newline
- ;; between them
- (let ((order (cdr import)))
- (and last-order
- (/= order last-order)
- (insert ?\n))
- (insert (format pattern (caar import)) ?\n)
- (setq last-order order)))))
-
-(defun javaimp-reset (arg)
- "Forget loaded trees state. With prefix arg, also reset jars
-cache."
- (interactive "P")
- (setq javaimp-project-forest nil)
- (when arg
- (setq javaimp-cached-jars nil)))
-
-(provide 'javaimp)
-
-;;; javaimp.el ends here
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] master 195a4b8: * externals-list: Convert javaimp to :external,
Stefan Monnier <=