Clojure: как получить путь к работающей директории JAR / root? - PullRequest
8 голосов
/ 14 марта 2012

В Java есть простой способ , чтобы получить путь к запущенному файлу JAR:

MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()

Но в Clojure у нас нет имени класса , толькопространство имен и функции.То же самое относится и к некомпилированным скриптам / REPL.

Итак, мои вопросы:

  1. Как мы можем найти путь к запущенному файлу jar ?
  2. Как найти путь к некомпилированным исходным файлам ?

Ответы [ 6 ]

8 голосов
/ 07 ноября 2012

По умолчанию имя вашего класса - это имя вашего скомпилированного AOT пространства имен (для этого предназначен gen-класс), поэтому вы можете просто использовать класс пространства имен.

(ns foo.core
  (:gen-class))

(defn this-jar
  "utility function to get the name of jar in which this function is invoked"
  [& [ns]]
  ;; The .toURI step is vital to avoid problems with special characters,
  ;; including spaces and pluses.
  ;; Source: https://stackoverflow.com/q/320542/7012#comment18478290_320595
  (-> (or ns (class *ns*))
      .getProtectionDomain .getCodeSource .getLocation .toURI .getPath))

(defn -main [& _]
  (println (this-jar foo.core)))

Результат бега:

$ java -cp foo-0.1.0-SNAPSHOT-standalone.jar foo.core
/home/rlevy/prj/foo/target/foo-0.1.0-SNAPSHOT-standalone.jar
2 голосов
/ 15 марта 2012

Идея classpath состоит в том, чтобы скрыть, откуда приходят классы.У вас могут быть классы с одним и тем же именем, загруженные из разных загрузчиков классов, у вас может быть один и тот же класс в нескольких банках, и вы полагаетесь на порядок путей к классам, чтобы выбрать правильный.

Почему вы хотите знать?Если по какой-либо другой причине, кроме целей отладки / ведения журнала, вы находитесь на опасной почве и должны действовать осторожно.

На самом деле для классов совершенно разумно не иметь jar-файла.Это может происходить в java для любых классов, генерируемых во время выполнения (например, прокси).

В clojure простой пример будет таким, как показано в сеансе repl ниже ... Вы увидите, что предложение @ mikera отлично работает для clojure.lang.Atom который является встроенным в класс.Но когда вы используете deftype для создания собственного типа, clojure генерирует класс, и у него нет местоположения ...

user> (prn (-> clojure.lang.Atom 
               (.getProtectionDomain) 
               (.getCodeSource) 
               (.getLocation)))
#<URL file:/workspace/clj-scratch/lib/clojure-1.3.0.jar>
nil
user> (deftype Foo [])
user.Foo
user> (prn (-> (Foo.)
               (.getClass)
               (.getProtectionDomain)
               (.getCodeSource)
               (.getLocation)))
nil
nil
user> 
1 голос
/ 30 октября 2017
(defn this-jar
  "utility function to get the name of jar in which this function is invoked"
  [& [ns]]
  (-> (or ns (class *ns*))
      .getProtectionDomain .getCodeSource .getLocation .toURI .getPath))

Обратите внимание, что крайне важно вызвать .toURI, чтобы избежать проблем с путями, в которых есть пробелы, как описано в эквивалентном вопросе Java: Как получить путь к работающему файлу JAR? .

1 голос
/ 14 марта 2012

Вы можете попробовать получить путь из класса, определенного самим Clojure, например:

(-> clojure.lang.Atom (.getProtectionDomain) (.getCodeSource) (.getLocation))

=> file:/some/path/to/clojure-1.3.0.jar

Я считаю, что это технически запущенный файл JAR, если вы запускаете сценарии Clojure или кодируете в REPL.

1 голос
/ 14 марта 2012

Я не пробовал этого, но, похоже, все, что вам нужно, это экземпляр класса. Так, например, вы не можете сделать это:

(-> (new Object) (.getClass) (.getProtectionDomain) (.getCodeSource) (.getLocation) (.getPath))
0 голосов
/ 12 июня 2012

найти исходные файлы в банке: tools.namespace / clojure-sources-in-jar

...