This tutorial tells how to use glidergun. We will discover all important glidergun features step-by-step.
To install glidergun (gun for short):
$ curl -L https://github.com/gliderlabs/glidergun/releases/download/v0.1.0/glidergun_0.1.0_$(uname -sm|tr \ _).tgz \
| tar -zxC /usr/local/bin
Create a new empty directory and enter it.
mkdir /tmp/guntest
cd /tmp/guntest
gun will search for a file called Gunfile
starting from $PWD and upwards.
If none found the init
command will be available.
$ gun
Available commands:
init Initialize a glidergun project directory
Use the init
command to create an empty Gunfile
which marks the directory as a valid gun project:
$ gun init
$ ls -la
-rw-r--r-- 1 sillyname wheel 0 Feb 3 09:26 Gunfile
Lets say we want to create a tool for managing github teams. Gun will search the cmds
directory for files with *.bash
extension.
$ mkdir cmds
$ cat > cmds/github.bash <<EOF
init() {
cmd-export gh-orgs
}
gh-orgs() {
declare desc="Lists your GithHub organizations"
echo "todo ..." | blue
}
EOF
We have 2 ordinary bash functions. As gun find *.bash files, it
will source
them and call init()
. We use cmd-export
to expose
a function as a gun command. We use the declare desc
to document the function. This docs is used by cmd-export.
The | blue
at the end is also gun feature, it colors the output. For all colors see: color.bash
Let's give it a go:
$ gun
Available commands:
gh-orgs Lists your GithHub organizations
...
$ gun gh-orgs
todo ...
Now lets use the github rest API to list your organizations. Change the gh-orgs function to:
gh-orgs() {
declare desc="Lists your GithHub organizations"
- echo "todo ..." | blue
+ curl -s \
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
+ https://api.github.com/user/orgs
}
If you try now you will get a Bad credentials
response, as
for github authorization, we need an oauth2 token. Lets declare
it in init() with env-import
:
init() {
cmd-export gh-orgs
+ env-import GITHUB_TOKEN
}
Now gun will complain about the missing env:
$ gun gh-orgs
!! Imported variable GITHUB_TOKEN must be set in profile or environment.
Go to https://github.com/settings/tokens to create one, and put in you Gunfile
:
export GITHUB_TOKEN=0a12b34c5d6e789fg0123h4i56j789klm01n2op3
If you run gun again, it will successfully list your orgs.
$ gun gh-orgs
[
{
"login": "gliderlabs",
"id": 8484931,
"url": "https://api.github.com/orgs/gliderlabs",
"repos_url": "https://api.github.com/orgs/gliderlabs/repos",
"events_url": "https://api.github.com/orgs/gliderlabs/events",
"hooks_url": "https://api.github.com/orgs/gliderlabs/hooks",
"issues_url": "https://api.github.com/orgs/gliderlabs/issues",
"members_url": "https://api.github.com/orgs/gliderlabs/members{/member}",
"public_members_url": "https://api.github.com/orgs/gliderlabs/public_members{/member}",
"avatar_url": "https://avatars.githubusercontent.com/u/8484931?v=3",
"description": ""
}
...
Its important to note, that gun forks a new bash process, and Gunfile is sourced only in that process.
Its a good practice to set meaningful default values whenever possible. So lets introduce the PAGE_SIZE
env var. We bind it to github's pagination functionality
init() {
deps-require jq
cmd-export gh-orgs
env-import GITHUB_TOKEN
+ env-import PAGE_SIZE 5
}
gh-orgs() {
declare desc="Lists your GithHub organizations"
: ${GITHUB_TOKEN:? go to https://github.com/settings/tokens to create one}
curl -s \
-H "Authorization: Bearer $GITHUB_TOKEN" \
- https://api.github.com/user/orgs
+ https://api.github.com/user/orgs?per_page=$PAGE_SIZE
}
The :env
command can be used to list all declared env vars with actual value:
$ gun :env
GITHUB_TOKEN = 0a12b34c5d6e789fg0123h4i56j789klm01n2op3
PAGE_SIZE = 1
Now we are getting closer, but there is to much output. Lets list only the organization's name.
Lets use jq, but you can take it granted the everybody has it.
deps-require
comes to the rescue. It will make sure
init() {
+ deps-require jq 1.4
cmd-export gh-orgs
env-import GITHUB_TOKEN
env-import PAGE_SIZE 5
}
gh-orgs() {
declare desc="Lists your GithHub organizations"
: ${GITHUB_TOKEN:? go to https://github.com/settings/tokens to create one}
curl -s \
-H "Authorization: Bearer $GITHUB_TOKEN" \
- https://api.github.com/user/orgs?per_page=$PAGE_SIZE
+ https://api.github.com/user/orgs?per_page=$PAGE_SIZE \
+ | jq ".[].login" -r
}
Dependencies are downloaded into .gun/bin/
folder, and this dir is placed in the begining of the
forked bash process's PATH. So this way you can make sure you are using the correct version.
$ gun gh-orgs
* Dependency required, installing jq latest ...
lalyos-trainings
sequenceiq
gliderlabs
the deps-require is a really
See the repository https://github.com/gliderlabs/glidergun-rack/blob/master/index/jq
Sometimes you want to have multiple set of environment variables, like one Gunfile
for
development and one for production. You can just add a postfix like: Gunfile.dev
or Gunfile.prod
.
To determine which one is to use, there 2 ways. You can set the GUN_DEFAULT_PROFILE
$ export GUN_DEFAULT_PROFILE=dev
$ gun gh-orgs
* Using default profile dev
...
Or you can add an extra first argument, which will specify the actual profile, and than cut of from the arg list (shift in bash terms)
$ gun dev gh-orgs
If you start to have a lot of commands it might make sense to group them together. See an example in ec2.bash
init() {
cmd-export-ns ec2 "EC2 instance management"
cmd-export ec2-ip
cmd-export ec2-info
cmd-export ec2-list
}
When you list available root commands (gun without any commands), you get only the namsecpase listed. If you specify a namespace insted of a command, you get the list of commands in that namespace:
$ gun
Available commands:
ec2 EC2 instance management
$ gun ec2
EC2 instance management
Available commands:
info Instance info by name or ID
ip Public or private IP by ID or tag
list List instances for a VPC
...
Remote modules are github repositories contaiening gun scripts. For example if you want to use all commands from this directory: https://github.com/gliderlabs/glidergun/tree/master/lib/aws You can refer to it by removing https:// at the begining, and tree/master/ from the middle:
gun :get github.com/gliderlabs/glidergun/lib/aws
You can ask for help about any command by appending an -h
to the end of the command.
$ gun gh-orgs -h
gh-orgs
Lists your GithHub organizations
gh-orgs ()
{
declare desc="Lists your GithHub organizations";
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user/orgs | jq ".[].login" -r
}
Or you can even trace the command by appending -t
. It acts like adding a set -x
into the bash script:
$ gun gh-orgs -t
+ cmd-ns '' gh-orgs
+ local ns=
+ shift
+ local cmd=gh-orgs
+ shift
+ local status=0
+ [[ -n exists ]]
+ gh-orgs
+ declare 'desc=Lists your GithHub organizations'
+ curl -s -H 'Authorization: Bearer 0a12b34c5d6e789fg0123h4i56j789klm01n2op3' https://api.github.com/user/orgs
+ jq '.[].login' -r
hortonworks
lalyos-trainings
sequenceiq
gliderlabs
Use the ::
meta-command.
gun :: non-exported-fn
If some dependency is missing from the original glidergun-rack just fork the repo and a text file named by the needed dependency.
See an example sed dependency, for docker-machine
https://github.com/lalyos/glidergun-rack/blob/master/index/docker-machine
In order to use your fork, you have to set the DEPS_REPO
env var in Gunfile:
export DEPS_REPO=https://raw.githubusercontent.com/lalyos/glidergun-rack/master/index
Actually hashcodes in rackfiles are optional, so for hacking around you can just leave them out.
There are some additional env vars you can change the default behaviour:
- GUN_PATH
- GUN_ROOT
If you have some gun modules in your local file system, you can use a :
separated list of those dirs.
export GUN_PATH=~/prj/gun-module-1:~/prj/gun-module-2:~/prj/gun-module-3
Now all 3 module's commands are available.
Normally you issue gun
commands in a specific directory. But if you want to create globally usable gun command,
you can create a gun project let say at ~/.gunroot
, and use the folloing alias:
alias gun='GUN_ROOT=~/.gunroot /usr/local/bin/gun'
Now you can run gun command even in directories which are not gun init
-ed. Meaning they, or any of they parent
dir doesn't contain a Gunfile.