diff --git a/README.md b/README.md index 141358e6..a5f0d356 100644 --- a/README.md +++ b/README.md @@ -564,6 +564,25 @@ less ... ``` +### Portable tree command + +``` shellsession +$ clojure -Sdeps '{:deps {org.clojure/tools.cli {:mvn/version "0.4.2"}}}' examples/tree.clj src +src +└── babashka + ├── impl + │ ├── tools + │ │ └── cli.clj +... + +$ examples/tree.clj src +src +└── babashka + ├── impl + │ ├── tools + │ │ └── cli.clj +``` + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support diff --git a/examples/tree.clj b/examples/tree.clj new file mode 100755 index 00000000..221efb15 --- /dev/null +++ b/examples/tree.clj @@ -0,0 +1,77 @@ +#!/usr/bin/env bb + +;; to run with clojure: clojure -Sdeps '{:deps {org.clojure/tools.cli {:mvn/version "0.4.2"}}}' examples/tree.clj src +;; to run with babashka: examples/tree.clj src + +(ns tree + "Tree command, inspired by https://github.com/lambdaisland/birch." + (:require [clojure.java.io :as io] + [clojure.tools.cli :refer [parse-opts]])) + +(def I-branch "│ ") + +(def T-branch "├── ") + +(def L-branch "└── ") + +(def SPACER " ") + +(defn file-tree + [^java.io.File path] + (let [children (.listFiles path) + dir? (.isDirectory path)] + (cond-> + {:name (.getName path) + :type (if dir? "directory" "file")} + dir? (assoc :contents + (map file-tree children))))) + +(defn render-tree + [{:keys [:name :contents]}] + (cons name + (mapcat + (fn [child index] + (let [subtree (render-tree child) + last? (= index (dec (count contents))) + prefix-first (if last? L-branch T-branch) + prefix-rest (if last? SPACER I-branch)] + (cons (str prefix-first (first subtree)) + (map #(str prefix-rest %) (next subtree))))) + contents + (range)))) + +(defn stats + [file-tree] + (apply merge-with + + {:total 1 + :directories (case (:type file-tree) + "directory" 1 + 0)} + (map stats (:contents file-tree)))) + +(def cli-options [["-E" "--edn" "Output tree as EDN"]]) + +(defn -main [& args] + (let [{:keys [options arguments]} + (parse-opts args cli-options) + path (io/file + (or (first arguments) + ".")) + tree (file-tree path) + {:keys [total directories]} + (stats tree)] + (if (:edn options) + (prn tree) + (do + (doseq [l (render-tree tree)] + (println l)) + (println) + (println + (str directories " directories, " (- total directories) " files")))))) + +(apply -main *command-line-args*) + +;;;; Scratch + +(comment + (-main "src" "-e" "-c")) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 57ba8bad..1435d6cf 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.37-SNAPSHOT +0.0.37 diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 5199e100..b9e2e29e 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -195,7 +195,8 @@ Everything after that is bound to *command-line-args*.")) conch me.raynes.conch.low-level async clojure.core.async csv clojure.data.csv} - :namespaces {'clojure.core core-extras + :namespaces {'clojure.core (assoc core-extras + '*command-line-args* command-line-args) 'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read-string edn/read-string} 'clojure.java.shell {'sh shell/sh} @@ -206,8 +207,7 @@ Everything after that is bound to *command-line-args*.")) 'me.raynes.conch.low-level conch-namespace 'clojure.core.async async-namespace 'clojure.data.csv csv/csv-namespace} - :bindings {'*command-line-args* command-line-args - 'java.lang.System/exit exit ;; override exit, so we have more control + :bindings {'java.lang.System/exit exit ;; override exit, so we have more control 'System/exit exit} :env env :features #{:bb}