Skip to content

Commit

Permalink
Merge pull request #49 from ahoy-cli/dev-47-init-script
Browse files Browse the repository at this point in the history
Fixes Issue #47
  • Loading branch information
Frank Carey authored Jan 22, 2017
2 parents 83fca54 + c0d8481 commit 9c8faca
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
docs/_build
# Ignore the ahoy binary when it's built
ahoy
.idea
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Test Status: master [![CircleCI](https://circleci.com/gh/ahoy-cli/ahoy/tree/master.svg?style=svg)](https://circleci.com/gh/ahoy-cli/ahoy/tree/master)

Ahoy is command line tool that gives each of your projects their own CLI app with with zero code and dependencies.
Ahoy is command line tool that gives each of your projects their own CLI app with with zero code and dependencies.

Simply write your commands in a yaml file and ahoy gives you lots of features like:
* a command listing
Expand All @@ -29,7 +29,6 @@ With ahoy, you can turn this into
- Consitent - Commands always run relative to the .ahoy.yml file, but can be called from any subfolder.
- Visual - See a list of all of your commands in one place, along with helpful descriptions.
- Flexible - Commands are specific to a single folder tree, so each repo/workspace can have its own commands
- Command Templates - Args can be dropped into your commands using `{{args}}`
- Fully interactive - your shells (like mysql) and prompts still work.
- Self-Documenting - Commands and help declared in .ahoy.yml show up as ahoy command help and bash completion of commands (see below)

Expand Down Expand Up @@ -122,36 +121,52 @@ GLOBAL OPTIONS:

## Version 2

All new features are being added to the v2 (master) branch of ahoy which is still in alpha and will have breaking changes with v1 ahoy files, so to use ahoy v2, you'll need to do the following:
All new features are being added to the v2 (master) branch of ahoy which is still in alpha and will have breaking changes with v1 ahoy files, so to use ahoy v2, you'll need to do the following:
- Upgrade to the ahoy v2 binary which currently needs to be compiled from source. If you are using homebrew, you can use that to upgrade to v2 using the following:
```
brew uninstall ahoy # Required or you'll get errors
brew uninstall ahoy # Required or you'll get errors
brew upgrade # Updates the tap
brew install ahoy --HEAD # Installs ahoy by compiling the latest from the master branch
ahoy # You should see full version that you're using.
```
- Change your `ahoyapi: v1` lines to `ahoyapi: v2`
- Change your `{{args}}` items to the default bash symbol `"$@"`

### New Features in v2
- Implements a new feature to import mulitple config files using the "imports" field.
- Uses the "last in wins" rule to deal with duplicate commands amongst the config files.

```
- Better handling of quotes by no longer using `{{args}}`. Use regular bash syntax like `"$@"` for all arguments, or `$1` for the first argument.
- You can now use a different entrypoint (the thing that runs your commands) instead of bash. Ex. using php, nodejs, python, etc.
- Plugins are now possible by overriding the entrypoint.

###Example of new yaml setup in v2

```Yaml
# All files must have v2 set or you'll get an error
ahoyapi: v2

# You can now override the entrypoint. This is the default if you don't override it.
# {{cmd}} is replaced with your command and {{name}} is the name of the command that was run (available as $0)
entrypoint:
- bash
- "-c"
- '{{cmd}}'
- '{{name}}'
commands:
list:
usage: List the commands from the imported config files.
# These commands will be aggregated together with later files overriding earlier ones if they exist.
imports:
- ./confirmation.ahoy.yml
- ./docker.ahoy.yml
- ./examples.ahoy.yml
```
### Planned v2 features
- Provide "drivers" or "plugins" for bash, docker-compose, kubernetes (these systems still work now, this would just make it easier)
- Do specific arg replacement like {{arg1}} and enable specifying specific arguments and flags in the ahoy file itself to cut down on parsing arguments in scripts.
- Enable specifying specific arguments and flags in the ahoy file itself to cut down on parsing arguments in scripts.
- Support for more built-in commands or a "verify" yaml option that would create a yes / no prompt for potentially destructive commands. (Are you sure you want to delete all your containers?)
- Pipe tab completion to another command (allows you to get tab completion)

- Support for configuration
## Previewing the Read the Docs documentation locally.
Expand Down
68 changes: 44 additions & 24 deletions ahoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import (
// Config handles the overall configuration in an ahoy.yml file
// with one Config per file.
type Config struct {
Usage string
AhoyAPI string
Commands map[string]Command
Usage string
AhoyAPI string
Commands map[string]Command
Entrypoint []string
}

// Command is an ahoy command detailed in ahoy.yml files. Multiple
Expand Down Expand Up @@ -116,6 +117,10 @@ func getConfig(file string) (Config, error) {
return config, err
}

if config.Entrypoint == nil {
config.Entrypoint = []string{"bash", "-c", "{{cmd}}", "{{name}}"}
}

return config, err
}

Expand Down Expand Up @@ -166,7 +171,6 @@ func getCommands(config Config) []cli.Command {

for _, name := range keys {
cmd := config.Commands[name]
cmdName := name

newCmd := cli.Command{
Name: name,
Expand All @@ -180,8 +184,42 @@ func getCommands(config Config) []cli.Command {

if cmd.Cmd != "" {
newCmd.Action = func(c *cli.Context) {
args = c.Args()
runCommand(cmdName, cmd.Cmd)
// For some unclear reason, if we don't add an item at the end here,
// the first argument is skipped... actually it's not!
// 'bash -c' says that arguments will be passed starting with $0, which also means that
// $@ skips the first item. See http://stackoverflow.com/questions/41043163/xargs-sh-c-skipping-the-first-argument
var cmdItems []string
var cmdArgs []string
var cmdEntrypoint []string

// c.Args() is not a slice apparently.
for _, arg := range c.Args() {
cmdArgs = append(cmdArgs, arg)
}

// Replace the entry point placeholders.
cmdEntrypoint = config.Entrypoint[:]
for i := range cmdEntrypoint {
if cmdEntrypoint[i] == "{{cmd}}" {
cmdEntrypoint[i] = cmd.Cmd
} else if cmdEntrypoint[i] == "{{name}}" {
cmdEntrypoint[i] = c.Command.Name
}
}
cmdItems = append(cmdEntrypoint, cmdArgs...)

if verbose {
log.Println("===> AHOY", name, "from", sourcefile, ":", cmdItems)
}
command := exec.Command(cmdItems[0], cmdItems[1:]...)
command.Dir = AhoyConf.srcDir
command.Stdout = os.Stdout
command.Stdin = os.Stdin
command.Stderr = os.Stderr
if err := command.Run(); err != nil {
fmt.Fprintln(os.Stderr)
os.Exit(1)
}
}
}

Expand All @@ -197,24 +235,6 @@ func getCommands(config Config) []cli.Command {
return exportCmds
}

func runCommand(name string, c string) {

cReplace := strings.Replace(c, "{{args}}", strings.Join(args, " "), -1)

if verbose {
log.Println("===> AHOY", name, "from", sourcefile, ":", cReplace)
}
cmd := exec.Command("bash", "-c", cReplace)
cmd.Dir = AhoyConf.srcDir
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Fprintln(os.Stderr)
os.Exit(1)
}
}

func addDefaultCommands(commands []cli.Command) []cli.Command {

defaultInitCmd := cli.Command{
Expand Down
2 changes: 1 addition & 1 deletion examples/confirmation.ahoy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ahoyapi: v2
commands:
confirm:
cmd: |
read -r -p "{{args}} [y/N] " response
read -r -p "$@ [y/N] " response
if [ $response = y ]
then
true
Expand Down
2 changes: 1 addition & 1 deletion examples/docker.ahoy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ commands:
cmd: "docker-compose stop && docker-compose rm && ahoy up"
usage: Start the docker compose-containers.
exec:
cmd: docker exec -it $(docker-compose ps -q cli) bash -c '{{args}}'
cmd: docker exec -it $(docker-compose ps -q cli) bash -c "$@"
usage: run a command in the docker-compose cli service container.
mysql:
cmd: "docker exec -it $(docker-compose ps -q cli) bash -c 'mysql -u$DB_ENV_MYSQL_USER -p$DB_ENV_MYSQL_PASSWORD -h$DB_PORT_3306_TCP_ADDR $DB_ENV_MYSQL_DATABASE'"
Expand Down
14 changes: 7 additions & 7 deletions examples/examples.ahoy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@ commands:
usage: Stop the vagrant box if one exists.

ps:
cmd: "docker-compose ps {{args}}"
cmd: docker-compose ps "$@"
usage: List the running docker-compose containers.

start:
cmd: "docker-compose start {{args}}"
cmd: docker-compose start "$@"
usage: Start the docker compose-containers.

stop:
cmd: "docker-compose stop {{args}}"
cmd: docker-compose stop "$@"
usage: Stop the docker-compose containers.

restart:
cmd: "docker-compose restart {{args}}"
cmd: docker-compose restart "$@"
usage: Restart the docker-compose containers.

drush:
cmd: "docker-compose run cli drush --root=docroot {{args}}"
cmd: docker-compose run cli drush --root=docroot "$@"
usage: Run drush commands in the cli service container.

bash:
cmd: "docker-compose run {{args}} bash"
cmd: docker-compose run "$1" bash
usage: Start a shell in the container (like ssh without actual ssh).

sqlc:
cmd: "docker-compose run cli drush --root=docroot sqlc"
usage: Connect to the default mysql database. Supports piping of data into the command.

behat:
cmd: 'docker-compose run cli bash -c "cd docroot/test && composer install --prefer-source --no-interaction && bin/behat -p docker {{args}}"'
cmd: docker-compose run cli bash -c "cd docroot/test && composer install --prefer-source --no-interaction && bin/behat -p docker $@"
usage: Run the behat tests within the container.

behat-init:
Expand Down
1 change: 1 addition & 0 deletions testdata/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export TEST1=test1
2 changes: 1 addition & 1 deletion testdata/docker.ahoy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ commands:
cmd: "docker-compose stop && docker-compose rm && ahoy up"
usage: Start the docker compose-containers.
exec:
cmd: docker exec -it $(docker-compose ps -q cli) bash -c '{{args}}'
cmd: docker exec -it $(docker-compose ps -q cli) bash -c "$@"
usage: run a command in the docker-compose cli service container.
mysql:
cmd: "docker exec -it $(docker-compose ps -q cli) bash -c 'mysql -u$DB_ENV_MYSQL_USER -p$DB_ENV_MYSQL_PASSWORD -h$DB_PORT_3306_TCP_ADDR $DB_ENV_MYSQL_DATABASE'"
Expand Down
12 changes: 12 additions & 0 deletions testdata/entrypoint-bash.ahoy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ahoyapi: v2
entrypoint:
- bash
- "-x"
- "-c"
- '{{cmd}}'
- '{{name}}'

commands:
echo:
cmd: |
echo "$@"
7 changes: 7 additions & 0 deletions testdata/entrypoint-php.ahoy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ahoyapi: v2
entrypoint: [php, "-r", '{{cmd}}']
commands:
echo:
cmd: |
array_shift($argv);
print(implode(" ", $argv) . "\n");
15 changes: 15 additions & 0 deletions testdata/entrypoint-prefix.ahoy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ahoyapi: v2
entrypoint:
- "bash"
- "-c"
- |
source ./config.sh
bash -c "$0" "$@"
- '{{cmd}}'
- '{{name}}'

commands:
echo-test:
cmd: |
ls "$@"
echo $TEST1
2 changes: 1 addition & 1 deletion testdata/simple.ahoy.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ahoyapi: v2
commands:
echo:
cmd: echo {{args}}
cmd: echo "$@"
19 changes: 19 additions & 0 deletions tests/entrypoint.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bats

@test "override bash entrypoint to add additional flags" {
run ./ahoy -f testdata/entrypoint-bash.ahoy.yml echo something
[ $status -eq 0 ]
echo "$output"
[ "${#lines[@]}" -eq 2 ]
[ "${lines[0]}" == "+ echo something" ]
[ "${lines[1]}" == "something" ]

}

@test "override bash entrypoint to use php instead" {
run ./ahoy -f testdata/entrypoint-php.ahoy.yml echo something
[ $status -eq 0 ]
echo "$output"
[ "${#lines[@]}" -eq 1 ]
[ "${lines[0]}" == "something" ]
}

0 comments on commit 9c8faca

Please sign in to comment.