Skip to content

Commit 78d29e9

Browse files
committed
Merge branch 'release/0.2.3'
2 parents afc4ecd + 89a8f87 commit 78d29e9

File tree

3 files changed

+73
-29
lines changed

3 files changed

+73
-29
lines changed

pom.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>clj-ssh</groupId>
55
<artifactId>clj-ssh</artifactId>
6-
<version>0.2.3-SNAPSHOT</version>
6+
<version>0.2.4-SNAPSHOT</version>
77
<name>clj-ssh</name>
88
<description>ssh from clojure</description>
99
<scm>
@@ -64,9 +64,11 @@
6464
</configuration>
6565
</plugin>
6666
<plugin>
67-
<groupId>org.apache.maven.plugins</groupId>
6867
<artifactId>maven-release-plugin</artifactId>
6968
<version>2.0</version>
69+
<configuration>
70+
<pushChanges>false</pushChanges>
71+
</configuration>
7072
</plugin>
7173
</plugins>
7274
</build>

src/clj_ssh/ssh.clj

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Licensed under EPL (http://www.eclipse.org/legal/epl-v10.html)"
8080

8181
;; Enable java logging of jsch when in clojure 1.2
8282
(when-feature deftype
83-
(def ssh-log-levels
83+
(def ^{:dynamic true} *ssh-log-levels*
8484
{com.jcraft.jsch.Logger/DEBUG :debug
8585
com.jcraft.jsch.Logger/INFO :info
8686
com.jcraft.jsch.Logger/WARN :warn
@@ -94,7 +94,7 @@ Licensed under EPL (http://www.eclipse.org/legal/epl-v10.html)"
9494
(>= level log-level))
9595
(log
9696
[_ level message]
97-
(logging/log (ssh-log-levels level) message nil "clj-ssh.ssh")))
97+
(logging/log (*ssh-log-levels* level) message nil "clj-ssh.ssh")))
9898

9999
(JSch/setLogger (SshLogger. com.jcraft.jsch.Logger/DEBUG)))
100100

@@ -325,12 +325,18 @@ keys. All other option key pairs will be passed as SSH config options."
325325
[#^Session session]
326326
(open-channel session :shell))
327327

328+
(defn- streams-for-out
329+
[out]
330+
(if (= :stream out)
331+
(let [os (java.io.PipedOutputStream.)]
332+
[os (java.io.PipedInputStream. os)])
333+
[(java.io.ByteArrayOutputStream.) nil]))
328334

329335
(defn ssh-shell
330336
"Run a ssh-shell."
331337
[#^Session session in out opts]
332338
(let [#^ChannelShell shell (open-channel session :shell)
333-
out-stream (java.io.ByteArrayOutputStream.)]
339+
[out-stream out-inputstream] (streams-for-out out)]
334340
(doto shell
335341
(.setInputStream
336342
(if (string? in)
@@ -342,20 +348,24 @@ keys. All other option key pairs will be passed as SSH config options."
342348
(call-method
343349
com.jcraft.jsch.ChannelSession 'setPty [Boolean/TYPE]
344350
shell (boolean (opts :pty))))
345-
(with-connection shell
346-
(while (connected? shell)
347-
(Thread/sleep 100))
348-
[(.getExitStatus shell)
349-
(if (= :bytes out)
350-
(.toByteArray out-stream)
351-
(.toString out-stream out))])))
351+
(if out-inputstream
352+
(do
353+
(connect shell)
354+
[shell out-inputstream])
355+
(with-connection shell
356+
(while (connected? shell)
357+
(Thread/sleep 100))
358+
[(.getExitStatus shell)
359+
(if (= :bytes out)
360+
(.toByteArray out-stream)
361+
(.toString out-stream out))]))))
352362

353363
(defn ssh-exec
354364
"Run a command via ssh-exec."
355365
[#^Session session #^String cmd in out opts]
356366
(let [#^ChannelExec exec (open-channel session :exec)
357-
out-stream (java.io.ByteArrayOutputStream.)
358-
err-stream (java.io.ByteArrayOutputStream.)]
367+
[out-stream out-inputstream] (streams-for-out out)
368+
[err-stream err-inputstream] (streams-for-out out)]
359369
(doto exec
360370
(.setInputStream
361371
(if (string? in)
@@ -369,16 +379,20 @@ keys. All other option key pairs will be passed as SSH config options."
369379
(call-method
370380
com.jcraft.jsch.ChannelSession 'setPty [Boolean/TYPE]
371381
exec (boolean (opts :pty))))
372-
(with-connection exec
373-
(while (connected? exec)
374-
(Thread/sleep 100))
375-
[(.getExitStatus exec)
376-
(if (= :bytes out)
377-
(.toByteArray out-stream)
378-
(.toString out-stream out))
379-
(if (= :bytes out)
380-
(.toByteArray err-stream)
381-
(.toString err-stream out))])))
382+
(if out-inputstream
383+
(do
384+
(connect exec)
385+
[exec out-inputstream err-inputstream])
386+
(with-connection exec
387+
(while (connected? exec)
388+
(Thread/sleep 100))
389+
[(.getExitStatus exec)
390+
(if (= :bytes out)
391+
(.toByteArray out-stream)
392+
(.toString out-stream out))
393+
(if (= :bytes out)
394+
(.toByteArray err-stream)
395+
(.toString err-stream out))]))))
382396

383397
(defn default-session [host username port password]
384398
(doto (session-impl
@@ -409,7 +423,11 @@ cmd specifies a command to exec. If no cmd is given, a shell is started and inp
409423
Options are
410424
411425
:in specifies input to the remote shell. A string or a stream.
412-
:out specify :bytes or a string with an encoding specification.
426+
:out specify :stream to obtain a an [inputstream shell],
427+
specify :bytes to obtain a byte array,
428+
or specify a string with an encoding specification for a
429+
result string. In the case of :stream, the shell can
430+
be polled for connected status.
413431
:return-map when followed by boolean true, sh returns a map of
414432
:exit => sub-process's exit code
415433
:out => sub-process's stdout (as byte[] or String)
@@ -437,14 +455,14 @@ Options are
437455
(let [result (ssh-shell
438456
session
439457
(:in opts) (:out opts) (dissoc opts :in :out :cmd))]
440-
(if (opts :return-map)
458+
(if (and (opts :return-map) (not= (:out opts) :stream))
441459
{:exit (first result) :out (second result)}
442460
result))
443461
(let [result (ssh-exec
444462
session
445463
(apply str (interpose " " (:cmd opts)))
446464
(:in opts) (:out opts) (dissoc opts :in :out :cmd))]
447-
(if (opts :return-map)
465+
(if (and (opts :return-map) (not= (:out opts) :stream))
448466
{:exit (first result) :out (second result) :err (last result)}
449467
result)))
450468
(finally

test/clj_ssh/ssh_test.clj

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ list, Alan Dipert and MeikelBrandmeyer."
234234
(let [result (ssh-shell session "echo hello;exit 1" "UTF-8" {})]
235235
(is (= 1 (first result)))
236236
(is (.contains (second result) "hello")))
237+
(let [[shell stream] (ssh-shell session "echo hello;exit 1" :stream {})]
238+
(while (connected? shell) (Thread/sleep 100))
239+
(is (= 1 (.getExitStatus shell)))
240+
(is (pos? (.available stream)))
241+
(let [bytes (byte-array 1024)
242+
n (.read stream bytes 0 1024)]
243+
(is (.contains (String. bytes 0 n) "hello"))))
237244
(let [result (ssh-shell session "exit $(tty -s)" "UTF-8" {:pty true})]
238245
(is (= 0 (first result))))
239246
(let [result (ssh-shell session "exit $(tty -s)" "UTF-8" {:pty nil})]
@@ -249,10 +256,27 @@ list, Alan Dipert and MeikelBrandmeyer."
249256
(is (= 0 (first result)))
250257
(is (.contains (second result) "bin"))
251258
(is (= "" (last result))))
252-
(let [result (ssh-exec session "/bin/bash -c 'lsxxxxx /'" nil "UTF-8" {})]
259+
(let [result (ssh-exec
260+
session "/bin/bash -c 'lsxxxxx /'" nil "UTF-8" {})]
253261
(is (not (= 0 (first result))))
254262
(is (= "" (second result)))
255-
(is (.contains (last result) "command not found")))))))
263+
(is (.contains (last result) "command not found")))
264+
(let [[exec out err] (ssh-exec
265+
session
266+
"/bin/bash -c 'ls / && lsxxxxx /'"
267+
nil :stream {})]
268+
(while (connected? exec) (Thread/sleep 100))
269+
(is (not= 0 (.getExitStatus exec)))
270+
(is (pos? (.available out)))
271+
(is (pos? (.available err)))
272+
(let [out-bytes (byte-array 1024)
273+
out-n (.read out out-bytes 0 1024)
274+
err-bytes (byte-array 1024)
275+
err-n (.read err err-bytes 0 1024)]
276+
(is (.contains (String. out-bytes 0 out-n) "bin"))
277+
(is (.contains
278+
(String. err-bytes 0 err-n)
279+
"command not found"))))))))
256280

257281
(deftest ssh-test
258282
(with-ssh-agent [false]

0 commit comments

Comments
 (0)