Permalink
Browse files

Add support for hooks

Currently sala only supports pre-set and post-set hooks.
  • Loading branch information...
1 parent 7778425 commit 5d96a145fa67a6fc3ed9ac4dab9f7fcf33139000 @nailor committed May 21, 2012
Showing with 136 additions and 0 deletions.
  1. +8 −0 sala/__init__.py
  2. +1 −0 sala/config.py
  3. +68 −0 sala/hooks.py
  4. +44 −0 test/hooks.t
  5. +15 −0 test/init.t
View
8 sala/__init__.py
@@ -28,6 +28,7 @@
from sala.config import Configuration
from sala.gpg import gpg_encrypt, gpg_decrypt
+from sala.hooks import init_hooks, run_hooks
if os.environ.get('SALA_TESTS_RUNNING'):
# getpass() reads from TTY. Override this behavior in tests.
@@ -194,6 +195,10 @@ def do_init(config, files, options):
os.mkdir(config.saladir)
gpg_encrypt(config, config.keyfile, passphrase, key)
+
+ if not os.path.exists(config.hooksdir):
+ os.mkdir(config.hooksdir)
+ init_hooks(config.hooksdir)
print('done')
@@ -242,6 +247,7 @@ def do_set(config, files, options):
print('')
for filename in files:
+ run_hooks('pre', 'set', config, filename)
pwlist = generate_passwords(config.get('password-generator'))
if pwlist:
options = range(len(pwlist))
@@ -275,6 +281,8 @@ def do_set(config, files, options):
make_parent_dirs(full_file_path)
gpg_encrypt(config, full_file_path, key, secret)
+ run_hooks('post', 'set', config, filename)
+
print('')
View
1 sala/config.py
@@ -35,6 +35,7 @@ def __init__(self, topdir):
self.topdir = topdir
self.saladir = os.path.join(topdir, '.sala')
self.keyfile = os.path.join(self.saladir, 'key')
+ self.hooksdir = os.path.join(self.saladir, 'hooks')
def __getattr__(self, key):
# Proxies ConfigParser getters like this:
View
68 sala/hooks.py
@@ -0,0 +1,68 @@
+from __future__ import unicode_literals, print_function
+
+import os
+import stat
+import subprocess
+
+_DEFAULT_HOOKS = {
+ 'post-set': '''#!/bin/sh
+
+# This is a sample post-set hook for sala that commits your changes
+# to git. To activate, remove .sample and make the file executable.
+
+# post-set receives the filename as a parameter.
+
+# git add $1 && git commit -m "Save $1."
+''',
+ 'pre-set': '''#!/bin/sh
+# Here you can include a pre-save hook
+ '''
+}
+
+
+def init_hooks(hooksdir):
+ for hook, value in _DEFAULT_HOOKS.items():
+ hookfile = os.path.join(hooksdir, '{0}.sample'.format(hook))
+ with open(hookfile, 'w') as f:
+ f.write(value)
+ mode = os.stat(hookfile)[0]
+ os.chmod(hookfile, mode | stat.S_IXUSR)
+
+
+def run_hooks(state, action, config, *args, **kwargs):
+ hook_name = '{0}-{1}'.format(state, action)
+
+ if hook_name not in _hook_actions:
+ return
+
+ # We need absolute path here as we're going to set the CWD to
+ # `config.topdir`
+ executable = os.path.join(os.path.abspath(config.hooksdir), hook_name)
+
+ if not os.path.isfile(executable):
+ return
+
+ if not os.access(executable, os.X_OK):
+ return
+
+ return _hook_actions[hook_name](executable, config, *args, **kwargs)
+
+
+def _run_hook(config, hook, *params):
+ args = [hook] + list(params)
+
+ # Overwrite SALADIR to provide correct SALADIR to the executable
+ env = os.environ.copy()
+ env['SALADIR'] = os.path.abspath(config.topdir)
+
+ return subprocess.Popen(args, env=env, cwd=config.topdir or None)
+
+
+def post_set(hook, config, filename):
+ process = _run_hook(config, hook, filename)
+ return process.wait() == 0
+
+
+_hook_actions = {
+ 'post-set': post_set,
+}
View
44 test/hooks.t
@@ -0,0 +1,44 @@
+ $ . $TESTDIR/lib.sh
+
+Non-executable post-set is not run:
+ $ init_password_store testpassword
+ $ mv .sala/hooks/post-set.sample .sala/hooks/post-set
+ $ chmod -x .sala/hooks/post-set
+ $ sala set foo <<EOF
+ > testpassword
+ > secret
+ > secret
+ > EOF
+ Enter the master passphrase:
+
+ Type a new secret for foo:
+ Confirm:
+
+
+SALADIR is available in post-set:
+ $ cleanup
+ $ mkdir store
+ $ write_config store/.sala/config << EOF
+ > password-generator
+ > EOF
+ $ SALADIR=store sala init >/dev/null 2>&1 << EOF
+ > testpassword
+ > testpassword
+ > EOF
+ $ cat > store/.sala/hooks/post-set << EOF
+ > #!/bin/sh
+ > echo "hooked" > \$SALADIR/\$1
+ > EOF
+ $ chmod +x store/.sala/hooks/post-set
+ $ SALADIR=store sala set foo <<EOF
+ > testpassword
+ > secret
+ > secret
+ > EOF
+ Enter the master passphrase:
+
+ Type a new secret for foo:
+ Confirm:
+
+ $ cat store/foo
+ hooked
View
15 test/init.t
@@ -43,6 +43,21 @@ Initialize a password store:
$ cat .sala/key | head -n 1
-----BEGIN PGP MESSAGE-----
+ $ test -d .sala/hooks
+
+ $ test -f .sala/hooks/post-set.sample
+
+ $ cat .sala/hooks/post-set.sample
+ #!/bin/sh
+
+ # This is a sample post-set hook for sala that commits your changes
+ # to git. To activate, remove .sample and make the file executable.
+
+ # post-set receives the filename as a parameter.
+
+ # git add $1 && git commit -m "Save $1."
+
+
Initialize with an empty password:
$ cleanup

0 comments on commit 5d96a14

Please sign in to comment.