2017-09-29 1 views
1

I ont une structure de dossiers comme celui-ci:des sous-dossiers de la liste Clojure des ressources en uberjar

  • ressources
    • un
      • b
        • x.txt
      • c
        • x.txt

J'ai créé mon pot avec runnable lein uberjar.

Lors de l'exécution de mon fichier jar, je souhaite répertorier les sous-dossiers de a.

Je sais que je peux obtenir le contenu des ressources/a/b/x.txt utilisant clojure.java.io

(slurp (clojure.java.io/resource "a/b/x.txt")) 

Mais je ne peux pas trouver un moyen simple d'énumérer les sous-dossiers.

(clojure.java.io/file (clojure.java.io/resource "a")) résulte simplement en un java.lang.IllegalArgumentException: Not a file parce que ce n'est pas un fichier, c'est une ressource dans le fichier jar.

Y a-t-il une bibliothèque qui fait cela?

+0

double possible de [Comment puis-je lister les fichiers dans un fichier JAR?] (https://stackoverflow.com/questions/1429172/how-do-i-list-the-files-inside-a-jar-file) – leetwinski

+0

Ni l'un ni l'autre ne montre 1) un moyen simple de le faire 2) une bibliothèque qui fait cela. Je refuse d'accepter que la réponse à ceci est un tas massif de code Java. – siltalau

+0

bien .. c'est une tâche triviale de traduire le code java en clojure. – leetwinski

Répondre

2

ici est le port de code à partir de la réponse spécifique java:

(ns my-project.core 
    (:require [clojure.string :as cs]) 
    (:import java.util.zip.ZipInputStream) 
    (:gen-class)) 

(defrecord HELPER []) 

(defn get-code-location [] 
    (when-let [src (.getCodeSource (.getProtectionDomain HELPER))] 
    (.getLocation src))) 

(defn list-zip-contents [zip-location] 
    (with-open [zip-stream (ZipInputStream. (.openStream zip-location))] 
    (loop [dirs []] 
     (if-let [entry (.getNextEntry zip-stream)] 
     (recur (conj dirs (.getName entry))) 
     dirs)))) 

(defn -main [& args] 
    (println (some->> (get-code-location) 
        list-zip-contents 
        (filter #(cs/starts-with? % "a/"))))) 

mis à un espace de noms principal et exécuter avec pot affichera tous les chemins dans le dossier /resources/a ..

java -jar ./target/my-project-0.1.0-SNAPSHOT-standalone.jar 
;;=> (a/ a/b/ a/b/222.txt a/222.txt) 

aussi quelques recherches rapides me conduisent à cette bibliothèque: https://github.com/ronmamo/reflections

il raccourcit le code, mais aussi exige certaines dépendances pour le projet (je suppose qu'il pourrait être indésirable):

[org.reflections/reflections "0.9.11"] 
[javax.servlet/servlet-api "2.5"] 
[com.google.guava/guava "23.0"] 

et le code est quelque chose comme ceci:

(ns my-project.core 
    (:require [clojure.string :as cs]) 
    (:import java.util.zip.ZipInputStream 
      [org.reflections 
      Reflections 
      scanners.ResourcesScanner 
      scanners.Scanner 
      util.ClasspathHelper 
      util.ConfigurationBuilder]) 
    (:gen-class)) 

(defn -main [& args] 
    (let [conf (doto (ConfigurationBuilder.) 
       (.setScanners (into-array Scanner [(ResourcesScanner.)])) 
       (.setUrls (ClasspathHelper/forClassLoader (make-array ClassLoader 0))))] 
    (println 
    (filter #(cs/starts-with? % "a/") 
      (.getResources (Reflections. conf) #".*"))))) 
+0

J'ai accepté cela comme la bonne réponse - ce qui est techniquement. La complexité de la solution me dit que j'essaie de faire la mauvaise chose entièrement. – siltalau

0

Une approche différente (mais je dois admettre qu'il ne se sent pas entièrement satisfaisant) est de lire le contenu au moment de la compilation. En supposant que vous avez une fonction list-files qui vous donne la liste de votre répertoire racine du projet:

(defmacro compile-time-filelist [] 
    `'~(list-files "resources/a")) 

ou

(defmacro compile-time-filelist [] 
    (vec (list-files "resources/a")))