Runfile Documentation
Table of Contents
Introduction
What is Runfile and how to use it.
Runfile Command Reference
An extensive description explaining how to construct your Runfile.
Jump directly to:
Runfile Location and Filename
All about the runfile search path, local and global (named) runfiles.
Creating Reusable Tasks
Create tasks you can reuse in more than one project.
Multiple Project Runfiles
For large projects with many Runfile tasks, you can easily separate
your Runfile to smaller files by using a .runfile
settings file.
Related Gems
Premade Tasks: runfile-tasks
Easily add common tasks for code testing, gem publishing and more.
Introduction to Runfile
Runfile lets you create command line applications in a way similar to Rake, but with the full power of Docopt command line options.
You create a Runfile
, and execute commands with
run command arguments -and --flags
.
If you are not familiar with Rake or Docopt...
You don't have to be.
These are just the tools that inspired Runfile (and docopt is used behind the scenes).
Think about Runfile as a way to easily define a command line application using Ruby code.
The fastest way to understand how Runfile works, is to create one or play with one of the examples
To create your first Runfile:
- Install Runfile - execute
gem install runfile
- Make sure it is installed - execute
run
- Create a template Runfile - execute
run new
- Execute your shiny new program - execute
run
If everything went well, you should now see:
Usage:
run command <arg> [--flag]
run (-h|--help|--version)
Take a look at the examples, or the Runfile Command Reference
If you are familiar with Rake...
If you know rake, then Runfile is like Rakefile. You use a special, lightweight language (DSL) to define tasks in ruby.
One of the key differences between a Runfile and a Rakefile, is that in a Runfile you can define a fairly expressive set of commands, with required/optional parameters and long/short option flags.
For example, defining a Runfile that responds to
run watch style.css --verbose --all
is done like this:
usage "watch <file> [--verbose --all]"
action :watch do |args|
say "Watching #{args['<file>']}"
say "Verbosity: High" if args['--verbose']
# your code here
end
If you are familiar with Docopt...
If you have ever used Docopt, you know it is one of the simplest ways to create expressive command line applications. Runfile is sort of a DSL around docopt.
Each command you use in the Runfile, adds a little something to the final "docopt" that will be generated.
For example, if you have this in your Runfile:
usage "greet <name> [--long --color]"
help "Say hello to <name>"
option "--long", "Show a longer greeting"
option "--color", "Use colored output"
The generated docopt will look like this:
$ run -h
Runfile 0.0.0
Usage:
run greet <name> [--long --color]
run (-h|--help|--version)
Commands:
greet <name> [--long --color]
Say hello to <name>
Options:
-h --help
Show this screen
--version
Show version
--long
Show a longer greeting
--color
Use colored output
Familiar right? Good. Familiar is good.
See the full Runfile Command Reference (it is short and not at all scary) or learn more about Runfile Locations and Filenames.
Runfile Command Reference
Runfile is ruby. You can write any ruby code in it as usual.
Tip: To create an initial Runfile, go to a folder that does not contain one already, and execute
run new
.
Runfile provides several commands to help you define your program and a handful of utility functions to make writing beautiful command line applications a breeze.
A simple Runfile looks like this ( more examples ):
usage "greet <name>"
help "Say hello to <name>"
action :greet do |args|
say "Hello #{args['<name>']}"
end
Defining Program Details
Commands to specify information about the program, such as its name and version.
Defining Program Actions
Commands to define program actions
Output Commands
Commands that can be executed in any action to print colorful, indented messages to the console.
Execution Commands
Commands that can be executed in any action to run external programs in the foreground or background easily.
Misc Commands
Additional commands you can use in your action blocks.
Defining Program Details
Cheatsheet
title 'My Utilities'
summary 'Utilities for my Rails'
version '0.1.0'
Reference
title string
Define the title of the application.
This command is optional.
Example: title "RoadRunner"
summary string
Define the one line application help message.
This command is optional.
Example: summary "My new application"
version string
Specify a version string for your program.
This command is optional.
Example: version "0.1.0"
Defining Program Actions
Cheatsheet
# --- Action Definition
usage "server PORT [--background]"
help "Start the server, optionally in the background"
option "-b --background", "Start in the background"
param "PORT", "Server port to listen on"
env_var "HOST", "Host address to listen to"
example "server 3000 -b"
action :server do |args|
# ... action code here
end
# --- Command Prefix
command 'prefix'
# all actions here will be prefixed by 'prefix'
action :anything do
# ...
end
endcommand
Reference
usage string
Specify the usage pattern of the following action
.
This string is expected to be in any format recognized by docopt.
In some cases ( compact usage example )
you may want to force-disable the usage text for the following action.
Simply use usage false
.
This command is optional if the action does not have any arguments.
Examples:
usage "command" # The next action (:command) has no
# arguments (optional in this case)
usage "greet <name>" # The next action (:greet) has one
# require argument, called 'name'
usage "run [--fast --slow]" # The next action (:run) has two
# optional flags.
usage false # Disable usage pattern for the next
# action.
help string
Specify the help message for the following action.
This is the message that will be displayed when you execute
run --help
This command is optional.
Example: help "Greet the user with a colorful 'Hello!'"
option string, description [, label]
Specify the help information for any of the option flags. This is the place where you can specify that a certain flag also has a short version.
Normally, the help message for all options appear under the Options:
caption. If you provide the third <label>
argument, it will appear
under a different caption.
See Also: Options Label Example
This command is optional unless the usage
pattern may be ambiguous.
Examples:
option "-c --color", "Show message with a color"
option "--force", "Force delete", "Delete Options"
param string, description [, label]
Specify the help information for any of the positional parameters. This is purely decorative and has no impact on the operation of the Runfile.
Normally, the help message for all parameters appear under the Parameters:
caption. If you provide the third <label>
argument, it will appear
under a different caption.
See Also: Parameters Example
This command is optional.
Examples:
param "PORT", "Server port to listen to"
param "SOURCE", "File to copy", "Copy Options"
env_var string, description [, label]
Specify the help information for any environment variables your Runfile may need. This is purely decorative and has no impact on the operation of the Runfile.
Normally, the help message for all environment variables appears under the
Environment Variables:
caption. If you provide the third <label>
argument, it will appear under a different caption.
See Also: Environment Variables Example
This command is optional.
Examples:
env_var "HOST", "Host address to listen on"
env_var "USER", "SSH user", "SSH Environment Variables"
example string
Add an example command to the general help information.
When adding an example, the command run --help
will show an
Examples:
section at the end of the help text, with all added examples.
You do not need to include the run
or run runfile_name
at the beginning
of your example text, it is done automatically.
See Also: Example Command Example
This command is optional.
Examples:
example "copy source.txt dest.txt --force"
example "copy source.txt --here"
action name [, alias] { block }
Define the actual action block that will be called.
This command is required
Examples:
# If you do not need to process any arguments:
action :command do
# your code here
end
# if you want to handle arguments defined in `usage`:
action :command do |args|
# your code here
# access any argument with arg['--flagname'] or arg['<arg>']
end
# If you wish to use commands with hyphen, simply use single quotes:
action :'drink-beer' do
# your code here
end
# To define an alias (shortcut) to a command, use:
action :command, :c do
# your code here
end
See Also: Alias Example
command string
The command
command lets you define a namespace. Once you use this
command, any subsequent action will be associated with this namespace.
This is a way to create sub commands.
Call without parameter to revert back to the global namespace.
This command is optional.
Example: command "html"
See Also: Namespace Example
endcommand
Alias of command
. Intended as a syntactic sugar so that you can end
a command 'namespace'
with endcommand
instead of an empty
command
.
This command is optional.
Output Commands
Cheatsheet
say 'anything'
say '!txtred!anything in red'
say 'only one !txtred!word!txtrst! in red'
resay 'go back to the beginning of the line'
say_status :download, 'Download in progress'
say_status :download, 'Download in progress', :txtblu
word_wrap ' Indent a potentially wrapping line by two spaces'
say word_wrap ' Indent a potentially wrapping line by two spaces and say it'
Reference
All these commands can be used inside your :action
blocks.
These commands are provided by the Colsole gem which is already bundled with Runfile.
say string
Print a message to screen, with support for color markers and partial strings.
End the string with a space to force the cursor to stay at the same line (otherwise, a newline is added).
Examples:
say "Hello world"
say "!txtgrn!I am green"
say "Legen... wait for it... "
say "dary"
resay string
Erase the current output line and print a new message. Should be
called only after a space terminated call to say
to ensure the
cursor is at the same line.
Examples:
say "Downloading... "
resay "Downloaded"
say_status status, message [, color]
Print a message to screen, with a colored status tag.
Examples:
say_status :success, "Task completed"
say_status :error, "Task failed", :txtred
word_wrap string [, length]
If you wish to print a string and make it wrap automatically based
on the width of the terminal, use word_wrap
.
The function is also sensitive to any leading spaces. These will be preserved in any wrapped line, so it is easy to print indented long strings.
Examples:
say word_wrap("one two three four", 10)
say word_wrap(" one two three four", 10)
say word_wrap "Some long line ... that ends here"
Execution Commands
Cheatsheet
# --- Running commands and services
run 'pwd'
run! 'pwd' # and exit
run_bg 'rails server'
run_bg 'rails server', log: 'my.log', pid: 'myserver'
stop_bg 'myserver'
# --- Before / After run hooks
before_run do |command|
command.gsub /^(rails|rake|cucumber)/, "bin/\\1"
end
after_run do |command|
puts "Finished #{command}"
end
# --- Configuration
Runfile.setup do |config|
config.pid_dir = 'tmp/pid'
config.quiet = true
end
# or...
Runfile.pid_dir = 'tmp'
Reference
run string
Print and run a command. Wait until it is done and continue.
This is executed using system
. If Runfile.quiet
is true, it will
not echo the command to the console.
Example:
run "rails server -b* -p3000"
run! string
Print and run a command, then exit. This is executed using exec
.
If Runfile.quiet
is true, it will not echo the command to the console.
Examples:
run! "rails server -b* -p3000"
puts "this message will never be shown"
run_bg string [, options]
Run a command in the background, which you can later stop with stop_bg
.
Available options are:
pid
- provide a string that will be used to name the PID file. This is the string you will later use instop_bg
. All PID files will be stored in the working directory, or inRunfile.pid_dir
.log
- provide a filename that will be used to log the output.
Examples:
run_bg 'some/long-running/process'
run_bg 'some/long-running/process', log: 'my.log', pid: 'daemon'
stop_bg string
Stop a command started with 'run_bg'. Provide the name of he pid file you used in 'run_bg'
Example:
stop_bg 'server'
before_run { block }
Intercept each call before executed. Can be used to modify the command, run something before it, or cancel it altogether.
Your block receives the command as argument, and should return a command to run or false to stop execution.
Examples:
# Prefix the command with "bin/" if it is rails, rake or cucumber
before_run do |command|
cmd.gsub /^(rails|rake|cucumber)/, "bin/\\1"
end
# Abort the command execution based on the value of an environment
# variable
before_run do |command|
ENV['PREVENT_EXECUTION'] ? false : command
end
after_run { block }
Intercept each call before it exits. Note this is only useful with run
and run_bg
but not with run!
which exits immediately after execution.
Examples:
after_run do |command|
puts "Finished #{command}"
end
Configuration
You can configure several aspects of how these commands behave.
Configuration can be done in one of two ways. Either use the direct
syntax: Runfile.option = value
, or provide a block:
Runfile.setup do |config|
config.option = value
end
Add the configuration anywhere in your Runfile (either inside an action or outside, at the beginning of the file).
pid_dir - configure folder for PID files
PID files are stored in the working directory by default.
Runfile.pid_dir = './tmp/pids'
quiet - run without echoing the command
By default, calls to run
will show the command before running it.
Set quiet
to true to change that.
Example:
Runfile.quiet = true
Example
See this example file sample usage or this feature file to get an idea of what is possible with this extension.
Misc Commands
Cheatsheet
execute 'other_action'
Reference
execute string
Call another action. This command accepts a single string argument
which should include the command as if you type it in the command
prompt (only without the run
prefix).
Example: execute "theme watch --all"
See Also: Cross Call Example
Runfile Location and Filename
Runfile is designed to help you create both project specific command line tools, and system wide command line applications.
Project Runfiles are simply named Runfile and can only be accessed in the same directory they live in.
Named Runfiles (*.runfile) can exist in several places:
*.runfile
in the current folder*.runfile
in~/runfile
and its sub directories*.runfile
in/etc/runfile
and its sub directories*.runfile
in any custom folder
When you execute run
, this is what happens:
- If there is a file called Runfile in the current directory, we will use it.
- If there is a file called .runfile in the current folder, we will use it as a configuration file to tell us where the runfiles are. (See Custom Location below).
- If not, search for *.runfiles in the runfile search directories and sub-directories.
- If one or more were found, show a list of all of them.
Using a project Runfile
$ cd /your/project
$ run new
Runfile created.
$ run
Usage:
run command <arg> [--flag]
run (-h|--help|--version)
$ run command hello
Command running...
$ cat Runfile
summary "Application description"
version "0.1.0"
usage "command <arg> [--flag]"
help "Help line for command"
option "-f --flag", "Help text for option"
action :command do |args|
say "Command running..."
end
Using Named Runfiles
$ cd /your/project
$ run new greet
greet.runfile created.
$ run
Runfile engine v0.7.0
Tip: Type 'run new' or 'run new name' to create a runfile.
For global access, place named.runfiles in ~/runfile/ or in /etc/runfile/ or
anywhere in the PATH.
run greet ........................ /path/to/file
$ run greet
Usage:
run greet command <arg> [--flag]
run greet (-h|--help|--version)
$ cd ~/runfile # or /etc/runfile
$ run new hotdog
hotdog.runfile created.
$ run
Runfile engine v0.4.0
Tip: Type 'run new' or 'run new name' to create a runfile.
For global access, place named.runfiles in ~/runfile/ or in /etc/runfile/ or
anywhere in the PATH.
run greet ........................ /path/to/file
run hotdog ....................... /path/to/file
Custom Location for Named Runfiles
For more advanced uses, you can define multiple Runfiles per project.
This can be handy if you have a large set of commands and wish to separate them to multiple files.
Simply create a .runfile
settings file in your project, and use it
to specify the location of the folder containing your runfiles.
# in .runfile
---
folder: lib/commands
This settings file supports several more options, like auto-loading a helper file, and creating command shortcuts.
Read more in the Multiple Project Runfiles page, or see the Settings Example
Ignoring the local Runfile
In case you are using both local Runfiles and global named runfiles, you may find yourself in a situation where you are trying to run a named runfile from a folder that contains a local Runfile.
The local Runfile will take precedence and not allow access to your global runfiles.
To overcome this issue, use run!
instead of run
.
The run!
command will ignore the local Runfile and only look for
named runfiles.
Note for RVM users
If you are using RVM, it is recommended you add this to your .bashrc
:
export NOEXEC_EXCLUDE="run!"
This will prevent RVM from silently prepending it with bundle exec
.
More information is available in the RVM documentation and in the RVM GitHub Repository.
Creating Reusable Tasks
You can easily build a set of tasks that can be reused in any Runfile.
Since this is pure ruby, there are many ways to do so. The below is an example.
Step 1: Create your common tasks file
Let's save this file as 'tasks.rb'
# The reusable tasks module
module MyCommonTasks
def self.tasks
# We can use the standard Runfile syntax here
command "make"
usage "cake [--chocolate|--cheese]"
help "Make some cake"
action :cake do |args|
say "Making a cake..."
say "... a chocolate cake" if args['--chocolate']
say "... a cheese cake" if args['--cheese']
end
usage "faces"
help "Make faces"
action :faces do |args|
say "Making faces"
end
endcommand
end
end
Step 2: Embed the tasks in your Runfile
Create a Runfile
file (you can simply run run make
) and paste this
content in it.
# include our common tasks file
require_relative "tasks"
title "My Runfile"
summary "A sample Runfile"
version "0.1.0"
# include the external tasks
MyCommonTasks.tasks
# continue with regular tasks
usage "hello [<name> --color]"
help "Say hello"
option "-c --color", "Greet with color"
action :hello do |args|
if args['--color']
say "!txtgrn!Hello #{args['<name>']}"
else
say "Hello #{args['<name>']}"
end
end
Step 3: Test the Runfile
Running run
will now show both the embedded and local tasks:
$ run
Usage:
run make cake [--chocolate|--cheese]
run make faces
run hello [<name> --color]
run (-h|--help|--version)
Packing reusable tasks as a gem
You can pack your reusable tasks as a gem for all to enjoy.
An example of such a gem, is the runfile-tasks gem which provides a collection of tasks like:
- Tasks for running tests (minitest, rspec, cucumber)
- Tasks for packing and publishing gems
And more.
Multiple Project Runfiles
Runfile provides another mechanism for more advanced uses.
This mechanism lets you have multiple named runfiles per project. This is useful when your Runfile becomes too large, or when you wish to separate it to logical units.
To use this mechanism, you need to:
- Delete the
Runfile
file from your project's folder. - Create a
.runfile
settings file (YAML) in your project's folder.
The .runfile Configuration File
# .runfile
# Runfile settings YAML
# Define the folder where *.runfile files reside.
folder: lib/commands
# Optional: File to load before any runfile.
# Consider this your "helper" file.
helper: helper.rb
# Optional: Message to show before the list of files.
# This string supports color markers.
intro: "!txtgrn!My Command Line"
# Optional: An array of shortcut commands
# Each of the keys here will be expanded to their values before Runfile
# tries to move on to the execution stage. In other words, if you have
# a shortcut saying "s: server --daemon", and you run "run s" it is
# exactly like you run "run server --daemon".
shortcuts:
s: server start
sd: server start --daemon
stat: server status
To see how it works, check out the Settings Example.
Now, whenever you execute run
, we will look for lib/commands/*.runfile
files and you can execute any of them like any other named runfile.
Running run
without any argument will show both the runfiles in the folder
and the available shortcuts.