Listing files in two separate directories in Clojure - clojure

I'm trying to get Overtone to work on my Windows 10 machine. I seem to have found a bug in the code that attempts to start the synthesizer server. Overtone depends on SuperCollider, and it looks up the location of scsynth.exe by looking at where SuperCollider is installed. But the code that is supposed to check both C:\Program Files and C:\Program Files (x86) only checks the first one that exists instead of both:
(import java.io File)
(let [p-files-dir (System/getenv "PROGRAMFILES(X86)")
p-files-dir (or p-files-dir (System/getenv "PROGRAMFILES"))
p-files-dir (File. p-files-dir)
p-files (map str (.listFiles p-files-dir))
p-files])
In my case, both directories exist, but SuperCollider only exists in C:\Program Files. The snippet above only lists files in C:\Program Files (x86).
How do I get this code to return all of the files in both directories, and not break when one doesn't exist?

You were not returning something from your let form, so notice here p-files is outside the []:
(let [p-files-dir-1 (System/getenv "PROGRAMFILES(X86)")
p-files-dir-2 (System/getenv "PROGRAMFILES")
p-files-dir-file-1 (File. p-files-dir-1)
p-files-dir-file-2 (File. p-files-dir-2)
p-files (map str (concat
(.listFiles p-files-dir-file-1)
(.listFiles p-files-dir-file-2)))]
p-files)
The answer to your question is that you can just concat together two lists, after which you would need to filter for the file.
Here's a shorter answer (the map str is not strictly necessary here):
(map str (concat ["a" "b" "c"] ["d" "e" "f"]))
;; => ("a" "b" "c" "d" "e" "f")
To remove all the temporary variables you could use this function:
(defn env-files [file-name]
(some-> file-name
System/getenv
File.
.listFiles))
Then the code becomes:
(map str (concat
(env-files "PROGRAMFILES(X86)")
(env-files "PROGRAMFILES")))

Related

How to include all files inside a folder using clojure

