progrium/dokku — pull request #312 by plietar (2013-11-16 17:20:06+00:00)
Title: Fix pluginhook problems by spliting commands into seperate hooks.

This solves the issues with pluginhook. Depends on https://github.com/progrium/pluginhook/pull/7
Fixes #236 and #272.
I'll try to explain how.

Because a single hook was used for all commands, the hooks needed to piped, so that multiple plugins could implement commands. A cat is used at the bottom of each `commands` hook.
If nothing is piped, the first `cat` caused the command to hang, waiting for `stdin`.
To fix this, `pluginhook` does not connect stdin if running from a pty.
However :
* this does not work through ssh, because ssh doesn't allocate a pty if a command is passed
* This prevents commands from running interactive commands.

As a workaround to the first problem, one could pipe an empty string into the command, to make the `cat` end, or force pty allocation in ssh using `-t`.

This PR solves both problems by spliting the `commands` hook into a hook per command.
For example, the `config:set` command is implemented in the `/var/lib/dokku/plugins/config/commands/config:set` hook.

Because of this, we do not need to chain the hooks using a `cat` at the bottom, which means commands de not hang at the end, even over ssh.
However, this does not fix the interactive commands problem, as pluginhook still closes the stdin of the first hook. This is still required for other non-commands hook.

The problem is solved using PR https://github.com/progrium/pluginhook/pull/7 which adds a `-s` option. This option causes pluginhook to only run the first hook it finds, and always connect stdin.

In the end :
* Commands over ssh do not hang. `ssh dokku@dokku.me logs app` for example
* Interactive commands work. `dokku run app vim` for example
* The combination of both, ie interactive commands over ssh, work, but require the `-t` flag. `ssh dokku@dokku.me run app vim`. There's no way to make it work w/o it, as your command will require a pty.

The only command which needs to be implemented by multiple plugins is `help`. As a solution, plugin implement it as a regular hook, ie in `/var/lib/dokku/plugins/config/hooks`, and a `help` command in the core `dokku` script overrides it.

As a bonus, because only one hook is ran, plugins can override command, if the plugin name is before is alphabetical order. This would allow override `deploy` for example, provided that the default command is moved to a `zz_dokku-standard` plugin. Fixes #296 and refs #298.
If this is done, we need to think about how to override help messages, which may differ.

I also added a `dokku shell` command. Initially it was just a test for interactive commands, but I find it quite nice, so I've included it with two other tiny commands `ls` and `docker` which make working in the shell easier.
Basically the shell offers a command prompt, one can type in commands, and they will be run as `dokku `.
When `dokku` is run w/o a command, the shell is run instead. This implies that even though it is an interactive command, running `ssh dokku@dokku.me` (w/o the `-t`) starts a fully working shell, as ssh always creates a pty if no command is given.

It supports command history, and that's about it. I tried adding basic completion, but there doesn't seem to be an easy way which doesn't involve re-writing the whole readline in bash. Maybe this can be done in a improved shell plugin, written in eg python ruby, overriding the default one.