Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shell_grunt2

Let somebody else run shell commands for you.

shell_grunt2 watches a directory tree and runs shell commands whenever a file changes. Which commands run for which files is described in a Lua file, so the rules can be as simple or as clever as you like.

Usage

$ shell_grunt2                      # watches '.' with tasks from ./watcher.lua
$ shell_grunt2 -f build/tasks.lua   # a different task file
$ shell_grunt2 -d src               # watch only a subdirectory
$ shell_grunt2 --check              # validate the task file and print the tasks
$ shell_grunt2 --run-at-startup     # run everything once, without waiting for a change

The task file is watched too: save it and the tasks are reloaded in place. If it does not compile, the error is printed and the watcher keeps running, so the next save picks it up.

Only one watcher runs per task file. The lock lives in the temp directory and records the owning pid, so a watcher that was killed does not block the next one.

The task file

The file must return a list of tasks. A minimal one:

return {
   {
      command = "cargo test",
   },
}

A task with everything spelled out:

return {
   {
      -- Shown in messages. Optional; defaults to "task #1".
      name = "rust",

      -- Optional. Called with the path that changed, relative to the watched
      -- tree; the task runs when it returns anything but false or nil. Without
      -- it, every change runs the task.
      should_run = function(path)
         if path:starts_with("target/") then
            return false
         end
         return path:ext() == "rs" or path:ext() == "toml"
      end,

      -- Wait this many milliseconds after the last change before starting, so a
      -- "save all" results in one run. Optional, defaults to 50.
      start_delay = 50,

      -- Clear the screen before running. Optional, defaults to true.
      clear_screen = true,

      -- Send output to these files, with colors removed. Optional.
      redirect_stdout = "/tmp/cargo.out",
      redirect_stderr = "/tmp/cargo.err",

      -- Keep output off the terminal. Optional, both default to false.
      suppress_stdout = false,
      suppress_stderr = false,

      -- Extra environment for the commands. Optional.
      environment = { RUST_BACKTRACE = "1" },

      -- Run in order, stop at the first failure.
      commands = {
         { name = "Check", command = "cargo check --color always" },
         { name = "Test",  command = "cargo test --color always" },
      },
   },
}

Commands

commands accepts several shapes, pick whichever is shortest for the job:

command  = "cargo check"                                    -- one command
commands = { "cargo check", "cargo test" }                  -- a chain
commands = { name = "Check", command = "cargo check" }      -- one, with a name
commands = {                                                -- a named chain
   { name = "Check", command = "cargo check" },
   { name = "Test",  command = "cargo test" },
}

A command table understands:

Key Meaning
command The command line. Required. Quoting works as in a shell: git commit -m 'a message'.
name Shown while running. Defaults to the command line.
work_directory Run the command here instead of in the current directory.
shell Run through $SHELL -c, so pipes, &&, globs and redirections work. Defaults to false.

Commands run in the order given and the chain stops at the first failure. A command that cannot be started at all - a typo in the binary name, for instance - counts as a failure but does not stop the watcher.

Paths

should_run is called with the path relative to the watched tree, so a change to /home/me/project/src/main.rs under shell_grunt2 -d /home/me/project arrives as src/main.rs. Anchored matches like path:starts_with("target/") therefore do what they look like they do. Files outside the watched tree - the task file, if you keep it elsewhere - keep their absolute path.

Path helpers

These are added to Lua's string table, so they work as methods on any string:

Helper "src/bin/main.rs" gives
path:ext() "rs" (nil if there is no extension)
path:basename() "main.rs"
path:dirname() "src/bin"
path:stem() "main"
path:starts_with("src/") true
path:ends_with(".rs") true

Everything else Lua offers works too, for example path:match("^src/") or path:find("test", 1, true).

Building

$ cargo build --release
$ cargo test

Lua is compiled in, there is nothing to install alongside it. Unix only - the tool signals child processes and shells out through $SHELL.

About

Let somebody else run shell commands for you

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages