Skip to content

DSL for generating shell scripts using clojure

Notifications You must be signed in to change notification settings

deadghost/stevedore

 
 

Repository files navigation

pallet.stevedore

Stevedore is a DSL for generating shell scripts using clojure.

Why?

While there is nothing wrong with normal shell scripting, Stevedore allows the ability to easily interpolate clojure values. As a consequence, we gain the benefits of being able to flexibly parameterize scripts and tailor them to target specific operating systems and their versions.

Installation

Stevedore is distributed as a jar, and is available in the clojars repository.

Installation is with lein or your favourite maven repository aware build tool.

lein project.clj

:dependencies [[com.palletops/stevedore "0.8.0-beta.7"]]

maven pom.xml

<dependencies>
  <dependency>
    <groupId>com.palletops</groupId>
    <artifactId>stevedore</artifactId>
    <version>0.8.0-beta.7</version>
  </dependency>
<dependencies>

<repositories>
  <repository>
    <id>clojars</id>
    <url>http://clojars.org/repo</url>
  </repository>
</repositories>

Examples

Basic Usage

Let's write a basic script; nothing fancy just a plain ole' thing you can easily write in your scripting language of choice. Very static.

(use 'pallet.stevedore)
(require 'pallet.stevedore.bash)

(print
 (with-script-language :pallet.stevedore.bash/bash
   (script
    ("ls" "/some/path")
    (defvar x 1)
    (println @x)
    (defn foo [x] ("ls" @x))
    ("foo" 1)
    (if (= a a)
      (println "Reassuring")
      (println "Ooops"))
    (println "I am" @("whomai")))))

Outputs:

    # form-init7685875326394262653.clj:2
ls /some/path
    # form-init7685875326394262653.clj:3
x=1
    # form-init7685875326394262653.clj:4
echo ${x}
foo() {
x=$1
    # form-init7685875326394262653.clj:5
ls ${x}
}
    # form-init7685875326394262653.clj:6
foo 1
    # form-init7685875326394262653.clj:7
if [ "a" == "a" ]; then echo Reassuring;else echo Ooops;fi
    # form-init7685875326394262653.clj:10
echo I am $(whomai)

Interpolating Clojure

Here is where we start seeing some power. Notice everything escaped with ~ gets evaluated as clojure code before becoming parts of arguments for script.

(print
 (with-script-language :pallet.stevedore.bash/bash
   (let [path "/some/path"]
     (script
      ("ls" ~path)
      ("ls" ~(.replace path "some" "other"))))))

Outputs:

    # form-init7685875326394262653.clj:6
ls /some/path
    # form-init7685875326394262653.clj:7
ls /other/path

Generating Scripts

That's cool, but here's one better. Let's do the same thing as the previous snippet but let's generate the script using a function that takes a path as an argument. This lets us generate a slightly different script with each different argument.

(defn list-path [path]
  "Replaces the \"some\" portion of path argument with the \"other\" string."
  (script
   ("ls" ~path)
   ("ls" ~(.replace path "some" "other"))))

(print (with-script-language :pallet.stevedore.bash/bash
         (list-path "/some/path")))

Outputs:

    # form-init7685875326394262653.clj:7
ls /some/path
    # form-init7685875326394262653.clj:8
ls /other/path
(print (with-script-language :pallet.stevedore.bash/bash
         (list-path "/some/different/path")))

Outputs:

    # form-init7685875326394262653.clj:7
ls /some/different/path
    # form-init7685875326394262653.clj:8
ls /other/different/path

Composing Scripts

Concatenate scripts together using do-script.

(print (with-script-language :pallet.stevedore.bash/bash
		 (do-script
          (list-path "/some/path")
          (list-path "/some/different/path"))))

Outputs:

# form-init7685875326394262653.clj:5
ls /some/path
    # form-init7685875326394262653.clj:6
ls /other/path
# form-init7685875326394262653.clj:5
ls /some/different/path
    # form-init7685875326394262653.clj:6
ls /other/different/path

Chain scripts together with && using chained-script.

(print (with-script-language :pallet.stevedore.bash/bash
		 (chained-script
          (list-path "/some/path")
          (list-path "/some/different/path"))))

Outputs:

# form-init7685875326394262653.clj:4
    # form-init7685875326394262653.clj:5
ls /some/path
    # form-init7685875326394262653.clj:6
ls /other/path && \
# form-init7685875326394262653.clj:5
    # form-init7685875326394262653.clj:5
ls /some/different/path
    # form-init7685875326394262653.clj:6
ls /other/different/path

Chain your scripts and exit if the chain fails using checked-script.

(print (with-script-language :pallet.stevedore.bash/bash
		 (checked-script
          (list-path "/some/path")
          (list-path "/some/different/path"))))

Outputs:

echo '    # form-init7685875326394262653.clj:5
ls /some/path
    # form-init7685875326394262653.clj:6
ls /other/path
...';
{
    # form-init7685875326394262653.clj:5
    # form-init7685875326394262653.clj:5
ls /some/different/path
    # form-init7685875326394262653.clj:6
ls /other/different/path

 } || { echo '#>     # form-init7685875326394262653.clj:5
ls /some/path
    # form-init7685875326394262653.clj:6
ls /other/path
 : FAIL'; exit 1;} >&2 
echo '#>     # form-init7685875326394262653.clj:5
ls /some/path
    # form-init7685875326394262653.clj:6
ls /other/path
 : SUCCESS'

Further Reading

Support

License

Licensed under EPL

Copyright 2010, 2011, 2012, 2013 Hugo Duncan.

About

DSL for generating shell scripts using clojure

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Clojure 92.5%
  • Shell 7.5%