Scripty:   Distributable shell scripts with dependencies
1 Using Scripty
2 Script Options
7.7

Scripty: Distributable shell scripts with dependencies

Alexis King <lexi.lambda@gmail.com>

 #lang scripty package: scripty-lib

The scripty language is a tool for developing self-installing shell scripts. Every Scripty script is composed of two parts: a script preamble, which describes metadata about the script, such as its dependencies, and a script body, which is the runnable body of the script. The body can be written in any Racket language, and it is not coupled to scripty’s reader syntax.

1 Using Scripty

Making a script with Scripty is not complicated, since the bulk of any Scripty script is just an ordinary Racket module. Since Racket treats lines starting with #! as comments, it’s quite easy to turn any module into a runnable Unix script. Here’s a simple example:

"hello.rkt"

#!/usr/bin/env racket
#lang racket/base
 
(displayln "Hello, world!")

Now it’s possible to run the above file as a Unix executable:

  $ chmod +x hello.rkt
  $ ./hello.rkt
  Hello, world!

This is great, but unfortunately, this approach won’t work so well if your script depends on some libraries a user doesn’t have. That’s where scripty comes in.

To convert any Racket module into a Scripty-managed script, add #lang scripty to the top, followed by a script preamble:

"parse.rkt"

#!/usr/bin/env racket
#lang scripty                              ; \ script preamble
#:dependencies '("base" "megaparsack-lib") ; /
------------------------------------------
#lang racket/base
 
(require megaparsack)

The preamble contains metadata about the script, such as its dependencies, as demonstrated by the above example, and it must be separated from the rest of the module by a line composed exclusively of at least 3 - characters.

The script preamble is followed by an ordinary Racket module, which forms the script body, and usually begins with a second #lang line. When the script is run from the command line, the script body will be run after dependencies have been installed.

When a user runs a Scripty script, but they don’t have all of the required dependencies already installed, they will be interactively prompted to ask if they would like to install them. If they agree, then the packages will be installed, and the script will be run. Otherwise, the script will terminate. If all packages are already installed, the script will run as usual.

Packages installed by scripty are marked as “auto-installed”, so running raco pkg remove --auto will remove them if they are not depended upon by other packages. If packages that a script depends on are uninstalled, then the user will simply be prompted to reinstall them the next time they run the script.

2 Script Options

Currently, the only option supported by the script preamble is #:dependencies.

  script-preamble = #:dependencies deps-expr

The deps-expr form is evaluated at phase one, and it should produce a list of package dependencies in the same format as the deps key of #lang info.