Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Unified Diff: tests/sample_pre_commit_hook

Issue 6877055: Move commit-queue/checkout into depot_tools so it can be reused by the try server. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: .gitignore Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tests/checkout_test.py ('k') | tests/subversion_config/config » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tests/sample_pre_commit_hook
diff --git a/tests/sample_pre_commit_hook b/tests/sample_pre_commit_hook
new file mode 100644
index 0000000000000000000000000000000000000000..ba67e5d82dfdedf55a4a7f6d06db2c89cf6622f1
--- /dev/null
+++ b/tests/sample_pre_commit_hook
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file at
+# http://src.chromium.org/viewvc/chrome/trunk/src/LICENSE
+
+"""Commit bot fake author svn server hook.
+
+Looks for svn commit --withrevprop realauthor=foo, replaces svn:author with this
+author and sets the property commitbot to the commit bot credential to signify
+this revision was committed with the commit bot.
+
+It achieves its goal using an undocumented way. This script could use 'svnlook'
+to read revprop properties but the code would still be needed to overwrite the
+properties.
+
+http://svnbook.red-bean.com/nightly/en/svn.reposadmin.create.html#svn.reposadmin.create.hooks
+strongly advise against modifying a transation in a commit because the svn
+client caches certain bits of repository data. Upon asking subversion devs,
+having the wrong svn:author cached on the commit checkout is the worst that can
+happen.
+
+This code doesn't care about this issue because only the commit bot will trigger
+this code, which runs in a controlled environment.
+
+The transaction file format is also extremely unlikely to change. If it does,
+the hook will throw an UnexpectedFileFormat exception which will be silently
+ignored.
+"""
+
+import os
+import re
+import sys
+
+
+class UnexpectedFileFormat(Exception):
+ """The transaction file format is not the format expected."""
+
+
+def read_svn_dump(filepath):
+ """Returns list of (K, V) from a keyed svn file.
+
+ Don't use a map so ordering is kept.
+
+ raise UnexpectedFileFormat if the file cannot be understood.
+ """
+ class InvalidHeaderLine(Exception):
+ """Raised by read_entry when the line read is not the format expected.
+ """
+
+ try:
+ f = open(filepath, 'rb')
+ except EnvironmentError:
+ raise UnexpectedFileFormat('The transaction file cannot be opened')
+
+ try:
+ out = []
+ def read_entry(entrytype):
+ header = f.readline()
+ match = re.match(r'^' + entrytype + ' (\d+)$', header)
+ if not match:
+ raise InvalidHeaderLine(header)
+ datalen = int(match.group(1))
+ data = f.read(datalen)
+ if len(data) != datalen:
+ raise UnpexpectedFileFormat(
+ 'Data value is not the expected length')
+ # Reads and ignore \n
+ if f.read(1) != '\n':
+ raise UnpexpectedFileFormat('Data value doesn\'t end with \\n')
+ return data
+
+ while True:
+ try:
+ key = read_entry('K')
+ except InvalidHeaderLine, e:
+ # Check if it's the end of the file.
+ if e.args[0] == 'END\n':
+ break
+ raise UnpexectedFileFormat('Failed to read a key: %s' % e)
+ try:
+ value = read_entry('V')
+ except InvalidHeaderLine, e:
+ raise UnpexectedFileFormat('Failed to read a value: %s' % e)
+ out.append([key, value])
+ return out
+ finally:
+ f.close()
+
+
+def write_svn_dump(filepath, data):
+ """Writes a svn keyed file with a list of (K, V)."""
+ f = open(filepath, 'wb')
+ try:
+ def write_entry(entrytype, value):
+ f.write('%s %d\n' % (entrytype, len(value)))
+ f.write(value)
+ f.write('\n')
+
+ for k, v in data:
+ write_entry('K', k)
+ write_entry('V', v)
+ f.write('END\n')
+ finally:
+ f.close()
+
+
+def find_key(data, key):
+ """Finds the item in a list of tuple where item[0] == key.
+
+ asserts if there is more than one item with the key.
+ """
+ items = [i for i in data if i[0] == key]
+ if not items:
+ return None
+ assert len(items) == 1
+ return items[0]
+
+
+def handle_commit_bot(repo_path, tx, commit_bot, admin_email):
+ """Replaces svn:author with realauthor and sets commit-bot."""
+ # The file format is described there:
+ # http://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
+ propfilepath = os.path.join(
+ repo_path, 'db', 'transactions', tx + '.txn', 'props')
+
+ # Do a lot of checks to make sure everything is in the expected format.
+ try:
+ data = read_svn_dump(propfilepath)
+ except UnexpectedFileFormat:
+ return (
+ 'Failed to parse subversion server transaction format.\n'
+ 'Please contact %s ASAP with\n'
+ 'this error message.') % admin_email
+ if not data:
+ return (
+ 'Failed to load subversion server transaction file.\n'
+ 'Please contact %s ASAP with\n'
+ 'this error message.') % admin_email
+
+ realauthor = find_key(data, 'realauthor')
+ if not realauthor:
+ # That's fine, there is no author to fake.
+ return
+
+ author = find_key(data, 'svn:author')
+ if not author or not author[1]:
+ return (
+ 'Failed to load svn:author from the transaction file.\n'
+ 'Please contact %s ASAP with\n'
+ 'this error message.') % admin_email
+
+ if author[1] != commit_bot:
+ # The author will not be changed and realauthor will be kept as a
+ # revision property.
+ return
+
+ if len(realauthor[1]) > 50:
+ return 'Fake author was rejected due to being too long.'
+
+ if not re.match(r'^[a-zA-Z0-9\@\-\_\+\%\.]+$', realauthor[1]):
+ return 'Fake author was rejected due to not passing regexp.'
+
+ # Overwrite original author
+ author[1] = realauthor[1]
+ # Remove realauthor svn property
+ data.remove(realauthor)
+ # Add svn property commit-bot=<commit-bot username>
+ data.append(('commit-bot', commit_bot))
+ write_svn_dump(propfilepath, data)
+
+
+def main():
+ # Replace with your commit-bot credential.
+ commit_bot = 'user1@example.com'
+ admin_email = 'dude@example.com'
+ ret = handle_commit_bot(sys.argv[1], sys.argv[2], commit_bot, admin_email)
+ if ret:
+ print >> sys.stderr, ret
+ return 1
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
+
+# vim: ts=4:sw=4:tw=80:et:
« no previous file with comments | « tests/checkout_test.py ('k') | tests/subversion_config/config » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698