Commit e37947de authored by Dan Villiom Podlaski Christiansen's avatar Dan Villiom Podlaski Christiansen
Browse files

compat: remove compatibility hacks for mercurial < 5.2

parent 51484ad0486d
Pipeline #21384 passed with stages
in 16 minutes and 24 seconds
......@@ -118,7 +118,6 @@ from mercurial.node import bin, hex, nullhex
from mercurial.i18n import _
from mercurial import (
bundlerepo,
cmdutil,
commands,
demandimport,
dirstate,
......@@ -132,46 +131,29 @@ from mercurial import (
localrepo,
manifest,
pycompat,
registrar,
repoview,
revset,
scmutil,
templatekw,
)
# COMPAT: hg 4.7 - demandimport.ignore was renamed to demandimport.IGNORES and
# became a set
try:
demandimport.IGNORES |= {
b'collections',
b'brotli', # only needed in Python 2.7
}
except AttributeError: # pre 4.7 API
demandimport.ignore.extend([
b'collections',
b'brotli',
])
demandimport.IGNORES |= {
b'collections',
}
__version__ = b'0.11.0dev'
testedwith = (b'4.4.2 4.5.3 4.6.2 4.7.2 4.8.2 4.9.1 5.0.2 5.1.2 5.2 5.3 5.4 '
b'5.5 5.6 5.7')
minimumhgversion = b'4.4'
testedwith = (b'5.2 5.3 5.4 5.5 5.6 5.7')
minimumhgversion = b'5.2'
buglink = b'https://foss.heptapod.net/mercurial/hg-git/issues'
cmdtable = {}
configtable = {}
try:
from mercurial import registrar
command = registrar.command(cmdtable)
configitem = registrar.configitem(configtable)
templatekeyword = registrar.templatekeyword()
except (ImportError, AttributeError):
command = cmdutil.command(cmdtable)
templatekeyword = compat.templatekeyword()
command = registrar.command(cmdtable)
configitem = registrar.configitem(configtable)
templatekeyword = registrar.templatekeyword()
else:
compat.registerconfigs(configitem)
compat.registerconfigs(configitem)
# support for `hg clone git://github.com/defunkt/facebox.git`
# also hg clone git+ssh://git@github.com/schacon/simplegit.git
......@@ -617,10 +599,9 @@ def revset_gitnode(repo, subset, x):
if 0 <= len(result) < 2:
return result
# added in 4.8
exctype = getattr(error, 'AmbiguousPrefixLookupError', error.LookupError)
raise exctype(rev, git.map_file, _(b'ambiguous identifier'))
raise error.AmbiguousPrefixLookupError(
rev, git.map_file, _(b'ambiguous identifier'),
)
def _gitnodekw(node, repo):
......@@ -632,23 +613,10 @@ def _gitnodekw(node, repo):
return gitnode
if (hgutil.safehasattr(templatekw, b'templatekeyword') and
hgutil.safehasattr(templatekw.templatekeyword._table[b'node'],
b'_requires')):
@templatekeyword(b'gitnode', requires={b'ctx', b'repo'})
def gitnodekw(context, mapping):
""":gitnode: String. The Git changeset identification hash, as a
40 hexadecimal digit string."""
node = context.resource(mapping, b'ctx')
repo = context.resource(mapping, b'repo')
return _gitnodekw(node, repo)
else:
# COMPAT: hg < 4.6 - templatekeyword API changed
@templatekeyword(b'gitnode')
def gitnodekw(**args):
""":gitnode: String. The Git changeset identification hash, as a
@templatekeyword(b'gitnode', requires={b'ctx', b'repo'})
def gitnodekw(context, mapping):
""":gitnode: String. The Git changeset identification hash, as a
40 hexadecimal digit string."""
node = args[b'ctx']
repo = args[b'repo']
return _gitnodekw(node, repo)
node = context.resource(mapping, b'ctx')
repo = context.resource(mapping, b'repo')
return _gitnodekw(node, repo)
......@@ -5,8 +5,7 @@ import subprocess
from dulwich.client import SSHGitClient, SubprocessWrapper
from mercurial import pycompat
from . import compat
from mercurial.utils import procutil
class SSHVendor(object):
......@@ -24,15 +23,15 @@ def generate_ssh_vendor(ui):
assert isinstance(command, str)
command = command.encode(SSHGitClient.DEFAULT_ENCODING)
sshcmd = ui.config(b"ui", b"ssh", b"ssh")
args = compat.sshargs(sshcmd, pycompat.bytesurl(host),
args = procutil.sshargs(sshcmd, pycompat.bytesurl(host),
username, port)
cmd = b'%s %s %s' % (sshcmd, args, compat.shellquote(command))
cmd = b'%s %s %s' % (sshcmd, args, procutil.shellquote(command))
# consistent with mercurial
ui.debug(b'running %s\n' % cmd)
# we cannot use Mercurial's procutil.popen4() since it
# always redirects stderr into a pipe
proc = subprocess.Popen(
compat.tonativestr(compat.quotecommand(cmd)),
procutil.tonativestr(cmd),
shell=True,
bufsize=0,
stdin=subprocess.PIPE,
......
from __future__ import generator_stop
import sys
from mercurial.i18n import _
from mercurial import (
context,
error,
hg,
pycompat,
templatekw,
ui,
util as hgutil,
)
try:
from mercurial.utils import procutil, stringutil
sshargs = procutil.sshargs
shellquote = procutil.shellquote
try:
quotecommand = procutil.quotecommand
except AttributeError:
# procutil.quotecommand() returned the argument unchanged on Python
# >= 2.7.1 and was removed after Mercurial raised the minimum
# Python version to 2.7.4.
assert sys.version_info[:3] >= (2, 7, 1)
quotecommand = pycompat.identity
binary = stringutil.binary
try:
# added in 4.8
tonativestr = procutil.tonativestr
except AttributeError:
assert not pycompat.ispy3
tonativestr = pycompat.identity
except ImportError:
assert not pycompat.ispy3
# these were moved in 4.6
sshargs = hgutil.sshargs
shellquote = hgutil.shellquote
quotecommand = hgutil.quotecommand
binary = hgutil.binary
tonativestr = pycompat.identity
try:
from mercurial.cmdutil import check_at_most_one_arg
except (ImportError, AttributeError):
......@@ -78,64 +43,6 @@ def check_incompatible_arguments(opts, first, others):
for other in others:
check_at_most_one_arg(opts, first, other)
try:
from mercurial.scmutil import isrevsymbol
except (ImportError, AttributeError):
# added in 4.6, although much more thorough; if you want better
# error checking, use the latest hg!
def isrevsymbol(repo, symbol):
try:
repo.lookup(symbol)
return True
except error.RepoLookupError:
return False
quote = hgutil.urlreq.quote
unquote = hgutil.urlreq.unquote
try:
from mercurial.hg import sharedreposource
except (ImportError, AttributeError):
# added in 4.6
def sharedreposource(repo):
"""Returns repository object for source repository of a shared repo.
If repo is not a shared repository, returns None.
"""
if repo.sharedpath == repo.path:
return None
if hgutil.safehasattr(repo, b'srcrepo') and repo.srcrepo:
return repo.srcrepo
# the sharedpath always ends in the .hg; we want the path to the repo
source = repo.vfs.split(repo.sharedpath)[0]
srcurl, branches = hg.parseurl(source)
srcrepo = hg.repository(repo.ui, srcurl)
repo.srcrepo = srcrepo
return srcrepo
def memfilectx(repo, changectx, path, data, islink=False,
isexec=False, copysource=None):
# Different versions of mercurial have different parameters to
# memfilectx. Try them from newest to oldest.
parameters_to_try = (
((repo, changectx, path, data), { 'copysource': copysource }), # hg >= 5.0
((repo, changectx, path, data), { 'copied': copysource }), # hg 4.5 - 4.9.1
((repo, path, data), { 'copied': copysource }), # hg 3.1 - 4.4.2
)
for (args, kwargs) in parameters_to_try:
try:
return context.memfilectx(*args,
islink=islink,
isexec=isexec,
**kwargs)
except TypeError as ex:
last_ex = ex
raise last_ex
CONFIG_DEFAULTS = {
b'git': {
......@@ -157,75 +64,7 @@ CONFIG_DEFAULTS = {
}
}
hasconfigitems = False
def registerconfigs(configitem):
global hasconfigitems
hasconfigitems = True
for section, items in CONFIG_DEFAULTS.items():
for item, default in items.items():
configitem(section, item, default=default)
def config(ui, subtype, section, item):
if subtype == b'string':
subtype = b''
getconfig = getattr(ui, 'config' + pycompat.sysstr(subtype))
if hasconfigitems:
return getconfig(section, item)
return getconfig(section, item, CONFIG_DEFAULTS[section][item])
class templatekeyword(object):
def __init__(self):
self._table = {}
def __call__(self, name):
def decorate(func):
templatekw.keywords.update({name: func})
return func
return decorate
class progress(object):
'''Simplified implementation of mercurial.scmutil.progress for
compatibility with hg < 4.7'''
def __init__(self, ui, _updatebar, topic, unit=b"", total=None):
self.ui = ui
self.pos = 0
self.topic = topic
self.unit = unit
self.total = total
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_tb):
self.complete()
def _updatebar(self, item=b""):
self.ui.progress(self.topic, self.pos, item, self.unit, self.total)
def update(self, pos, item=b"", total=None):
self.pos = pos
if total is not None:
self.total = total
self._updatebar(item)
def increment(self, step=1, item=b"", total=None):
self.update(self.pos + step, item, total)
def complete(self):
self.unit = b""
self.total = None
self.update(None)
# no makeprogress in < 4.7
if hgutil.safehasattr(ui.ui, b'makeprogress'):
def makeprogress(ui, topic, unit=b"", total=None):
return ui.makeprogress(topic, unit, total)
else:
def makeprogress(ui, topic, unit=b"", total=None):
return progress(ui, None, topic, unit, total)
# git2hg.py - convert Git repositories and commits to Mercurial ones
from __future__ import generator_stop
from dulwich.objects import Commit, Tag
from . import compat
from mercurial import util as hgutil
def find_incoming(git_object_store, git_map, refs):
'''find what commits need to be imported
......@@ -128,7 +126,7 @@ def extract_hg_metadata(message, git_extra):
branch = data
if command == b'extra':
k, v = data.split(b" : ", 1)
extra[k] = compat.unquote(v)
extra[k] = hgutil.urlreq.unquote(v)
git_fn = 0
for field, data in git_extra:
......@@ -138,16 +136,16 @@ def extract_hg_metadata(message, git_extra):
command = field[3:]
if command == b'rename':
before, after = data.split(b':', 1)
renames[compat.unquote(after)] = compat.unquote(before)
renames[hgutil.urlreq.unquote(after)] = hgutil.urlreq.unquote(before)
elif command == b'extra':
k, v = data.split(b':', 1)
extra[compat.unquote(k)] = compat.unquote(v)
extra[hgutil.urlreq.unquote(k)] = hgutil.urlreq.unquote(v)
else:
# preserve ordering in Git by using an incrementing integer for
# each field. Note that extra metadata in Git is an ordered list
# of pairs.
hg_field = b'GIT%d-%s' % (git_fn, field)
git_fn += 1
extra[compat.quote(hg_field)] = compat.quote(data)
extra[hgutil.urlreq.quote(hg_field)] = hgutil.urlreq.quote(data)
return (message, renames, branch, extra)
......@@ -17,12 +17,14 @@ from dulwich import diff_tree
from mercurial.i18n import _
from mercurial.node import hex, bin, nullid
from mercurial.utils import dateutil
from mercurial import (
bookmarks,
commands,
context,
encoding,
error,
hg,
phases,
pycompat,
url,
......@@ -31,7 +33,6 @@ from mercurial import (
)
from . import _ssh
from . import compat
from . import git2hg
from . import hg2git
from . import util
......@@ -58,13 +59,6 @@ RE_GIT_PROGRESS = re.compile(br'\((\d+)/(\d+)\)')
RE_AUTHOR_FILE = re.compile(br'\s*=\s*')
# mercurial.utils.dateutil functions were in mercurial.util in Mercurial < 4.6
try:
from mercurial.utils import dateutil
dateutil.parsedate
except ImportError:
dateutil = hgutil
CALLBACK_BUFFER = b''
......@@ -95,7 +89,7 @@ class GitProgress(object):
if self._progress and self._progress.topic != topic:
self.flush()
if not self._progress:
self._progress = compat.makeprogress(self.ui, topic)
self._progress = self.ui.makeprogress(topic)
pos, total = map(int, m.group(1, 2))
self._progress.update(pos, total=total)
......@@ -113,9 +107,9 @@ class GitProgress(object):
def get_repo_and_gitdir(repo):
if repo.shared():
repo = compat.sharedreposource(repo)
repo = hg.sharedreposource(repo)
if compat.config(repo.ui, b'bool', b'git', b'intree'):
if repo.ui.configbool(b'git', b'intree'):
gitdir = repo.wvfs.join(b'.git')
else:
gitdir = repo.vfs.join(b'git')
......@@ -144,8 +138,8 @@ class GitHandler(object):
self.init_author_file()
self.branch_bookmark_suffix = compat.config(
ui, b'string', b'git', b'branch_bookmark_suffix')
self.branch_bookmark_suffix = ui.config(b'git',
b'branch_bookmark_suffix')
self._map_git_real = None
self._map_hg_real = None
......@@ -198,7 +192,7 @@ class GitHandler(object):
def init_author_file(self):
self.author_map = {}
authors_path = compat.config(self.ui, b'string', b'git', b'authors')
authors_path = self.ui.config(b'git', b'authors')
if authors_path:
with open(self.repo.wvfs.join(authors_path)) as f:
for line in f:
......@@ -503,7 +497,7 @@ class GitHandler(object):
topic = b'find commits to export'
unit = b'commits'
with compat.makeprogress(repo.ui, topic, unit, todo_total) as progress:
with repo.ui.makeprogress(topic, unit, todo_total) as progress:
export = []
for ctx in to_export:
item = hex(ctx.node())
......@@ -538,9 +532,8 @@ class GitHandler(object):
exporter = hg2git.IncrementalChangesetExporter(
self.repo, pctx, self.git.object_store, gitcommit)
mapsavefreq = compat.config(self.ui, b'int', b'hggit',
b'mapsavefrequency')
with compat.makeprogress(self.ui, b'exporting', total=total) as progress:
mapsavefreq = self.ui.configint(b'hggit', b'mapsavefrequency')
with self.repo.ui.makeprogress(b'exporting', total=total) as progress:
for i, ctx in enumerate(export):
progress.update(i, total=total)
self.export_hg_commit(ctx.node(), exporter)
......@@ -697,7 +690,7 @@ class GitHandler(object):
name = self.get_valid_git_username_email(a.group(1))
email = self.get_valid_git_username_email(a.group(2))
if a.group(3) is not None and len(a.group(3)) != 0:
name += b' ext:(' + compat.quote(a.group(3)) + b')'
name += b' ext:(' + hgutil.urlreq.quote(a.group(3)) + b')'
author = b'%s <%s>'\
% (self.get_valid_git_username_email(name),
self.get_valid_git_username_email(email))
......@@ -743,8 +736,7 @@ class GitHandler(object):
# HG EXTRA INFORMATION
# test only -- do not document this!
extra_in_message = compat.config(self.ui, b'bool', b'git',
b'debugextrainmessage')
extra_in_message = self.ui.configbool(b'git', b'debugextrainmessage')
extra_message = b''
git_extra = []
if ctx.branch() != b'default':
......@@ -762,7 +754,7 @@ class GitHandler(object):
git_extraitems.sort()
for i, field, value in git_extraitems:
git_extra.append((compat.unquote(field), compat.unquote(value)))
git_extra.append((hgutil.urlreq.unquote(field), hgutil.urlreq.unquote(value)))
if extra.get(b'hg-git-rename-source', None) != b'git':
renames = []
......@@ -779,8 +771,8 @@ class GitHandler(object):
extra_message += (b"rename : " + oldfile + b" => " +
newfile + b"\n")
else:
spec = b'%s:%s' % (compat.quote(oldfile),
compat.quote(newfile))
spec = b'%s:%s' % (hgutil.urlreq.quote(oldfile),
hgutil.urlreq.quote(newfile))
git_extra.append((b'HG:rename', spec))
# hg extra items always go at the end
......@@ -791,10 +783,10 @@ class GitHandler(object):
else:
if extra_in_message:
extra_message += (b"extra : " + key + b" : " +
compat.quote(value) + b"\n")
hgutil.urlreq.quote(value) + b"\n")
else:
spec = b'%s:%s' % (compat.quote(key),
compat.quote(value))
spec = b'%s:%s' % (hgutil.urlreq.quote(key),
hgutil.urlreq.quote(value))
git_extra.append((b'HG:extra', spec))
if extra_message:
......@@ -823,9 +815,8 @@ class GitHandler(object):
else:
self.ui.status(_(b"no changes found\n"))
mapsavefreq = compat.config(self.ui, b'int', b'hggit',
b'mapsavefrequency')
with compat.makeprogress(self.ui, b'importing', unit=b'commits', total=total) as progress:
mapsavefreq = self.ui.configint(b'hggit', b'mapsavefrequency')
with self.ui.makeprogress(b'importing', unit=b'commits', total=total) as progress:
for i, csha in enumerate(commits):
progress.update(i)
commit = commit_cache[csha]
......@@ -937,7 +928,7 @@ class GitHandler(object):
m = RE_GIT_AUTHOR_EXTRA.match(commit.author)
if m:
name = m.group(1)
ex = compat.unquote(m.group(2))
ex = hgutil.urlreq.unquote(m.group(2))
email = m.group(3)
author = name + b' <' + email + b'>' + ex
......@@ -997,10 +988,10 @@ class GitHandler(object):
if copied:
copied_path = copied[0]
return compat.memfilectx(unfiltered, memctx, f, data,
islink=b'l' in e,
isexec=b'x' in e,
copysource=copied_path)
return context.memfilectx(unfiltered, memctx, f, data,
islink=b'l' in e,
isexec=b'x' in e,
copysource=copied_path)
p1, p2 = (nullid, nullid)
octopus = False
......@@ -1347,7 +1338,7 @@ class GitHandler(object):
'''filter refs by minimum date
This only works for refs that are available locally.'''
min_date = compat.config(self.ui, b'string', b'git', b'mindate')
min_date = self.ui.config(b'git', b'mindate')
if min_date is None:
return refs
......@@ -1471,7 +1462,7 @@ class GitHandler(object):
# -f/--force is deliberately unimplemented and unmentioned
# as its git semantics are quite confusing
if compat.isrevsymbol(self.repo, tag):
if scmutil.isrevsymbol(self.repo, tag):
raise error.Abort(b"the name '%s' already exists" % tag)
if check_ref_format(b'refs/tags/' + tag):
......@@ -1496,7 +1487,7 @@ class GitHandler(object):
suffix = self.branch_bookmark_suffix or b''
changes = []
for head, sha in compat.iteritems(heads):
for head, sha in heads.items():
# refs contains all the refs in the server, not just
# the ones we are pulling
hgsha = self.map_hg_get(sha)
......@@ -1662,21 +1653,20 @@ class GitHandler(object):
@hgutil.propertycache
def _rename_detector(self):
# disabled by default to avoid surprises
similarity = compat.config(self.ui, b'int', b'git', b'similarity')
similarity = self.ui.configint(b'git', b'similarity')
if similarity < 0 or similarity > 100:
raise error.Abort(_(b'git.similarity must be between 0 and 100'))
if similarity == 0:
return None
# default is borrowed from Git
max_files = compat.config(self.ui, b'int', b'git', b'renamelimit')
max_files = self.ui.configint(b'git', b'renamelimit')
if max_files < 0:
raise error.Abort(_(b'git.renamelimit must be non-negative'))
if max_files == 0:
max_files = None
find_copies_harder = compat.config(self.ui, b'bool', b'git',
b'findcopiesharder')
find_copies_harder = self.ui.configbool(b'git', b'findcopiesharder')
return diff_tree.RenameDetector(self.git.object_store,
rename_threshold=similarity,
max_files=max_files,
......@@ -1686,7 +1676,7 @@ class GitHandler(object):
"""Parse .gitmodules from a git tree specified by tree_obj
:return: list of tuples (submodule path, url, name),
where name is quoted part of the section's name, or
where name is hgutil.urlreq.quoted part of the section's name, or
empty list if nothing found
"""
rv = []
......@@ -1725,7 +1715,7 @@ class GitHandler(object):
def audit_hg_path(self, path):
if b'.hg' in path.split(b'/'):
if compat.config(self.ui, b'bool', b'git', b'blockdothg'):
if self.ui.configbool(b'git', b'blockdothg'):
raise error.Abort(