Giter Club home page Giter Club logo

pluginhook's Introduction

pluginhook

A simple plugin system for Bash programs that's better than just hook scripts.

Plugins as a better way

Let's take the core benefits of hook scripts and re-structure it slightly:

  1. Instead of focusing on hook scripts, we focus on plugins -- a directory of hook scripts
  2. Like hook scripts, plugins are active by being in a certain place. But they can be named anything
  3. Multiple plugins can handle a hook. Either for fanout event triggering, or for pipeline filtering

So what is a plugin? A directory full of hook scripts. When a hook is triggered, all arguments provided in the trigger are given to each hook script. They also receive STDIN in a pipelined fashion.

Triggering plugin hooks

You use the pluginhook command to trigger hooks as if you might call a traditional hook script directly. Where before you might have triggered by calling something like:

hooks/post-commit $REV $USER

You'd instead trigger like this:

pluginhook post-commit $REV $USER

The pluginhook command simply loops through all plugin directories found in the path defined by the environment variable PLUGIN_PATH and passes the same arguments to any hook scripts by that name. This means installing a plugin is as simple as putting it in your PLUGIN_PATH. Then any plugin that has the post-commit hook script will be run.

Pipeline filtering with plugins

You don't just get a "broadcast" mechanism for arguments. You also get stream pipelining. If you pipe a stream into pluginhook, it will be passed through each plugin hook, letting each plugin act as a filtering process. By clearly defining how a hook should be used and how it can play well with others, this becomes very powerful infrastructure.

Here is a plugin we'll call upper implementing a text hook (which would be in $PLUGIN_PATH/upper/text):

#!/usr/bin/env python
import sys
sys.stdout.write(sys.stdin.read().upper())

Here is a plugin we'll call reverse that also implements a text hook ($PLUGIN_PATH/reverse/text):

#!/usr/bin/env ruby
puts STDIN.read.strip.reverse

One plugin uses Python to implement the hook, the other uses Ruby. But it doesn't matter, they work together when you trigger the hook:

$ echo "hello world" | pluginhook text
DLROW OLLEH

Only plugins that implement a hook are used as filters for that hook, so there's no need to implement pass-through hooks if a plugin doesn't care about a hook.

If ordering is important, you can always rename your plugin directory to start with a number, which will define an order of execution. A plugin author might care about when it is run, but it's up to the user to take their advice or decide to run it in a different position in the order, by simply renaming the plugin script.

What's wrong with just hook scripts?

Lots of shell-based systems use hook scripts as a means to allow users to extend or customize behavior. Popular examples are Git and SVN, but many systems from libvirt to NPM to OS X use this pattern. Shell scripts make for a great way to expose hooks because the shell environment is ubiquitous and lets you easily call into scripts or programs written in your language of choice.

The standard implementation of hook scripts is to have a shell script with an execute bit in a particular location that's named after the hook. The most famous example is the "post-commit" hook of SVN, which if hooks/post-commit exists in your repository directory with an execute bit, it will trigger this script after each commit. Some systems let you register hooks by providing a location instead of using convention.

However, in either case, each hook points to one script. The only way for a third-party piece of software to "hook in" is to install itself as the one hook script, or have you manually install it by calling it from your existing hook script. What's more, if a third-party piece of software wants to use multiple hooks, you have to deal with this several times over. Not only is this a hassle, but leads to complex and non-obvious configurations.

Author

Jeff Lindsay [email protected]

License

MIT

pluginhook's People

Contributors

progrium avatar plietar avatar asm89 avatar

Stargazers

