babashka / process

Clojure library for shelling out / spawning sub-processes
Eclipse Public License 1.0
221 stars 29 forks source link

Documentation about tee #26

Open borkdude opened 4 years ago

borkdude commented 4 years ago

The use case for tee is to redirect output to stdout but also to capture it in a file. We could make a built-in construct for this so you can use it to print to stdout but also capture the out stream.

(require '[babashka.process :refer [pipeline pb]]
         '[clojure.java.io :as io])

(let [[catp teep] (pipeline (pb ["cat"]) (pb ["tee" "log.txt"] {:out :inherit}))]
  ;; write to cat every 100 milliseconds 10 times
  (future
    (with-open [writer (io/writer (:in catp))]
      (loop [i 0]
        (when (< i 10)
          (binding [*out* writer]
            (println i)
            (flush))
          (Thread/sleep 100)
          (recur (inc i))))))

  @teep ;; wait for the tee process to finish
  ;; finally we print the file's content
  (println (slurp "log.txt")))

(shutdown-agents)

Also see https://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/output/TeeOutputStream.html

This code is close but doesn't work yet:

(ns tee
  (:require [babashka.process :refer [process]]
            [clojure.java.io :as io])
  (:import [java.io InputStream]))

(defn tee [proc out-1 out-2]
  (let [^InputStream in (:out proc)
        ^java.lang.Process proc (:proc proc)]
    (loop [alive? (.isAlive proc) idx 0]
      (if-not alive?
        (recur (.isAlive proc) idx)
        (let [j (.available in)]
          (when (pos? j)
            (prn :read idx j)
            (let [buf (byte-array j)]
              (.read in buf idx j)
              (io/copy buf out-1)
              (io/copy buf out-2)))
          (when (.isAlive proc)
            (recur alive? (+ idx j))))))))

(def catp (process ["cat"]))

(future
  (with-open [writer (io/writer (:in catp))]
    (loop [i 0]
      (when (< i 10)
        (binding [*out* writer]
          (println i))
        (Thread/sleep 100)
        (recur (inc i))))))

(tee catp *out* *out*)

@catp

(shutdown-agents)
duzunov commented 2 years ago

This would be quite useful - i.e. in CI where you might have long running commands you want to interrupt instead of waiting for them to time out or error out