blob: 011f1c56fcd43745ea1a5333c47c6893fd7acb5e [file] [log] [blame]
# Copyright (c) 2011 elego Software Solutions GmbH <info@elego.de>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Python module helpful for writing hook scripts.
#
# This is mostly an example for calling 'svnlook' and 'svn' from Python hooks
# and for reading simple configuration files. While it's an example, this may
# also be useful in a production environment as is.
#
# To use this, place this file next to your python hook scripts (e.g. in
# 'repos/hooks/'). To be able use these functions, you may simply write:
# from hook_toolbox import *
# NOTE: Adjust the BIN_PATH according to your operating system, to get valid
# paths to your binaries (e.g. '/usr/bin/svnlook'):
BIN_PATH = '/usr/bin'
import sys, os, subprocess, shlex
def get_log_message(*args):
'''Synopsis:
get_log_message(repos, '-t', transaction) (from pre-commit hook)
get_log_message(repos, '-r', revision) (from post-commit hook)
Returns the log message as a string.
'''
cmd = [os.path.join(BIN_PATH, 'svnlook'), 'propget', '--revprop']
cmd.extend(args)
cmd.append('svn:log')
return run(*cmd)
def get_changed_paths(*args):
'''Synopsis:
get_changed_paths(repos, '-t', transaction) (from pre-commit hook)
get_changed_paths(repos, '-r', revision) (from post-commit hook)
Returns the list of changed paths, relative to the repository root.
'''
cmd = [os.path.join(BIN_PATH, 'svnlook'), 'changed']
cmd.extend(args)
changes = run(*cmd)
#print changes
# First four chars of each svnlook output line show the kind of change.
# The rest of the line is the complete repository path. See:
# http://svnbook.red-bean.com/nightly/en/svn.ref.svnlook.c.changed.html
changed_paths = [ line[4:] for line in changes.split('\n') if len(line) > 4 ]
#print '%s:\n '%(' '.join(args)), '\n '.join(changed_paths)
return changed_paths
def has_path_changed(path, changed_paths):
'''Returns True if any changed path begins with the given path.
path: A path relative to the repos root, without leading slash.
changed_paths: A list obtained from the function get_changed_paths().'''
for changed_path in changed_paths:
if changed_path.startswith(path):
return True
return False
def read_config(repos, filename, expected_tokens_per_line=-1):
'''Reads the file <repos>/conf/<filename> line wise and tokenizes each
line according to shell syntax rules. For example, a file like
# comments & blank lines ignored
aaa bb
cccc "d d d" ee
ff
would return a list
[ ['aaa', 'bb'],
['cccc', 'd d d', 'ee'],
['ff'] ]
If expected_tokens_per_line is > 0, then only the lines matching the
given number of tokens are returned. In above example, passing
expected_tokens_per_line=2 would yield just:
[ ['aaa', 'bb'] ]
Returns an empty list if no such config file exists.
'''
path = os.path.join(repos, 'conf', filename)
if not os.path.exists(path):
print('Not present:', path)
return []
config_lines = open(path).readlines()
tokenized_lines = [ shlex.split(line, True) for line in config_lines ]
tokenized_lines = [ tokens for tokens in tokenized_lines if tokens ]
if expected_tokens_per_line < 1:
return tokenized_lines
matching_lines = [ tokens for tokens in tokenized_lines
if len(tokens) == expected_tokens_per_line ]
if len(matching_lines) < len(tokenized_lines):
print('*** %d syntax errors in %s' % (
len(tokenized_lines) - len(matching_lines),
path))
return matching_lines
def update_working_copy(wc_path):
if not os.path.exists(wc_path):
print('--> *** Cannot find working copy', wc_path)
return None
return run(os.path.join(BIN_PATH, 'svn'), 'update', wc_path)
def run(*cmd):
'''Call the given command & args and return what it printed to stdout.
e.g. result = run('/usr/bin/svn', 'info', wc_dir_path) '''
print('-->', ' '.join(cmd))
stdout = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]
print(stdout.strip())
return stdout