Plugin Development Quickstart

Note

This part of the documentation is extremely sparse and will be updated very soon.

One of the main goals of virtstrap is to provide a simple way to create plugins that can extend the functions of virtstrap for each project. Plugins can add functionality using two different objects:

  • Command - A Command is any new command that you’d like to add to the command line interface
  • Hook - A Hook is essentially an event listener. The hooks listen for events that occur during a command. The default events for almost every command are before and after. As a convention, commands should declare the events they call.

This quickstart guide goes through the creation of a hook. Eventually this will contain information on creating new commands.

A Quick Note About virtstrap’s Structure

In order to understand plugins, you have to understand a bit about how virtstrap works. Virtstrap has multiple packages explained below:

  • virtstrap-core - The majority of virtstrap’s logic is here. The other packages are dependent on this package. You cannot write plugins for this package. If you wish to extend it then refer to Contributing to Virtstrap.
  • virtstrap - This is the system wide package that contains the script for the vstrap command. It also contains the logic for the init and commands commands. Plugins written for virtstrap apply to the entire system. So the plugins for virtstrap should most likely be commands as hooks may cause unwanted functionality on different projects.
  • virtstrap-local - Contains all the logic pertaining to anything project specific. Plugins written for virtstrap-local allow you to vary functionality depending on project. In general, the suggestion is to write plugins for virtstrap-local.

So let’s start by creating a new virtstrap-local plugin.

Creating A virtstrap-local Plugin

Like mentioned previously, virtstrap-local is the suggested package to extend with plugins. The reason is that your changes won’t interfere with other projects on your system and it allows your plugins to be used in a repeatable fashion.

Step 1: Start a new python package

Virtstrap plugins, like buildout recipe’s, are simply python packages. The package simple registers a module to an entry point and virtstrap takes over from there. So let’s start out by creating a new package for to create our new plugin:

$ mkdir virtstrap-new-plugin
$ cd virtstrap-new-plugin
$ mkdir virtstrap_new_plugin
$ touch virtstrap_new_plugin/__init__.py

Note

For the time being, virtstrap assumes you’re using a unix environment. At this time windows is untested although plans are in the works for a future release.

What we just did is create the scaffolding for a new python package. Next, we need to create a setup.py file. Open up your favorite editor (mine is vim) and copy this code (you can edit this if you are actually going to use this):

from setuptools import setup, find_packages
import sys, os

version = '0.0.0-dev'

setup(
    name='virtstrap-new-plugin',
    version=version,
    description="A new virtstrap plugin",
    long_description="""A new virtstrap plugin""",
    classifiers=[],
    keywords='virtstrap',
    author='John Doe',
    author_email='someone@someemail-place.com',
    url='',
    license='MIT',
    packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
    include_package_data=True,
    zip_safe=False,
    install_requires=[
        #'virtstrap-local',
    ],
    entry_points={
        'virtstrap_local.plugins': [
            'plugin = virtstrap_new_plugin.plugin',
        ]
    },
)

Step 2: Write the plugin!

In general the best way to get something new out of virtstrap is to use hooks to listen for events that commands issue. Commands will almost always issue the before and after event. The easiest way to determine what events are available is to use the event attribute of a command.

Here is a simple example:

from virtstrap import hooks

@hooks.create('install', ['after'])
def new_install_hook(event, options, **kwargs):
    print "I appear after install has completed!"

So what did this all do? Let’s break it down!

  1. First we need to import virtstrap.hooks which provides the virtstrap.hooks.create decorator.
  2. Next we use the virtstrap.hooks.create decorator to define what command event we’d like to listen to. It requires two arguments.
    1. The name of the command that you’d like to listen to - in our case the install command
    2. A list of events you’d like to listen for - in this case the after event.
  3. Now we create the actual hook logic in the decorated function new_install_hook. The decorator expects the decorated function to accept two arguments and an arbitrary set of keyword arguments:
    1. event - This is the current event that is being processed
    2. options - This is an object representing the command line argument options. It should be used as read-only.
  4. Finally we just print a message to the user (using an unrecommended method of output... more on this later)

The above example is the bare minimum you’d need to write to create a hook. Really, it’s pretty lame. It simply prints the statement I appear after install has completed upon receiving the after event from the install command. However, let’s do something a tad more interesting:

from virtstrap import hooks
from virtstrap.log import logger

@hooks.create('install', ['after'])
def new_install_hook(event, options, project=None, **kwargs):
    logger.info('The current path of the project is %s' % project.path())

There are three changes here.

  1. We added an import on the second line to virtstrap.log.logger. This is the recommended way to output to the user. It allows virtstrap to log any messages, but also display pertinent messages to the user depending on the verbosity settings.
  2. The new_install_hook function now has a different argument list. We’ve added project=None to the list of arguments. The project argument is passed in by install command’s after event. The project object is an abstraction to the current project’s directory and configuration information.
  3. Finally on the last line we use the logger‘s info method to display the current path of the project to the user.

There, that’s a bit more interesting. However, it still does almost nothing. Let’s do something crazy - like initialize a git repository!

Here goes:

from virtstrap import hooks
from virtstrap.log import logger
from virtstrap.utils import call_subprocess

@hooks.create('install', ['after'])
def new_install_hook(event, options, project=None, **kwargs):
    logger.info('Initializing a git repository for project at %s'
                    % project.path())
    call_subprocess(['git', 'init', project.path()], show_stdout=False)

WOO! Finally, we’re getting somewhere. This is what just happened:

  1. We import virtstrap.utils.call_subprocess. This allows us to call a subprocess. It just makes dealing with subprocesses a tad bit easier. For now, you’ll just have to trust it.
  2. The next major change we introduce is running call_subprocess on the last line of code. What this line does is creates a git repository in your project root. Granted, this isn’t really that useful after the install command has been run but it is definitely more interesting than printing out useless strings.

Step 3: Using the plugin

In order for you to use this plugin let’s test it out with a new project.

Do the following in any directory you wish to use:

$ mkdir test-project
$ cd test-project

Next create a VEfile:

$ vim VEfile

Place this inside of it

plugins:
  - virtstrap-new-plugin:
    - file://PATH_TO_PLUGIN

Just replace PATH_TO_PLUGIN with the actual path to the plugin’s directory.

Step 4: Init the project. Watch the magic happen

Finally, from within your new project directory do this:

$ vstrap init

You should see the following:

... (normal virtstrap messages)
Initializing a git repository for project at SOME_DIRECTORY
... (more messages)

Now you can do this:

$ git status

And it you should see that there’s a git repository in your current directory!

Recap: This is just an example and not a useful one.

As stated previously, this example isn’t very useful in a real project. If you’d like to see a useful example of this type of plugin checkout virtstrap-ruby-bundler