mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
0649f5c865
Upcoming patches will switch to the new-style command decorator instead of the explicit command table. That doesn't mesh well with top-level command functions defined in other modules.
101 lines
3.2 KiB
Python
101 lines
3.2 KiB
Python
# verify.py - verify Mercurial revisions
|
|
#
|
|
# Copyright 2014 Facebook.
|
|
#
|
|
# This software may be used and distributed according to the terms
|
|
# of the GNU General Public License, incorporated herein by reference.
|
|
|
|
import stat
|
|
|
|
from mercurial import error
|
|
from mercurial import util as hgutil
|
|
from mercurial.node import hex, bin, nullid
|
|
from mercurial.i18n import _
|
|
from mercurial import scmutil
|
|
|
|
from dulwich import diff_tree
|
|
from dulwich.objects import Commit, S_IFGITLINK
|
|
|
|
def verify(ui, repo, hgctx):
|
|
'''verify that a Mercurial rev matches the corresponding Git rev
|
|
|
|
Given a Mercurial revision that has a corresponding Git revision in the map,
|
|
this attempts to answer whether that revision has the same contents as the
|
|
corresponding Git revision.
|
|
|
|
'''
|
|
handler = repo.githandler
|
|
|
|
gitsha = handler.map_git_get(hgctx.hex())
|
|
if not gitsha:
|
|
# TODO deal better with commits in the middle of octopus merges
|
|
raise hgutil.Abort(_('no git commit found for rev %s') % hgctx,
|
|
hint=_('if this is an octopus merge, verify against the last rev'))
|
|
|
|
try:
|
|
gitcommit = handler.git.get_object(gitsha)
|
|
except KeyError:
|
|
raise hgutil.Abort(_('git equivalent %s for rev %s not found!') %
|
|
(gitsha, hgctx))
|
|
if not isinstance(gitcommit, Commit):
|
|
raise hgutil.Abort(_('git equivalent %s for rev %s is not a commit!') %
|
|
(gitsha, hgctx))
|
|
|
|
ui.status(_('verifying rev %s against git commit %s\n') % (hgctx, gitsha))
|
|
failed = False
|
|
|
|
# TODO check commit message and other metadata
|
|
|
|
dirkind = stat.S_IFDIR
|
|
|
|
hgfiles = set(hgctx)
|
|
# TODO deal with submodules
|
|
hgfiles.discard('.hgsubstate')
|
|
hgfiles.discard('.hgsub')
|
|
gitfiles = set()
|
|
|
|
i = 0
|
|
for gitfile, dummy in diff_tree.walk_trees(handler.git.object_store,
|
|
gitcommit.tree, None):
|
|
if gitfile.mode == dirkind:
|
|
continue
|
|
# TODO deal with submodules
|
|
if (gitfile.mode == S_IFGITLINK or gitfile.path == '.hgsubstate'
|
|
or gitfile.path == '.hgsub'):
|
|
continue
|
|
ui.progress('verify', i, total=len(hgfiles))
|
|
i += 1
|
|
gitfiles.add(gitfile.path)
|
|
|
|
try:
|
|
fctx = hgctx[gitfile.path]
|
|
except error.LookupError:
|
|
# we'll deal with this at the end
|
|
continue
|
|
|
|
hgflags = fctx.flags()
|
|
gitflags = handler.convert_git_int_mode(gitfile.mode)
|
|
if hgflags != gitflags:
|
|
ui.write(_("file has different flags: %s (hg '%s', git '%s')\n") %
|
|
(gitfile.path, hgflags, gitflags))
|
|
failed = True
|
|
if fctx.data() != handler.git[gitfile.sha].data:
|
|
ui.write(_('difference in: %s\n') % gitfile.path)
|
|
failed = True
|
|
|
|
ui.progress('verify', None, total=len(hgfiles))
|
|
|
|
if hgfiles != gitfiles:
|
|
failed = True
|
|
missing = gitfiles - hgfiles
|
|
for f in sorted(missing):
|
|
ui.write(_('file found in git but not hg: %s\n') % f)
|
|
unexpected = hgfiles - gitfiles
|
|
for f in sorted(unexpected):
|
|
ui.write(_('file found in hg but not git: %s\n') % f)
|
|
|
|
if failed:
|
|
return 1
|
|
else:
|
|
return 0
|