summaryrefslogtreecommitdiff
path: root/lib/codereview/codereview.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/codereview/codereview.py')
-rw-r--r--lib/codereview/codereview.py105
1 files changed, 93 insertions, 12 deletions
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index b3d9a67ae..457b18351 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -144,7 +144,7 @@ class CL(object):
dir = CodeReviewDir(ui, repo)
os.unlink(dir + "/cl." + self.name)
- def Subject(self):
+ def Subject(self):
s = line1(self.desc)
if len(s) > 60:
s = s[0:55] + "..."
@@ -152,7 +152,9 @@ class CL(object):
s = "code review %s: %s" % (self.name, s)
return s
- def Upload(self, ui, repo, send_mail=False):
+ def Upload(self, ui, repo, send_mail=False, gofmt=True):
+ if ui.configbool("codereview", "force_gofmt", False) and gofmt:
+ CheckGofmt(ui, repo, self.files)
os.chdir(repo.root)
form_fields = [
("content_upload", "1"),
@@ -434,6 +436,15 @@ def ChangedFiles(ui, repo, pats, opts):
l.sort()
return l
+# Return list of changed files in repository that match pats and still exist.
+def ChangedExistingFiles(ui, repo, pats, opts):
+ matcher = cmdutil.match(repo, pats, opts)
+ node1, node2 = cmdutil.revpair(repo, None)
+ modified, added, _ = repo.status(node1, node2, matcher)[:3]
+ l = modified + added
+ l.sort()
+ return l
+
# Return list of files claimed by existing CLs
def TakenFiles(ui, repo):
return Taken(ui, repo).keys()
@@ -540,9 +551,36 @@ def ReplacementForCmdutilMatch(repo, pats=[], opts={}, globbed=False, default='r
if err != '':
raise util.Abort("loading CL " + clname + ": " + err)
files = Add(files, cl.files)
- pats = Sub(pats, taken) + ['path:'+f for f in files]
+ pats = Sub(pats, taken) + ['path:'+f for f in files]
return original_match(repo, pats=pats, opts=opts, globbed=globbed, default=default)
+def RelativePath(path, cwd):
+ n = len(cwd)
+ if path.startswith(cwd) and path[n] == '/':
+ return path[n+1:]
+ return path
+
+# Check that gofmt run on the list of files does not change them
+def CheckGofmt(ui, repo, files):
+ f = [f for f in files if f.endswith('.go')]
+ if not f:
+ return
+ cwd = os.getcwd()
+ files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
+ try:
+ stdin, stdout, stderr = os.popen3(["gofmt", "-l"] + files)
+ stdin.close()
+ except:
+ raise util.Abort("gofmt: " + ExceptionDetail())
+ data = stdout.read()
+ errors = stderr.read()
+ if len(errors) > 0:
+ ui.warn("gofmt errors:\n" + errors.rstrip() + "\n")
+ return
+ if len(data) > 0:
+ raise util.Abort("gofmt needs to format these files (run hg gofmt):\n" + data)
+ return
+
#######################################################################
# Mercurial commands
@@ -592,7 +630,7 @@ def change(ui, repo, *pats, **opts):
files = ChangedFiles(ui, repo, pats, opts)
taken = TakenFiles(ui, repo)
files = Sub(files, taken)
-
+
if opts["delete"]:
if name == "new":
return "cannot use -d with file patterns"
@@ -643,7 +681,7 @@ def change(ui, repo, *pats, **opts):
ui.write("CL created: " + cl.url + "\n")
return
-def codereview_login(ui, repo, **opts):
+def code_login(ui, repo, **opts):
"""log in to code review server
Logs in to the code review server, saving a cookie in
@@ -653,16 +691,16 @@ def codereview_login(ui, repo, **opts):
def file(ui, repo, clname, pat, *pats, **opts):
"""assign files to or remove files from a change list
-
+
Assign files to or (with -d) remove files from a change list.
-
+
The -d option only removes files from the change list.
It does not edit them or remove them from the repository.
"""
pats = tuple([pat] + list(pats))
if not GoodCLName(clname):
return "invalid CL name " + clname
-
+
dirty = {}
cl, err = LoadCL(ui, repo, clname, web=False)
if err != '':
@@ -709,8 +747,34 @@ def file(ui, repo, clname, pat, *pats, **opts):
for d, _ in dirty.items():
d.Flush(ui, repo)
return
-
+
+def gofmt(ui, repo, *pats, **opts):
+ """apply gofmt to modified files
+
+ Applies gofmt to the modified files in the repository that match
+ the given patterns.
+ """
+ files = ChangedExistingFiles(ui, repo, pats, opts)
+ files = [f for f in files if f.endswith(".go")]
+ if not files:
+ return "no modified go files"
+ cwd = os.getcwd()
+ files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
+ try:
+ if os.spawnvp(os.P_WAIT, "gofmt", ["gofmt", "-l", "-w"] + files) != 0:
+ raise util.Abort("gofmt did not exit cleanly")
+ except error.Abort, e:
+ raise
+ except:
+ raise util.Abort("gofmt: " + ExceptionDetail())
+ return
+
def mail(ui, repo, *pats, **opts):
+ """mail a change for review
+
+ Uploads a patch to the code review server and then sends mail
+ to the reviewer and CC list asking for a review.
+ """
cl, err = CommandLineCL(ui, repo, pats, opts)
if err != "":
return err
@@ -723,9 +787,14 @@ def mail(ui, repo, *pats, **opts):
PostMessage(cl.name, pmsg, send_mail="checked", subject=cl.Subject())
def nocommit(ui, repo, *pats, **opts):
+ """(disabled when using this extension)"""
return "The codereview extension is enabled; do not use commit."
def pending(ui, repo, *pats, **opts):
+ """show pending changes
+
+ Lists pending changes followed by a list of unassigned but modified files.
+ """
m = LoadAllCL(ui, repo, web=True)
names = m.keys()
names.sort()
@@ -902,6 +971,10 @@ def uisetup(ui):
commands.table["^commit|ci"] = (nocommit, [], "")
def upload(ui, repo, name, **opts):
+ """upload diffs to the code review server
+
+ Uploads the current modifications for a given change to the server.
+ """
repo.ui.quiet = True
cl, err = LoadCL(ui, repo, name, web=True)
if err != "":
@@ -931,8 +1004,11 @@ cmdtable = {
],
"[-i] [-o] change# or FILE ..."
),
- "codereview-login": (
- codereview_login,
+ # Would prefer to call this codereview-login, but then
+ # hg help codereview prints the help for this command
+ # instead of the help for the extension.
+ "code-login": (
+ code_login,
[],
"",
),
@@ -948,6 +1024,11 @@ cmdtable = {
],
"[-d] change# FILE ..."
),
+ "^gofmt": (
+ gofmt,
+ [],
+ "FILE ..."
+ ),
"^pending|p": (
pending,
[],
@@ -1198,7 +1279,7 @@ def RietveldSetup(ui, repo):
# if not ui.has_section("codereview"):
# cmdtable = {}
# return
-
+
if not ui.verbose:
verbosity = 0