Skip to content

Commit af37636

Browse files
committed
Update project tooling & add subshell helpers
1 parent f628d1e commit af37636

File tree

7 files changed

+100
-146
lines changed

7 files changed

+100
-146
lines changed

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
## Added
44

5-
## Fixed
6-
7-
## Changed
5+
- Added subshell utilities
86

97
# 0.0.10 (2021-08-25 / 91ddd3b)
108

@@ -17,4 +15,4 @@ First release with basic shell utility API
1715
- ls
1816
- basename/extension/strip-ext
1917
- mkdir-p
20-
- ...
18+
- ...

bb.edn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{:deps
2+
{lambdaisland/open-source {:git/url "https://github.com/lambdaisland/open-source"
3+
:git/sha "7ce125cbd14888590742da7ab3b6be9bba46fc7a"}}}

bb_deps.edn

Lines changed: 0 additions & 4 deletions
This file was deleted.

bin/bb

Lines changed: 0 additions & 125 deletions
This file was deleted.

bin/proj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!bin/bb
1+
#!/usr/bin/env bb
22

33
(ns proj
44
(:require [lioss.main :as lioss]))
@@ -8,7 +8,3 @@
88
:inception-year 2021
99
:description "Globbing and other shell/file utils"
1010
:group-id "com.lambdaisland"})
11-
12-
;; Local Variables:
13-
;; mode:clojure
14-
;; End:

deps.edn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{:paths ["src" "resources"]
22

33
:deps
4-
{org.clojure/clojure {:mvn/version "1.10.3"}}
4+
{org.clojure/clojure {:mvn/version "1.11.1"}}
55

66
:aliases
77
{:dev
@@ -10,4 +10,4 @@
1010

1111
:test
1212
{:extra-paths ["test"]
13-
:extra-deps {lambdaisland/kaocha {:mvn/version "1.0.861"}}}}}
13+
:extra-deps {lambdaisland/kaocha {:mvn/version "1.87.1366"}}}}}

src/lambdaisland/shellutils.clj

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,104 @@
11
(ns lambdaisland.shellutils
2-
"Globbing and other shell-like filename handling
2+
"Globbing and other shell-like filename handling, and subshell handling
33
44
Extracted from https://github.com/lambdaisland/open-source and further improved"
5-
(:require [clojure.java.io :as io])
6-
(:import (java.io File)
7-
(java.nio.file Path Paths)))
5+
(:require
6+
[clojure.java.io :as io]
7+
[clojure.string :as str])
8+
(:import
9+
(java.io File)
10+
(java.nio.file Path Paths)))
11+
12+
(defn cli-opts
13+
"Options map from lambdaisland.cli, if it is used. We auto-detect certain flags,
14+
like --dry-run."
15+
[]
16+
(some-> (try (requiring-resolve 'lambdaisland.cli/*opts*) (catch Exception _)) deref))
817

918
(def ^:dynamic *cwd*
1019
"Current working directory
1120
12-
Relative paths are resolved starting from this location. Defaults to the CWD
13-
of the JVM, as exposed through the 'user.dir' property."
21+
Relative paths are resolved starting from this location, and it is used for
22+
subshells. Defaults to the CWD of the JVM, as exposed through the 'user.dir'
23+
property."
1424
(System/getProperty "user.dir"))
1525

26+
(defmacro with-cwd [cwd & body]
27+
`(let [prev# *cwd*
28+
cwd# (File. *cwd* ~cwd)]
29+
(binding [*cwd* cwd#]
30+
(try
31+
(System/setProperty "user.dir" (str cwd#))
32+
~@body
33+
(finally
34+
(System/setProperty "user.dir" prev#))))))
35+
36+
(defmacro with-temp-cwd
37+
"Same as with-cwd except that it creates a temp dir
38+
in *cwd* and evals the body inside it.
39+
40+
It cleans up the temp dir afterwards also removing
41+
any temp files created within it."
42+
[& body]
43+
;; FIXME: use Files/createTempDirectory
44+
`(let [cwd# ".temp"
45+
dir# (File. *cwd* cwd#)]
46+
(.mkdirs dir#)
47+
(with-cwd cwd# ~@body)
48+
(delete-recursively dir#)))
49+
50+
(defn slurp-cwd [f]
51+
(slurp (File. *cwd* f)))
52+
53+
(defn spit-cwd [f c]
54+
(spit (File. *cwd* f) c))
55+
56+
(defn fatal [& msg]
57+
(apply println "[\033[0;31mFATAL\033[0m] " msg)
58+
(System/exit -1))
59+
60+
(defn process-builder [args]
61+
(doto (ProcessBuilder. args)
62+
(.inheritIO)))
63+
64+
;; (def windows? (str/starts-with? (System/getProperty "os.name") "Windows"))
65+
66+
(defn- cmd->str [args]
67+
(str/join " " (map #(if (str/includes? % " ") (pr-str %) %) args)))
68+
69+
(defn spawn
70+
"Like [[clojure.java.shell/sh]], but inherit IO stream from the parent process,
71+
and prints out the invocation. By default terminates when a command
72+
fails (non-zero exit code).
73+
74+
If the last argument is a map, it is used for options
75+
- `:dir` Directory to execute in
76+
- `:continue-on-error?` Should a non-zero exit code be ignored.
77+
- `:fail-message` Error message to show when the command returns a non-zero exit code"
78+
[& args]
79+
(let [[opts args] (if (map? (last args))
80+
[(last args) (butlast args)]
81+
[{} args])
82+
dir (:dir opts *cwd*)
83+
;; args (if windows? (cons "winpty" args) args)
84+
]
85+
(println "=>" (cmd->str args) (str "(in " dir ")") "")
86+
(when-not (:dry-run (cli-opts))
87+
(let [res (-> (process-builder args)
88+
(cond-> dir
89+
(.directory (io/file dir)))
90+
.start
91+
.waitFor)]
92+
(when (and (not= 0 res) (not (:continue-on-error? opts)))
93+
(fatal (:fail-message opts "command failed") res))
94+
res))))
95+
96+
(defn bash
97+
"Interpret the command as a bash script, allows using redirects, pipes and other
98+
bash features."
99+
[& args]
100+
(spawn "bash" "-c" (str/join " " args)))
101+
16102
(defmacro with-cwd
17103
"Execute `body` with [[*cwd*]] set to `cwd`."
18104
[cwd & body]

0 commit comments

Comments
 (0)