Frage Clojure: Wie bekomme ich den Pfad eines laufenden JAR / Root-Quellverzeichnisses?


In Java gibt es ein einfacher Weg um den Pfad einer laufenden JAR-Datei zu erhalten:

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

Aber in Clojure wir habe keinen Klassennamen, nur Namespace und Funktionen. Gleiches gilt für die nicht kompilierten Skripte / REPL.

Also meine Fragen sind:

  1. Wie können wir ein finden? Pfad zur laufenden JAR-Datei?
  2. Wie können wir ein finden? Pfad zu nicht kompilierten Quelldateien?

8
2018-03-14 01:33


Ursprung


Antworten:


Standardmäßig ist der Name Ihrer Klasse der Name Ihres AOT-kompilierten Namespace (dafür steht gen-class), Sie können also einfach die Klasse des Namespace verwenden.

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

(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 .getPath))

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

Ergebnis des Laufens:

$ java -cp foo-0.1.0-SNAPSHOT-standalone.jar foo.core
/home/rlevy/prj/foo/target/foo-0.1.0-SNAPSHOT-standalone.jar

7
2017-11-07 19:43



Die Idee des Klassenpfades ist es, zu verbergen, woher Klassen kommen. Möglicherweise haben Sie Klassen mit demselben Namen, die von verschiedenen Klassenladeprogrammen geladen wurden. Sie können dieselbe Klasse in mehreren JARs haben und auf die Klassenpfadordnung angewiesen sein, um die richtige Klasse auszuwählen.

Warum willst du das wissen? Wenn es aus einem anderen Grund als Debug / Logging-Zwecken ist, sind Sie auf gefährlichem Boden und sollten vorsichtig vorgehen.

In der Tat ist es für Klassen völlig vernünftig, keine JAR-Datei zu haben. Dies kann in Java für alle von der Laufzeit generierten Klassen (Think Proxies) passieren.

In clojure wäre ein einfaches Beispiel, wie es in der folgenden Replikationssitzung gezeigt wird ... Sie werden sehen, dass der Vorschlag von @ mikera gut funktioniert clojure.lang.Atom Das ist eine eingebaute Klasse. Aber wenn du ein verwendest deftype Um einen eigenen Typ zu erstellen, erzeugt clojure eine Klasse und hat keinen Ort ...

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> 

2
2018-03-15 13:09



Ich habe das nicht versucht, aber es scheint, als ob alles, was Sie brauchen, eine Klasseninstanz ist. Also zum Beispiel können Sie das nicht tun:

(-> (new Object) (.getClass) (.getProtectionDomain) (.getCodeSource) (.getLocation) (.getPath))

1
2018-03-14 01:57



Sie könnten versuchen, den Pfad von einer Klasse zu erhalten, die von Clojure selbst definiert wurde, z. B .:

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

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

Ich glaube, das ist technisch die laufende JAR-Datei, wenn Sie Clojure-Skripte oder -Codierung an der REPL ausführen.


1
2018-03-14 02:58



Quelldateien in einem Jar finden: tools.namespace / clojure-sources-in-jar


0
2018-06-12 01:58



(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))

Beachten Sie, dass es wichtig ist, anzurufen .toURI um Probleme mit Pfaden zu vermeiden, die Leerzeichen haben, wie in der entsprechenden Java-Frage beschrieben: Wie bekomme ich den Pfad einer laufenden JAR-Datei?.


0
2017-10-30 15:11