From fc1ada15551c3ff7e5b65a5d7ce183ece50385fb Mon Sep 17 00:00:00 2001 From: lalyos Date: Mon, 2 Mar 2015 13:45:11 +0100 Subject: [PATCH 01/19] curl follows redirects --- include/deps.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deps.bash b/include/deps.bash index f92356c..6413673 100644 --- a/include/deps.bash +++ b/include/deps.bash @@ -36,7 +36,7 @@ deps-install() { tmpdir="$(deps-dir)/tmp" mkdir -p "$tmpdir" tmpfile="${tmpdir:?}/$name" - curl -s $url > "$tmpfile" + curl -Ls $url > "$tmpfile" if [[ "$checksum" ]]; then if ! [[ "$(cat "$tmpfile" | checksum md5)" = "$checksum" ]]; then echo "!! Dependency checksum failed: $name $version $checksum" | red From ab92833b4a880b4baff43611071494d3546cd81f Mon Sep 17 00:00:00 2001 From: lalyos Date: Mon, 2 Mar 2015 16:23:53 +0100 Subject: [PATCH 02/19] Change dir into GUN_ROOT In case GUN_ROOT isn't in the parent chain, but given explicitly bu env var: `GUN_ROOT=/etc/mygunroot gun` gun-find-root should `cd` into it. --- include/gun.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/gun.bash b/include/gun.bash index f2dc5f7..bf15073 100644 --- a/include/gun.bash +++ b/include/gun.bash @@ -44,8 +44,9 @@ gun-find-root() { done if [[ -f "$path/Gunfile" ]]; then GUN_ROOT="$path" - cd "$GUN_ROOT" fi + + [[ -d "$GUN_ROOT" ]] && cd $GUN_ROOT } main() { From 5e325ef15b3a4ff8f528139156a846fa35ac0ea9 Mon Sep 17 00:00:00 2001 From: lalyos Date: Mon, 2 Mar 2015 19:31:22 +0100 Subject: [PATCH 03/19] Changelog added to PR-16 and PR-17 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2408b4e..2874913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased][unreleased] ### Fixed +- Resolved issue where `deps-install` download url has a riderect +- Ensure `gun-find-root` changes working directory to $GUN_ROOT ### Added From a679d1a8ffe0afc07348b995cbe7700bfd6e75bd Mon Sep 17 00:00:00 2001 From: lalyos Date: Tue, 3 Mar 2015 16:07:24 +0100 Subject: [PATCH 04/19] ensure 0 return code when TRACE enabled fixes PR #16 if combined with TRACE=1 --- include/gun.bash | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/gun.bash b/include/gun.bash index bf15073..8fe2aa5 100644 --- a/include/gun.bash +++ b/include/gun.bash @@ -46,7 +46,9 @@ gun-find-root() { GUN_ROOT="$path" fi - [[ -d "$GUN_ROOT" ]] && cd $GUN_ROOT + if [[ -d "$GUN_ROOT" ]]; then + cd $GUN_ROOT + fi } main() { From 3035e372e78c997493b816a8a1e388213f49c3ee Mon Sep 17 00:00:00 2001 From: lalyos Date: Wed, 11 Mar 2015 19:42:19 +0100 Subject: [PATCH 05/19] Fix deps-check to accept symlinked binaries Some package like the gcloud sdk, installs itself in a dir structure witn bin,lib, ... Symlinking from .gun/bin/gcloud -> .gun/google-cloud-sdk/bin/gcloud seems the easiest solution --- include/deps.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deps.bash b/include/deps.bash index 6413673..0e1cc42 100644 --- a/include/deps.bash +++ b/include/deps.bash @@ -19,7 +19,7 @@ deps-require() { deps-check() { declare name="$1" version="${2:-latest}" - [[ -f "$(deps-dir)/bin/$name" ]] + [[ -e "$(deps-dir)/bin/$name" ]] } deps-install() { From 89bbad10f5c5689434a2fd8815007c7ec17fa8ab Mon Sep 17 00:00:00 2001 From: lalyos Date: Thu, 12 Mar 2015 08:09:11 +0100 Subject: [PATCH 06/19] Fixing dependency extension extraction When filename=some.tar.gz the double # eats up 'some.tar.' and leaves only 'gz' single # extracts correct 'tar.gz' --- include/deps.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/deps.bash b/include/deps.bash index 6413673..6d6331a 100644 --- a/include/deps.bash +++ b/include/deps.bash @@ -45,7 +45,7 @@ deps-install() { fi cd "$tmpdir" filename="$(basename "$url")" - extension="${filename##*.}" + extension="${filename#*.}" case "$extension" in zip) unzip "$tmpfile" > /dev/null;; tgz|tar.gz) tar -zxf "$tmpfile" > /dev/null;; From 60dd39aa9679df15a423d88c98a7ab97dbc0e8c4 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Sun, 31 May 2015 18:00:37 -0500 Subject: [PATCH 07/19] some basic tests using basht --- .gitignore | 1 + CHANGELOG.md | 2 +- Makefile | 4 +++ tests/project.bash | 35 ++++++++++++++++++++++ tests/project/.gun/.gitignore | 2 -- tests/project/cmds/aws.bash | 16 ---------- tests/project/cmds/bar.bash | 2 +- tests/project/cmds/foo.bash | 1 + tests/util/test | 56 ----------------------------------- 9 files changed, 43 insertions(+), 76 deletions(-) create mode 100644 tests/project.bash delete mode 100644 tests/project/.gun/.gitignore delete mode 100644 tests/project/cmds/aws.bash delete mode 100755 tests/util/test diff --git a/.gitignore b/.gitignore index 2962cca..292a595 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build release bindata.go +tests/project/.gun diff --git a/CHANGELOG.md b/CHANGELOG.md index 2874913..258f583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased][unreleased] ### Fixed -- Resolved issue where `deps-install` download url has a riderect +- Resolved issue where `deps-install` download URL has a redirect - Ensure `gun-find-root` changes working directory to $GUN_ROOT ### Added diff --git a/Makefile b/Makefile index c741ad7..268e722 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,13 @@ build: install: build install build/$(shell uname -s)/gun /usr/local/bin +test: + basht tests/*.bash + deps: go get -u github.com/jteeuwen/go-bindata/... go get -u github.com/progrium/gh-release/... + go get -u github.com/progrium/basht/... go get || true release: diff --git a/tests/project.bash b/tests/project.bash new file mode 100644 index 0000000..d628959 --- /dev/null +++ b/tests/project.bash @@ -0,0 +1,35 @@ + +setup() { + cd "$(dirname "${BASH_SOURCE[0]}")/project" + gun &> /dev/null +} +setup + +T_hello-cmd() { + result="$(gun hello)" + [[ "$result" == "Hello!" ]] +} + +T_foo-namespace-cmd() { + result="$(gun foo hello)" + [[ "$result" == "Hello from foo" ]] +} + +T_bar-namespace-cmd() { + result="$(gun bar hello)" + [[ "$result" == "Hello from bar" ]] +} + +T_foo-env-import() { + [[ "$(gun env | grep AWS_ACCESS_KEY_ID)" ]] +} + +T_prod-profile() { + result="$(gun prod env)" + [[ "$result" == "AWS_ACCESS_KEY_ID = prod-access-key" ]] +} + +T_stage-profile() { + result="$(gun stage env)" + [[ "$result" == "AWS_ACCESS_KEY_ID = staging-access-key" ]] +} diff --git a/tests/project/.gun/.gitignore b/tests/project/.gun/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/tests/project/.gun/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/tests/project/cmds/aws.bash b/tests/project/cmds/aws.bash deleted file mode 100644 index 24ce4e7..0000000 --- a/tests/project/cmds/aws.bash +++ /dev/null @@ -1,16 +0,0 @@ - -init() { - env-import AWS_ACCESS_KEY_ID - env-import AWS_SECRET_ACCESS_KEY - deps-require aws -} - -aws-json() { - : ${AWS_ACCESS_KEY_ID:?} ${AWS_SECRET_ACCESS_KEY:?} - aws --output json $@ -} - -aws-text() { - : ${AWS_ACCESS_KEY_ID:?} ${AWS_SECRET_ACCESS_KEY:?} - aws --output text $@ -} \ No newline at end of file diff --git a/tests/project/cmds/bar.bash b/tests/project/cmds/bar.bash index 911387d..98233a4 100644 --- a/tests/project/cmds/bar.bash +++ b/tests/project/cmds/bar.bash @@ -2,7 +2,7 @@ init() { cmd-export-ns bar "Bar namespace" cmd-export bar-hello - deps-require jq 1.4 + #deps-require jq 1.4 } bar-hello() { diff --git a/tests/project/cmds/foo.bash b/tests/project/cmds/foo.bash index 58a4eaf..251336c 100644 --- a/tests/project/cmds/foo.bash +++ b/tests/project/cmds/foo.bash @@ -3,6 +3,7 @@ init() { cmd-export-ns foo "Foo namespace" cmd-export foo-hello + env-import AWS_ACCESS_KEY_ID "" } foo-hello() { diff --git a/tests/util/test b/tests/util/test deleted file mode 100755 index a712b93..0000000 --- a/tests/util/test +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -__contains() { - local e; for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done; return 1 -} - -__fail-macro() { - local line="$1"; shift - __test_status=1 - __test_message="$line: $@" -} -fail='eval __fail-macro $BASH_SOURCE:$LINENO' - -main() { - local run failed start stop duration - declare -a processed - run=0 - failed=0 - for file in $@; do - source "$file" - for t in $(declare -F | grep 'declare -f test_' | awk '{print $3}'); do - if ! __contains "$t" "${processed[@]}"; then - unset __test_status __test_message - echo "=== RUN $t" - start="$SECONDS" - $t - __test_status=${__test_status:-$?} - stop="$SECONDS" - duration=$(($stop-$start)) - processed+=("$t") - run=$(($run+1)) - if [[ "$__test_status" == 0 ]]; then - echo "--- PASS $t (${duration}s)" - else - failed=$(($failed+1)) - echo "--- FAIL $t (${duration}s)" - echo " $__test_message" - echo - fi - fi - done - done - echo - if [[ "$failed" == "0" ]]; then - echo "Ran $run tests." - echo - echo "PASS" - else - echo "Ran $run tests. $failed failed." - echo - echo "FAIL" - exit $failed - fi -} - -[[ "$0" == "$BASH_SOURCE" ]] && main "$@" From d551bc89295d58b2a7423e020f243b00b12ca8a6 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Sun, 31 May 2015 18:09:13 -0500 Subject: [PATCH 08/19] make tests runnable by circleci --- Makefile | 3 ++- circle.yml | 4 ++-- tests/project.bash | 16 +++++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 268e722..a15f553 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ install: build install build/$(shell uname -s)/gun /usr/local/bin test: - basht tests/*.bash + go install + GUN=glidergun basht tests/*.bash deps: go get -u github.com/jteeuwen/go-bindata/... diff --git a/circle.yml b/circle.yml index 6e02c38..cc42d71 100644 --- a/circle.yml +++ b/circle.yml @@ -10,10 +10,10 @@ dependencies: test: override: - - /bin/true + - make test deployment: release: branch: release commands: - - make release \ No newline at end of file + - make release diff --git a/tests/project.bash b/tests/project.bash index d628959..7f6ee66 100644 --- a/tests/project.bash +++ b/tests/project.bash @@ -1,35 +1,37 @@ +export GUN="${GUN:-gun}" + setup() { cd "$(dirname "${BASH_SOURCE[0]}")/project" - gun &> /dev/null + $GUN &> /dev/null } setup T_hello-cmd() { - result="$(gun hello)" + result="$($GUN hello)" [[ "$result" == "Hello!" ]] } T_foo-namespace-cmd() { - result="$(gun foo hello)" + result="$($GUN foo hello)" [[ "$result" == "Hello from foo" ]] } T_bar-namespace-cmd() { - result="$(gun bar hello)" + result="$($GUN bar hello)" [[ "$result" == "Hello from bar" ]] } T_foo-env-import() { - [[ "$(gun env | grep AWS_ACCESS_KEY_ID)" ]] + [[ "$($GUN env | grep AWS_ACCESS_KEY_ID)" ]] } T_prod-profile() { - result="$(gun prod env)" + result="$($GUN prod env)" [[ "$result" == "AWS_ACCESS_KEY_ID = prod-access-key" ]] } T_stage-profile() { - result="$(gun stage env)" + result="$($GUN stage env)" [[ "$result" == "AWS_ACCESS_KEY_ID = staging-access-key" ]] } From ec5f0447802775aa56a9e6cb6a86ab1f8c80679e Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Sun, 31 May 2015 18:14:23 -0500 Subject: [PATCH 09/19] set up circleci workspace. also save artifact while we're at it --- Makefile | 10 +++++++++- circle.yml | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a15f553..123ecbb 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ NAME=glidergun BINARYNAME=gun +OWNER=gliderlabs ARCH=$(shell uname -m) VERSION=0.0.7 @@ -26,7 +27,14 @@ release: tar -zcf release/$(NAME)_$(VERSION)_Linux_$(ARCH).tgz -C build/Linux $(BINARYNAME) tar -zcf release/$(NAME)_$(VERSION)_Darwin_$(ARCH).tgz -C build/Darwin $(BINARYNAME) gh-release checksums sha256 - gh-release create gliderlabs/$(NAME) $(VERSION) $(shell git rev-parse --abbrev-ref HEAD) v$(VERSION) + gh-release create $(OWNER)/$(NAME) $(VERSION) $(shell git rev-parse --abbrev-ref HEAD) v$(VERSION) + +circleci: + rm ~/.gitconfig + rm -rf /home/ubuntu/.go_workspace/src/github.com/$(OWNER)/$(NAME) && cd .. \ + && mkdir -p /home/ubuntu/.go_workspace/src/github.com/$(OWNER) \ + && mv $(NAME) /home/ubuntu/.go_workspace/src/github.com/$(OWNER)/$(NAME) \ + && ln -s /home/ubuntu/.go_workspace/src/github.com/$(OWNER)/$(NAME) $(NAME) clean: rm -rf build release diff --git a/circle.yml b/circle.yml index cc42d71..a28376d 100644 --- a/circle.yml +++ b/circle.yml @@ -1,12 +1,13 @@ dependencies: pre: - - rm ~/.gitconfig - - make deps + - make circleci override: + - make deps - make build post: - tar -czvf $CIRCLE_ARTIFACTS/gun-linux.tgz -C build/Linux gun - tar -czvf $CIRCLE_ARTIFACTS/gun-darwin.tgz -C build/Darwin gun + - tar -czvf $CIRCLE_ARTIFACTS/go-workspace.tgz -C ~/.go_workspace . test: override: From 1c7321a9ad29e8ce4e578a349d50e59d6b43c746 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Sun, 31 May 2015 19:15:11 -0500 Subject: [PATCH 10/19] made gun commands special. added trace flag. some refactoring and optimization --- CHANGELOG.md | 9 +++++++++ Makefile | 1 + include/cmd.bash | 33 ++++++++++++++++++++++----------- include/fn.bash | 2 +- include/gun.bash | 17 +++++++++++------ tests/project.bash | 11 ++++++++--- tests/project/Gunfile | 5 +++++ 7 files changed, 57 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 258f583..cd057da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,19 @@ All notable changes to this project will be documented in this file. - Ensure `gun-find-root` changes working directory to $GUN_ROOT ### Added +- `-t` and `--trace` as last argument, enables `-x` closer to command +- Basic test coverage +- Build artifacts on CircleCI, including Go workspace +- Calling help explicitly will show second level commands ### Removed ### Changed +- `version` builtin command is now `:version` +- `help` builtin command is now `:help` +- `update` builtin command is now `:update` +- `env` builtin command is now `:env` +- `fn` builtin command is now `::` ## [0.0.7] - 2015-02-20 ### Added diff --git a/Makefile b/Makefile index 123ecbb..9dd91ed 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ install: build install build/$(shell uname -s)/gun /usr/local/bin test: + go-bindata include go install GUN=glidergun basht tests/*.bash diff --git a/include/cmd.bash b/include/cmd.bash index 26b3b5e..4375e8d 100644 --- a/include/cmd.bash +++ b/include/cmd.bash @@ -45,7 +45,7 @@ cmd-ns() { local ns="$1"; shift local cmd="$1"; shift || true local status=0 - if cmd-list "$ns" | grep ^$cmd\$ &> /dev/null; then + if [[ "${CMDS["$ns:$cmd"]+exists}" ]]; then ${CMDS["$ns:$cmd"]} "$@" else if [[ "$cmd" ]]; then @@ -54,19 +54,30 @@ cmd-ns() { elif [[ "$ns" ]]; then echo "$(fn-desc "$ns")" fi - echo - echo "Available commands:" - for cmd in $(cmd-list "$ns"); do - printf " %-24s %s\n" "$cmd" "$(fn-desc "${CMDS["$ns:$cmd"]}")" - #for subcmd in $(cmd-list "$cmd"); do - # printf " %-24s %s\n" "$subcmd" "$(fn-desc "${CMDS["$cmd:$subcmd"]}")" - #done - done - echo + cmd-available "$ns" exit $status fi } +cmd-available() { + declare ns="$1" full="$2" + echo + echo "Available commands:" + for cmd in $(cmd-list "$ns" | grep -v '^:'); do + printf " %-24s %s\n" "$cmd" "$(fn-desc "${CMDS["$ns:$cmd"]}")" + if [[ "$full" ]]; then + for subcmd in $(cmd-list "$cmd"); do + printf " %-24s %s\n" "$subcmd" "$(fn-desc "${CMDS["$cmd:$subcmd"]}")" + done + fi + done + echo + for specialcmd in $(cmd-list "$ns" | grep '^:'); do + printf " %-24s %s\n" "$specialcmd" "$(fn-desc "${CMDS["$ns:$specialcmd"]}")" + done + echo +} + cmd-help() { declare desc="Shows help information for a command" declare args="$@" @@ -76,6 +87,6 @@ cmd-help() { local fn="${CMDS["$ns:$cmd"]}" fn-info "$fn" 1 else - cmd-ns "" + cmd-available "" 1 fi } diff --git a/include/fn.bash b/include/fn.bash index 639424e..431bf8a 100644 --- a/include/fn.bash +++ b/include/fn.bash @@ -31,7 +31,7 @@ fn-source() { } fn-call() { - declare desc="Run arbitrary function" + declare desc="Run function in environment" declare fn="$1"; shift "$fn" "$@" } diff --git a/include/gun.bash b/include/gun.bash index 8fe2aa5..204e1dd 100644 --- a/include/gun.bash +++ b/include/gun.bash @@ -71,20 +71,25 @@ main() { if [[ -d "$GUN_MODULE_DIR" ]]; then module-load-dir "$GUN_MODULE_DIR" fi - cmd-export env-show env - cmd-export fn-call fn + cmd-export env-show :env + cmd-export fn-call :: else cmd-export gun-init init fi - cmd-export cmd-help help - cmd-export gun-version version - cmd-export gun-update update + cmd-export cmd-help :help + cmd-export gun-version :version + cmd-export gun-update :update if [[ "${!#}" == "-h" || "${!#}" == "--help" ]]; then local args=("$@") unset args[${#args[@]}-1] - cmd-ns "" help "${args[@]}" + cmd-ns "" :help "${args[@]}" + elif [[ "${!#}" == "-t" || "${!#}" == "--trace" ]]; then + local args=("$@") + unset args[${#args[@]}-1] + set -x + cmd-ns "" "${args[@]}" else cmd-ns "" "$@" fi diff --git a/tests/project.bash b/tests/project.bash index 7f6ee66..7ad8d1d 100644 --- a/tests/project.bash +++ b/tests/project.bash @@ -23,15 +23,20 @@ T_bar-namespace-cmd() { } T_foo-env-import() { - [[ "$($GUN env | grep AWS_ACCESS_KEY_ID)" ]] + [[ "$($GUN :env | grep AWS_ACCESS_KEY_ID)" ]] } T_prod-profile() { - result="$($GUN prod env)" + result="$($GUN prod :env)" [[ "$result" == "AWS_ACCESS_KEY_ID = prod-access-key" ]] } T_stage-profile() { - result="$($GUN stage env)" + result="$($GUN stage :env)" [[ "$result" == "AWS_ACCESS_KEY_ID = staging-access-key" ]] } + +T_aliased-cmd() { + result="$($GUN aliased)" + [[ "$result" == "aliased" ]] +} diff --git a/tests/project/Gunfile b/tests/project/Gunfile index 9ece66c..79ba149 100644 --- a/tests/project/Gunfile +++ b/tests/project/Gunfile @@ -1,9 +1,14 @@ init() { cmd-export hello + cmd-export aliased-cmd aliased } hello() { declare desc="Says hello" echo "Hello!" } + +aliased-cmd() { + echo "aliased" +} From ff178414c83ec29a29edee8b77e0e63d730d6748 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 09:59:03 -0500 Subject: [PATCH 11/19] - compiling without cgo for static binary - renamed include directory to src - bumped to 0.1.0 for next release --- CHANGELOG.md | 1 + Makefile | 29 ++++++++++++++++++----------- glidergun.go | 14 +++++++------- {include => src}/cmd.bash | 0 {include => src}/color.bash | 0 {include => src}/deps.bash | 0 {include => src}/env.bash | 0 {include => src}/fn.bash | 0 {include => src}/gun.bash | 0 {include => src}/module.bash | 0 10 files changed, 26 insertions(+), 18 deletions(-) rename {include => src}/cmd.bash (100%) rename {include => src}/color.bash (100%) rename {include => src}/deps.bash (100%) rename {include => src}/env.bash (100%) rename {include => src}/fn.bash (100%) rename {include => src}/gun.bash (100%) rename {include => src}/module.bash (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd057da..61585db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. ### Removed ### Changed +- Static compilation of binary - `version` builtin command is now `:version` - `help` builtin command is now `:help` - `update` builtin command is now `:update` diff --git a/Makefile b/Makefile index 9dd91ed..7e20f3a 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +2,28 @@ NAME=glidergun BINARYNAME=gun OWNER=gliderlabs ARCH=$(shell uname -m) -VERSION=0.0.7 +VERSION=0.1.0 + +build: src + mkdir -p build/Linux && GOOS=linux CGO_ENABLED=0 go build -a \ + -installsuffix cgo \ + -ldflags "-X main.Version $(VERSION)" \ + -o build/Linux/$(BINARYNAME) + mkdir -p build/Darwin && GOOS=darwin CGO_ENABLED=0 go build -a \ + -installsuffix cgo \ + -ldflags "-X main.Version $(VERSION)" \ + -o build/Darwin/$(BINARYNAME) + +test: src + go install + GUN=glidergun basht tests/*.bash -build: - go-bindata include - mkdir -p build/Linux && GOOS=linux go build -ldflags "-X main.Version $(VERSION)" -o build/Linux/$(BINARYNAME) - mkdir -p build/Darwin && GOOS=darwin go build -ldflags "-X main.Version $(VERSION)" -o build/Darwin/$(BINARYNAME) +src: + go-bindata src install: build install build/$(shell uname -s)/gun /usr/local/bin -test: - go-bindata include - go install - GUN=glidergun basht tests/*.bash - deps: go get -u github.com/jteeuwen/go-bindata/... go get -u github.com/progrium/gh-release/... @@ -40,4 +47,4 @@ circleci: clean: rm -rf build release -.PHONY: build release +.PHONY: build release src diff --git a/glidergun.go b/glidergun.go index a03ed5a..9361c26 100644 --- a/glidergun.go +++ b/glidergun.go @@ -106,12 +106,12 @@ func main() { "checksum": Checksum, "selfupdate": Selfupdate, }, []string{ - "include/fn.bash", - "include/cmd.bash", - "include/module.bash", - "include/env.bash", - "include/gun.bash", - "include/deps.bash", - "include/color.bash", + "src/fn.bash", + "src/cmd.bash", + "src/module.bash", + "src/env.bash", + "src/gun.bash", + "src/deps.bash", + "src/color.bash", }, Asset, true) } diff --git a/include/cmd.bash b/src/cmd.bash similarity index 100% rename from include/cmd.bash rename to src/cmd.bash diff --git a/include/color.bash b/src/color.bash similarity index 100% rename from include/color.bash rename to src/color.bash diff --git a/include/deps.bash b/src/deps.bash similarity index 100% rename from include/deps.bash rename to src/deps.bash diff --git a/include/env.bash b/src/env.bash similarity index 100% rename from include/env.bash rename to src/env.bash diff --git a/include/fn.bash b/src/fn.bash similarity index 100% rename from include/fn.bash rename to src/fn.bash diff --git a/include/gun.bash b/src/gun.bash similarity index 100% rename from include/gun.bash rename to src/gun.bash diff --git a/include/module.bash b/src/module.bash similarity index 100% rename from include/module.bash rename to src/module.bash From 5fb7ca139d902779e592064e127fc7978a76673b Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 10:20:28 -0500 Subject: [PATCH 12/19] - `GUN_PATH` used for module sourcing with `PATH`-like semantics - Deprecated `GUN_MODULE_PATH` in favor of `GUN_PATH` - Standard error used for warnings and errors --- CHANGELOG.md | 3 +++ src/deps.bash | 6 +++--- src/env.bash | 2 +- src/gun.bash | 13 ++++++++----- src/module.bash | 4 +++- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61585db..3e8b0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,13 @@ All notable changes to this project will be documented in this file. - Basic test coverage - Build artifacts on CircleCI, including Go workspace - Calling help explicitly will show second level commands +- `GUN_PATH` used for module sourcing with `PATH`-like semantics ### Removed ### Changed +- Deprecated `GUN_MODULE_PATH` in favor of `GUN_PATH` +- Standard error used for warnings and errors - Static compilation of binary - `version` builtin command is now `:version` - `help` builtin command is now `:help` diff --git a/src/deps.bash b/src/deps.bash index eef136e..ac02d98 100644 --- a/src/deps.bash +++ b/src/deps.bash @@ -13,7 +13,7 @@ deps-dir() { deps-require() { declare name="$1" version="${2:-latest}" deps-check "$name" "$version" && return - echo "* Dependency required, installing $name $version ..." | yellow + echo "* Dependency required, installing $name $version ..." | >&2 yellow deps-install "$name" "$version" } @@ -29,7 +29,7 @@ deps-install() { index=$(curl -s "$DEPS_REPO/$name") tag="$(uname -s)_$(uname -m | grep -s 64 > /dev/null && echo amd64 || echo 386)" if ! dep="$(echo "$index" | grep -i -e "^$version $tag " -e "^$version \* ")"; then - echo "!! Dependency not in index: $name $version" | red + echo "!! Dependency not in index: $name $version" | >&2 red exit 2 fi IFS=' ' read v t url checksum <<< "$dep" @@ -39,7 +39,7 @@ deps-install() { curl -Ls $url > "$tmpfile" if [[ "$checksum" ]]; then if ! [[ "$(cat "$tmpfile" | checksum md5)" = "$checksum" ]]; then - echo "!! Dependency checksum failed: $name $version $checksum" | red + echo "!! Dependency checksum failed: $name $version $checksum" | >&2 red exit 2 fi fi diff --git a/src/env.bash b/src/env.bash index ec03bc4..84fc0a9 100644 --- a/src/env.bash +++ b/src/env.bash @@ -5,7 +5,7 @@ env-import() { declare var="$1" default="$2" if [[ -z "${!var+x}" ]]; then if [[ -z "${2+x}" ]]; then - echo "!! Imported variable $var must be set in profile or environment." | red + echo "!! Imported variable $var must be set in profile or environment." | >&2 red exit 2 else export $var="$default" diff --git a/src/gun.bash b/src/gun.bash index 204e1dd..af1618b 100644 --- a/src/gun.bash +++ b/src/gun.bash @@ -2,7 +2,8 @@ readonly latest_version_url="https://dl.gliderlabs.com/glidergun/latest/version.txt" readonly latest_checksum_url="https://dl.gliderlabs.com/glidergun/latest/%s.tgz.sha256" -declare GUN_MODULE_DIR="${GUN_MODULE_DIR:-cmds}" +declare GUN_MODULE_DIR="${GUN_MODULE_DIR:-cmds}" # deprecated +declare GUN_PATH="${GUN_PATH:-"$GUN_MODULE_DIR"}" gun-init() { declare desc="Initialize a glidergun project directory" @@ -65,12 +66,14 @@ main() { shift elif [[ "$GUN_DEFAULT_PROFILE" && -f "Gunfile.$GUN_DEFAULT_PROFILE" ]]; then module-load "Gunfile.$GUN_DEFAULT_PROFILE" - echo "* Using default profile $GUN_DEFAULT_PROFILE" | yellow + echo "* Using default profile $GUN_DEFAULT_PROFILE" | >&2 yellow GUN_PROFILE="$GUN_DEFAULT_PROFILE" fi - if [[ -d "$GUN_MODULE_DIR" ]]; then - module-load-dir "$GUN_MODULE_DIR" - fi + local gun_module_paths + IFS=':' read -ra gun_module_paths <<< "$GUN_PATH" + for path in "${gun_module_paths[@]}"; do + module-load-dir "$path" + done cmd-export env-show :env cmd-export fn-call :: else diff --git a/src/module.bash b/src/module.bash index a883fdf..c86080e 100644 --- a/src/module.bash +++ b/src/module.bash @@ -9,7 +9,9 @@ module-load() { module-load-dir() { declare dir="$1" + shopt -s nullglob for path in $dir/*.bash; do module-load "$path" done -} \ No newline at end of file + shopt -u nullglob +} From 495d249c3b1bd7f2731f120e7f4b23b6881e705b Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 11:44:12 -0500 Subject: [PATCH 13/19] - added basic remote module support - added `:get` cli command for fetching modules - added `module-require` for fetching and loading remote modules if not installed - use of `.gun` dir now uses `GUN_DIR` --- glidergun.go | 2 +- src/deps.bash | 20 +++++++------- src/gun.bash | 19 +++++++------ src/module.bash | 54 +++++++++++++++++++++++++++++++++++++ tests/project/cmds/bar.bash | 1 + 5 files changed, 76 insertions(+), 20 deletions(-) diff --git a/glidergun.go b/glidergun.go index 9361c26..fb080c3 100644 --- a/glidergun.go +++ b/glidergun.go @@ -108,9 +108,9 @@ func main() { }, []string{ "src/fn.bash", "src/cmd.bash", - "src/module.bash", "src/env.bash", "src/gun.bash", + "src/module.bash", "src/deps.bash", "src/color.bash", }, Asset, true) diff --git a/src/deps.bash b/src/deps.bash index ac02d98..2312a58 100644 --- a/src/deps.bash +++ b/src/deps.bash @@ -3,11 +3,7 @@ declare DEPS_REPO="${DEPS_REPO:-https://raw.githubusercontent.com/gliderlabs/glidergun-rack/master/index}" deps-init() { - export PATH="$(deps-dir)/bin:$PATH" -} - -deps-dir() { - echo "${GUN_ROOT:?}/.gun" # hmm, glidergun specific... + export PATH="$GUN_DIR/bin:$PATH" } deps-require() { @@ -19,13 +15,15 @@ deps-require() { deps-check() { declare name="$1" version="${2:-latest}" - [[ -e "$(deps-dir)/bin/$name" ]] + [[ -e "$GUN_DIR/bin/$name" ]] } deps-install() { declare name="$1" version="${2:-latest}" - local tag index tmpdir tmpfile dep filename extension install - mkdir -p "$(deps-dir)/bin" + local tag index gundir bindir tmpdir tmpfile dep filename extension install + gundir="$(cd $GUN_DIR; pwd)" + bindir="$gundir/bin" + mkdir -p "$bindir" index=$(curl -s "$DEPS_REPO/$name") tag="$(uname -s)_$(uname -m | grep -s 64 > /dev/null && echo amd64 || echo 386)" if ! dep="$(echo "$index" | grep -i -e "^$version $tag " -e "^$version \* ")"; then @@ -33,7 +31,7 @@ deps-install() { exit 2 fi IFS=' ' read v t url checksum <<< "$dep" - tmpdir="$(deps-dir)/tmp" + tmpdir="$gundir/tmp" mkdir -p "$tmpdir" tmpfile="${tmpdir:?}/$name" curl -Ls $url > "$tmpfile" @@ -53,12 +51,12 @@ deps-install() { install="$(echo "$index" | grep "^# install: " || true)" if [[ "$install" ]]; then IFS=':' read _ script <<< "$install" - export PREFIX="$(deps-dir)" + export PREFIX="$gundir" eval "$script" > /dev/null unset PREFIX else chmod +x "$tmpfile" - mv "$tmpfile" "$(deps-dir)/bin" + mv "$tmpfile" "$bindir" fi cd - > /dev/null rm -rf "${tmpdir:?}" diff --git a/src/gun.bash b/src/gun.bash index af1618b..c7aa531 100644 --- a/src/gun.bash +++ b/src/gun.bash @@ -4,11 +4,11 @@ readonly latest_checksum_url="https://dl.gliderlabs.com/glidergun/latest/%s.tgz. declare GUN_MODULE_DIR="${GUN_MODULE_DIR:-cmds}" # deprecated declare GUN_PATH="${GUN_PATH:-"$GUN_MODULE_DIR"}" +declare GUN_DIR="${GUN_DIR:-.gun}" gun-init() { declare desc="Initialize a glidergun project directory" touch Gunfile - mkdir -p .gun if [[ -f .gitignore ]]; then printf "\n.gun\nGunfile.*\n" >> .gitignore fi @@ -41,15 +41,16 @@ gun-update() { gun-find-root() { local path="$PWD" while [[ "$path" != "" && ! -f "$path/Gunfile" ]]; do - path="${path%/*}" - done + path="${path%/*}" + done if [[ -f "$path/Gunfile" ]]; then - GUN_ROOT="$path" - fi + GUN_ROOT="$path" + fi - if [[ -d "$GUN_ROOT" ]]; then - cd $GUN_ROOT - fi + if [[ -d "$GUN_ROOT" ]]; then + cd $GUN_ROOT + mkdir -p $GUN_DIR + fi } main() { @@ -69,6 +70,7 @@ main() { echo "* Using default profile $GUN_DEFAULT_PROFILE" | >&2 yellow GUN_PROFILE="$GUN_DEFAULT_PROFILE" fi + module-load-remote local gun_module_paths IFS=':' read -ra gun_module_paths <<< "$GUN_PATH" for path in "${gun_module_paths[@]}"; do @@ -81,6 +83,7 @@ main() { fi cmd-export cmd-help :help + cmd-export module-get :get cmd-export gun-version :version cmd-export gun-update :update diff --git a/src/module.bash b/src/module.bash index c86080e..0abd0fd 100644 --- a/src/module.bash +++ b/src/module.bash @@ -1,4 +1,6 @@ +declare GUN_REMOTE_MODULES="${GUN_REMOTE_MODULES:-$GUN_DIR/modules}" + module-load() { declare filename="$1" source "$filename" @@ -15,3 +17,55 @@ module-load-dir() { done shopt -u nullglob } + +module-load-remote() { + shopt -s nullglob + for module in $GUN_REMOTE_MODULES/**/*.bash; do + module-load "$module" + done + shopt -u nullglob +} + +module-require() { + declare url="$1" as="$2" + module-check "$url" "$as" && return + echo "* Module required, installing $as from $url ..." | >&2 yellow + module-get "$url" "$as" + module-load-dir "$GUN_REMOTE_MODULES/$as" +} + +module-check() { + declare url="$1" as="$2" + : "${url:?}" + if [[ ! "$as" ]]; then + as="$(basename ${url%%.git})" + fi + [[ -d "$GUN_REMOTE_MODULES/$as" ]] +} + +module-get() { + declare desc="Install or update a remote module by URL" + declare url="$1" as="$2" + : "${url:?}" + if [[ ! "$(which git)" ]]; then + echo "!! git is required for fetching modules"| >&2 red + exit 2 + fi + if [[ ! "$url" =~ ^http ]]; then + url="http://$url" + fi + if [[ ! "$as" ]]; then + as="$(basename ${url%%.git})" + fi + local tmproot tmprepo scheme domain user repo path + IFS="/" read scheme _ domain user repo path <<< "$url" + tmproot="${GUN_DIR:?}/tmp" + tmprepo="$tmproot/$domain/$user/$repo" + mkdir -p "$tmprepo" + git clone --quiet --depth 1 "$scheme//$domain/$user/$repo" "$tmprepo" + rm -rf "${tmprepo:?}/.git" + rm -rf "${GUN_REMOTE_MODULES:?}/$as" + mkdir -p "$GUN_REMOTE_MODULES" + mv "$tmprepo/$path" "$GUN_REMOTE_MODULES/$as" + rm -rf "${tmproot:?}" +} diff --git a/tests/project/cmds/bar.bash b/tests/project/cmds/bar.bash index 98233a4..9ee0666 100644 --- a/tests/project/cmds/bar.bash +++ b/tests/project/cmds/bar.bash @@ -3,6 +3,7 @@ init() { cmd-export-ns bar "Bar namespace" cmd-export bar-hello #deps-require jq 1.4 + #module-require github.com/gliderlabs/herokuish/include herokuish } bar-hello() { From 613d4047dbb235d6f04c65bfa5f91ab628b6b98a Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 11:55:41 -0500 Subject: [PATCH 14/19] initial aws library --- lib/aws/aws.bash | 18 +++++ lib/aws/ec2.bash | 182 ++++++++++++++++++++++++++++++++++++++++++++++ lib/aws/util.bash | 21 ++++++ 3 files changed, 221 insertions(+) create mode 100644 lib/aws/aws.bash create mode 100644 lib/aws/ec2.bash create mode 100644 lib/aws/util.bash diff --git a/lib/aws/aws.bash b/lib/aws/aws.bash new file mode 100644 index 0000000..9f76eed --- /dev/null +++ b/lib/aws/aws.bash @@ -0,0 +1,18 @@ +# Shared AWS functions wrapping aws-cli + +init() { + env-import AWS_DEFAULT_REGION + env-import AWS_ACCESS_KEY_ID + env-import AWS_SECRET_ACCESS_KEY + + deps-require aws + deps-require jq 1.4 +} + +aws-json() { + aws --output json $@ +} + +aws-text() { + aws --output text $@ +} diff --git a/lib/aws/ec2.bash b/lib/aws/ec2.bash new file mode 100644 index 0000000..51c1adb --- /dev/null +++ b/lib/aws/ec2.bash @@ -0,0 +1,182 @@ +# EC2 in VPC helpers and commands + +SSH_HOST="" +SSH_OPTS="${SSH_OPTS:--o PasswordAuthentication=no -o StrictHostKeyChecking=no}" + +init() { + env-import EC2_VPC "" + env-import SSH_USER "core" + env-import SSH_BASTION_USER "$SSH_USER" + + cmd-export-ns ec2 "EC2 instance management" + cmd-export ec2-list + cmd-export ec2-info + cmd-export ec2-ssh + cmd-export ec2-pssh + cmd-export ec2-rsync + cmd-export ec2-prsync + cmd-export ec2-ip + cmd-export ec2-tag + cmd-export ec2-untag + cmd-export ec2-vpcs + cmd-export ec2-terminate +} + +ec2-info() { + declare desc="Instance info by name or ID" + declare instance="$1" + if [[ "${instance:0:2}" != "i-" ]]; then + instance="$(ec2-id instance $instance)" + fi + aws-json ec2 describe-instances --filters "Name=instance-id,Values=$instance" \ + | jq '.Reservations[].Instances[] as $instance | + $instance.Tags[] | select(.Key == "Name") | .Value as $name | { + name: $name, + labels: [$instance.Tags[] | select(.Value == null) | .Key], + state: $instance.State.Name, + private_ip: $instance.PrivateIpAddress, + public_ip: $instance.PublicIpAddress, + instance_id: $instance.InstanceId, + subnet_id: $instance.SubnetId }' +} + +ec2-ip() { + declare desc="Public or private IP by ID or tag" + declare type="$1" key="$2" value="$3" + local filter vpc_id + if [[ "${key:0:2}" = "i-" ]]; then + filter="Name=instance-id,Values=$key" + else + filter="Name=tag:$key,Values=$value" + fi + vpc_id="$(ec2-id vpc ${EC2_VPC:?})" + aws-json ec2 describe-instances --filters "Name=vpc-id,Values=$vpc_id" "$filter" \ + | jq -r ".Reservations[0].Instances[0].${type^}IpAddress // empty" +} + +ec2-setup-ssh-bastion() { + declare instance="$1" + local bastion_ip + bastion_ip="$(ec2-ip public bastion)" + if [[ "$bastion_ip" ]]; then + SSH_OPTS="$SSH_OPTS -o \"ProxyCommand=ssh -W %h:%p $BASTION_USER@$bastion_ip\"" + SSH_HOST="$(ec2-ip private $instance)" + fi +} + +ec2-ssh() { + declare desc="SSH to instance by name or ID" + declare instance="${1:?}"; shift + if [[ "${instance:0:2}" != "i-" ]]; then + instance="$(ec2-id instance $instance)" + fi + ec2-setup-ssh-bastion "$instance" + SSH_HOST="${SSH_HOST:-$(ec2-ip public $instance)}" + local cmd + if [[ "$1" ]]; then + cmd="set -eo pipefail; $@" + fi + eval $(ssh-cmd "$SSH_USER@${SSH_HOST:?}") -- "$(printf '%q' "$cmd")" +} + +ec2-pssh() { + declare desc="Parallel SSH to instances by label" + declare label="$1"; shift + ec2-list "${label:?}" \ + | jq -r .[].name \ + | parallel "ec2-ssh {} $(printf '%q ' "$@") | sed 's/^/{}: /'" +} + +ec2-rsync() { + declare desc="Rsync files to instance by name or ID" + declare instance="${1:?}" path="$2" remote="$3" + if [[ "${instance:0:2}" != "i-" ]]; then + instance="$(ec2-id instance $instance)" + fi + ec2-setup-ssh-bastion "$instance" + SSH_HOST="${SSH_HOST:-$(ec2-ip public $instance)}" + rsync -rzue "$(ssh-cmd)" \ + --rsync-path "mkdir -p $(dirname $remote) && rsync" \ + "${path:?}" "$SSH_USER@${SSH_HOST:?}:${remote:?}" +} + +ec2-prsync() { + declare desc="Parallel rsync files to instances by label" + declare label="$1" path="$2" remote="$3" + ec2-list "${label:?}" \ + | jq -r .[].name \ + | parallel "ec2-rsync {} $path $remote | sed 's/^/{}: /'" +} + +ec2-list() { + declare desc="List instances for a VPC" + declare label="$1" + local vpc_id label_filter + vpc_id="$(ec2-id vpc ${EC2_VPC:?})" + if [[ "$label" ]]; then + label_filter="Name=tag:$label,Values=" + fi + aws-json ec2 describe-instances --filters "Name=vpc-id,Values=${vpc_id:?}" "$label_filter" \ + | jq '[.Reservations[].Instances[] as $instance | + $instance.Tags[] | select(.Key == "Name") | .Value as $name | { + name: $name, + labels: [$instance.Tags[] | select(.Value == null) | .Key], + private_ip: $instance.PrivateIpAddress, + instance_id: $instance.InstanceId, + subnet_id: $instance.SubnetId }]' +} + +ec2-factory() { + declare id_selector="$1"; shift + aws-json ec2 $@ | jq -e -r "$id_selector" +} + +ec2-tag() { + declare desc="Tag an EC2 resource" + declare resource="$1" key="$2" value="$3" + aws-json ec2 create-tags \ + --resources "${resource:?}" \ + --tags "Key=${key:?},Value=${value}" > /dev/null +} + +ec2-untag() { + declare desc="Untag an EC2 resource" + declare resource="$1" key="$2" + aws-json ec2 delete-tags \ + --resources "${resource:?}" \ + --tags "Key=${key:?}" > /dev/null +} + +ec2-id() { + declare type="$1" name="$2" + local json_type filter_name extra_filter + filter_name="tag:Name" + json_type="$(titleize ${type//-/ })" + json_type="${json_type// /}" + json_collection="${json_type}s" + if [[ "$type" = "instance" ]]; then + json_collection="Reservations[0].$json_collection" + extra_filter="Name=instance-state-name,Values=running" + fi + if [[ "$type" = "security-group" ]]; then + filter_name="group-name" + json_type="Group" + fi + aws-json ec2 "describe-${type}s" \ + --filters "$extra_filter" "Name=$filter_name,Values=$name" \ + | jq -e -r ".${json_collection}[0].${json_type}Id" +} + +ec2-terminate() { + declare desc="Terminate instance by ID" + declare id="$1" + aws-json ec2 terminate-instances --instance-ids "${id:?}" +} + +ec2-vpcs() { + declare desc="List VPCs" + aws-json ec2 describe-vpcs | jq '.Vpcs[] as $vpc | + $vpc.Tags[] | select(.Key == "Name") | .Value as $name | { + name: $name, + id: $vpc.VpcId }' +} diff --git a/lib/aws/util.bash b/lib/aws/util.bash new file mode 100644 index 0000000..93daf5f --- /dev/null +++ b/lib/aws/util.bash @@ -0,0 +1,21 @@ +# Temporary place for utility functions + +parallel() { + declare cmd="$@" + declare -a pids + for line in $(cat); do + eval "${cmd//\{\}/$line} &" + pids+=($!) + done + local failed=$((0)) + for pid in ${pids[@]}; do + if ! wait $pid; then + failed=$((failed + 1)) + fi + done + return $((failed)) +} + +ssh-cmd() { + echo "ssh -A $SSH_OPTS $@" +} From be67e7b9152007063b3cb3e7d02f7e46ca584c55 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 11:59:54 -0500 Subject: [PATCH 15/19] fixing module-require --- src/module.bash | 3 +++ tests/project/cmds/bar.bash | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/module.bash b/src/module.bash index 0abd0fd..ab638ed 100644 --- a/src/module.bash +++ b/src/module.bash @@ -29,6 +29,9 @@ module-load-remote() { module-require() { declare url="$1" as="$2" module-check "$url" "$as" && return + if [[ ! "$as" ]]; then + as="$(basename ${url%%.git})" + fi echo "* Module required, installing $as from $url ..." | >&2 yellow module-get "$url" "$as" module-load-dir "$GUN_REMOTE_MODULES/$as" diff --git a/tests/project/cmds/bar.bash b/tests/project/cmds/bar.bash index 9ee0666..eae8150 100644 --- a/tests/project/cmds/bar.bash +++ b/tests/project/cmds/bar.bash @@ -3,7 +3,7 @@ init() { cmd-export-ns bar "Bar namespace" cmd-export bar-hello #deps-require jq 1.4 - #module-require github.com/gliderlabs/herokuish/include herokuish + #module-require github.com/gliderlabs/glidergun/lib/aws } bar-hello() { From d94857f7d003cb461ee115f2dcedd38e61c60593 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 12:06:17 -0500 Subject: [PATCH 16/19] consul and releases wip modules --- lib/consul/consul.bash | 118 +++++++++++++++++++++++++++++++++++++ lib/releases/config.bash | 38 ++++++++++++ lib/releases/releases.bash | 59 +++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 lib/consul/consul.bash create mode 100644 lib/releases/config.bash create mode 100644 lib/releases/releases.bash diff --git a/lib/consul/consul.bash b/lib/consul/consul.bash new file mode 100644 index 0000000..c212dbe --- /dev/null +++ b/lib/consul/consul.bash @@ -0,0 +1,118 @@ +# Commands for working with Consul KV + +init() { + env-import CONSUL_URL + env-import CONSUL_AUTH "" + + cmd-export-ns consul "Consul key-value operations" + cmd-export consul-import + cmd-export consul-export + cmd-export consul-get + cmd-export consul-encoded + cmd-export consul-set + cmd-export consul-ls + cmd-export consul-del + cmd-export consul-info + cmd-export consul-open + cmd-export consul-service +} + +consul-cmd() { + declare path="$1"; shift + local cmd="curl" + if [[ "$CONSUL_AUTH" ]]; then + cmd="curl -u $CONSUL_AUTH" + fi + $cmd --fail -Ss "${CONSUL_URL:?}$path" "$@" +} + +consul-info() { + declare desc="Show all metadata for key" + declare key="${1/#\//}" + consul-cmd "/v1/kv/$key" \ + | jq -r .[] +} + +consul-get() { + declare desc="Get the value of key" + declare key="${1/#\//}" + consul-encoded "$key" \ + | base64 -d \ + | echo "$(cat)" +} + +consul-encoded() { + declare desc="Get the base64 encoded value of key" + declare key="${1/#\//}" + consul-cmd "/v1/kv/$key" \ + | jq -r .[].Value +} + +consul-set() { + declare desc="Set the value of key" + declare key="${1/#\//}" value="$2" + consul-cmd "/v1/kv/$key" -X PUT -d "$value" > /dev/null +} + +consul-del() { + declare desc="Delete key" + declare key="${1/#\//}" + consul-cmd "/v1/kv/$key" -X DELETE > /dev/null +} + +consul-ls() { + declare desc="List keys under key" + declare key="${1/#\//}" + if [[ ! "$key" ]]; then + consul-cmd "/v1/kv/?keys&separator=/" \ + | jq -r .[] \ + | sed 's|/$||' + else + consul-cmd "/v1/kv/$key/?keys&separator=/" \ + | jq -r .[] \ + | sed "s|$key/||" \ + | grep -v ^$ \ + | sed 's|/$||' + fi +} + +consul-export() { + declare desc="Export values to Bash variables" + declare key="${1/#\//}" + consul-cmd "/v1/kv/$key/?recurse" \ + | jq -r '.[] | [.Key, .Value] | join(" ")' \ + | sed "s|$key/||" \ + | grep -v '^\s*$' \ + | \ + while read key value; do + key="${key^^}" + key="${key//\//_}" + printf "$key=%s\n" "$(echo "$value" | base64 -d)" + done +} + +consul-import() { + declare desc="Import Bash variables under key" + declare key="${1/#\//}" + input="$(cat)" + eval "$input" || exit 2 + IFS=$'\n' + for line in $input; do + IFS='=' read k v <<< "$line" + IFS=' ' consul-cmd "/v1/kv/${key:?}/$k" -X PUT -d "${!k}" > /dev/null + done + unset IFS +} + +consul-open() { + declare desc="Opens Consul UI in browser (OS X only)" + declare page="$1" + local scheme url + IFS=':' read scheme url <<< "$CONSUL_URL" + open "$scheme://${CONSUL_AUTH}@${url##//}#$page" +} + +consul-service() { + declare service="$1" + consul-cmd "/v1/health/service/$service?passing" +} diff --git a/lib/releases/config.bash b/lib/releases/config.bash new file mode 100644 index 0000000..a21d594 --- /dev/null +++ b/lib/releases/config.bash @@ -0,0 +1,38 @@ +# Release config commands +# WARNING: work in progress + +init() { + cmd-export-ns config "Manage service config" + cmd-export config-get + cmd-export config-set + cmd-export config-unset + cmd-export config-edit +} + +config-edit() { + declare desc="Edit service config in Consul UI (OS X)" + declare service="$1" + consul-open "/dc1/kv/${EC2_VPC:?}/config/${service:?}/" +} + +config-get() { + declare desc="Get service config" + declare service="$1" key="$2" + if [[ "$key" ]]; then + consul-get "${EC2_VPC:?}/config/${service:?}/${key:?}" + else + consul-export "${EC2_VPC:?}/config/${service:?}" + fi +} + +config-set() { + declare desc="Set service config" + declare service="$1" key="$2" value="$3" + consul-set "${EC2_VPC:?}/config/${service:?}/${key:?}" "$value" +} + +config-unset() { + declare desc="Unset service config" + declare service="$1" key="$2" + consul-del "${EC2_VPC:?}/config/${service:?}/${key:?}" +} diff --git a/lib/releases/releases.bash b/lib/releases/releases.bash new file mode 100644 index 0000000..372f403 --- /dev/null +++ b/lib/releases/releases.bash @@ -0,0 +1,59 @@ +# Release management commands +# WARNING: work in progress + +init() { + cmd-export-ns release "Release management" + cmd-export release-create + cmd-export release-show + cmd-export release-latest + cmd-export release-current + cmd-export release-get +} + +release-create() { + declare desc="Create a new release" + declare service="$1" + if ! release-latest "$service" > /dev/null 2>&1; then + #consul-set "${EC2_VPC:?}/releases/${service:?}/current" "v0" + consul-set "${EC2_VPC:?}/releases/${service:?}/latest" "v0" + fi + local snapshot latest + snapshot="$(consul-export "${EC2_VPC:?}/config/${service:?}" || true)" + latest="$(release-latest $service)" + latest="v$((${latest/v/}+1))" + consul-set "${EC2_VPC:?}/releases/${service:?}/$latest" "$snapshot" + consul-set "${EC2_VPC:?}/releases/${service:?}/latest" "$latest" + echo "$latest" +} + +release-get() { + declare desc="Get contents of existing release" + declare service="$1" version="$2" + consul-get "${EC2_VPC:?}/releases/${service:?}/v${version/v/}" +} + +release-current() { + declare desc="Get or set current release version" + declare service="$1" version="$2" + if [[ "$version" ]]; then + release-get "$service" "$version" > /dev/null + consul-set "${EC2_VPC:?}/releases/${service:?}/current" "v${version/v/}" + fi + consul-get "${EC2_VPC:?}/releases/${service:?}/current" +} + +release-latest() { + declare desc="Get latest release version" + declare service="$1" + consul-get "${EC2_VPC:?}/releases/${service:?}/latest" +} + +release-show() { + declare desc="Show releases information" + declare service="$1" + echo "Latest: $(release-latest $service)" + echo "Current: $(release-current $service)" + consul-ls "${EC2_VPC:?}/releases/${service:?}" \ + | grep -v latest \ + | grep -v current +} From 69c692a87e7a77e5cb2964ccc777c36b386a3007 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Mon, 1 Jun 2015 12:08:46 -0500 Subject: [PATCH 17/19] adding lib readme and updating main readme --- README.md | 2 +- lib/README.md | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 lib/README.md diff --git a/README.md b/README.md index 02aa52a..de30814 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,4 @@ ## Upgrading - $ gun update + $ gun :update diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..41bbcf7 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,12 @@ +# glidergun module library + +## Require example +``` +init() { + module-require github.com/gliderlabs/glidergun/lib/aws +} +``` + +## Updating a module + + $ gun :get github.com/gliderlabs/glidergun/lib/aws From 076e6fcc93713f81bbce72d2536b550c4cbc1275 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Thu, 2 Jul 2015 15:45:43 -0500 Subject: [PATCH 18/19] cleaned up whitespace and refactored --- src/gun.bash | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/gun.bash b/src/gun.bash index c7aa531..763e00f 100644 --- a/src/gun.bash +++ b/src/gun.bash @@ -41,16 +41,24 @@ gun-update() { gun-find-root() { local path="$PWD" while [[ "$path" != "" && ! -f "$path/Gunfile" ]]; do - path="${path%/*}" - done + path="${path%/*}" + done if [[ -f "$path/Gunfile" ]]; then - GUN_ROOT="$path" - fi + GUN_ROOT="$path" + fi - if [[ -d "$GUN_ROOT" ]]; then - cd $GUN_ROOT + if [[ -d "$GUN_ROOT" ]]; then + cd $GUN_ROOT mkdir -p $GUN_DIR - fi + fi +} + +gun-reload-path() { + local gun_module_paths + IFS=':' read -ra gun_module_paths <<< "$GUN_PATH" + for path in "${gun_module_paths[@]}"; do + module-load-dir "$path" + done } main() { @@ -71,11 +79,7 @@ main() { GUN_PROFILE="$GUN_DEFAULT_PROFILE" fi module-load-remote - local gun_module_paths - IFS=':' read -ra gun_module_paths <<< "$GUN_PATH" - for path in "${gun_module_paths[@]}"; do - module-load-dir "$path" - done + gun-reload-path cmd-export env-show :env cmd-export fn-call :: else From 825920183229db0ebc7f7c7420dcbc4943e2dd45 Mon Sep 17 00:00:00 2001 From: Jeff Lindsay Date: Thu, 2 Jul 2015 16:08:21 -0500 Subject: [PATCH 19/19] made sure changelog is up to date --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e8b0a1..ff50a25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,18 @@ # Change Log All notable changes to this project will be documented in this file. + ## [Unreleased][unreleased] ### Fixed + +### Added + +### Removed + +### Changed + +## [0.1.0] - 2015-07-02 +### Fixed - Resolved issue where `deps-install` download URL has a redirect - Ensure `gun-find-root` changes working directory to $GUN_ROOT @@ -12,6 +22,7 @@ All notable changes to this project will be documented in this file. - Build artifacts on CircleCI, including Go workspace - Calling help explicitly will show second level commands - `GUN_PATH` used for module sourcing with `PATH`-like semantics +- Added some initial remote module libraries ### Removed @@ -85,7 +96,8 @@ All notable changes to this project will be documented in this file. ### Fixed - Fixed profiles not loading -[unreleased]: https://github.com/gliderlabs/glidergun/compare/v0.0.7...HEAD +[unreleased]: https://github.com/gliderlabs/glidergun/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/gliderlabs/glidergun/compare/v0.0.7...v0.1.0 [0.0.7]: https://github.com/gliderlabs/glidergun/compare/v0.0.6...v0.0.7 [0.0.6]: https://github.com/gliderlabs/glidergun/compare/v0.0.5...v0.0.6 [0.0.5]: https://github.com/gliderlabs/glidergun/compare/v0.0.4...v0.0.5