2012-03-14 14 views
8

In Java c'è una simple way per ottenere il percorso di un file jar in esecuzione:Clojure: come ottenere il percorso di una directory sorgente JAR/root in esecuzione?

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

Ma in Clojure abbiamo non abbiamo nome della classe, solo spazio dei nomi e funzioni. La stessa cosa vale per gli script non compilati/REPL.

Quindi le mie domande sono:

  1. Come possiamo trovare una via alla esecuzione file jar?
  2. Come trovare un percorso per i file di origine non completati?
+0

Se si desidera trovare questo percorso per individuare risorse (come immagini, ecc.), È possibile raggrupparle all'interno del JAR. Java ha un'API per accedere ai file di risorse che sono impacchettati all'interno di un JAR. –

+0

@AlexD: risorse come le immagini non sono l'unico utilizzo possibile. Potrei dover eseguire programmi a riga di comando separati con i miei JAR/script, o potrei aver bisogno di registrare il mio programma nel sistema. Inoltre alcuni framework si basano sui percorsi reali nel filesystem, non sugli URI in JAR. – ffriend

risposta

1

Non l'ho provato, ma sembra che tutto ciò che serve sia un'istanza di classe. Così, per esempio, si può non fare questo:

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

Sfortunatamente, no - '.getCodeSource' restituisce' nil' e tutte le interruzioni di catena. – ffriend

1

si potrebbe provare a ottenere il percorso da una classe definita da Clojure per sé, ad esempio:

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

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

Credo che questo sia tecnicamente il file jar in esecuzione se si stanno eseguendo script Clojure o codice al REPL.

+0

Il programma in esecuzione tecnicamente risiede nella memoria :) Ho bisogno di un percorso per _my_ jar/sources. L'utente può mettere 'clojure.jar' separatamente dal mio codice e collegarlo tramite' classpath', quindi il mio programma non saprà ancora dove si trova. – ffriend

2

L'idea di classpath è di nascondere da dove vengono le classi. Potresti avere classi con lo stesso nome caricate da diversi classloader, potresti avere la stessa classe in più jar e fare affidamento sull'ordinamento del classpath per scegliere quello corretto.

Perché vuoi sapere? Se è per qualsiasi altra ragione che non sia il debug/logging, sei su un terreno pericoloso e dovresti procedere con cautela.

In effetti è perfettamente ragionevole che le classi non abbiano file jar. Questo può accadere in Java per qualsiasi classe generata in runtime (si pensi ai proxy).

In clojure un semplice esempio sarebbe come mostrato nella sessione di sostituzione in basso ... Vedrete il suggerimento di @ mikera funziona bene per clojure.lang.Atom che è un built-in classe. Ma quando si utilizza un deftype per creare il proprio tipo, clojure genera una classe e non ha posizione ...

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> 
+0

Capisco tutto questo, ma non sto limitando i possibili modi ai caricatori di classi Java - Clojure può avere il proprio metodo per individuare i file in esecuzione. Ad esempio, quando alcune funzioni generano un'eccezione, Clojure runtime stampa stacktrace con i nomi di tutti i file corrispondenti. Quindi credo che ci sia un modo (forse non molto severo) per ottenere queste informazioni da una sceneggiatura. – ffriend

+0

L'unico modo per ottenere classi nella JVM è tramite classloader. il clojure non può fornire un altro modo, perché la JVM lo impedisce per ragioni di sicurezza. Le tracce dello stack in clojure sono stacktraces JVM. La generazione al volo di classi è il motivo per cui le tracce dello stack del clojure sono così difficili da interpretare. per esempio. la valutazione di un modulo nel REPL causa la generazione di una classe senza origine sottostante - quindi in questo caso si ottiene un elemento stack senza informazioni sui file ... – sw1nn

+0

I file '.clj' non sono classi e quindi sono tracciati dal runtime Clojure stesso . Il punto principale è che i runtime JVM o Clojure sanno sempre da dove caricano il codice. – ffriend

0

file sorgente scoperta in un vaso: tools.namespace/clojure-sources-in-jar

+0

Sono interessato a come trovare il percorso del file JAR o file .clj non compilato, ad es per ottenere il percorso di un codice in esecuzione e non come trovare il file .clj in particolare l'archivio JAR. – ffriend

+0

trova i file sorgente in una directory? usa tools.namespace/find-clojure-sources-in-dir. –

+0

Devo trovare il percorso per _running_ code. Non conosco la directory e nemmeno la struttura del progetto, conosco solo il punto corrente del programma e voglio sapere dove si trova il codice (sorgente o compilato). Per esempio. Voglio trovare un altro file, che si trova nella stessa directory del file con la mia funzione. Ma la mia funzione potrebbe essere nel file .clj, compilato .class o all'interno di .jar, che viene aggiunto a classpath separatamente dagli altri jar tramite l'opzione -cp. Non so come l'utente della mia funzione lo aggiungerà al progetto. Potrebbe persino rinominare il mio file .clj, ma la mia funzione dovrebbe comunque trovare la posizione corretta. – ffriend

5

Per impostazione predefinita il il nome della tua classe è il nome del tuo spazio dei nomi compilato con AOT (questo è ciò che è per gen-class), quindi puoi semplicemente usare la classe dello spazio dei nomi.

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

risultato dell'esecuzione:

$ java -cp foo-0.1.0-SNAPSHOT-standalone.jar foo.core 
/home/rlevy/prj/foo/target/foo-0.1.0-SNAPSHOT-standalone.jar 
0
(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)) 

Si noti che è fondamentale per chiamare .toURI per evitare problemi con i percorsi che hanno spazi come descritto nella domanda equivalente Java: How to get the path of a running JAR file?.

Problemi correlati