#At file:///Users/cmiller/.bazaar/plugins/mysql/
116 C Miller 2008-06-23 [merge]
Merge from trunk.
added:
sanity.py
modified:
.bzr-mysql/default.conf
__init__.py
emailer.py
hooks.py
=== modified file '.bzr-mysql/default.conf'
--- a/.bzr-mysql/default.conf 2008-05-21 22:17:24 +0000
+++ b/.bzr-mysql/default.conf 2008-06-18 10:43:25 +0000
@@ -1,5 +1,5 @@
[MYSQL]
tree_location = bzr+ssh://bk-internal.mysql.com/home/bk/bazaar/mysql_plugins/
-post_commit_to = mtaylor@stripped, cmiller@stripped
post_push_to = bzr@stripped
+post_commit_to = commits@stripped, bzr@stripped
tree_name = mysql_plugins
=== modified file '__init__.py'
--- a/__init__.py 2008-05-30 21:43:58 +0000
+++ b/__init__.py 2008-06-23 15:09:10 +0000
@@ -31,9 +31,10 @@ lazy_import(globals(), """
import collapse
import parent
import hooks
+import sanity
""")
-version_info = (0, 3, 6)
+version_info = (0, 3, 10)
register_command(parent.cmd_parent)
register_command(collapse.cmd_collapse)
@@ -73,6 +74,11 @@ try:
except:
mutter("bzr-mysql: Can't install post_push_hook")
+try:
+ install_hook_named_or_not("pre_commit", sanity.pre_commit_hook, "pre_commit hook that does sanity checks")
+except:
+ mutter("bzr-mysql: Can't install pre_commit_hook")
+
# vim: sta
# vi: et sw=4 ts=4
=== modified file 'emailer.py'
--- a/emailer.py 2008-05-30 10:14:30 +0000
+++ b/emailer.py 2008-06-19 00:03:41 +0000
@@ -41,6 +41,7 @@ from bzrlib.trace import mutter, note, w
from bzrlib.email_message import EmailMessage
from bzrlib.smtp_connection import SMTPConnection
from bzrlib.util import bencode
+from bzrlib.osutils import get_terminal_encoding
class Sendmail(object):
def __init__(self, config):
@@ -48,12 +49,15 @@ class Sendmail(object):
self.mailer = config.get_user_option('post_commit_mailer',
False,"/usr/lib/sendmail")
- def send_email(self, message):
+ def send_email(self, message, sender=None):
"""Spawn a 'sendmail' subprocess to send the email."""
# TODO think up a good test for this, but I think it needs
# a custom binary shipped with. RBC 20051021
cmd = [ self.mailer, '-t' ]
+ if sender:
+ cmd.append('-f')
+ cmd.append(sender)
try:
process = subprocess.Popen( cmd,
@@ -75,7 +79,7 @@ class Sendmail(object):
raise
except OSError, e:
if e.errno == errno.ENOENT:
- raise errors.BzrError("sendmail is not installed !?")
+ raise errors.BzrError("Mailer '%s' is not installed !?" % (self.mailer))
else:
raise
@@ -120,24 +124,25 @@ class EmailSender(object):
self.blueprint_ids_found = list()
self.bug_search_done = False
+ # We request several pieces of text from the bzr core, which it
+ # intends to be emitted to the user, and as such should (!?) already
+ # be encoded. Since we need to deal with Unicode a few times, we
+ # must know this encoding name and later use it to decode strings.
+ self.encoding = get_terminal_encoding()
+
def search_for_bugs(self, commit_message):
""" scan entire log output for mentions of bugs, worklogs """
- self.bug_ids_found = list(set(re.findall(r"(?i)\bbug[#:=]? ?(\d+)",
+ self.bug_ids_found = list(set(re.findall(r"(?i)\bbug[ ]*#[ ]*(\d+)",
commit_message.encode("utf8"))))
- self.worklog_ids_found = list(set(re.findall(r"(?i)\bwl[#:=]? ?(\d+)",
+ self.worklog_ids_found = list(set(re.findall(r"(?i)\bwl[ ]*#[ ]*(\d+)",
commit_message.encode("utf8"))))
- self.blueprint_ids_found = list(set(re.findall(r"(?i)\bblueprint[#:=]? ?(\d+)",
+ self.blueprint_ids_found = list(set(re.findall(r"(?i)\bblueprint[ ]*#[ ]*(\d+)",
commit_message.encode("utf8"))))
- self.bug_ids_found.sort()
- self.worklog_ids_found.sort()
- self.blueprint_ids_found.sort()
-
-
-
def pre_message(self):
+ # This had better be in the same encoding as the output. :\
the_message = self.config.get_user_option('pre_message', False,
'#At %(url)s\n\n')
return the_message % dict(url=self.url(),
@@ -162,7 +167,7 @@ class EmailSender(object):
return
if self._diff is None:
- self._diff = ""
+ self._diff = u""
return self._diff
def difflimit(self):
@@ -236,14 +241,13 @@ class EmailSender(object):
alist = AddressList(to_addrs)
to_addrs = [formataddr(x) for x in alist.addresslist]
+ assert isinstance(body, unicode), type(body)
+ assert isinstance(diff, unicode), type(diff)
+ message = EmailMessage(from_addr, to_addrs, subject, body + diff)
- body=unicode(body)+unicode(diff)
-
- message = EmailMessage(from_addr, to_addrs, subject, body)
for header in headers:
message[header[0]] = header[1]
-
return message
def send(self):
@@ -259,7 +263,7 @@ class EmailSender(object):
SMTPConnection(self.config).send_email(self.get_message())
else:
mutter("sending using process")
- Sendmail(self.config).send_email(self.get_message())
+ Sendmail(self.config).send_email(self.get_message(), sender=self.from_address())
def headers(self, commit_message):
the_headers = [ ('X-CSetKey',str(self.new_revid)),
@@ -271,8 +275,8 @@ class EmailSender(object):
project = self.project()
if project is not None:
the_headers.append(('X-Project',project))
- for bug_id in self.bug_ids_found:
- the_headers.append(('X-Bug',str(bug_id)))
+ if len(self.bug_ids_found) > 0:
+ the_headers.append(('X-Bug',str(self.bug_ids_found[0])))
for wl_id in self.worklog_ids_found:
the_headers.append(('X-Worklog',str(wl_id)))
for blueprint_id in self.blueprint_ids_found:
@@ -312,9 +316,9 @@ class EmailSender(object):
return "patch-%s.diff" % (self.revno,)
- def per_file_comments_as_string(self, a_revision):
- """ Concatenates all file comments for inclusion in the email """
- # see revisionview.py in bzr-gtk plugin: per-file comments are in
+ def per_file_messages_as_string(self, a_revision):
+ """ Concatenates all file messages for inclusion in the email """
+ # see revisionview.py in bzr-gtk plugin: per-file messages are in
# property 'file-info' and bencode/decode-d.
file_info = a_revision.properties.get('file-info', None)
if file_info is None:
@@ -330,7 +334,7 @@ class EmailSender(object):
message = message.replace('\n', '\n' + spacing)
text = text + ' %s\n%s\n' % (fi['path'], message)
if text:
- return 'per-file comments:\n' + text
+ return 'per-file messages:\n' + text
return ''
def show_diff_trees_minus_p(self, tree_old, tree_new, diff_content):
@@ -385,10 +389,10 @@ class CommitSender(EmailSender):
self.show_diff_trees_minus_p(tree_old, tree_new, diff_content)
numlines = diff_content.getvalue().count('\n')+1
if numlines <= difflimit:
- return diff_content.getvalue()
+ return diff_content.getvalue().decode(self.encoding)
else:
- return ("\nDiff too large for email"
- " (%d lines, the limit is %d).\n"
+ return (u"\nDiff too large for email"
+ u" (%d lines, the limit is %d).\n"
% (numlines, difflimit))
def body(self):
@@ -400,9 +404,6 @@ class CommitSender(EmailSender):
rev1 = None
rev2 = None
- # use 'replace' so that we don't abort if trying to write out
- # in e.g. the default C locale.
-
# We must use StringIO.StringIO because we want a Unicode string that
# we can pass to send_email and have that do the proper encoding.
outf = StringIO.StringIO()
@@ -421,9 +422,10 @@ class CommitSender(EmailSender):
verbose=True
)
- self._body = (
- outf.getvalue() +
- self.per_file_comments_as_string(self.revision) )
+ outf.write(self.per_file_messages_as_string(self.revision))
+
+ # Decode the stuff planned for output to get Unicode.
+ self._body = outf.getvalue().decode(self.encoding)
return self._body
@@ -433,6 +435,25 @@ class PushSender(EmailSender):
def body(self):
""" Return the bzr log to work as the 'commit message' here """
if self._body is None:
+ # We need the revno of the old revision in-the-new-tree
+ note("Generating post-push message")
+ try:
+ # Optimized case - if it works on the old_revid, we don't need
+ # to do the slow code below.
+ self.old_revno = self.branch.revision_id_to_revno(self.old_revid)
+ except:
+ b=self.branch
+ b.lock_read()
+ g = b.repository.get_graph()
+ last = b.last_revision()
+ while True:
+ last_but_one = b.repository.get_revision(last).parent_ids[0]
+ introduced_by_last = g.find_unique_ancestors(last, [last_but_one])
+ if self.old_revid in introduced_by_last:
+ break
+ last = last_but_one
+ self.old_revno = b.revision_id_to_revno(last)
+
outf = StringIO.StringIO()
lf = log_formatter('short',
@@ -440,12 +461,14 @@ class PushSender(EmailSender):
to_file=outf
)
- mutter("Getting log information for (%s:%s)" % (self.old_revno+1,self.new_revno))
+ mutter("Getting log information for (%s:%s)" % (self.old_revno,self.new_revno))
log.show_log(self.branch, lf, verbose=True,
direction='reverse',
- start_revision=self.old_revno+1,
+ start_revision=self.old_revno,
end_revision=self.new_revno)
- self._body = outf.getvalue()
+
+ self._body = outf.getvalue().decode(self.encoding)
+ note("Sending post-push message")
return self._body
@@ -464,10 +487,10 @@ class PushSender(EmailSender):
self.show_diff_trees_minus_p(tree_old, tree_new, diff_content)
numlines = diff_content.getvalue().count('\n')+1
if numlines <= difflimit:
- self._diff = diff_content.getvalue()
+ self._diff = diff_content.getvalue().decode(self.encoding)
else:
- self._diff = ("\nDiff too large for email"
- " (%d lines, the limit is %d).\n"
+ self._diff = (u"\nDiff too large for email"
+ u" (%d lines, the limit is %d).\n"
% (numlines, difflimit))
return self._diff
@@ -482,10 +505,10 @@ class PushSender(EmailSender):
vals = dict(tree=self.tree_name_or_url(),
user=self.user(),
- old_revno=self.old_revno+1,
+ old_revno=self.old_revno,
new_revno=self.new_revno,
ref_subject=self.ref_subject())
- if self.old_revno+1==self.new_revno:
+ if self.old_revno==self.new_revno:
theSubject = "bzr push into %(tree)s branch (%(user)s:%(old_revno)s) %(ref_subject)s" % vals
else:
theSubject = "bzr push into %(tree)s branch (%(user)s:%(old_revno)s to %(new_revno)s) %(ref_subject)s" % vals
=== modified file 'hooks.py'
--- a/hooks.py 2008-05-06 01:00:18 +0000
+++ b/hooks.py 2008-06-18 13:10:28 +0000
@@ -38,22 +38,31 @@ def branch_commit_hook(local, master, ol
emailer.CommitSender(master, old_revno, old_revid, new_revno,
new_revid, PluginBranchConfig("mysql",master),
local_branch=local).send_maybe()
- finally:
- master.unlock()
+ except Exception, e:
+ note("WARNING: Problem with post-commit email hook. ")
+ note("\t %s" % str(e))
+ note("Please see .bzr.log for more information")
+ # Can't do finally here - some people have older python
+ master.unlock()
def branch_push_hook(push_result):
"""Send an email after a push"""
if push_result.old_revid != push_result.new_revid:
config = PluginBranchConfig("mysql", push_result.source_branch)
- emailer.PushSender(push_result.source_branch,
- push_result.old_revno, push_result.old_revid,
- push_result.new_revno, push_result.new_revid,
- config,
- local_branch=push_result.local_branch,
- target_branch=push_result.target_branch,
- master_branch=push_result.master_branch,
- ).send_maybe()
+ try:
+ emailer.PushSender(push_result.source_branch,
+ push_result.old_revno, push_result.old_revid,
+ push_result.new_revno, push_result.new_revid,
+ config,
+ local_branch=push_result.local_branch,
+ target_branch=push_result.target_branch,
+ master_branch=push_result.master_branch,
+ ).send_maybe()
+ except Exception, e:
+ note("WARNING: Problem with post-push email hook.")
+ note("\t %s" % str(e))
+
if config.get_user_option("buildbot_location", False, None) is not None:
try:
mutter("running buildbot hook")
=== added file 'sanity.py'
--- a/sanity.py 1970-01-01 00:00:00 +0000
+++ b/sanity.py 2008-06-20 16:32:51 +0000
@@ -0,0 +1,59 @@
+import sys
+import bzrlib.errors
+
+def sanity_check_file(tree, path, unresolved, potentially_unresolved):
+ file_id = tree.path2id(path)
+ state = 0
+ for ln in tree.get_file(file_id, path):
+ if ln.startswith('<<<<<<<') and not ln.startswith('<<<<<<<<'):
+ if state == 0:
+ state = 1
+ potentially_unresolved.add(path)
+ if ln.startswith('=======') and not ln.startswith('========'):
+ if state == 1:
+ state = 2
+ if ln.startswith('>>>>>>>') and not ln.startswith('>>>>>>>>'):
+ if state == 2:
+ unresolved.add(path)
+ break
+ else:
+ potentially_unresolved.add(path)
+
+def pre_commit_hook(hook_local, hook_master, old_revno, old_revid, new_revno, new_revid, tree_delta, future_tree):
+ unresolved = set([])
+ potentially_unresolved = set([])
+
+ for oldpath, newpath, id, kind, text_modified, meta_modified in tree_delta.renamed:
+ if text_modified and kind == "file":
+ sanity_check_file(future_tree, newpath, unresolved, potentially_unresolved)
+ for path, id, kind, text_modified, meta_modified in tree_delta.modified:
+ if text_modified and kind == "file":
+ sanity_check_file(future_tree, path, unresolved, potentially_unresolved)
+ potentially_unresolved.difference_update(unresolved)
+
+ err = ''
+ if len(unresolved) > 0:
+ err += """
+
+You are committing unresolved conflicts!
+========================================
+
+Files:
+"""
+ for i in unresolved:
+ err += ' - %s\n' % (i)
+ if len(potentially_unresolved) > 0:
+ err += """
+
+You are committing files with conflict markers!
+Did you resolve a conflict incompletely?
+===============================================
+
+Files:
+"""
+ for i in potentially_unresolved:
+ err += ' - %s\n' % (i)
+
+ if err != '':
+ raise bzrlib.errors.BzrError(err)
+
| Thread |
|---|
| • bzr commit into mysql_plugins branch (bzrdev:116) | C Miller | 23 Jun |