How to include all files inside a folder using clojure.
Here is my code:
(defn LoadFiles[]
(include "utils")
)
(LoadFiles)
But the above code is not working.
As far as i know, there's no include in clojure (correct me if i'm wrong).
You should use use or require for that.
This one should probably work (for all the .clj files in utils top level, but you can easily extend it to be recursive):
(defn list-sources [path]
(map #(str path "." (second (re-matches #"^(\w+)\.clj$" (.getName %))))
(filter #(.isFile %) (file-seq path))))
(run! #(require (vector (symbol %) :refer :all))
(list-sources (java.io.File. "utils")))
Maybe something like:
(defn load-files [dir]
(doseq [f (file-seq (File. dir))
:when (.isFile f)]
(load-file (.getAbsolutePath f))))
(load-files "utils")

Clojure, console: println output not always visible

Subj. There's a working program, which basically copies filesystem trees recursively. Somehow println from inside the recursive function won't show any output.
build-album calls traverse-dir; I can see the "10" in the console, but never any "11"s -- should be a lot of them. (println "11") can't possibly miss the path of execution, since files get really copied (the line above). This is not quite nice, since the project is meant as a console application, reporting to the user each copied file, lest he should suspect freezing. This is no joke, because the app is intended to upload albums to mobile phones.
(defn traverse-dir
"Traverses the (source) directory, preorder"
[src-dir dst-step]
(let [{:keys [options arguments]} *parsed-args*
dst-root (arguments 1)
[dirs files] (list-dir-groomed (fs/list-dir src-dir))
dir-handler (fn [dir-obj]
"Processes the current directory, source side;
creates properly named directory destination side, if necessary"
(let [dir (.getPath dir-obj)
step (str dst-step *nix-sep* (fs/base-name dir-obj))]
(fs/mkdir (str dst-root step))
(traverse-dir dir step)))
file-handler (fn [file-obj]
"Copies the current file, properly named and tagged"
(let [dst-path (str dst-root dst-step *nix-sep* (.getName file-obj))]
(fs/copy file-obj (fs/file dst-path))
(println "11")
dst-path))]
(concat (map dir-handler dirs) (map file-handler files))))
(defn build-album
"Copy source files to destination according
to command line options"
[]
(let [{:keys [options arguments]} *parsed-args*
output (traverse-dir (arguments 0) "")]
(println "10")
output))
Might be the problem with lazy sequences: you build a lazy seq which is never realized and thus the code never executes. Try calling doall on the result of traverse-dir:
(doall (concat (map dir-handler dirs) (map file-handler files))))

Clojure create directory hierarchy - but not in a procedural way

Let's say I need to create the following directory structure in Clojure:
a
\--b
| \--b1
| \--b2
\--c
\-c1
Instead of doing procedural things like the following:
(def a (File. "a"))
(.mkdir a)
(def b (File. a "b"))
(.mkdir b)
;; ...
... is there a clever way to somehow represent the above actions as data, declaratively, and then create the hierarchy in one fell swoop?
a quick and simple approach would be to make a vector of dirs to create and map mkdir on to it:
user> (map #(.mkdir (java.io.File. %)) ["a", "a/b" "a/b/c"])
(true true true)
or you can specify your dir structure as a tree and use zippers to walk it making the dirs on the way:
(def dirs ["a" ["b" ["b1" "b2"]] ["c" ["c1"]]])
(defn make-dir-tree [original]
(loop [loc (zip/vector-zip original)]
(if (zip/end? loc)
(zip/root loc)
(recur (zip/next
(do (if (not (vector? (zip/node loc)))
(let [path (apply str (interpose "/" (butlast (map first (zip/path loc)))))
name (zip/node loc)]
(if (empty? path)
(.mkdir (java.io.File. name))
(.mkdir (java.io.File. (str path "/" name))))))
loc))))))
(make-dir-tree dirs)
.
arthur#a:~/hello$ find a
a
a/c
a/c/c1
a/b
a/b/c
a/b/b2
a/b/b1
If you are doing a lot of general systems administration then something heavier may be in order. The pallet project is a library for doing system administration of all sorts on physical and cloud hosted systems (though it tends to lean towards the cloudy stuff). Specifically the directory
Another option if you want to easily handle creating recursive directories is to use .mkdirs
user> (require '[clojure.java.io :as io]')
user> (.mkdirs (io/file "a/b/c/d"))
You can use absolute path eg. /a/b/c/d or else it will be created relative to the path you initiated the repl from.
Also handy to check if given path is not an existing directory
user> (.isDirectory (io/file "a/b/c/d"))

how to load resources from a specific .jar file using clojure.java.io

In clojure.java.io, there is a io/resource function but I think it just loads the resource of the current jar that is running. Is there a way to specify the .jar file that the resource is in?
For example:
I have a jar file: /path/to/abc.jar
abc.jar when unzipped contains some/text/output.txt in the root of the unzipped directory
output.txt contains the string "The required text that I want."
I need functions that can do these operations:
(list-jar "/path/to/abc.jar" "some/text/")
;; => "output.txt"
(read-from-jar "/path/to/abc.jar" "some/text/output.txt")
;; => "The required text that I want"
Thanks in advance!
From Ankur's comments, I managed to piece together the functions that I needed:
The java.util.jar.JarFile object does the job.
you can call the method (.entries (Jarfile. a-path)) to give the list of files but instead of returning a tree structure:
i.e:
/dir-1
/file-1
/file-2
/dir-2
/file-3
/dir-3
/file-4
it returns an enumeration of filenames:
/dir-1/file-1, /dir-1/file-2, /dir-1/dir-2/file-3, /dir-1/dir-3/file-4
The following functions I needed are defined below:
(import java.util.jar.JarFile)
(defn list-jar [jar-path inner-dir]
(if-let [jar (JarFile. jar-path)]
(let [inner-dir (if (and (not= "" inner-dir) (not= "/" (last inner-dir)))
(str inner-dir "/")
inner-dir)
entries (enumeration-seq (.entries jar))
names (map (fn [x] (.getName x)) entries)
snames (filter (fn [x] (= 0 (.indexOf x inner-dir))) names)
fsnames (map #(subs % (count inner-dir)) snames)]
fsnames)))
(defn read-from-jar [jar-path inner-path]
(if-let [jar (JarFile. jar-path)]
(if-let [entry (.getJarEntry jar inner-path)]
(slurp (.getInputStream jar entry)))))
Usage:
(read-from-jar "/Users/Chris/.m2/repository/lein-newnew/lein-newnew/0.3.5/lein-newnew-0.3.5.jar"
"leiningen/new.clj")
;=> "The list of built-in templates can be shown with `lein help new`....."
(list-jar "/Users/Chris/.m2/repository/lein-newnew/lein-newnew/0.3.5/lein-newnew-0.3.5.jar" "leiningen")
;; => (new/app/core.clj new/app/project.clj .....)

How can I display the definition of a function in Clojure at the REPL?

I'm looking for the ability to have the REPL print the current definition of a function. Is there any way to do this?
For example, given:
(defn foo [] (if true "true"))
I'd like to say something like
(print-definition foo)
and get something along the lines of
(foo [] (if true "true"))
printed.
An alternative to source (which should be available via clojure.repl/source when starting a REPL, as of 1.2.0. If you're working with 1.1.0 or lower, source is in clojure.contrib.repl-utils.), for REPL use, instead of looking at functions defined in a .clj file:
(defmacro defsource
"Similar to clojure.core/defn, but saves the function's definition in the var's
:source meta-data."
{:arglists (:arglists (meta (var defn)))}
[fn-name & defn-stuff]
`(do (defn ~fn-name ~#defn-stuff)
(alter-meta! (var ~fn-name) assoc :source (quote ~&form))
(var ~fn-name)))
(defsource foo [a b] (+ a b))
(:source (meta #'foo))
;; => (defsource foo [a b] (+ a b))
A simple print-definition:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
#' is just a reader macro, expanding from #'foo to (var foo):
(macroexpand '#'reduce)
;; => (var reduce)
You'll want to import the repl namespace, and use the source function from it:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
Though this wouldn't work in the REPL, only where the function is defined in a .clj file on the classpath. Which doesn't answer your question, then: you'd need to have a defn that stores, in the metadata of the fn it defines, the source of the function. Then you'd write a function that recalls that bit of metadata. That shouldn't be terribly difficult.
Clojure doesn't have a decompiler, so that means there's no way to get at the source of an arbitrary function unless it was a defn loaded from disk. However, you can use a neat hack called serializable-fn to create a function that has its source form stored in its metadata: http://github.com/Seajure/serializable-fn
The defsource answer is very similar to this, but this solution works with arbitrary fns, not just top-level defns. It also makes fns print prettily at the repl without a special printing function.
In clojure 1.2's REPL, the source function is immediately available. You can use it this way:
$ java -cp clojure.jar clojure.main
Clojure 1.2.0
user=> (source slurp)
(defn slurp
"Reads the file named by f using the encoding enc into a string
and returns it."
{:added "1.0"}
([f & opts]
(let [opts (normalize-slurp-opts opts)
sb (StringBuilder.)]
(with-open [#^java.io.Reader r (apply jio/reader f opts)]
(loop [c (.read r)]
(if (neg? c)
(str sb)
(do
(.append sb (char c))
(recur (.read r)))))))))
nil
user=>
A few other functions are also automatically imported into the REPL's user namespace from the clojure.repl library. See the API doc here.
However, as pointed out in other answers here, you can't use source as is to print back functions you have defined in the REPL.
I asked exactly this question on the Clojure mailing list recently and the answers included overriding parts of the REPL to stash the input (and output) away for future reference as well as an override of defn to store the source in metadata (which you could then easily retrieve in the REPL).
Read the thread on the Clojure mailing list