Vitaly Fedorov avatar John Ciprian avatar Kirill Zholnay avatar J Hughes avatar Jason Todd avatar Martin Bučko avatar Eduardo Bellido Bellido avatar Lajos Papp avatar  avatar Soma Szelpal avatar  avatar Scott Ivey avatar Leonid Shirmanov avatar Corey Butler avatar Theofanis Despoudis avatar  avatar Eric avatar Isagani Mendoza avatar Gabriel Francisco avatar  avatar GAURAV avatar Chris N. avatar cytec avatar Nikolay Kolev avatar Aaron Heckmann avatar Brandon Ashworth avatar D. Bohdan avatar Hady Mahmoud avatar António P. P. Almeida avatar Josh Harrison avatar  avatar Wu avatar Vas Kaloidis avatar Steve Phillips avatar Christian Eikermann avatar Charles Chan avatar Vlada Petrović avatar Ziyad Parekh avatar Guillermo Greising avatar Valeriu Zdrobău avatar LLast Oatt avatar Ben Haan avatar Stefano Azzolini avatar Vaughan Rouesnel avatar Kepi avatar Dave Henderson avatar Der Soulstealer avatar Bob Aman avatar Ryan Pitts avatar Reinhard Nägele avatar Vladislav Supalov avatar Andrew Sliwinski avatar Rimantas (Rimas) Mocevicius avatar Bruce Wang avatar Kien Nguyen avatar Andre Behrens avatar Dennis Payonk avatar John Pribula avatar Sandy Vanderbleek avatar  avatar Laurian Gridinoc avatar Cyrill v.W. avatar Abdul Qabiz avatar Sean Lynch avatar Michele Orsi avatar Jayaseelan Yezhuaralai avatar  avatar Goran Gajic avatar Bastien Chatelard avatar 发条朋克 avatar ☰☱☲☳☴☵☶☷ avatar John-Henry Liberty avatar Alberto García Lamela avatar  avatar Dmitriy Kiriyenko avatar x2q avatar Wil Tan avatar Jose-Luis Rivas avatar Raphaël Valyi avatar Branko Vukmirovic avatar Dustin Chapman avatar Vedarth Kulkarni avatar Tony Worm avatar Stig Kleppe-Jørgensen avatar MOZGIII avatar Anthony Panozzo avatar  avatar Baptiste Fontaine avatar Kouhei Maeda avatar Isao Sugimoto avatar Aaron C. de Bruyn avatar Hiroaki Nakamura avatar Denis Zgonjanin avatar Sam avatar mixxmac avatar Marat Garafutdinov avatar Javier Tejero avatar Matt Valdez avatar Pawel Kasperek avatar Maksim Soltan avatar

Watchers

 avatar Stig Kleppe-Jørgensen avatar Manfred Touron avatar Tim Chen avatar Chen Bruce avatar Kyle Smith avatar Christian Hammerl avatar James Cloos avatar JMSwag avatar Guillermo Greising avatar  avatar Bohdan Kmit avatar Walter Di Carlo avatar Jordi Masramon avatar  avatar  avatar Vitaly Fedorov avatar

pluginhook's Issues

Debug Flag?

Using dokku, I'm having an issue where pluginhook is erroring out, but I have not way to capture the error. Would it be possible to add a debug flag to show stdout/stderr?

I tried doing this in go myself, but I'm having version mismatch issues between the compiler and the code.

Only last plugin commands are executed

I noticed that only alphabeticaly-last plugin commands can be executed, even if all of them are displayed on "help".

For example, with a fresh install of dokku:

$ pluginhook commands help
    logs <app>      Show the last logs for an application
    url <app>       Show the URL for an application
$  pluginhook commands url myapp  # Nginx plugin
    http://myapp.mydomain.com
$ pluginhook commands logs myapp  # 00_dokku-standard plugin
$ (no output)

By extension dokku logs myapp does not work on dokku ;)

Missing LICENSE file

Hi,

While I've been working on the Debian's packaging for pluginhook I noticed that, although the README.md file mentions MIT as the license under which the sources are distributed, the sources lack a proper LICENSE or COPYING file.

Could you please add such file to clarify the license terms?

Thanks for considering.

Pluginhook runs plugin scripts in parallel, which may be a problem for certain scripted tasks

An example of the situation is:

  • dokku plugins each have their own install script
  • running pluginhook install will run all of these scripts in parallel
  • if more than one of these scripts includes use of apt-get, there's a pretty high likelihood that they'll both be trying to use apt-get in two processes. In one process, apt-get will be unable to get the dpkg lock and will therefore fail
  • the result is that plugins may fail to install their dependencies, potentially at random

@progrium, what's your preferred course of action to resolve this? @asm89 and I were discussing two possibilities last night:

  • plugin script authors should explicitly make sure scripts run safely in parallel with each other, e.g. through use of flock
  • there could be a way to force pluginhook to run scripts in series, e.g. in the form of a -serial flag which dokku could use for running install phases of plugins

Either of these approaches would work, I think, but each has some fairly significant tradeoffs.

Any strong preference either way?

Pluginhook hangs when launched from ssh

If I specify a command to ssh, sshd runs it in a non-interactive session.
This causes pluginhook to attach an stdin to the first plugin process, and thus to hang.

Running ssh with -t (eg ssh -t dokku@host logs) forces an interactive session whichs makes it work.
Alternatively running echo | ssh dokku@host logs works too.

If have no idea whether there is a simple fix to the problem.
The workaround above might be the only easy solution.

environment variable to indicate currently running hook

As a potential solution to dokku/dokku#425, I think it would make sense for pluginhook to inject an environment variable that scripts can check for to see if they were triggered by a pluginhook call, and what the trigger was.

For example, the solution to the mentioned issue would be to check for RUNNING_PLUGINHOOK=pre-release and just not trigger the restart code in config:set if true.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.