codereview: sync from Go.

LGTM=rsc
R=rsc
https://codereview.appspot.com/67820044
This commit is contained in:
Shenghou Ma 2014-02-24 01:21:48 -05:00
parent 66ad987412
commit db800afb4e

View file

@ -61,6 +61,14 @@ import time
from mercurial import commands as hg_commands
from mercurial import util as hg_util
# bind Plan 9 preferred dotfile location
if os.sys.platform == 'plan9':
try:
import plan9
n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)
except ImportError:
pass
defaultcc = None
codereview_disabled = None
real_rollback = None
@ -155,7 +163,8 @@ default_to_utf8()
global_status = None
def set_status(s):
# print >>sys.stderr, "\t", time.asctime(), s
if verbosity > 0:
print >>sys.stderr, time.asctime(), s
global global_status
global_status = s
@ -268,7 +277,7 @@ class CL(object):
s += "\tAuthor: " + cl.copied_from + "\n"
if not quick:
s += "\tReviewer: " + JoinComma(cl.reviewer) + "\n"
for (who, line) in cl.lgtm:
for (who, line, _) in cl.lgtm:
s += "\t\t" + who + ": " + line + "\n"
s += "\tCC: " + JoinComma(cl.cc) + "\n"
s += "\tFiles:\n"
@ -358,6 +367,8 @@ class CL(object):
msg = lines[0]
patchset = lines[1].strip()
patches = [x.split(" ", 1) for x in lines[2:]]
else:
print >>sys.stderr, "Server says there is nothing to upload (probably wrong):\n" + msg
if response_body.startswith("Issue updated.") and quiet:
pass
else:
@ -484,9 +495,15 @@ def CutDomain(s):
return s
def JoinComma(l):
seen = {}
uniq = []
for s in l:
typecheck(s, str)
return ", ".join(l)
if s not in seen:
seen[s] = True
uniq.append(s)
return ", ".join(uniq)
def ExceptionDetail():
s = str(sys.exc_info()[0])
@ -544,10 +561,10 @@ def LoadCL(ui, repo, name, web=True):
cl.private = d.get('private', False) != False
cl.lgtm = []
for m in d.get('messages', []):
if m.get('approval', False) == True:
if m.get('approval', False) == True or m.get('disapproval', False) == True:
who = re.sub('@.*', '', m.get('sender', ''))
text = re.sub("\n(.|\n)*", '', m.get('text', ''))
cl.lgtm.append((who, text))
cl.lgtm.append((who, text, m.get('approval', False)))
set_status("loaded CL " + name)
return cl, ''
@ -711,7 +728,10 @@ Examples:
'''
def promptyesno(ui, msg):
return ui.promptchoice(msg, ["&yes", "&no"], 0) == 0
if hgversion >= "2.7":
return ui.promptchoice(msg + " $$ &yes $$ &no", 0) == 0
else:
return ui.promptchoice(msg, ["&yes", "&no"], 0) == 0
def promptremove(ui, repo, f):
if promptyesno(ui, "hg remove %s (y/n)?" % (f,)):
@ -807,7 +827,7 @@ def EditCL(ui, repo, cl):
# For use by submit, etc. (NOT by change)
# Get change list number or list of files from command line.
# If files are given, make a new change list.
def CommandLineCL(ui, repo, pats, opts, defaultcc=None):
def CommandLineCL(ui, repo, pats, opts, op="verb", defaultcc=None):
if len(pats) > 0 and GoodCLName(pats[0]):
if len(pats) != 1:
return None, "cannot specify change number and file names"
@ -821,7 +841,7 @@ def CommandLineCL(ui, repo, pats, opts, defaultcc=None):
cl.local = True
cl.files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo))
if not cl.files:
return None, "no files changed"
return None, "no files changed (use hg %s <number> to use existing CL)" % op
if opts.get('reviewer'):
cl.reviewer = Add(cl.reviewer, SplitCommaSpace(opts.get('reviewer')))
if opts.get('cc'):
@ -972,7 +992,7 @@ def ReadContributors(ui, repo):
f = open(repo.root + '/CONTRIBUTORS', 'r')
except:
ui.write("warning: cannot open %s: %s\n" % (opening, ExceptionDetail()))
return
return {}
contributors = {}
for line in f:
@ -1027,23 +1047,19 @@ def FindContributor(ui, repo, user=None, warn=True):
hgversion = hg_util.version()
# We require Mercurial 1.9 and suggest Mercurial 2.0.
# We require Mercurial 1.9 and suggest Mercurial 2.1.
# The details of the scmutil package changed then,
# so allowing earlier versions would require extra band-aids below.
# Ubuntu 11.10 ships with Mercurial 1.9.1 as the default version.
hg_required = "1.9"
hg_suggested = "2.0"
hg_suggested = "2.1"
old_message = """
The code review extension requires Mercurial """+hg_required+""" or newer.
You are using Mercurial """+hgversion+""".
To install a new Mercurial, use
sudo easy_install mercurial=="""+hg_suggested+"""
or visit http://mercurial.selenic.com/downloads/.
To install a new Mercurial, visit http://mercurial.selenic.com/downloads/.
"""
linux_message = """
@ -1171,6 +1187,25 @@ def hg_pull(ui, repo, **opts):
ui.write(line + '\n')
return err
def hg_update(ui, repo, **opts):
w = uiwrap(ui)
ui.quiet = False
ui.verbose = True # for file list
err = hg_commands.update(ui, repo, **opts)
for line in w.output().split('\n'):
if isNoise(line):
continue
if line.startswith('moving '):
line = 'mv ' + line[len('moving '):]
if line.startswith('getting ') and line.find(' to ') >= 0:
line = 'mv ' + line[len('getting '):]
if line.startswith('getting '):
line = '+ ' + line[len('getting '):]
if line.startswith('removing '):
line = '- ' + line[len('removing '):]
ui.write(line + '\n')
return err
def hg_push(ui, repo, **opts):
w = uiwrap(ui)
ui.quiet = False
@ -1190,6 +1225,10 @@ def hg_commit(ui, repo, *pats, **opts):
commit_okay = False
def precommithook(ui, repo, **opts):
if hgversion >= "2.1":
from mercurial import phases
if repo.ui.config('phases', 'new-commit') >= phases.secret:
return False
if commit_okay:
return False # False means okay.
ui.write("\ncodereview extension enabled; use mail, upload, or submit instead of commit\n\n")
@ -1247,24 +1286,8 @@ def MatchAt(ctx, pats=None, opts=None, globbed=False, default='relpath'):
#######################################################################
# Commands added by code review extension.
# As of Mercurial 2.1 the commands are all required to return integer
# exit codes, whereas earlier versions allowed returning arbitrary strings
# to be printed as errors. We wrap the old functions to make sure we
# always return integer exit codes now. Otherwise Mercurial dies
# with a TypeError traceback (unsupported operand type(s) for &: 'str' and 'int').
# Introduce a Python decorator to convert old functions to the new
# stricter convention.
def hgcommand(f):
def wrapped(ui, repo, *pats, **opts):
err = f(ui, repo, *pats, **opts)
if type(err) is int:
return err
if not err:
return 0
raise hg_util.Abort(err)
wrapped.__doc__ = f.__doc__
return wrapped
return f
#######################################################################
# hg change
@ -1293,42 +1316,42 @@ def change(ui, repo, *pats, **opts):
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
dirty = {}
if len(pats) > 0 and GoodCLName(pats[0]):
name = pats[0]
if len(pats) != 1:
return "cannot specify CL name and file patterns"
raise hg_util.Abort("cannot specify CL name and file patterns")
pats = pats[1:]
cl, err = LoadCL(ui, repo, name, web=True)
if err != '':
return err
raise hg_util.Abort(err)
if not cl.local and (opts["stdin"] or not opts["stdout"]):
return "cannot change non-local CL " + name
raise hg_util.Abort("cannot change non-local CL " + name)
else:
name = "new"
cl = CL("new")
if repo[None].branch() != "default":
return "cannot create CL outside default branch; switch with 'hg update default'"
raise hg_util.Abort("cannot create CL outside default branch; switch with 'hg update default'")
dirty[cl] = True
files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo))
if opts["delete"] or opts["deletelocal"]:
if opts["delete"] and opts["deletelocal"]:
return "cannot use -d and -D together"
raise hg_util.Abort("cannot use -d and -D together")
flag = "-d"
if opts["deletelocal"]:
flag = "-D"
if name == "new":
return "cannot use "+flag+" with file patterns"
raise hg_util.Abort("cannot use "+flag+" with file patterns")
if opts["stdin"] or opts["stdout"]:
return "cannot use "+flag+" with -i or -o"
raise hg_util.Abort("cannot use "+flag+" with -i or -o")
if not cl.local:
return "cannot change non-local CL " + name
raise hg_util.Abort("cannot change non-local CL " + name)
if opts["delete"]:
if cl.copied_from:
return "original author must delete CL; hg change -D will remove locally"
raise hg_util.Abort("original author must delete CL; hg change -D will remove locally")
PostMessage(ui, cl.name, "*** Abandoned ***", send_mail=cl.mailed)
EditDesc(cl.name, closed=True, private=cl.private)
cl.Delete(ui, repo)
@ -1338,7 +1361,7 @@ def change(ui, repo, *pats, **opts):
s = sys.stdin.read()
clx, line, err = ParseCL(s, name)
if err != '':
return "error parsing change list: line %d: %s" % (line, err)
raise hg_util.Abort("error parsing change list: line %d: %s" % (line, err))
if clx.desc is not None:
cl.desc = clx.desc;
dirty[cl] = True
@ -1360,7 +1383,7 @@ def change(ui, repo, *pats, **opts):
cl.files = files
err = EditCL(ui, repo, cl)
if err != "":
return err
raise hg_util.Abort(err)
dirty[cl] = True
for d, _ in dirty.items():
@ -1391,7 +1414,7 @@ def code_login(ui, repo, **opts):
a file in your home directory.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
MySend(None)
@ -1411,8 +1434,10 @@ def clpatch(ui, repo, clname, **opts):
name as the Author: line but add your own name to a Committer: line.
"""
if repo[None].branch() != "default":
return "cannot run hg clpatch outside default branch"
return clpatch_or_undo(ui, repo, clname, opts, mode="clpatch")
raise hg_util.Abort("cannot run hg clpatch outside default branch")
err = clpatch_or_undo(ui, repo, clname, opts, mode="clpatch")
if err:
raise hg_util.Abort(err)
@hgcommand
def undo(ui, repo, clname, **opts):
@ -1423,8 +1448,10 @@ def undo(ui, repo, clname, **opts):
you can add the reason for the undo to the description.
"""
if repo[None].branch() != "default":
return "cannot run hg undo outside default branch"
return clpatch_or_undo(ui, repo, clname, opts, mode="undo")
raise hg_util.Abort("cannot run hg undo outside default branch")
err = clpatch_or_undo(ui, repo, clname, opts, mode="undo")
if err:
raise hg_util.Abort(err)
@hgcommand
def release_apply(ui, repo, clname, **opts):
@ -1468,13 +1495,13 @@ def release_apply(ui, repo, clname, **opts):
"""
c = repo[None]
if not releaseBranch:
return "no active release branches"
raise hg_util.Abort("no active release branches")
if c.branch() != releaseBranch:
if c.modified() or c.added() or c.removed():
raise hg_util.Abort("uncommitted local changes - cannot switch branches")
err = hg_clean(repo, releaseBranch)
if err:
return err
raise hg_util.Abort(err)
try:
err = clpatch_or_undo(ui, repo, clname, opts, mode="backport")
if err:
@ -1482,13 +1509,12 @@ def release_apply(ui, repo, clname, **opts):
except Exception, e:
hg_clean(repo, "default")
raise e
return None
def rev2clname(rev):
# Extract CL name from revision description.
# The last line in the description that is a codereview URL is the real one.
# Earlier lines might be part of the user-written description.
all = re.findall('(?m)^http://codereview.appspot.com/([0-9]+)$', rev.description())
all = re.findall('(?m)^https?://codereview.appspot.com/([0-9]+)$', rev.description())
if len(all) > 0:
return all[-1]
return ""
@ -1586,24 +1612,24 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
return "local repository is out of date; sync to get %s" % (vers)
patch1, err = portPatch(repo, patch, vers, id)
if err != "":
if not opts["ignore_hgpatch_failure"]:
if not opts["ignore_hgapplydiff_failure"]:
return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
else:
patch = patch1
argv = ["hgpatch"]
argv = ["hgapplydiff"]
if opts["no_incoming"] or mode == "backport":
argv += ["--checksync=false"]
try:
cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
except:
return "hgpatch: " + ExceptionDetail() + "\nInstall hgpatch with:\n$ go get code.google.com/p/go.codereview/cmd/hgpatch\n"
return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get code.google.com/p/go.codereview/cmd/hgapplydiff\n"
out, err = cmd.communicate(patch)
if cmd.returncode != 0 and not opts["ignore_hgpatch_failure"]:
return "hgpatch failed"
if cmd.returncode != 0 and not opts["ignore_hgapplydiff_failure"]:
return "hgapplydiff failed"
cl.local = True
cl.files = out.strip().split()
if not cl.files and not opts["ignore_hgpatch_failure"]:
if not cl.files and not opts["ignore_hgapplydiff_failure"]:
return "codereview issue %s has no changed files" % clname
files = ChangedFiles(ui, repo, [])
extra = Sub(cl.files, files)
@ -1618,6 +1644,17 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
else:
ui.write(cl.PendingText() + "\n")
# warn if clpatch will modify file already in another CL (it's unsafe to submit them)
if mode == "clpatch":
msgs = []
cls = LoadAllCL(ui, repo, web=False)
for k, v in cls.iteritems():
isec = Intersect(v.files, cl.files)
if isec and k != clname:
msgs.append("CL " + k + ", because it also modifies " + ", ".join(isec) + ".")
if msgs:
ui.warn("warning: please double check before submitting this CL and:\n\t" + "\n\t".join(msgs) + "\n")
# portPatch rewrites patch from being a patch against
# oldver to being a patch against newver.
def portPatch(repo, patch, oldver, newver):
@ -1687,7 +1724,7 @@ def download(ui, repo, clname, **opts):
followed by its diff, downloaded from the code review server.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
cl, vers, patch, err = DownloadCL(ui, repo, clname)
if err != "":
@ -1709,7 +1746,7 @@ def file(ui, repo, clname, pat, *pats, **opts):
It does not edit them or remove them from the repository.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
pats = tuple([pat] + list(pats))
if not GoodCLName(clname):
@ -1773,19 +1810,20 @@ def gofmt(ui, repo, *pats, **opts):
the given patterns.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
files = ChangedExistingFiles(ui, repo, pats, opts)
files = gofmt_required(files)
if not files:
return "no modified go files"
ui.status("no modified go files\n")
return
cwd = os.getcwd()
files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
try:
cmd = ["gofmt", "-l"]
if not opts["list"]:
cmd += ["-w"]
if os.spawnvp(os.P_WAIT, "gofmt", cmd + files) != 0:
if subprocess.call(cmd + files) != 0:
raise hg_util.Abort("gofmt did not exit cleanly")
except hg_error.Abort, e:
raise
@ -1807,11 +1845,11 @@ def mail(ui, repo, *pats, **opts):
to the reviewer and CC list asking for a review.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc)
cl, err = CommandLineCL(ui, repo, pats, opts, op="mail", defaultcc=defaultcc)
if err != "":
return err
raise hg_util.Abort(err)
cl.Upload(ui, repo, gofmt_just_warn=True)
if not cl.reviewer:
# If no reviewer is listed, assign the review to defaultcc.
@ -1819,15 +1857,15 @@ def mail(ui, repo, *pats, **opts):
# codereview.appspot.com/user/defaultcc
# page, so that it doesn't get dropped on the floor.
if not defaultcc:
return "no reviewers listed in CL"
raise hg_util.Abort("no reviewers listed in CL")
cl.cc = Sub(cl.cc, defaultcc)
cl.reviewer = defaultcc
cl.Flush(ui, repo)
if cl.files == []:
return "no changed files, not sending mail"
raise hg_util.Abort("no changed files, not sending mail")
cl.Mail(ui, repo)
cl.Mail(ui, repo)
#######################################################################
# hg p / hg pq / hg ps / hg pending
@ -1853,7 +1891,7 @@ def pending(ui, repo, *pats, **opts):
Lists pending changes followed by a list of unassigned but modified files.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
quick = opts.get('quick', False)
short = opts.get('short', False)
@ -1868,7 +1906,7 @@ def pending(ui, repo, *pats, **opts):
ui.write(cl.PendingText(quick=quick) + "\n")
if short:
return
return 0
files = DefaultFiles(ui, repo, [])
if len(files) > 0:
s = "Changed files not in any CL:\n"
@ -1890,7 +1928,7 @@ def submit(ui, repo, *pats, **opts):
Bails out if the local repository is not in sync with the remote one.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
# We already called this on startup but sometimes Mercurial forgets.
set_mercurial_encoding_to_utf8()
@ -1898,9 +1936,9 @@ def submit(ui, repo, *pats, **opts):
if not opts["no_incoming"] and hg_incoming(ui, repo):
need_sync()
cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc)
cl, err = CommandLineCL(ui, repo, pats, opts, op="submit", defaultcc=defaultcc)
if err != "":
return err
raise hg_util.Abort(err)
user = None
if cl.copied_from:
@ -1909,20 +1947,29 @@ def submit(ui, repo, *pats, **opts):
typecheck(userline, str)
about = ""
if cl.reviewer:
about += "R=" + JoinComma([CutDomain(s) for s in cl.reviewer]) + "\n"
if not cl.lgtm and not opts.get('tbr') and not isAddca(cl):
raise hg_util.Abort("this CL has not been LGTM'ed")
if cl.lgtm:
about += "LGTM=" + JoinComma([CutDomain(who) for (who, line, approval) in cl.lgtm if approval]) + "\n"
reviewer = cl.reviewer
if opts.get('tbr'):
tbr = SplitCommaSpace(opts.get('tbr'))
for name in tbr:
if name.startswith('golang-'):
raise hg_util.Abort("--tbr requires a person, not a mailing list")
cl.reviewer = Add(cl.reviewer, tbr)
about += "TBR=" + JoinComma([CutDomain(s) for s in tbr]) + "\n"
if reviewer:
about += "R=" + JoinComma([CutDomain(s) for s in reviewer]) + "\n"
if cl.cc:
about += "CC=" + JoinComma([CutDomain(s) for s in cl.cc]) + "\n"
if not cl.reviewer:
return "no reviewers listed in CL"
raise hg_util.Abort("no reviewers listed in CL")
if not cl.local:
return "cannot submit non-local CL"
raise hg_util.Abort("cannot submit non-local CL")
# upload, to sync current patch and also get change number if CL is new.
if not cl.copied_from:
@ -1957,7 +2004,7 @@ def submit(ui, repo, *pats, **opts):
ret = hg_commit(ui, repo, *['path:'+f for f in cl.files], message=message, user=userline)
commit_okay = False
if ret:
return "nothing changed"
raise hg_util.Abort("nothing changed")
node = repo["-1"].node()
# push to remote; if it fails for any reason, roll back
try:
@ -1968,12 +2015,16 @@ def submit(ui, repo, *pats, **opts):
# Push changes to remote. If it works, we're committed. If not, roll back.
try:
hg_push(ui, repo)
if hg_push(ui, repo):
raise hg_util.Abort("push error")
except hg_error.Abort, e:
if e.message.find("push creates new heads") >= 0:
# Remote repository had changes we missed.
need_sync()
raise
except urllib2.HTTPError, e:
print >>sys.stderr, "pushing to remote server failed; do you have commit permissions?"
raise
except:
real_rollback()
raise
@ -1985,11 +2036,11 @@ def submit(ui, repo, *pats, **opts):
"(^https?://([^@/]+@)?code\.google\.com/p/([^/.]+)(\.[^./]+)?/?)", url)
if m:
if m.group(1): # prj.googlecode.com/hg/ case
changeURL = "http://code.google.com/p/%s/source/detail?r=%s" % (m.group(3), changeURL)
changeURL = "https://code.google.com/p/%s/source/detail?r=%s" % (m.group(3), changeURL)
elif m.group(4) and m.group(7): # code.google.com/p/prj.subrepo/ case
changeURL = "http://code.google.com/p/%s/source/detail?r=%s&repo=%s" % (m.group(6), changeURL, m.group(7)[1:])
changeURL = "https://code.google.com/p/%s/source/detail?r=%s&repo=%s" % (m.group(6), changeURL, m.group(7)[1:])
elif m.group(4): # code.google.com/p/prj/ case
changeURL = "http://code.google.com/p/%s/source/detail?r=%s" % (m.group(6), changeURL)
changeURL = "https://code.google.com/p/%s/source/detail?r=%s" % (m.group(6), changeURL)
else:
print >>sys.stderr, "URL: ", url
else:
@ -2010,7 +2061,12 @@ def submit(ui, repo, *pats, **opts):
err = hg_clean(repo, "default")
if err:
return err
return None
return 0
def isAddca(cl):
rev = cl.reviewer
isGobot = 'gobot' in rev or 'gobot@swtch.com' in rev or 'gobot@golang.org' in rev
return cl.desc.startswith('A+C:') and 'Generated by addca.' in cl.desc and isGobot
#######################################################################
# hg sync
@ -2023,10 +2079,22 @@ def sync(ui, repo, **opts):
into the local repository.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
if not opts["local"]:
err = hg_pull(ui, repo, update=True)
# If there are incoming CLs, pull -u will do the update.
# If there are no incoming CLs, do hg update to make sure
# that an update always happens regardless. This is less
# surprising than update depending on incoming CLs.
# It is important not to do both hg pull -u and hg update
# in the same command, because the hg update will end
# up marking resolve conflicts from the hg pull -u as resolved,
# causing files with <<< >>> markers to not show up in
# hg resolve -l. Yay Mercurial.
if hg_incoming(ui, repo):
err = hg_pull(ui, repo, update=True)
else:
err = hg_update(ui, repo)
if err:
return err
sync_changes(ui, repo)
@ -2037,7 +2105,7 @@ def sync_changes(ui, repo):
# Double-check them by looking at the Rietveld log.
for rev in hg_log(ui, repo, limit=100, template="{node}\n").split():
desc = repo[rev].description().strip()
for clname in re.findall('(?m)^http://(?:[^\n]+)/([0-9]+)$', desc):
for clname in re.findall('(?m)^https?://(?:[^\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)
@ -2064,7 +2132,7 @@ def sync_changes(ui, repo):
ui.warn("CL %s has no files; delete (abandon) with hg change -d %s\n" % (cl.name, cl.name))
else:
ui.warn("CL %s has no files; delete locally with hg change -D %s\n" % (cl.name, cl.name))
return
return 0
#######################################################################
# hg upload
@ -2076,17 +2144,17 @@ def upload(ui, repo, name, **opts):
Uploads the current modifications for a given change to the server.
"""
if codereview_disabled:
return codereview_disabled
raise hg_util.Abort(codereview_disabled)
repo.ui.quiet = True
cl, err = LoadCL(ui, repo, name, web=True)
if err != "":
return err
raise hg_util.Abort(err)
if not cl.local:
return "cannot upload non-local change"
raise hg_util.Abort("cannot upload non-local change")
cl.Upload(ui, repo)
print "%s%s\n" % (server_url_base, cl.name)
return
return 0
#######################################################################
# Table of commands, supplied to Mercurial for installation.
@ -2115,7 +2183,7 @@ cmdtable = {
"^clpatch": (
clpatch,
[
('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
('', 'no_incoming', None, 'disable check for incoming changes'),
],
"change#"
@ -2174,7 +2242,7 @@ cmdtable = {
"^release-apply": (
release_apply,
[
('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
('', 'no_incoming', None, 'disable check for incoming changes'),
],
"change#"
@ -2197,7 +2265,7 @@ cmdtable = {
"^undo": (
undo,
[
('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
('', 'no_incoming', None, 'disable check for incoming changes'),
],
"change#"
@ -2229,6 +2297,7 @@ def reposetup(ui, repo):
if codereview_init:
return
codereview_init = True
start_status_thread()
# Read repository-specific options from lib/codereview/codereview.cfg or codereview.cfg.
root = ''
@ -2366,7 +2435,7 @@ def IsRietveldSubmitted(ui, clname, hex):
return False
for msg in dict.get("messages", []):
text = msg.get("text", "")
m = re.match('\*\*\* Submitted as [^*]*?([0-9a-f]+) \*\*\*', text)
m = re.match('\*\*\* Submitted as [^*]*?r=([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
@ -2460,6 +2529,8 @@ def MySend1(request_path, payload=None,
self._Authenticate()
if request_path is None:
return
if timeout is None:
timeout = 30 # seconds
old_timeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(timeout)
@ -2468,7 +2539,7 @@ def MySend1(request_path, payload=None,
while True:
tries += 1
args = dict(kwargs)
url = "http://%s%s" % (self.host, request_path)
url = "https://%s%s" % (self.host, request_path)
if args:
url += "?" + urllib.urlencode(args)
req = self._CreateRequest(url=url, data=payload)
@ -2580,7 +2651,7 @@ def RietveldSetup(ui, repo):
if x is not None:
email = x
server_url_base = "http://" + server + "/"
server_url_base = "https://" + server + "/"
testing = ui.config("codereview", "testing")
force_google_account = ui.configbool("codereview", "force_google_account", False)
@ -2609,7 +2680,7 @@ def RietveldSetup(ui, repo):
rpc = None
global releaseBranch
tags = repo.branchtags().keys()
tags = repo.branchmap().keys()
if 'release-branch.go10' in tags:
# NOTE(rsc): This tags.sort is going to get the wrong
# answer when comparing release-branch.go9 with
@ -2755,7 +2826,9 @@ class ClientLoginError(urllib2.HTTPError):
def __init__(self, url, code, msg, headers, args):
urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
self.args = args
self.reason = args["Error"]
# .reason is now a read-only property based on .msg
# this means we ignore 'msg', but that seems to work fine.
self.msg = args["Error"]
class AbstractRpcServer(object):
@ -2858,7 +2931,7 @@ class AbstractRpcServer(object):
# This is a dummy value to allow us to identify when we're successful.
continue_location = "http://localhost/"
args = {"continue": continue_location, "auth": auth_token}
req = self._CreateRequest("http://%s/_ah/login?%s" % (self.host, urllib.urlencode(args)))
req = self._CreateRequest("https://%s/_ah/login?%s" % (self.host, urllib.urlencode(args)))
try:
response = self.opener.open(req)
except urllib2.HTTPError, e:
@ -2888,31 +2961,31 @@ class AbstractRpcServer(object):
try:
auth_token = self._GetAuthToken(credentials[0], credentials[1])
except ClientLoginError, e:
if e.reason == "BadAuthentication":
if e.msg == "BadAuthentication":
print >>sys.stderr, "Invalid username or password."
continue
if e.reason == "CaptchaRequired":
if e.msg == "CaptchaRequired":
print >>sys.stderr, (
"Please go to\n"
"https://www.google.com/accounts/DisplayUnlockCaptcha\n"
"and verify you are a human. Then try again.")
break
if e.reason == "NotVerified":
if e.msg == "NotVerified":
print >>sys.stderr, "Account not verified."
break
if e.reason == "TermsNotAgreed":
if e.msg == "TermsNotAgreed":
print >>sys.stderr, "User has not agreed to TOS."
break
if e.reason == "AccountDeleted":
if e.msg == "AccountDeleted":
print >>sys.stderr, "The user account has been deleted."
break
if e.reason == "AccountDisabled":
if e.msg == "AccountDisabled":
print >>sys.stderr, "The user account has been disabled."
break
if e.reason == "ServiceDisabled":
if e.msg == "ServiceDisabled":
print >>sys.stderr, "The user's access to the service has been disabled."
break
if e.reason == "ServiceUnavailable":
if e.msg == "ServiceUnavailable":
print >>sys.stderr, "The service is not available; try again later."
break
raise
@ -2948,7 +3021,7 @@ class AbstractRpcServer(object):
while True:
tries += 1
args = dict(kwargs)
url = "http://%s%s" % (self.host, request_path)
url = "https://%s%s" % (self.host, request_path)
if args:
url += "?" + urllib.urlencode(args)
req = self._CreateRequest(url=url, data=payload)