On 22 October 2012 17:54, Aaron Bentley <span dir="ltr"><<a href="mailto:aaron@aaronbentley.com" target="_blank">aaron@aaronbentley.com</a>></span> wrote:<br><div class="gmail_quote"><div class="im"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
On 12-10-22 12:15 PM, Stuart Moore wrote:<br>
> Hello,<br>
><br>
> We're trying to use a server-side hook to check which files are<br>
> changed in a commit, and if those changes are inappropriate (e.g.<br>
> including temporary files) prevent that change being committed.<br>
> (Ideally I'd also be able to examine those files' contents before<br>
> the commit happened.)<br>
><br>
> I've had a real problem working out how I'm meant to do this - I've<br>
> been investigating the "pre_change_branch_tip" hook, but it doesn't<br>
> seem to have any way of geting a list of the files changed in this<br>
> commit.<br>
<br>
</div><br>Not itself, but a Branch has access to all the revisions, and<br>
pre_change_branch_tip will tell you what revisions to look at.<br>
<br>
Using the old_revid and new_revid, you can call<br>
self.repository.revision_trees, to get the old and new trees, then<br>
Tree.compare or Tree.iter_changes to compare them.<br>
<br></blockquote></div><br></div>Thank you, this seems to be giving me what I want. The last thing I'm trying to do is get the repository's path (we have more than one repository on the sever where this is being deployed, and it'd be good to know which the plugin was operating in). I can't see any obvious methods on the Repository object (which I can get from params.branch.repository). So how do I get the repository's path? <br>
<br>If anyone else wants to use this, the code I've been using is below. I haven't included the "run_filters_on_file" function as that's rather custom, but it returns a list of strings, one for each error (reason the commit can't happen). If there are any errors from any files, the commit doesn't happen. If there is an exception for another reason (e.g. our config file has got corrupt) then it won't allow any more commits until the situation is fixed. As far as I can tell so far, having this server side works with the way we tend to work.<br>
<br>def convert_byte_string_to_unicode(bytestring):<br> if(len(bytestring)==0):<br> return bytestring<br> # <a href="http://pypi.python.org/pypi/chardet" target="_blank">http://pypi.python.org/pypi/chardet</a><br>
import chardet<br>
charset = chardet.detect(bytestring)<br> encoding = charset['encoding']<br> if(encoding is None):<br> return bytestring<br> import codecs<br> codec = codecs.getdecoder(encoding)<br> decoded = unicode(codec(bytestring))<br>
return decoded <br> <br>class FileInTree:<br> def __init__(self, tree, path, file_id):<br> self.tree = tree<br> self.path = path<br> self.file_id = file_id<br>
self.content = None<br><br> def getContent(self):<br> if(self.content is None):<br> content = self.tree.get_file_text(self.file_id)<br> self.content = convert_byte_string_to_unicode(content)<br>
return self.content<br> <br>def pre_change_branch_tip(params):<br> errors = []<br> try:<br> import os<br> import bzrlib.config<br> from bzrlib.errors import TipChangeRejected<br> global filter_config<br>
# Don't interfere with uncommit.<br> if params.new_revno < params.old_revno:<br> return<br> load_config()<br> repo = params.branch.repository<br> old_tree = repo.revision_tree(params.old_revid);<br>
new_tree = repo.revision_tree(params.new_revid);<br> delta = new_tree.changes_from(old_tree);<br><br> for added in delta.added:<br> if added[2] == 'file':<br> file = FileInTree(new_tree,added[0],added[1])<br>
errors += run_filters_on_file(file)<br> for renamed in delta.renamed:<br> if renamed[3] == 'file':<br> file = FileInTree(new_tree,renamed[1],renamed[2])<br> errors += run_filters_on_file(file)<br>
for modified in delta.modified:<br> if modified[2]== 'file':<br> file = FileInTree(new_tree, modified[0], modified[1])<br> errors += run_filters_on_file(file)<br> except (Exception) as e:<br>
import StringIO<br> import logging<br> exception_logger = logging.getLogger('ExceptionLogger')<br> exception_msg = StringIO.StringIO()<br> stream_handler = logging.StreamHandler(exception_msg);<br>
exception_logger.addHandler(stream_handler)<br> exception_logger.exception(e);<br><br> raise TipChangeRejected("An error occured; no more commits until fixed." + exception_msg.getvalue())<br>
if(len(errors)>0):<br> raise TipChangeRejected("\n".join(errors))<br><br>
</div><br>