Commit 1fa87ada authored by Russ Cox's avatar Russ Cox

codereview: extra repo sanity check

Also work around Mercurial issue 3023.

If anyone has local changes in their repo (due to
patch queues or whatever) stop them from leaking
into the main repository.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5144043
parent ba444d84
...@@ -38,7 +38,7 @@ For example, if change 123456 contains the files x.go and y.go, ...@@ -38,7 +38,7 @@ For example, if change 123456 contains the files x.go and y.go,
"hg diff @123456" is equivalent to"hg diff x.go y.go". "hg diff @123456" is equivalent to"hg diff x.go y.go".
''' '''
from mercurial import cmdutil, commands, hg, util, error, match from mercurial import cmdutil, commands, hg, util, error, match, discovery
from mercurial.node import nullrev, hex, nullid, short from mercurial.node import nullrev, hex, nullid, short
import os, re, time import os, re, time
import stat import stat
...@@ -71,9 +71,12 @@ except: ...@@ -71,9 +71,12 @@ except:
try: try:
from mercurial.discovery import findcommonincoming from mercurial.discovery import findcommonincoming
from mercurial.discovery import findoutgoing
except: except:
def findcommonincoming(repo, remote): def findcommonincoming(repo, remote):
return repo.findcommonincoming(remote) return repo.findcommonincoming(remote)
def findoutgoing(repo, remote):
return repo.findoutgoing(remote)
# in Mercurial 1.9 the cmdutil.match and cmdutil.revpair moved to scmutil # in Mercurial 1.9 the cmdutil.match and cmdutil.revpair moved to scmutil
if hgversion >= '1.9': if hgversion >= '1.9':
...@@ -1738,6 +1741,11 @@ def submit(ui, repo, *pats, **opts): ...@@ -1738,6 +1741,11 @@ def submit(ui, repo, *pats, **opts):
return "dry run; not submitted" return "dry run; not submitted"
set_status("pushing " + cl.name + " to remote server") set_status("pushing " + cl.name + " to remote server")
other = getremote(ui, repo, opts)
if findoutgoing(repo, other):
raise util.Abort("local repository corrupt or out-of-phase with remote: found outgoing changes")
m = match.exact(repo.root, repo.getcwd(), cl.files) m = match.exact(repo.root, repo.getcwd(), cl.files)
node = repo.commit(ustr(opts['message']), ustr(userline), opts.get('date'), m) node = repo.commit(ustr(opts['message']), ustr(userline), opts.get('date'), m)
if not node: if not node:
...@@ -1758,7 +1766,6 @@ def submit(ui, repo, *pats, **opts): ...@@ -1758,7 +1766,6 @@ def submit(ui, repo, *pats, **opts):
# push changes to remote. # push changes to remote.
# if it works, we're committed. # if it works, we're committed.
# if not, roll back # if not, roll back
other = getremote(ui, repo, opts)
r = repo.push(other, False, None) r = repo.push(other, False, None)
if r == 0: if r == 0:
raise util.Abort("local repository out of date; must sync before submit") raise util.Abort("local repository out of date; must sync before submit")
...@@ -3130,6 +3137,7 @@ class MercurialVCS(VersionControlSystem): ...@@ -3130,6 +3137,7 @@ class MercurialVCS(VersionControlSystem):
super(MercurialVCS, self).__init__(options) super(MercurialVCS, self).__init__(options)
self.ui = ui self.ui = ui
self.repo = repo self.repo = repo
self.status = None
# Absolute path to repository (we can be in a subdir) # Absolute path to repository (we can be in a subdir)
self.repo_dir = os.path.normpath(repo.root) self.repo_dir = os.path.normpath(repo.root)
# Compute the subdir # Compute the subdir
...@@ -3188,6 +3196,33 @@ class MercurialVCS(VersionControlSystem): ...@@ -3188,6 +3196,33 @@ class MercurialVCS(VersionControlSystem):
unknown_files.append(fn) unknown_files.append(fn)
return unknown_files return unknown_files
def get_hg_status(self, rev, path):
# We'd like to use 'hg status -C path', but that is buggy
# (see http://mercurial.selenic.com/bts/issue3023).
# Instead, run 'hg status -C' without a path
# and skim the output for the path we want.
if self.status is None:
if use_hg_shell:
out = RunShell(["hg", "status", "-C", "--rev", rev])
else:
fui = FakeMercurialUI()
ret = commands.status(fui, self.repo, *[], **{'rev': [rev], 'copies': True})
if ret:
raise util.Abort(ret)
out = fui.output
self.status = out.splitlines()
for i in range(len(self.status)):
# line is
# A path
# M path
# etc
line = self.status[i]
if line[2:] == path:
if i+1 < len(self.status) and self.status[i+1][:2] == ' ':
return self.status[i:i+2]
return self.status[i:i+1]
raise util.Abort("no status for " + path)
def GetBaseFile(self, filename): def GetBaseFile(self, filename):
set_status("inspecting " + filename) set_status("inspecting " + filename)
# "hg status" and "hg cat" both take a path relative to the current subdir # "hg status" and "hg cat" both take a path relative to the current subdir
...@@ -3197,20 +3232,7 @@ class MercurialVCS(VersionControlSystem): ...@@ -3197,20 +3232,7 @@ class MercurialVCS(VersionControlSystem):
new_content = None new_content = None
is_binary = False is_binary = False
oldrelpath = relpath = self._GetRelPath(filename) oldrelpath = relpath = self._GetRelPath(filename)
# "hg status -C" returns two lines for moved/copied files, one otherwise out = self.get_hg_status(self.base_rev, relpath)
if use_hg_shell:
out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
else:
fui = FakeMercurialUI()
ret = commands.status(fui, self.repo, *[relpath], **{'rev': [self.base_rev], 'copies': True})
if ret:
raise util.Abort(ret)
out = fui.output
out = out.splitlines()
# HACK: strip error message about missing file/directory if it isn't in
# the working copy
if out[0].startswith('%s: ' % relpath):
out = out[1:]
status, what = out[0].split(' ', 1) status, what = out[0].split(' ', 1)
if len(out) > 1 and status == "A" and what == relpath: if len(out) > 1 and status == "A" and what == relpath:
oldrelpath = out[1].strip() oldrelpath = out[1].strip()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment