summaryrefslogtreecommitdiff
path: root/lib/codereview/codereview.py
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-11-04 15:17:01 -0800
committerRuss Cox <rsc@golang.org>2009-11-04 15:17:01 -0800
commit3805f428cb2363dfe69d37ef00e4670b11334ceb (patch)
tree5de162cabd4c844fdc09af6c84900e7aac160def /lib/codereview/codereview.py
parent0b92ce67ff3a1ce51cc11dbaf6e0f30830d783af (diff)
downloadgolang-3805f428cb2363dfe69d37ef00e4670b11334ceb.tar.gz
avoid infinite recursion in matcher.
after sync (or sync --local), clean up repository: * look for and close CLs submitted on our behalf * remove unmodified files from CLs * warn about empty CLs R=r http://go/go-review/1017029
Diffstat (limited to 'lib/codereview/codereview.py')
-rw-r--r--lib/codereview/codereview.py94
1 files changed, 79 insertions, 15 deletions
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index 6bb6ad276..b3d9a67ae 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -40,6 +40,7 @@ import os, re
import stat
import threading
from HTMLParser import HTMLParser
+from xml.etree import ElementTree as ET
try:
hgversion = util.version()
@@ -277,6 +278,9 @@ def ExceptionDetail():
s += ": " + arg
return s
+def IsLocalCL(ui, repo, name):
+ return GoodCLName(name) and os.access(CodeReviewDir(ui, repo) + "/cl." + name, 0)
+
# Load CL from disk and/or the web.
def LoadCL(ui, repo, name, web=True):
if not GoodCLName(name):
@@ -738,9 +742,10 @@ def pending(ui, repo, *pats, **opts):
def reposetup(ui, repo):
global original_match
- original_match = cmdutil.match
- cmdutil.match = ReplacementForCmdutilMatch
- RietveldSetup(ui, repo)
+ if original_match is None:
+ original_match = cmdutil.match
+ cmdutil.match = ReplacementForCmdutilMatch
+ RietveldSetup(ui, repo)
def CheckContributor(ui, repo):
user = ui.config("ui", "username")
@@ -838,13 +843,14 @@ def sync(ui, repo, **opts):
Incorporates recent changes from the remote repository
into the local repository.
"""
- ui.status = sync_note
- ui.note = sync_note
- other = getremote(ui, repo, opts)
- modheads = repo.pull(other)
- err = commands.postincoming(ui, repo, modheads, True, "tip")
- if err:
- return err
+ if not opts["local"]:
+ ui.status = sync_note
+ ui.note = sync_note
+ other = getremote(ui, repo, opts)
+ modheads = repo.pull(other)
+ err = commands.postincoming(ui, repo, modheads, True, "tip")
+ if err:
+ return err
sync_changes(ui, repo)
def sync_note(msg):
@@ -853,7 +859,43 @@ def sync_note(msg):
sys.stdout.write(msg)
def sync_changes(ui, repo):
- pass
+ # Look through recent change log descriptions to find
+ # potential references to http://.*/our-CL-number.
+ # Double-check them by looking at the Rietveld log.
+ get = util.cachefunc(lambda r: repo[r].changeset())
+ changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get, {'rev': None})
+ n = 0
+ for st, rev, fns in changeiter:
+ if st != 'iter':
+ continue
+ n += 1
+ if n > 100:
+ break
+ desc = repo[rev].description().strip()
+ for clname in re.findall('(?m)^http://(?:[^\n]+)/([0-9]+)$', desc):
+ if IsLocalCL(ui, repo, clname) and IsRietveldSubmitted(ui, clname, repo[rev].hex()):
+ ui.warn("CL %s submitted as %s; closing\n" % (clname, repo[rev]))
+ cl, err = LoadCL(ui, repo, clname, web=False)
+ if err != "":
+ ui.warn("loading CL %s: %s\n" % (clname, err))
+ continue
+ EditDesc(cl.name, closed="checked")
+ cl.Delete(ui, repo)
+
+ # Remove files that are not modified from the CLs in which they appear.
+ all = LoadAllCL(ui, repo, web=False)
+ changed = ChangedFiles(ui, repo, [], {})
+ for _, cl in all.items():
+ extra = Sub(cl.files, changed)
+ if extra:
+ ui.warn("Removing unmodified files from CL %s:\n" % (cl.name,))
+ for f in extra:
+ ui.warn("\t%s\n" % (f,))
+ cl.files = Sub(cl.files, extra)
+ cl.Flush(ui, repo)
+ if not cl.files:
+ ui.warn("CL %s has no files; suggest hg change -d %s\n" % (cl.name, cl.name))
+ return
def uisetup(ui):
if "^commit|ci" in commands.table:
@@ -926,8 +968,10 @@ cmdtable = {
),
"^sync": (
sync,
- [],
- "",
+ [
+ ('', 'local', None, 'do not pull changes from remote repository')
+ ],
+ "[--local]",
),
"^upload": (
upload,
@@ -989,12 +1033,32 @@ class FormParser(HTMLParser):
if self.curdata is not None:
self.curdata += data
+# XML parser
+def XMLGet(ui, path):
+ try:
+ data = MySend(path, force_auth=False);
+ except:
+ ui.warn("XMLGet %s: %s\n" % (path, ExceptionDetail()))
+ return None
+ return ET.XML(data)
+
+def IsRietveldSubmitted(ui, clname, hex):
+ feed = XMLGet(ui, "/rss/issue/" + clname)
+ if feed is None:
+ return False
+ for sum in feed.findall("{http://www.w3.org/2005/Atom}entry/{http://www.w3.org/2005/Atom}summary"):
+ text = sum.findtext("", None).strip()
+ m = re.match('\*\*\* Submitted as [^*]*?([0-9a-f]+) \*\*\*', text)
+ if m is not None and len(m.group(1)) >= 8 and hex.startswith(m.group(1)):
+ return True
+ return False
+
# Like upload.py Send but only authenticates when the
# redirect is to www.google.com/accounts. This keeps
# unnecessary redirects from happening during testing.
def MySend(request_path, payload=None,
content_type="application/octet-stream",
- timeout=None,
+ timeout=None, force_auth=True,
**kwargs):
"""Sends an RPC and returns the response.
@@ -1015,7 +1079,7 @@ def MySend(request_path, payload=None,
if rpc == None:
rpc = GetRpcServer(upload_options)
self = rpc
- if not self.authenticated:
+ if not self.authenticated and force_auth:
self._Authenticate()
if request_path is None:
return