Facio has the ability to run hooks. Hooks are pieces of code that are run either before or after the project template is rendered.
Hooks are defined on a per project basis and are set in a file which resides in the project template itself. This file is called .facio.hooks.yml. It is a YAML formated file consisting of a before and an after list of python dotted paths to code to run. For example:
before:
- path.to.foo
after:
- path.to.bar
Facio also has some bundled hooks you can use out of the box.
These will continue to grow and improve as Facio matures further. Currently there are only python related hooks.
For Django projects a secret key is need to protect your project. Django generates this for you when you run django-admin.py startproject for example. Facio can also do this and add a new variable to the template context.
To use this create a .facio.hooks.yml file at the root of your project template and add the following:
before:
- facio.hooks.django.secret
And in your template you can use the {{ DJANGO_SECRET_KEY }} variable, for example the secret key would normally go in settings.py:
...
SECRET_KEY = '{{ DJANGO_SECRET_KEY }}'
..
Facio can automatically create a python virtual environment for your project. Add this hook in either the before or after list.
after:
- facio.hooks.python.virtualenv
This hook will ask for the following information with sensible defaults set, so you can just press enter to skip.
This hook allows you to install your project as a python module provided your project has a setup.py correctly configured in the templates root directory.
Note
Since your template is required to have been processed before this hook can be run you should only define this hook in the after list of ~/.facio.hooks.yml.
after:
- facio.hooks.python.setup
This hook will ask you for the following information with sensible defaults set so you can just press enter to skip.
You can write your own hook if you need to. Your hook will need to meet the following criteria:
Warning
How to add your custom hook onto the python path is beyond the scope of this documentation. If your hook cannot be imported it will not work. See http://www.scotttorborg.com/python-packaging/ for a very helpful guide on python packaging.
Let’s make a simple hook that prints “hello world”. Create a file in your home directory a new directory called my_hooks and inside create 2 files:
And add the following content into hello.py.
def run():
print 'hello world'
This has created a new python module called my_hooks and inside we have a hello.py python file that can be imported containing our run function.
That’s it, now all we need to do is get it on the python path. How to add your custom hook onto the python path is beyond the scope of this document, see http://www.scotttorborg.com/python-packaging/ for a very helpful guide on python packaging.
Facio has a state module where the current state of Facio is stored. Simply import it:
from facio.state import state
You can also add extra context variables in hooks for use in your template.
# my_hooks.foo
from facio.state import state
def run():
state.update_context_variables({'FOO': 'bar'})
The hook above adds a new FOO context variable with the value of bar so you can use {{ FOO }} in your templates.
You can also access returned values from other hooks that have run. This can be useful to provide sensible defaults in prompts or even to not run the currently executing hook unless another in the chain has run.
# my_hooks.bar
from facio.state import state
def run():
call = state.get_hook_call('my_hooks.foo')
if call:
print 'my_hooks.foo has run'
As described above hook data can be stored for use by other hooks later in the chain. To save data all you need to do is have your run function return something.
# my_hooks.baz
def run():
return "foobar"
When baz is called the value foobar will be stored so later hooks can use it:
# my_hooks.faff
def run():
print state.get_hook_call('my_hooks.baz')
This will print "foobar".
If you want your hook to prompt a user for information or print out helpful colored messages you can extend from the FacioBase class. You can find more information about this in the API documentation.
# my_hooks.flop
from facio.base import FacioBase
class Flop(FacioBase):
def __init__(self):
val = self.gather('Enter a number: ')
self.out('You entered: {0}'.format(val))
def run():
flop = Flop()
return flop
As mentioned Facio has several bundled hooks, you can use these as templates to writting your own.