On Python 3, our module importer automatically rewrites xrange()
to pycompat.xrange().
We want to move away from the custom importer on Python 3.
This commit converts all instances of xrange() to use
pycompat.xrange().
durin42 |
hg-reviewers |
On Python 3, our module importer automatically rewrites xrange()
to pycompat.xrange().
We want to move away from the custom importer on Python 3.
This commit converts all instances of xrange() to use
pycompat.xrange().
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from mercurial import ( | from mercurial import ( | ||||
error, | error, | ||||
extensions, | extensions, | ||||
match, | match, | ||||
pycompat, | |||||
registrar, | registrar, | ||||
util, | util, | ||||
) | ) | ||||
from mercurial.utils import ( | from mercurial.utils import ( | ||||
procutil, | procutil, | ||||
) | ) | ||||
urlreq = util.urlreq | urlreq = util.urlreq | ||||
ui.readconfig(cfg, sections=['acl.groups', 'acl.allow.branches', | ui.readconfig(cfg, sections=['acl.groups', 'acl.allow.branches', | ||||
'acl.deny.branches', 'acl.allow', 'acl.deny']) | 'acl.deny.branches', 'acl.allow', 'acl.deny']) | ||||
allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') | allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') | ||||
denybranches = buildmatch(ui, None, user, 'acl.deny.branches') | denybranches = buildmatch(ui, None, user, 'acl.deny.branches') | ||||
allow = buildmatch(ui, repo, user, 'acl.allow') | allow = buildmatch(ui, repo, user, 'acl.allow') | ||||
deny = buildmatch(ui, repo, user, 'acl.deny') | deny = buildmatch(ui, repo, user, 'acl.deny') | ||||
for rev in xrange(repo[node].rev(), len(repo)): | for rev in pycompat.xrange(repo[node].rev(), len(repo)): | ||||
ctx = repo[rev] | ctx = repo[rev] | ||||
branch = ctx.branch() | branch = ctx.branch() | ||||
if denybranches and denybranches(branch): | if denybranches and denybranches(branch): | ||||
raise error.Abort(_('acl: user "%s" denied on branch "%s"' | raise error.Abort(_('acl: user "%s" denied on branch "%s"' | ||||
' (changeset "%s")') | ' (changeset "%s")') | ||||
% (user, branch, ctx)) | % (user, branch, ctx)) | ||||
if allowbranches and not allowbranches(branch): | if allowbranches and not allowbranches(branch): | ||||
raise error.Abort(_('acl: user "%s" not allowed on branch "%s"' | raise error.Abort(_('acl: user "%s" not allowed on branch "%s"' |
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from mercurial import ( | from mercurial import ( | ||||
encoding, | encoding, | ||||
extensions, | extensions, | ||||
graphmod, | graphmod, | ||||
pycompat, | |||||
templatekw, | templatekw, | ||||
) | ) | ||||
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | ||||
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | ||||
# be specifying the version(s) of Mercurial they are tested with, or | # be specifying the version(s) of Mercurial they are tested with, or | ||||
# leave the attribute unspecified. | # leave the attribute unspecified. | ||||
testedwith = 'ships-with-hg-core' | testedwith = 'ships-with-hg-core' | ||||
if after == ' ' and not before == ' ': | if after == ' ' and not before == ' ': | ||||
return '\xE2\x94\xA4' # U+2524 ┤ | return '\xE2\x94\xA4' # U+2524 ┤ | ||||
return '\xE2\x94\xBC' # U+253C ┼ | return '\xE2\x94\xBC' # U+253C ┼ | ||||
return edge | return edge | ||||
def convertedges(line): | def convertedges(line): | ||||
line = ' %s ' % line | line = ' %s ' % line | ||||
pretty = [] | pretty = [] | ||||
for idx in xrange(len(line) - 2): | for idx in pycompat.xrange(len(line) - 2): | ||||
pretty.append(prettyedge(line[idx], line[idx + 1], line[idx + 2])) | pretty.append(prettyedge(line[idx], line[idx + 1], line[idx + 2])) | ||||
return ''.join(pretty) | return ''.join(pretty) | ||||
def getprettygraphnode(orig, *args, **kwargs): | def getprettygraphnode(orig, *args, **kwargs): | ||||
node = orig(*args, **kwargs) | node = orig(*args, **kwargs) | ||||
if node == 'o': | if node == 'o': | ||||
return '\xE2\x97\x8B' # U+25CB ○ | return '\xE2\x97\x8B' # U+25CB ○ | ||||
if node == '@': | if node == '@': |
import errno | import errno | ||||
import re | import re | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from mercurial.node import hex | from mercurial.node import hex | ||||
from mercurial import ( | from mercurial import ( | ||||
encoding, | encoding, | ||||
pycompat, | |||||
registrar, | registrar, | ||||
ui as uimod, | ui as uimod, | ||||
util, | util, | ||||
) | ) | ||||
from mercurial.utils import ( | from mercurial.utils import ( | ||||
dateutil, | dateutil, | ||||
procutil, | procutil, | ||||
) | ) | ||||
try: | try: | ||||
st = vfs.stat(name) | st = vfs.stat(name) | ||||
except OSError: | except OSError: | ||||
pass | pass | ||||
else: | else: | ||||
if st.st_size >= maxsize: | if st.st_size >= maxsize: | ||||
path = vfs.join(name) | path = vfs.join(name) | ||||
maxfiles = ui.configint('blackbox', 'maxfiles') | maxfiles = ui.configint('blackbox', 'maxfiles') | ||||
for i in xrange(maxfiles - 1, 1, -1): | for i in pycompat.xrange(maxfiles - 1, 1, -1): | ||||
rotate(oldpath='%s.%d' % (path, i - 1), | rotate(oldpath='%s.%d' % (path, i - 1), | ||||
newpath='%s.%d' % (path, i)) | newpath='%s.%d' % (path, i)) | ||||
rotate(oldpath=path, | rotate(oldpath=path, | ||||
newpath=maxfiles > 0 and path + '.1') | newpath=maxfiles > 0 and path + '.1') | ||||
return vfs(name, 'a') | return vfs(name, 'a') | ||||
def wrapui(ui): | def wrapui(ui): | ||||
class blackboxui(ui.__class__): | class blackboxui(ui.__class__): |
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from mercurial.node import short | from mercurial.node import short | ||||
from mercurial import ( | from mercurial import ( | ||||
error, | error, | ||||
pycompat, | |||||
registrar, | registrar, | ||||
revlog, | revlog, | ||||
scmutil, | scmutil, | ||||
util, | util, | ||||
) | ) | ||||
cmdtable = {} | cmdtable = {} | ||||
command = registrar.command(cmdtable) | command = registrar.command(cmdtable) | ||||
dataread.seek(flog.length(r), 1) | dataread.seek(flog.length(r), 1) | ||||
return newcomp | return newcomp | ||||
# Rewrite censored revlog entry with (padded) tombstone data. | # Rewrite censored revlog entry with (padded) tombstone data. | ||||
pad = ' ' * (flog.rawsize(crev) - len(tombstone)) | pad = ' ' * (flog.rawsize(crev) - len(tombstone)) | ||||
offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED) | offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED) | ||||
# Rewrite all following filelog revisions fixing up offsets and deltas. | # Rewrite all following filelog revisions fixing up offsets and deltas. | ||||
for srev in xrange(crev + 1, len(flog)): | for srev in pycompat.xrange(crev + 1, len(flog)): | ||||
if crev in flog.parentrevs(srev): | if crev in flog.parentrevs(srev): | ||||
# Immediate children of censored node must be re-added as fulltext. | # Immediate children of censored node must be re-added as fulltext. | ||||
try: | try: | ||||
revdata = flog.revision(srev) | revdata = flog.revision(srev) | ||||
except error.CensoredNodeError as e: | except error.CensoredNodeError as e: | ||||
revdata = e.tombstone | revdata = e.tombstone | ||||
dlen = rewrite(srev, offset, revdata) | dlen = rewrite(srev, offset, revdata) | ||||
else: | else: |
if c.branch in branches: | if c.branch in branches: | ||||
p = branches[c.branch] | p = branches[c.branch] | ||||
else: | else: | ||||
# first changeset on a new branch | # first changeset on a new branch | ||||
# the parent is a changeset with the branch in its | # the parent is a changeset with the branch in its | ||||
# branchpoints such that it is the latest possible | # branchpoints such that it is the latest possible | ||||
# commit without any intervening, unrelated commits. | # commit without any intervening, unrelated commits. | ||||
for candidate in xrange(i): | for candidate in pycompat.xrange(i): | ||||
if c.branch not in changesets[candidate].branchpoints: | if c.branch not in changesets[candidate].branchpoints: | ||||
if p is not None: | if p is not None: | ||||
break | break | ||||
continue | continue | ||||
p = candidate | p = candidate | ||||
c.parents = [] | c.parents = [] | ||||
if p is not None: | if p is not None: |
ui.setconfig('extensions', 'eol', '', source='internal') | ui.setconfig('extensions', 'eol', '', source='internal') | ||||
extensions.loadall(ui, ['eol']) | extensions.loadall(ui, ['eol']) | ||||
def _checkhook(ui, repo, node, headsonly): | def _checkhook(ui, repo, node, headsonly): | ||||
# Get revisions to check and touched files at the same time | # Get revisions to check and touched files at the same time | ||||
ensureenabled(ui) | ensureenabled(ui) | ||||
files = set() | files = set() | ||||
revs = set() | revs = set() | ||||
for rev in xrange(repo[node].rev(), len(repo)): | for rev in pycompat.xrange(repo[node].rev(), len(repo)): | ||||
revs.add(rev) | revs.add(rev) | ||||
if headsonly: | if headsonly: | ||||
ctx = repo[rev] | ctx = repo[rev] | ||||
files.update(ctx.files()) | files.update(ctx.files()) | ||||
for pctx in ctx.parents(): | for pctx in ctx.parents(): | ||||
revs.discard(pctx.rev()) | revs.discard(pctx.rev()) | ||||
failed = [] | failed = [] | ||||
for rev in revs: | for rev in revs: |
chunk = 100 | chunk = 100 | ||||
while True: | while True: | ||||
if chunk > i: | if chunk > i: | ||||
chunk = i | chunk = i | ||||
i = 0 | i = 0 | ||||
else: | else: | ||||
i -= chunk | i -= chunk | ||||
for x in xrange(chunk): | for x in pycompat.xrange(chunk): | ||||
if i + x >= count: | if i + x >= count: | ||||
l[chunk - x:] = [0] * (chunk - x) | l[chunk - x:] = [0] * (chunk - x) | ||||
break | break | ||||
if full is not None: | if full is not None: | ||||
if (i + x) in repo: | if (i + x) in repo: | ||||
l[x] = repo[i + x] | l[x] = repo[i + x] | ||||
l[x].changeset() # force reading | l[x].changeset() # force reading | ||||
else: | else: | ||||
if (i + x) in repo: | if (i + x) in repo: | ||||
l[x] = 1 | l[x] = 1 | ||||
for x in xrange(chunk - 1, -1, -1): | for x in pycompat.xrange(chunk - 1, -1, -1): | ||||
if l[x] != 0: | if l[x] != 0: | ||||
yield (i + x, full is not None and l[x] or None) | yield (i + x, full is not None and l[x] or None) | ||||
if i == 0: | if i == 0: | ||||
break | break | ||||
# calculate and return the reachability bitmask for sha | # calculate and return the reachability bitmask for sha | ||||
def is_reachable(ar, reachable, sha): | def is_reachable(ar, reachable, sha): | ||||
if len(ar) == 0: | if len(ar) == 0: | ||||
return 1 | return 1 | ||||
mask = 0 | mask = 0 | ||||
for i in xrange(len(ar)): | for i in pycompat.xrange(len(ar)): | ||||
if sha in reachable[i]: | if sha in reachable[i]: | ||||
mask |= 1 << i | mask |= 1 << i | ||||
return mask | return mask | ||||
reachable = [] | reachable = [] | ||||
stop_sha1 = [] | stop_sha1 = [] | ||||
want_sha1 = [] | want_sha1 = [] |
keep = lines[index] == 'True' | keep = lines[index] == 'True' | ||||
index += 1 | index += 1 | ||||
# Rules | # Rules | ||||
rules = [] | rules = [] | ||||
rulelen = int(lines[index]) | rulelen = int(lines[index]) | ||||
index += 1 | index += 1 | ||||
for i in xrange(rulelen): | for i in pycompat.xrange(rulelen): | ||||
ruleaction = lines[index] | ruleaction = lines[index] | ||||
index += 1 | index += 1 | ||||
rule = lines[index] | rule = lines[index] | ||||
index += 1 | index += 1 | ||||
rules.append((ruleaction, rule)) | rules.append((ruleaction, rule)) | ||||
# Replacements | # Replacements | ||||
replacements = [] | replacements = [] | ||||
replacementlen = int(lines[index]) | replacementlen = int(lines[index]) | ||||
index += 1 | index += 1 | ||||
for i in xrange(replacementlen): | for i in pycompat.xrange(replacementlen): | ||||
replacement = lines[index] | replacement = lines[index] | ||||
original = node.bin(replacement[:40]) | original = node.bin(replacement[:40]) | ||||
succ = [node.bin(replacement[i:i + 40]) for i in | succ = [node.bin(replacement[i:i + 40]) for i in | ||||
range(40, len(replacement), 40)] | range(40, len(replacement), 40)] | ||||
replacements.append((original, succ)) | replacements.append((original, succ)) | ||||
index += 1 | index += 1 | ||||
backupfile = lines[index] | backupfile = lines[index] |
__str__ = encoding.strmethod(__bytes__) | __str__ = encoding.strmethod(__bytes__) | ||||
def _delmsg(self): | def _delmsg(self): | ||||
'''Remove existing message, keeping the rest of the comments fields. | '''Remove existing message, keeping the rest of the comments fields. | ||||
If comments contains 'subject: ', message will prepend | If comments contains 'subject: ', message will prepend | ||||
the field and a blank line.''' | the field and a blank line.''' | ||||
if self.message: | if self.message: | ||||
subj = 'subject: ' + self.message[0].lower() | subj = 'subject: ' + self.message[0].lower() | ||||
for i in xrange(len(self.comments)): | for i in pycompat.xrange(len(self.comments)): | ||||
if subj == self.comments[i].lower(): | if subj == self.comments[i].lower(): | ||||
del self.comments[i] | del self.comments[i] | ||||
self.message = self.message[2:] | self.message = self.message[2:] | ||||
break | break | ||||
ci = 0 | ci = 0 | ||||
for mi in self.message: | for mi in self.message: | ||||
while mi != self.comments[ci]: | while mi != self.comments[ci]: | ||||
ci += 1 | ci += 1 | ||||
# Drop useless copy information | # Drop useless copy information | ||||
for f in list(repo.dirstate.copies()): | for f in list(repo.dirstate.copies()): | ||||
repo.dirstate.copy(None, f) | repo.dirstate.copy(None, f) | ||||
for f in r: | for f in r: | ||||
repo.dirstate.remove(f) | repo.dirstate.remove(f) | ||||
# if the patch excludes a modified file, mark that | # if the patch excludes a modified file, mark that | ||||
# file with mtime=0 so status can see it. | # file with mtime=0 so status can see it. | ||||
mm = [] | mm = [] | ||||
for i in xrange(len(m) - 1, -1, -1): | for i in pycompat.xrange(len(m) - 1, -1, -1): | ||||
if not match1(m[i]): | if not match1(m[i]): | ||||
mm.append(m[i]) | mm.append(m[i]) | ||||
del m[i] | del m[i] | ||||
for f in m: | for f in m: | ||||
repo.dirstate.normal(f) | repo.dirstate.normal(f) | ||||
for f in mm: | for f in mm: | ||||
repo.dirstate.normallookup(f) | repo.dirstate.normallookup(f) | ||||
for f in forget: | for f in forget: | ||||
def unapplied(self, repo, patch=None): | def unapplied(self, repo, patch=None): | ||||
if patch and patch not in self.series: | if patch and patch not in self.series: | ||||
raise error.Abort(_("patch %s is not in series file") % patch) | raise error.Abort(_("patch %s is not in series file") % patch) | ||||
if not patch: | if not patch: | ||||
start = self.seriesend() | start = self.seriesend() | ||||
else: | else: | ||||
start = self.series.index(patch) + 1 | start = self.series.index(patch) + 1 | ||||
unapplied = [] | unapplied = [] | ||||
for i in xrange(start, len(self.series)): | for i in pycompat.xrange(start, len(self.series)): | ||||
pushable, reason = self.pushable(i) | pushable, reason = self.pushable(i) | ||||
if pushable: | if pushable: | ||||
unapplied.append((i, self.series[i])) | unapplied.append((i, self.series[i])) | ||||
self.explainpushable(i) | self.explainpushable(i) | ||||
return unapplied | return unapplied | ||||
def qseries(self, repo, missing=None, start=0, length=None, status=None, | def qseries(self, repo, missing=None, start=0, length=None, status=None, | ||||
summary=False): | summary=False): | ||||
self.ui.write('\n') | self.ui.write('\n') | ||||
applied = set([p.name for p in self.applied]) | applied = set([p.name for p in self.applied]) | ||||
if length is None: | if length is None: | ||||
length = len(self.series) - start | length = len(self.series) - start | ||||
if not missing: | if not missing: | ||||
if self.ui.verbose: | if self.ui.verbose: | ||||
idxwidth = len("%d" % (start + length - 1)) | idxwidth = len("%d" % (start + length - 1)) | ||||
for i in xrange(start, start + length): | for i in pycompat.xrange(start, start + length): | ||||
patch = self.series[i] | patch = self.series[i] | ||||
if patch in applied: | if patch in applied: | ||||
char, state = 'A', 'applied' | char, state = 'A', 'applied' | ||||
elif self.pushable(i)[0]: | elif self.pushable(i)[0]: | ||||
char, state = 'U', 'unapplied' | char, state = 'U', 'unapplied' | ||||
else: | else: | ||||
char, state = 'G', 'guarded' | char, state = 'G', 'guarded' | ||||
pfx = '' | pfx = '' | ||||
"""If all_patches is False, return the index of the next pushable patch | """If all_patches is False, return the index of the next pushable patch | ||||
in the series, or the series length. If all_patches is True, return the | in the series, or the series length. If all_patches is True, return the | ||||
index of the first patch past the last applied one. | index of the first patch past the last applied one. | ||||
""" | """ | ||||
end = 0 | end = 0 | ||||
def nextpatch(start): | def nextpatch(start): | ||||
if all_patches or start >= len(self.series): | if all_patches or start >= len(self.series): | ||||
return start | return start | ||||
for i in xrange(start, len(self.series)): | for i in pycompat.xrange(start, len(self.series)): | ||||
p, reason = self.pushable(i) | p, reason = self.pushable(i) | ||||
if p: | if p: | ||||
return i | return i | ||||
self.explainpushable(i) | self.explainpushable(i) | ||||
return len(self.series) | return len(self.series) | ||||
if self.applied: | if self.applied: | ||||
p = self.applied[-1].name | p = self.applied[-1].name | ||||
try: | try: | ||||
q = repo.mq | q = repo.mq | ||||
applied = set(p.name for p in q.applied) | applied = set(p.name for p in q.applied) | ||||
patch = None | patch = None | ||||
args = list(args) | args = list(args) | ||||
if opts.get(r'list'): | if opts.get(r'list'): | ||||
if args or opts.get(r'none'): | if args or opts.get(r'none'): | ||||
raise error.Abort(_('cannot mix -l/--list with options or ' | raise error.Abort(_('cannot mix -l/--list with options or ' | ||||
'arguments')) | 'arguments')) | ||||
for i in xrange(len(q.series)): | for i in pycompat.xrange(len(q.series)): | ||||
status(i) | status(i) | ||||
return | return | ||||
if not args or args[0][0:1] in '-+': | if not args or args[0][0:1] in '-+': | ||||
if not q.applied: | if not q.applied: | ||||
raise error.Abort(_('no patches applied')) | raise error.Abort(_('no patches applied')) | ||||
patch = q.applied[-1].name | patch = q.applied[-1].name | ||||
if patch is None and args[0][0:1] not in '-+': | if patch is None and args[0][0:1] not in '-+': | ||||
patch = args.pop(0) | patch = args.pop(0) | ||||
Returns 0 on success.''' | Returns 0 on success.''' | ||||
q = repo.mq | q = repo.mq | ||||
opts = pycompat.byteskwargs(opts) | opts = pycompat.byteskwargs(opts) | ||||
guards = q.active() | guards = q.active() | ||||
pushable = lambda i: q.pushable(q.applied[i].name)[0] | pushable = lambda i: q.pushable(q.applied[i].name)[0] | ||||
if args or opts.get('none'): | if args or opts.get('none'): | ||||
old_unapplied = q.unapplied(repo) | old_unapplied = q.unapplied(repo) | ||||
old_guarded = [i for i in xrange(len(q.applied)) if not pushable(i)] | old_guarded = [i for i in pycompat.xrange(len(q.applied)) | ||||
if not pushable(i)] | |||||
q.setactive(args) | q.setactive(args) | ||||
q.savedirty() | q.savedirty() | ||||
if not args: | if not args: | ||||
ui.status(_('guards deactivated\n')) | ui.status(_('guards deactivated\n')) | ||||
if not opts.get('pop') and not opts.get('reapply'): | if not opts.get('pop') and not opts.get('reapply'): | ||||
unapplied = q.unapplied(repo) | unapplied = q.unapplied(repo) | ||||
guarded = [i for i in xrange(len(q.applied)) if not pushable(i)] | guarded = [i for i in pycompat.xrange(len(q.applied)) | ||||
if not pushable(i)] | |||||
if len(unapplied) != len(old_unapplied): | if len(unapplied) != len(old_unapplied): | ||||
ui.status(_('number of unguarded, unapplied patches has ' | ui.status(_('number of unguarded, unapplied patches has ' | ||||
'changed from %d to %d\n') % | 'changed from %d to %d\n') % | ||||
(len(old_unapplied), len(unapplied))) | (len(old_unapplied), len(unapplied))) | ||||
if len(guarded) != len(old_guarded): | if len(guarded) != len(old_guarded): | ||||
ui.status(_('number of guarded, applied patches has changed ' | ui.status(_('number of guarded, applied patches has changed ' | ||||
'from %d to %d\n') % | 'from %d to %d\n') % | ||||
(len(old_guarded), len(guarded))) | (len(old_guarded), len(guarded))) | ||||
ui.note(_('active guards:\n')) | ui.note(_('active guards:\n')) | ||||
for g in guards: | for g in guards: | ||||
ui.write(g, '\n') | ui.write(g, '\n') | ||||
else: | else: | ||||
ui.write(_('no active guards\n')) | ui.write(_('no active guards\n')) | ||||
reapply = opts.get('reapply') and q.applied and q.applied[-1].name | reapply = opts.get('reapply') and q.applied and q.applied[-1].name | ||||
popped = False | popped = False | ||||
if opts.get('pop') or opts.get('reapply'): | if opts.get('pop') or opts.get('reapply'): | ||||
for i in xrange(len(q.applied)): | for i in pycompat.xrange(len(q.applied)): | ||||
if not pushable(i): | if not pushable(i): | ||||
ui.status(_('popping guarded patches\n')) | ui.status(_('popping guarded patches\n')) | ||||
popped = True | popped = True | ||||
if i == 0: | if i == 0: | ||||
q.pop(repo, all=True) | q.pop(repo, all=True) | ||||
else: | else: | ||||
q.pop(repo, q.applied[i - 1].name) | q.pop(repo, q.applied[i - 1].name) | ||||
break | break |
from mercurial import ( | from mercurial import ( | ||||
changegroup, | changegroup, | ||||
error, | error, | ||||
extensions, | extensions, | ||||
manifest, | manifest, | ||||
match as matchmod, | match as matchmod, | ||||
mdiff, | mdiff, | ||||
node, | node, | ||||
pycompat, | |||||
revlog, | revlog, | ||||
util, | util, | ||||
) | ) | ||||
def setup(): | def setup(): | ||||
def _cgmatcher(cgpacker): | def _cgmatcher(cgpacker): | ||||
localmatcher = cgpacker._repo.narrowmatch() | localmatcher = cgpacker._repo.narrowmatch() | ||||
# is pointed to by linknode. "Know" is in scare | # is pointed to by linknode. "Know" is in scare | ||||
# quotes because I haven't done enough examination | # quotes because I haven't done enough examination | ||||
# of edge cases to convince myself this is really | # of edge cases to convince myself this is really | ||||
# a fact - it works for all the (admittedly | # a fact - it works for all the (admittedly | ||||
# thorough) cases in our testsuite, but I would be | # thorough) cases in our testsuite, but I would be | ||||
# somewhat unsurprised to find a case in the wild | # somewhat unsurprised to find a case in the wild | ||||
# where this breaks down a bit. That said, I don't | # where this breaks down a bit. That said, I don't | ||||
# know if it would hurt anything. | # know if it would hurt anything. | ||||
for i in xrange(rev, 0, -1): | for i in pycompat.xrange(rev, 0, -1): | ||||
if revlog.linkrev(i) == clrev: | if revlog.linkrev(i) == clrev: | ||||
return i | return i | ||||
# We failed to resolve a parent for this node, so | # We failed to resolve a parent for this node, so | ||||
# we crash the changegroup construction. | # we crash the changegroup construction. | ||||
raise error.Abort( | raise error.Abort( | ||||
'unable to resolve parent while packing %r %r' | 'unable to resolve parent while packing %r %r' | ||||
' for changeset %r' % (revlog.indexfile, rev, clrev)) | ' for changeset %r' % (revlog.indexfile, rev, clrev)) | ||||
return node.nullrev | return node.nullrev |
ui.status(_('rebasing shelved changes\n')) | ui.status(_('rebasing shelved changes\n')) | ||||
stats = merge.graft(repo, shelvectx, shelvectx.p1(), | stats = merge.graft(repo, shelvectx, shelvectx.p1(), | ||||
labels=['shelve', 'working-copy'], | labels=['shelve', 'working-copy'], | ||||
keepconflictparent=True) | keepconflictparent=True) | ||||
if stats.unresolvedcount: | if stats.unresolvedcount: | ||||
tr.close() | tr.close() | ||||
nodestoremove = [repo.changelog.node(rev) | nodestoremove = [repo.changelog.node(rev) | ||||
for rev in xrange(oldtiprev, len(repo))] | for rev in pycompat.xrange(oldtiprev, len(repo))] | ||||
shelvedstate.save(repo, basename, pctx, tmpwctx, nodestoremove, | shelvedstate.save(repo, basename, pctx, tmpwctx, nodestoremove, | ||||
branchtorestore, opts.get('keep'), activebookmark) | branchtorestore, opts.get('keep'), activebookmark) | ||||
raise error.InterventionRequired( | raise error.InterventionRequired( | ||||
_("unresolved conflicts (see 'hg resolve', then " | _("unresolved conflicts (see 'hg resolve', then " | ||||
"'hg unshelve --continue')")) | "'hg unshelve --continue')")) | ||||
with repo.dirstate.parentchange(): | with repo.dirstate.parentchange(): | ||||
repo.setparents(tmpwctx.node(), nodemod.nullid) | repo.setparents(tmpwctx.node(), nodemod.nullid) |
from __future__ import absolute_import | from __future__ import absolute_import | ||||
import re | import re | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from mercurial.node import ( | from mercurial.node import ( | ||||
short, | short, | ||||
) | ) | ||||
from mercurial import ( | from mercurial import ( | ||||
pycompat, | |||||
registrar, | registrar, | ||||
) | ) | ||||
from mercurial.utils import ( | from mercurial.utils import ( | ||||
stringutil, | stringutil, | ||||
) | ) | ||||
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | ||||
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | ||||
halt = False | halt = False | ||||
seen = set() | seen = set() | ||||
# we try to walk changesets in reverse order from newest to | # we try to walk changesets in reverse order from newest to | ||||
# oldest, so that if we see a file multiple times, we take the | # oldest, so that if we see a file multiple times, we take the | ||||
# newest version as canonical. this prevents us from blocking a | # newest version as canonical. this prevents us from blocking a | ||||
# changegroup that contains an unacceptable commit followed later | # changegroup that contains an unacceptable commit followed later | ||||
# by a commit that fixes the problem. | # by a commit that fixes the problem. | ||||
tip = repo['tip'] | tip = repo['tip'] | ||||
for rev in xrange(repo.changelog.tiprev(), repo[node].rev() - 1, -1): | for rev in pycompat.xrange(repo.changelog.tiprev(), | ||||
repo[node].rev() - 1, -1): | |||||
c = repo[rev] | c = repo[rev] | ||||
for f in c.files(): | for f in c.files(): | ||||
if f in seen or f not in tip or f not in c: | if f in seen or f not in tip or f not in c: | ||||
continue | continue | ||||
seen.add(f) | seen.add(f) | ||||
data = c[f].data() | data = c[f].data() | ||||
if not stringutil.binary(data) and newline in data: | if not stringutil.binary(data) and newline in data: | ||||
if not halt: | if not halt: |
# ancestor.py - generic DAG ancestor algorithm for mercurial | # ancestor.py - generic DAG ancestor algorithm for mercurial | ||||
# | # | ||||
# Copyright 2006 Matt Mackall <mpm@selenic.com> | # Copyright 2006 Matt Mackall <mpm@selenic.com> | ||||
# | # | ||||
# This software may be used and distributed according to the terms of the | # This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | # GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
import collections | import collections | ||||
import heapq | import heapq | ||||
from .node import nullrev | from .node import nullrev | ||||
from . import ( | |||||
pycompat, | |||||
) | |||||
def commonancestorsheads(pfunc, *nodes): | def commonancestorsheads(pfunc, *nodes): | ||||
"""Returns a set with the heads of all common ancestors of all nodes, | """Returns a set with the heads of all common ancestors of all nodes, | ||||
heads(::nodes[0] and ::nodes[1] and ...) . | heads(::nodes[0] and ::nodes[1] and ...) . | ||||
pfunc must return a list of parent vertices for a given vertex. | pfunc must return a list of parent vertices for a given vertex. | ||||
""" | """ | ||||
if not isinstance(nodes, set): | if not isinstance(nodes, set): | ||||
# anything in revs > start is definitely not an ancestor of bases | # anything in revs > start is definitely not an ancestor of bases | ||||
# revs <= start needs to be investigated | # revs <= start needs to be investigated | ||||
start = max(bases) | start = max(bases) | ||||
keepcount = sum(1 for r in revs if r > start) | keepcount = sum(1 for r in revs if r > start) | ||||
if len(revs) == keepcount: | if len(revs) == keepcount: | ||||
# no revs to consider | # no revs to consider | ||||
return | return | ||||
for curr in xrange(start, min(revs) - 1, -1): | for curr in pycompat.xrange(start, min(revs) - 1, -1): | ||||
if curr not in bases: | if curr not in bases: | ||||
continue | continue | ||||
revs.discard(curr) | revs.discard(curr) | ||||
bases.update(pfunc(curr)) | bases.update(pfunc(curr)) | ||||
if len(revs) == keepcount: | if len(revs) == keepcount: | ||||
# no more potential revs to discard | # no more potential revs to discard | ||||
break | break | ||||
# Now we walk down in reverse topo order, adding parents of nodes | # Now we walk down in reverse topo order, adding parents of nodes | ||||
# already visited to the sets while maintaining the invariants. When a | # already visited to the sets while maintaining the invariants. When a | ||||
# node is found in both revsvisit and basesvisit, it is removed from | # node is found in both revsvisit and basesvisit, it is removed from | ||||
# revsvisit and added to bothvisit. When revsvisit becomes empty, there | # revsvisit and added to bothvisit. When revsvisit becomes empty, there | ||||
# are no more ancestors of revs that aren't also ancestors of bases, so | # are no more ancestors of revs that aren't also ancestors of bases, so | ||||
# exit. | # exit. | ||||
missing = [] | missing = [] | ||||
for curr in xrange(start, nullrev, -1): | for curr in pycompat.xrange(start, nullrev, -1): | ||||
if not revsvisit: | if not revsvisit: | ||||
break | break | ||||
if curr in bothvisit: | if curr in bothvisit: | ||||
bothvisit.remove(curr) | bothvisit.remove(curr) | ||||
# curr's parents might have made it into revsvisit through | # curr's parents might have made it into revsvisit through | ||||
# another path | # another path | ||||
for p in pfunc(curr): | for p in pfunc(curr): |
rawheader = inpart.read(rbcstruct.size) | rawheader = inpart.read(rbcstruct.size) | ||||
cache = op.repo.revbranchcache() | cache = op.repo.revbranchcache() | ||||
cl = op.repo.unfiltered().changelog | cl = op.repo.unfiltered().changelog | ||||
while rawheader: | while rawheader: | ||||
header = rbcstruct.unpack(rawheader) | header = rbcstruct.unpack(rawheader) | ||||
total += header[1] + header[2] | total += header[1] + header[2] | ||||
utf8branch = inpart.read(header[0]) | utf8branch = inpart.read(header[0]) | ||||
branch = encoding.tolocal(utf8branch) | branch = encoding.tolocal(utf8branch) | ||||
for x in xrange(header[1]): | for x in pycompat.xrange(header[1]): | ||||
node = inpart.read(20) | node = inpart.read(20) | ||||
rev = cl.rev(node) | rev = cl.rev(node) | ||||
cache.setdata(branch, rev, node, False) | cache.setdata(branch, rev, node, False) | ||||
for x in xrange(header[2]): | for x in pycompat.xrange(header[2]): | ||||
node = inpart.read(20) | node = inpart.read(20) | ||||
rev = cl.rev(node) | rev = cl.rev(node) | ||||
cache.setdata(branch, rev, node, True) | cache.setdata(branch, rev, node, True) | ||||
rawheader = inpart.read(rbcstruct.size) | rawheader = inpart.read(rbcstruct.size) | ||||
cache.write() | cache.write() | ||||
@parthandler('pushvars') | @parthandler('pushvars') | ||||
def bundle2getvars(op, part): | def bundle2getvars(op, part): |
total=changesets) | total=changesets) | ||||
self._unpackmanifests(repo, revmap, trp, progress) | self._unpackmanifests(repo, revmap, trp, progress) | ||||
needfiles = {} | needfiles = {} | ||||
if repo.ui.configbool('server', 'validate'): | if repo.ui.configbool('server', 'validate'): | ||||
cl = repo.changelog | cl = repo.changelog | ||||
ml = repo.manifestlog | ml = repo.manifestlog | ||||
# validate incoming csets have their manifests | # validate incoming csets have their manifests | ||||
for cset in xrange(clstart, clend): | for cset in pycompat.xrange(clstart, clend): | ||||
mfnode = cl.changelogrevision(cset).manifest | mfnode = cl.changelogrevision(cset).manifest | ||||
mfest = ml[mfnode].readdelta() | mfest = ml[mfnode].readdelta() | ||||
# store file cgnodes we must see | # store file cgnodes we must see | ||||
for f, n in mfest.iteritems(): | for f, n in mfest.iteritems(): | ||||
needfiles.setdefault(f, set()).add(n) | needfiles.setdefault(f, set()).add(n) | ||||
# process the files | # process the files | ||||
repo.ui.status(_("adding file changes\n")) | repo.ui.status(_("adding file changes\n")) | ||||
hookargs = dict(tr.hookargs) | hookargs = dict(tr.hookargs) | ||||
else: | else: | ||||
hookargs = dict(tr.hookargs) | hookargs = dict(tr.hookargs) | ||||
hookargs['node'] = hex(cl.node(clstart)) | hookargs['node'] = hex(cl.node(clstart)) | ||||
hookargs['node_last'] = hex(cl.node(clend - 1)) | hookargs['node_last'] = hex(cl.node(clend - 1)) | ||||
repo.hook('pretxnchangegroup', | repo.hook('pretxnchangegroup', | ||||
throw=True, **pycompat.strkwargs(hookargs)) | throw=True, **pycompat.strkwargs(hookargs)) | ||||
added = [cl.node(r) for r in xrange(clstart, clend)] | added = [cl.node(r) for r in pycompat.xrange(clstart, clend)] | ||||
phaseall = None | phaseall = None | ||||
if srctype in ('push', 'serve'): | if srctype in ('push', 'serve'): | ||||
# Old servers can not push the boundary themselves. | # Old servers can not push the boundary themselves. | ||||
# New servers won't push the boundary if changeset already | # New servers won't push the boundary if changeset already | ||||
# exists locally as secret | # exists locally as secret | ||||
# | # | ||||
# We should not use added here but the list of all change in | # We should not use added here but the list of all change in | ||||
# the bundle | # the bundle | ||||
p = revlog.parentrevs(revs[0])[0] | p = revlog.parentrevs(revs[0])[0] | ||||
revs.insert(0, p) | revs.insert(0, p) | ||||
# build deltas | # build deltas | ||||
progress = None | progress = None | ||||
if units is not None: | if units is not None: | ||||
progress = self._repo.ui.makeprogress(_('bundling'), unit=units, | progress = self._repo.ui.makeprogress(_('bundling'), unit=units, | ||||
total=(len(revs) - 1)) | total=(len(revs) - 1)) | ||||
for r in xrange(len(revs) - 1): | for r in pycompat.xrange(len(revs) - 1): | ||||
if progress: | if progress: | ||||
progress.update(r + 1) | progress.update(r + 1) | ||||
prev, curr = revs[r], revs[r + 1] | prev, curr = revs[r], revs[r + 1] | ||||
linknode = lookup(revlog.node(curr)) | linknode = lookup(revlog.node(curr)) | ||||
for c in self.revchunk(revlog, curr, prev, linknode): | for c in self.revchunk(revlog, curr, prev, linknode): | ||||
yield c | yield c | ||||
if progress: | if progress: | ||||
deltas = source.deltaiter() | deltas = source.deltaiter() | ||||
if not fl.addgroup(deltas, revmap, trp): | if not fl.addgroup(deltas, revmap, trp): | ||||
raise error.Abort(_("received file revlog group is empty")) | raise error.Abort(_("received file revlog group is empty")) | ||||
except error.CensoredBaseError as e: | except error.CensoredBaseError as e: | ||||
raise error.Abort(_("received delta base is censored: %s") % e) | raise error.Abort(_("received delta base is censored: %s") % e) | ||||
revisions += len(fl) - o | revisions += len(fl) - o | ||||
if f in needfiles: | if f in needfiles: | ||||
needs = needfiles[f] | needs = needfiles[f] | ||||
for new in xrange(o, len(fl)): | for new in pycompat.xrange(o, len(fl)): | ||||
n = fl.node(new) | n = fl.node(new) | ||||
if n in needs: | if n in needs: | ||||
needs.remove(n) | needs.remove(n) | ||||
else: | else: | ||||
raise error.Abort( | raise error.Abort( | ||||
_("received spurious file revlog entry")) | _("received spurious file revlog entry")) | ||||
if not needs: | if not needs: | ||||
del needfiles[f] | del needfiles[f] |
self._realopener = opener | self._realopener = opener | ||||
self._delayed = False | self._delayed = False | ||||
self._delaybuf = None | self._delaybuf = None | ||||
self._divert = False | self._divert = False | ||||
self.filteredrevs = frozenset() | self.filteredrevs = frozenset() | ||||
def tiprev(self): | def tiprev(self): | ||||
for i in xrange(len(self) -1, -2, -1): | for i in pycompat.xrange(len(self) -1, -2, -1): | ||||
if i not in self.filteredrevs: | if i not in self.filteredrevs: | ||||
return i | return i | ||||
def tip(self): | def tip(self): | ||||
"""filtered version of revlog.tip""" | """filtered version of revlog.tip""" | ||||
return self.node(self.tiprev()) | return self.node(self.tiprev()) | ||||
def __contains__(self, rev): | def __contains__(self, rev): | ||||
"""filtered version of revlog.__contains__""" | """filtered version of revlog.__contains__""" | ||||
return (0 <= rev < len(self) | return (0 <= rev < len(self) | ||||
and rev not in self.filteredrevs) | and rev not in self.filteredrevs) | ||||
def __iter__(self): | def __iter__(self): | ||||
"""filtered version of revlog.__iter__""" | """filtered version of revlog.__iter__""" | ||||
if len(self.filteredrevs) == 0: | if len(self.filteredrevs) == 0: | ||||
return revlog.revlog.__iter__(self) | return revlog.revlog.__iter__(self) | ||||
def filterediter(): | def filterediter(): | ||||
for i in xrange(len(self)): | for i in pycompat.xrange(len(self)): | ||||
if i not in self.filteredrevs: | if i not in self.filteredrevs: | ||||
yield i | yield i | ||||
return filterediter() | return filterediter() | ||||
def revs(self, start=0, stop=None): | def revs(self, start=0, stop=None): | ||||
"""filtered version of revlog.revs""" | """filtered version of revlog.revs""" | ||||
for i in super(changelog, self).revs(start, stop): | for i in super(changelog, self).revs(start, stop): | ||||
# revision on the transaction. | # revision on the transaction. | ||||
rev = len(self) | rev = len(self) | ||||
node = super(changelog, self)._addrevision(node, rawtext, transaction, | node = super(changelog, self)._addrevision(node, rawtext, transaction, | ||||
*args, **kwargs) | *args, **kwargs) | ||||
revs = transaction.changes.get('revs') | revs = transaction.changes.get('revs') | ||||
if revs is not None: | if revs is not None: | ||||
if revs: | if revs: | ||||
assert revs[-1] + 1 == rev | assert revs[-1] + 1 == rev | ||||
revs = xrange(revs[0], rev + 1) | revs = pycompat.xrange(revs[0], rev + 1) | ||||
else: | else: | ||||
revs = xrange(rev, rev + 1) | revs = pycompat.xrange(rev, rev + 1) | ||||
transaction.changes['revs'] = revs | transaction.changes['revs'] = revs | ||||
return node | return node |
Only files, no patterns. Check the history of each file. | Only files, no patterns. Check the history of each file. | ||||
Examines filelog entries within minrev, maxrev linkrev range | Examines filelog entries within minrev, maxrev linkrev range | ||||
Returns an iterator yielding (linkrev, parentlinkrevs, copied) | Returns an iterator yielding (linkrev, parentlinkrevs, copied) | ||||
tuples in backwards order | tuples in backwards order | ||||
""" | """ | ||||
cl_count = len(repo) | cl_count = len(repo) | ||||
revs = [] | revs = [] | ||||
for j in xrange(0, last + 1): | for j in pycompat.xrange(0, last + 1): | ||||
linkrev = filelog.linkrev(j) | linkrev = filelog.linkrev(j) | ||||
if linkrev < minrev: | if linkrev < minrev: | ||||
continue | continue | ||||
# only yield rev for which we have the changelog, it can | # only yield rev for which we have the changelog, it can | ||||
# happen while doing "hg log" during a pull or commit | # happen while doing "hg log" during a pull or commit | ||||
if linkrev >= cl_count: | if linkrev >= cl_count: | ||||
break | break | ||||
wanted = lazywantedset() | wanted = lazywantedset() | ||||
# it might be worthwhile to do this in the iterator if the rev range | # it might be worthwhile to do this in the iterator if the rev range | ||||
# is descending and the prune args are all within that range | # is descending and the prune args are all within that range | ||||
for rev in opts.get('prune', ()): | for rev in opts.get('prune', ()): | ||||
rev = repo[rev].rev() | rev = repo[rev].rev() | ||||
ff = _followfilter(repo) | ff = _followfilter(repo) | ||||
stop = min(revs[0], revs[-1]) | stop = min(revs[0], revs[-1]) | ||||
for x in xrange(rev, stop - 1, -1): | for x in pycompat.xrange(rev, stop - 1, -1): | ||||
if ff.match(x): | if ff.match(x): | ||||
wanted = wanted - [x] | wanted = wanted - [x] | ||||
# Now that wanted is correctly initialized, we can iterate over the | # Now that wanted is correctly initialized, we can iterate over the | ||||
# revision range, yielding only revisions in wanted. | # revision range, yielding only revisions in wanted. | ||||
def iterate(): | def iterate(): | ||||
if follow and match.always(): | if follow and match.always(): | ||||
ff = _followfilter(repo, onlyfirst=opts.get('follow_first')) | ff = _followfilter(repo, onlyfirst=opts.get('follow_first')) | ||||
def want(rev): | def want(rev): | ||||
return ff.match(rev) and rev in wanted | return ff.match(rev) and rev in wanted | ||||
else: | else: | ||||
def want(rev): | def want(rev): | ||||
return rev in wanted | return rev in wanted | ||||
it = iter(revs) | it = iter(revs) | ||||
stopiteration = False | stopiteration = False | ||||
for windowsize in increasingwindows(): | for windowsize in increasingwindows(): | ||||
nrevs = [] | nrevs = [] | ||||
for i in xrange(windowsize): | for i in pycompat.xrange(windowsize): | ||||
rev = next(it, None) | rev = next(it, None) | ||||
if rev is None: | if rev is None: | ||||
stopiteration = True | stopiteration = True | ||||
break | break | ||||
elif want(rev): | elif want(rev): | ||||
nrevs.append(rev) | nrevs.append(rev) | ||||
for rev in sorted(nrevs): | for rev in sorted(nrevs): | ||||
fns = fncache.get(rev) | fns = fncache.get(rev) |
for lnum, cstart, cend, line in matchlines(body): | for lnum, cstart, cend, line in matchlines(body): | ||||
s = linestate(line, lnum, cstart, cend) | s = linestate(line, lnum, cstart, cend) | ||||
m.append(s) | m.append(s) | ||||
def difflinestates(a, b): | def difflinestates(a, b): | ||||
sm = difflib.SequenceMatcher(None, a, b) | sm = difflib.SequenceMatcher(None, a, b) | ||||
for tag, alo, ahi, blo, bhi in sm.get_opcodes(): | for tag, alo, ahi, blo, bhi in sm.get_opcodes(): | ||||
if tag == 'insert': | if tag == 'insert': | ||||
for i in xrange(blo, bhi): | for i in pycompat.xrange(blo, bhi): | ||||
yield ('+', b[i]) | yield ('+', b[i]) | ||||
elif tag == 'delete': | elif tag == 'delete': | ||||
for i in xrange(alo, ahi): | for i in pycompat.xrange(alo, ahi): | ||||
yield ('-', a[i]) | yield ('-', a[i]) | ||||
elif tag == 'replace': | elif tag == 'replace': | ||||
for i in xrange(alo, ahi): | for i in pycompat.xrange(alo, ahi): | ||||
yield ('-', a[i]) | yield ('-', a[i]) | ||||
for i in xrange(blo, bhi): | for i in pycompat.xrange(blo, bhi): | ||||
yield ('+', b[i]) | yield ('+', b[i]) | ||||
def display(fm, fn, ctx, pstates, states): | def display(fm, fn, ctx, pstates, states): | ||||
rev = scmutil.intrev(ctx) | rev = scmutil.intrev(ctx) | ||||
if fm.isplain(): | if fm.isplain(): | ||||
formatuser = ui.shortuser | formatuser = ui.shortuser | ||||
else: | else: | ||||
formatuser = str | formatuser = str |
else: | else: | ||||
raise error.Abort("error: '%s' conflicts with file '%s' in " | raise error.Abort("error: '%s' conflicts with file '%s' in " | ||||
"%s." % (path, component, | "%s." % (path, component, | ||||
self.p1().rev())) | self.p1().rev())) | ||||
# Test that each new directory to be created to write this path from p2 | # Test that each new directory to be created to write this path from p2 | ||||
# is not a file in p1. | # is not a file in p1. | ||||
components = path.split('/') | components = path.split('/') | ||||
for i in xrange(len(components)): | for i in pycompat.xrange(len(components)): | ||||
component = "/".join(components[0:i]) | component = "/".join(components[0:i]) | ||||
if component in self.p1(): | if component in self.p1(): | ||||
fail(path, component) | fail(path, component) | ||||
# Test the other direction -- that this path from p2 isn't a directory | # Test the other direction -- that this path from p2 isn't a directory | ||||
# in p1 (test that p1 doesn't any paths matching `path/*`). | # in p1 (test that p1 doesn't any paths matching `path/*`). | ||||
match = matchmod.match('/', '', [path + '/'], default=b'relpath') | match = matchmod.match('/', '', [path + '/'], default=b'relpath') | ||||
matches = self.p1().manifest().matches(match) | matches = self.p1().manifest().matches(match) |
seen.add(i) | seen.add(i) | ||||
yield i | yield i | ||||
break | break | ||||
def _builddescendantsmap(repo, startrev, followfirst): | def _builddescendantsmap(repo, startrev, followfirst): | ||||
"""Build map of 'rev -> child revs', offset from startrev""" | """Build map of 'rev -> child revs', offset from startrev""" | ||||
cl = repo.changelog | cl = repo.changelog | ||||
nullrev = node.nullrev | nullrev = node.nullrev | ||||
descmap = [[] for _rev in xrange(startrev, len(cl))] | descmap = [[] for _rev in pycompat.xrange(startrev, len(cl))] | ||||
for currev in cl.revs(startrev + 1): | for currev in cl.revs(startrev + 1): | ||||
p1rev, p2rev = cl.parentrevs(currev) | p1rev, p2rev = cl.parentrevs(currev) | ||||
if p1rev >= startrev: | if p1rev >= startrev: | ||||
descmap[p1rev - startrev].append(currev) | descmap[p1rev - startrev].append(currev) | ||||
if not followfirst and p2rev != nullrev and p2rev >= startrev: | if not followfirst and p2rev != nullrev and p2rev >= startrev: | ||||
descmap[p2rev - startrev].append(currev) | descmap[p2rev - startrev].append(currev) | ||||
return descmap | return descmap | ||||
# diff hunks 1:1, dropping lines as necessary. | # diff hunks 1:1, dropping lines as necessary. | ||||
# * Repeat the last line as a last resort. | # * Repeat the last line as a last resort. | ||||
# First, replace as much as possible without repeating the last line. | # First, replace as much as possible without repeating the last line. | ||||
remaining = [(parent, []) for parent, _blocks in pblocks] | remaining = [(parent, []) for parent, _blocks in pblocks] | ||||
for idx, (parent, blocks) in enumerate(pblocks): | for idx, (parent, blocks) in enumerate(pblocks): | ||||
for (a1, a2, b1, b2), _t in blocks: | for (a1, a2, b1, b2), _t in blocks: | ||||
if a2 - a1 >= b2 - b1: | if a2 - a1 >= b2 - b1: | ||||
for bk in xrange(b1, b2): | for bk in pycompat.xrange(b1, b2): | ||||
if child.fctxs[bk] == childfctx: | if child.fctxs[bk] == childfctx: | ||||
ak = min(a1 + (bk - b1), a2 - 1) | ak = min(a1 + (bk - b1), a2 - 1) | ||||
child.fctxs[bk] = parent.fctxs[ak] | child.fctxs[bk] = parent.fctxs[ak] | ||||
child.linenos[bk] = parent.linenos[ak] | child.linenos[bk] = parent.linenos[ak] | ||||
child.skips[bk] = True | child.skips[bk] = True | ||||
else: | else: | ||||
remaining[idx][1].append((a1, a2, b1, b2)) | remaining[idx][1].append((a1, a2, b1, b2)) | ||||
# Then, look at anything left, which might involve repeating the last | # Then, look at anything left, which might involve repeating the last | ||||
# line. | # line. | ||||
for parent, blocks in remaining: | for parent, blocks in remaining: | ||||
for a1, a2, b1, b2 in blocks: | for a1, a2, b1, b2 in blocks: | ||||
for bk in xrange(b1, b2): | for bk in pycompat.xrange(b1, b2): | ||||
if child.fctxs[bk] == childfctx: | if child.fctxs[bk] == childfctx: | ||||
ak = min(a1 + (bk - b1), a2 - 1) | ak = min(a1 + (bk - b1), a2 - 1) | ||||
child.fctxs[bk] = parent.fctxs[ak] | child.fctxs[bk] = parent.fctxs[ak] | ||||
child.linenos[bk] = parent.linenos[ak] | child.linenos[bk] = parent.linenos[ak] | ||||
child.skips[bk] = True | child.skips[bk] = True | ||||
return child | return child | ||||
def annotate(base, parents, skiprevs=None, diffopts=None): | def annotate(base, parents, skiprevs=None, diffopts=None): |
if c == '.': | if c == '.': | ||||
yield 'n', (r, [p1]) | yield 'n', (r, [p1]) | ||||
p1 = r | p1 = r | ||||
r += 1 | r += 1 | ||||
c = nextch() | c = nextch() | ||||
elif c == '+': | elif c == '+': | ||||
c, digs = nextrun(nextch(), pycompat.bytestr(string.digits)) | c, digs = nextrun(nextch(), pycompat.bytestr(string.digits)) | ||||
n = int(digs) | n = int(digs) | ||||
for i in xrange(0, n): | for i in pycompat.xrange(0, n): | ||||
yield 'n', (r, [p1]) | yield 'n', (r, [p1]) | ||||
p1 = r | p1 = r | ||||
r += 1 | r += 1 | ||||
elif c in '*/': | elif c in '*/': | ||||
if c == '*': | if c == '*': | ||||
c = nextch() | c = nextch() | ||||
c, pref = nextstring(c) | c, pref = nextstring(c) | ||||
prefs = [pref] | prefs = [pref] |
total = 0 | total = 0 | ||||
for type, data in dagparser.parsedag(text): | for type, data in dagparser.parsedag(text): | ||||
if type == 'n': | if type == 'n': | ||||
total += 1 | total += 1 | ||||
if mergeable_file: | if mergeable_file: | ||||
linesperrev = 2 | linesperrev = 2 | ||||
# make a file with k lines per rev | # make a file with k lines per rev | ||||
initialmergedlines = ['%d' % i for i in xrange(0, total * linesperrev)] | initialmergedlines = ['%d' % i | ||||
for i in pycompat.xrange(0, total * linesperrev)] | |||||
initialmergedlines.append("") | initialmergedlines.append("") | ||||
tags = [] | tags = [] | ||||
progress = ui.makeprogress(_('building'), unit=_('revisions'), | progress = ui.makeprogress(_('building'), unit=_('revisions'), | ||||
total=total) | total=total) | ||||
with progress, repo.wlock(), repo.lock(), repo.transaction("builddag"): | with progress, repo.wlock(), repo.lock(), repo.transaction("builddag"): | ||||
at = -1 | at = -1 | ||||
atbranch = 'default' | atbranch = 'default' | ||||
if opts.get("dump"): | if opts.get("dump"): | ||||
numrevs = len(r) | numrevs = len(r) | ||||
ui.write(("# rev p1rev p2rev start end deltastart base p1 p2" | ui.write(("# rev p1rev p2rev start end deltastart base p1 p2" | ||||
" rawsize totalsize compression heads chainlen\n")) | " rawsize totalsize compression heads chainlen\n")) | ||||
ts = 0 | ts = 0 | ||||
heads = set() | heads = set() | ||||
for rev in xrange(numrevs): | for rev in pycompat.xrange(numrevs): | ||||
dbase = r.deltaparent(rev) | dbase = r.deltaparent(rev) | ||||
if dbase == -1: | if dbase == -1: | ||||
dbase = rev | dbase = rev | ||||
cbase = r.chainbase(rev) | cbase = r.chainbase(rev) | ||||
clen = r.chainlen(rev) | clen = r.chainlen(rev) | ||||
p1, p2 = r.parentrevs(rev) | p1, p2 = r.parentrevs(rev) | ||||
rs = r.rawsize(rev) | rs = r.rawsize(rev) | ||||
ts = ts + rs | ts = ts + rs | ||||
def addsize(size, l): | def addsize(size, l): | ||||
if l[0] is None or size < l[0]: | if l[0] is None or size < l[0]: | ||||
l[0] = size | l[0] = size | ||||
if size > l[1]: | if size > l[1]: | ||||
l[1] = size | l[1] = size | ||||
l[2] += size | l[2] += size | ||||
numrevs = len(r) | numrevs = len(r) | ||||
for rev in xrange(numrevs): | for rev in pycompat.xrange(numrevs): | ||||
p1, p2 = r.parentrevs(rev) | p1, p2 = r.parentrevs(rev) | ||||
delta = r.deltaparent(rev) | delta = r.deltaparent(rev) | ||||
if format > 0: | if format > 0: | ||||
addsize(r.rawsize(rev), datasize) | addsize(r.rawsize(rev), datasize) | ||||
if p2 != nullrev: | if p2 != nullrev: | ||||
nummerges += 1 | nummerges += 1 | ||||
size = r.length(rev) | size = r.length(rev) | ||||
if delta == nullrev: | if delta == nullrev: |
# diffhelper.py - helper routines for patch | # diffhelper.py - helper routines for patch | ||||
# | # | ||||
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others | # Copyright 2009 Matt Mackall <mpm@selenic.com> and others | ||||
# | # | ||||
# This software may be used and distributed according to the terms of the | # This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | # GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from .i18n import _ | from .i18n import _ | ||||
from . import ( | from . import ( | ||||
error, | error, | ||||
pycompat, | |||||
) | ) | ||||
def addlines(fp, hunk, lena, lenb, a, b): | def addlines(fp, hunk, lena, lenb, a, b): | ||||
"""Read lines from fp into the hunk | """Read lines from fp into the hunk | ||||
The hunk is parsed into two arrays, a and b. a gets the old state of | The hunk is parsed into two arrays, a and b. a gets the old state of | ||||
the text, b gets the new state. The control char from the hunk is saved | the text, b gets the new state. The control char from the hunk is saved | ||||
when inserting into a, but not b (for performance while deleting files.) | when inserting into a, but not b (for performance while deleting files.) | ||||
""" | """ | ||||
while True: | while True: | ||||
todoa = lena - len(a) | todoa = lena - len(a) | ||||
todob = lenb - len(b) | todob = lenb - len(b) | ||||
num = max(todoa, todob) | num = max(todoa, todob) | ||||
if num == 0: | if num == 0: | ||||
break | break | ||||
for i in xrange(num): | for i in pycompat.xrange(num): | ||||
s = fp.readline() | s = fp.readline() | ||||
if not s: | if not s: | ||||
raise error.ParseError(_('incomplete hunk')) | raise error.ParseError(_('incomplete hunk')) | ||||
if s == "\\ No newline at end of file\n": | if s == "\\ No newline at end of file\n": | ||||
fixnewline(hunk, a, b) | fixnewline(hunk, a, b) | ||||
continue | continue | ||||
if s == '\n' or s == '\r\n': | if s == '\n' or s == '\r\n': | ||||
# Some patches may be missing the control char | # Some patches may be missing the control char | ||||
a is assumed to have a control char at the start of each line, this char | a is assumed to have a control char at the start of each line, this char | ||||
is ignored in the compare. | is ignored in the compare. | ||||
""" | """ | ||||
alen = len(a) | alen = len(a) | ||||
blen = len(b) | blen = len(b) | ||||
if alen > blen - bstart or bstart < 0: | if alen > blen - bstart or bstart < 0: | ||||
return False | return False | ||||
for i in xrange(alen): | for i in pycompat.xrange(alen): | ||||
if a[i][1:] != b[i + bstart]: | if a[i][1:] != b[i + bstart]: | ||||
return False | return False | ||||
return True | return True |
eaw = getattr(unicodedata, 'east_asian_width', None) | eaw = getattr(unicodedata, 'east_asian_width', None) | ||||
if eaw is not None: | if eaw is not None: | ||||
return sum([eaw(c) in _wide and 2 or 1 for c in d]) | return sum([eaw(c) in _wide and 2 or 1 for c in d]) | ||||
return len(d) | return len(d) | ||||
def getcols(s, start, c): | def getcols(s, start, c): | ||||
'''Use colwidth to find a c-column substring of s starting at byte | '''Use colwidth to find a c-column substring of s starting at byte | ||||
index start''' | index start''' | ||||
for x in xrange(start + c, len(s)): | for x in pycompat.xrange(start + c, len(s)): | ||||
t = s[start:x] | t = s[start:x] | ||||
if colwidth(t) == c: | if colwidth(t) == c: | ||||
return t | return t | ||||
def trim(s, width, ellipsis='', leftside=False): | def trim(s, width, ellipsis='', leftside=False): | ||||
"""Trim string 's' to at most 'width' columns (including 'ellipsis'). | """Trim string 's' to at most 'width' columns (including 'ellipsis'). | ||||
If 'leftside' is True, left side of string 's' is trimmed. | If 'leftside' is True, left side of string 's' is trimmed. | ||||
return ellipsis[:width + len(ellipsis)] | return ellipsis[:width + len(ellipsis)] | ||||
if leftside: | if leftside: | ||||
uslice = lambda i: u[i:] | uslice = lambda i: u[i:] | ||||
concat = lambda s: ellipsis + s | concat = lambda s: ellipsis + s | ||||
else: | else: | ||||
uslice = lambda i: u[:-i] | uslice = lambda i: u[:-i] | ||||
concat = lambda s: s + ellipsis | concat = lambda s: s + ellipsis | ||||
for i in xrange(1, len(u)): | for i in pycompat.xrange(1, len(u)): | ||||
usub = uslice(i) | usub = uslice(i) | ||||
if ucolwidth(usub) <= width: | if ucolwidth(usub) <= width: | ||||
return concat(usub.encode(_sysstr(encoding))) | return concat(usub.encode(_sysstr(encoding))) | ||||
return ellipsis # no enough room for multi-column characters | return ellipsis # no enough room for multi-column characters | ||||
def lower(s): | def lower(s): | ||||
"best-effort encoding-aware case-folding of local string s" | "best-effort encoding-aware case-folding of local string s" | ||||
try: | try: |
Data depends on type. | Data depends on type. | ||||
""" | """ | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from .node import nullrev | from .node import nullrev | ||||
from . import ( | from . import ( | ||||
dagop, | dagop, | ||||
pycompat, | |||||
smartset, | smartset, | ||||
util, | util, | ||||
) | ) | ||||
CHANGESET = 'C' | CHANGESET = 'C' | ||||
PARENT = 'P' | PARENT = 'P' | ||||
GRANDPARENT = 'G' | GRANDPARENT = 'G' | ||||
MISSINGPARENT = 'M' | MISSINGPARENT = 'M' | ||||
nodeline.extend( | nodeline.extend( | ||||
_getnodelineedgestail( | _getnodelineedgestail( | ||||
echars, idx, state['lastindex'], ncols, coldiff, | echars, idx, state['lastindex'], ncols, coldiff, | ||||
state['lastcoldiff'], fix_nodeline_tail)) | state['lastcoldiff'], fix_nodeline_tail)) | ||||
# shift_interline is the line containing the non-vertical | # shift_interline is the line containing the non-vertical | ||||
# edges between this entry and the next | # edges between this entry and the next | ||||
shift_interline = echars[:idx * 2] | shift_interline = echars[:idx * 2] | ||||
for i in xrange(2 + coldiff): | for i in pycompat.xrange(2 + coldiff): | ||||
shift_interline.append(' ') | shift_interline.append(' ') | ||||
count = ncols - idx - 1 | count = ncols - idx - 1 | ||||
if coldiff == -1: | if coldiff == -1: | ||||
for i in xrange(count): | for i in pycompat.xrange(count): | ||||
shift_interline.extend(['/', ' ']) | shift_interline.extend(['/', ' ']) | ||||
elif coldiff == 0: | elif coldiff == 0: | ||||
shift_interline.extend(echars[(idx + 1) * 2:ncols * 2]) | shift_interline.extend(echars[(idx + 1) * 2:ncols * 2]) | ||||
else: | else: | ||||
for i in xrange(count): | for i in pycompat.xrange(count): | ||||
shift_interline.extend(['\\', ' ']) | shift_interline.extend(['\\', ' ']) | ||||
# draw edges from the current node to its parents | # draw edges from the current node to its parents | ||||
_drawedges(echars, edges, nodeline, shift_interline) | _drawedges(echars, edges, nodeline, shift_interline) | ||||
# lines is the list of all graph lines to print | # lines is the list of all graph lines to print | ||||
lines = [nodeline] | lines = [nodeline] | ||||
if add_padding_line: | if add_padding_line: |
yield ctx | yield ctx | ||||
def keywordsearch(query): | def keywordsearch(query): | ||||
lower = encoding.lower | lower = encoding.lower | ||||
qw = lower(query).split() | qw = lower(query).split() | ||||
def revgen(): | def revgen(): | ||||
cl = web.repo.changelog | cl = web.repo.changelog | ||||
for i in xrange(len(web.repo) - 1, 0, -100): | for i in pycompat.xrange(len(web.repo) - 1, 0, -100): | ||||
l = [] | l = [] | ||||
for j in cl.revs(max(0, i - 99), i): | for j in cl.revs(max(0, i - 99), i): | ||||
ctx = web.repo[j] | ctx = web.repo[j] | ||||
l.append(ctx) | l.append(ctx) | ||||
l.reverse() | l.reverse() | ||||
for e in l: | for e in l: | ||||
yield e | yield e | ||||
'rightline': rightline or '', | 'rightline': rightline or '', | ||||
} | } | ||||
def _getcompblockgen(context, leftlines, rightlines, opcodes): | def _getcompblockgen(context, leftlines, rightlines, opcodes): | ||||
for type, llo, lhi, rlo, rhi in opcodes: | for type, llo, lhi, rlo, rhi in opcodes: | ||||
len1 = lhi - llo | len1 = lhi - llo | ||||
len2 = rhi - rlo | len2 = rhi - rlo | ||||
count = min(len1, len2) | count = min(len1, len2) | ||||
for i in xrange(count): | for i in pycompat.xrange(count): | ||||
yield _compline(type=type, | yield _compline(type=type, | ||||
leftlineno=llo + i + 1, | leftlineno=llo + i + 1, | ||||
leftline=leftlines[llo + i], | leftline=leftlines[llo + i], | ||||
rightlineno=rlo + i + 1, | rightlineno=rlo + i + 1, | ||||
rightline=rightlines[rlo + i]) | rightline=rightlines[rlo + i]) | ||||
if len1 > len2: | if len1 > len2: | ||||
for i in xrange(llo + count, lhi): | for i in pycompat.xrange(llo + count, lhi): | ||||
yield _compline(type=type, | yield _compline(type=type, | ||||
leftlineno=i + 1, | leftlineno=i + 1, | ||||
leftline=leftlines[i], | leftline=leftlines[i], | ||||
rightlineno=None, | rightlineno=None, | ||||
rightline=None) | rightline=None) | ||||
elif len2 > len1: | elif len2 > len1: | ||||
for i in xrange(rlo + count, rhi): | for i in pycompat.xrange(rlo + count, rhi): | ||||
yield _compline(type=type, | yield _compline(type=type, | ||||
leftlineno=None, | leftlineno=None, | ||||
leftline=None, | leftline=None, | ||||
rightlineno=i + 1, | rightlineno=i + 1, | ||||
rightline=rightlines[i]) | rightline=rightlines[i]) | ||||
def _getcompblock(leftlines, rightlines, opcodes): | def _getcompblock(leftlines, rightlines, opcodes): | ||||
args = (leftlines, rightlines, opcodes) | args = (leftlines, rightlines, opcodes) |
# and not a unicode: we're just getting the encoded length anyway, | # and not a unicode: we're just getting the encoded length anyway, | ||||
# and using an r-string to make it portable between Python 2 and 3 | # and using an r-string to make it portable between Python 2 and 3 | ||||
# doesn't work because then the \r is a literal backslash-r | # doesn't work because then the \r is a literal backslash-r | ||||
# instead of a carriage return. | # instead of a carriage return. | ||||
valuelen = limit - len(fmt % r'000') - len(': \r\n') | valuelen = limit - len(fmt % r'000') - len(': \r\n') | ||||
result = [] | result = [] | ||||
n = 0 | n = 0 | ||||
for i in xrange(0, len(value), valuelen): | for i in pycompat.xrange(0, len(value), valuelen): | ||||
n += 1 | n += 1 | ||||
result.append((fmt % str(n), pycompat.strurl(value[i:i + valuelen]))) | result.append((fmt % str(n), pycompat.strurl(value[i:i + valuelen]))) | ||||
return result | return result | ||||
def _wraphttpresponse(resp): | def _wraphttpresponse(resp): | ||||
"""Wrap an HTTPResponse with common error handlers. | """Wrap an HTTPResponse with common error handlers. | ||||
def __getitem__(self, changeid): | def __getitem__(self, changeid): | ||||
if changeid is None: | if changeid is None: | ||||
return context.workingctx(self) | return context.workingctx(self) | ||||
if isinstance(changeid, context.basectx): | if isinstance(changeid, context.basectx): | ||||
return changeid | return changeid | ||||
if isinstance(changeid, slice): | if isinstance(changeid, slice): | ||||
# wdirrev isn't contiguous so the slice shouldn't include it | # wdirrev isn't contiguous so the slice shouldn't include it | ||||
return [context.changectx(self, i) | return [context.changectx(self, i) | ||||
for i in xrange(*changeid.indices(len(self))) | for i in pycompat.xrange(*changeid.indices(len(self))) | ||||
if i not in self.changelog.filteredrevs] | if i not in self.changelog.filteredrevs] | ||||
try: | try: | ||||
return context.changectx(self, changeid) | return context.changectx(self, changeid) | ||||
except error.WdirUnsupported: | except error.WdirUnsupported: | ||||
return context.workingctx(self) | return context.workingctx(self) | ||||
def __contains__(self, changeid): | def __contains__(self, changeid): | ||||
"""True if the given changeid exists | """True if the given changeid exists | ||||
"journal", | "journal", | ||||
"undo", | "undo", | ||||
aftertrans(renames), | aftertrans(renames), | ||||
self.store.createmode, | self.store.createmode, | ||||
validator=validate, | validator=validate, | ||||
releasefn=releasefn, | releasefn=releasefn, | ||||
checkambigfiles=_cachedfiles, | checkambigfiles=_cachedfiles, | ||||
name=desc) | name=desc) | ||||
tr.changes['revs'] = xrange(0, 0) | tr.changes['revs'] = pycompat.xrange(0, 0) | ||||
tr.changes['obsmarkers'] = set() | tr.changes['obsmarkers'] = set() | ||||
tr.changes['phases'] = {} | tr.changes['phases'] = {} | ||||
tr.changes['bookmarks'] = {} | tr.changes['bookmarks'] = {} | ||||
tr.hookargs['txnid'] = txnid | tr.hookargs['txnid'] = txnid | ||||
# note: writing the fncache only during finalize mean that the file is | # note: writing the fncache only during finalize mean that the file is | ||||
# outdated when running hooks. As fncache is used for streaming clone, | # outdated when running hooks. As fncache is used for streaming clone, | ||||
# this is not expected to break anything that happen during the hooks. | # this is not expected to break anything that happen during the hooks. |
blen = b2 - bstart + aend - a2 | blen = b2 - bstart + aend - a2 | ||||
func = "" | func = "" | ||||
if opts.showfunc: | if opts.showfunc: | ||||
lastpos, func = lastfunc | lastpos, func = lastfunc | ||||
# walk backwards from the start of the context up to the start of | # walk backwards from the start of the context up to the start of | ||||
# the previous hunk context until we find a line starting with an | # the previous hunk context until we find a line starting with an | ||||
# alphanumeric char. | # alphanumeric char. | ||||
for i in xrange(astart - 1, lastpos - 1, -1): | for i in pycompat.xrange(astart - 1, lastpos - 1, -1): | ||||
if l1[i][0:1].isalnum(): | if l1[i][0:1].isalnum(): | ||||
func = b' ' + l1[i].rstrip() | func = b' ' + l1[i].rstrip() | ||||
# split long function name if ASCII. otherwise we have no | # split long function name if ASCII. otherwise we have no | ||||
# idea where the multi-byte boundary is, so just leave it. | # idea where the multi-byte boundary is, so just leave it. | ||||
if encoding.isasciistr(func): | if encoding.isasciistr(func): | ||||
func = func[:41] | func = func[:41] | ||||
lastfunc[1] = func | lastfunc[1] = func | ||||
break | break | ||||
# by recording this hunk's starting point as the next place to | # by recording this hunk's starting point as the next place to | ||||
# start looking for function lines, we avoid reading any line in | # start looking for function lines, we avoid reading any line in | ||||
# the file more than once. | # the file more than once. | ||||
lastfunc[0] = astart | lastfunc[0] = astart | ||||
# zero-length hunk ranges report their start line as one less | # zero-length hunk ranges report their start line as one less | ||||
if alen: | if alen: | ||||
astart += 1 | astart += 1 | ||||
if blen: | if blen: | ||||
bstart += 1 | bstart += 1 | ||||
hunkrange = astart, alen, bstart, blen | hunkrange = astart, alen, bstart, blen | ||||
hunklines = ( | hunklines = ( | ||||
["@@ -%d,%d +%d,%d @@%s\n" % (hunkrange + (func,))] | ["@@ -%d,%d +%d,%d @@%s\n" % (hunkrange + (func,))] | ||||
+ delta | + delta | ||||
+ [' ' + l1[x] for x in xrange(a2, aend)] | + [' ' + l1[x] for x in pycompat.xrange(a2, aend)] | ||||
) | ) | ||||
# If either file ends without a newline and the last line of | # If either file ends without a newline and the last line of | ||||
# that file is part of a hunk, a marker is printed. If the | # that file is part of a hunk, a marker is printed. If the | ||||
# last line of both files is identical and neither ends in | # last line of both files is identical and neither ends in | ||||
# a newline, print only one marker. That's the only case in | # a newline, print only one marker. That's the only case in | ||||
# which the hunk can end in a shared line without a newline. | # which the hunk can end in a shared line without a newline. | ||||
skip = False | skip = False | ||||
if not t1.endswith('\n') and astart + alen == len(l1) + 1: | if not t1.endswith('\n') and astart + alen == len(l1) + 1: | ||||
for i in xrange(len(hunklines) - 1, -1, -1): | for i in pycompat.xrange(len(hunklines) - 1, -1, -1): | ||||
if hunklines[i].startswith(('-', ' ')): | if hunklines[i].startswith(('-', ' ')): | ||||
if hunklines[i].startswith(' '): | if hunklines[i].startswith(' '): | ||||
skip = True | skip = True | ||||
hunklines[i] += '\n' | hunklines[i] += '\n' | ||||
hunklines.insert(i + 1, _missing_newline_marker) | hunklines.insert(i + 1, _missing_newline_marker) | ||||
break | break | ||||
if not skip and not t2.endswith('\n') and bstart + blen == len(l2) + 1: | if not skip and not t2.endswith('\n') and bstart + blen == len(l2) + 1: | ||||
for i in xrange(len(hunklines) - 1, -1, -1): | for i in pycompat.xrange(len(hunklines) - 1, -1, -1): | ||||
if hunklines[i].startswith('+'): | if hunklines[i].startswith('+'): | ||||
hunklines[i] += '\n' | hunklines[i] += '\n' | ||||
hunklines.insert(i + 1, _missing_newline_marker) | hunklines.insert(i + 1, _missing_newline_marker) | ||||
break | break | ||||
yield hunkrange, hunklines | yield hunkrange, hunklines | ||||
# bdiff.blocks gives us the matching sequences in the files. The loop | # bdiff.blocks gives us the matching sequences in the files. The loop | ||||
# below finds the spaces between those matching sequences and translates | # below finds the spaces between those matching sequences and translates |
_tablere.match(block['lines'][0]) and | _tablere.match(block['lines'][0]) and | ||||
block['lines'][0] == block['lines'][-1]): | block['lines'][0] == block['lines'][-1]): | ||||
block['type'] = 'table' | block['type'] = 'table' | ||||
block['header'] = False | block['header'] = False | ||||
div = block['lines'][0] | div = block['lines'][0] | ||||
# column markers are ASCII so we can calculate column | # column markers are ASCII so we can calculate column | ||||
# position in bytes | # position in bytes | ||||
columns = [x for x in xrange(len(div)) | columns = [x for x in pycompat.xrange(len(div)) | ||||
if div[x:x + 1] == '=' and (x == 0 or | if div[x:x + 1] == '=' and (x == 0 or | ||||
div[x - 1:x] == ' ')] | div[x - 1:x] == ' ')] | ||||
rows = [] | rows = [] | ||||
for l in block['lines'][1:-1]: | for l in block['lines'][1:-1]: | ||||
if l == div: | if l == div: | ||||
block['header'] = True | block['header'] = True | ||||
continue | continue | ||||
row = [] | row = [] | ||||
parents.append(i) | parents.append(i) | ||||
if name == section: | if name == section: | ||||
if lastparents != parents: | if lastparents != parents: | ||||
llen = len(lastparents) | llen = len(lastparents) | ||||
plen = len(parents) | plen = len(parents) | ||||
if llen and llen != plen: | if llen and llen != plen: | ||||
collapse = False | collapse = False | ||||
s = [] | s = [] | ||||
for j in xrange(3, plen - 1): | for j in pycompat.xrange(3, plen - 1): | ||||
parent = parents[j] | parent = parents[j] | ||||
if (j >= llen or | if (j >= llen or | ||||
lastparents[j] != parent): | lastparents[j] != parent): | ||||
s.append(len(blocks)) | s.append(len(blocks)) | ||||
sec = sections[parent][2] | sec = sections[parent][2] | ||||
blocks.append(sec[0]) | blocks.append(sec[0]) | ||||
blocks.append(sec[-1]) | blocks.append(sec[-1]) | ||||
if s: | if s: |
else: | else: | ||||
o3 = o2 + sha1size * numpar | o3 = o2 + sha1size * numpar | ||||
parents = unpack(sha1fmt * numpar, data[o2:o3]) | parents = unpack(sha1fmt * numpar, data[o2:o3]) | ||||
# read metadata | # read metadata | ||||
off = o3 + metasize * nummeta | off = o3 + metasize * nummeta | ||||
metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off]) | metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off]) | ||||
metadata = [] | metadata = [] | ||||
for idx in xrange(0, len(metapairsize), 2): | for idx in pycompat.xrange(0, len(metapairsize), 2): | ||||
o1 = off + metapairsize[idx] | o1 = off + metapairsize[idx] | ||||
o2 = o1 + metapairsize[idx + 1] | o2 = o1 + metapairsize[idx + 1] | ||||
metadata.append((data[off:o1], data[o1:o2])) | metadata.append((data[off:o1], data[o1:o2])) | ||||
off = o2 | off = o2 | ||||
yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents) | yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents) | ||||
def _fm1encodeonemarker(marker): | def _fm1encodeonemarker(marker): |
self.dirty = True | self.dirty = True | ||||
return 0 | return 0 | ||||
# ok, we couldn't match the hunk. Lets look for offsets and fuzz it | # ok, we couldn't match the hunk. Lets look for offsets and fuzz it | ||||
self.hash = {} | self.hash = {} | ||||
for x, s in enumerate(self.lines): | for x, s in enumerate(self.lines): | ||||
self.hash.setdefault(s, []).append(x) | self.hash.setdefault(s, []).append(x) | ||||
for fuzzlen in xrange(self.ui.configint("patch", "fuzz") + 1): | for fuzzlen in pycompat.xrange(self.ui.configint("patch", "fuzz") + 1): | ||||
for toponly in [True, False]: | for toponly in [True, False]: | ||||
old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly) | old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly) | ||||
oldstart = oldstart + self.offset + self.skew | oldstart = oldstart + self.offset + self.skew | ||||
oldstart = min(oldstart, len(self.lines)) | oldstart = min(oldstart, len(self.lines)) | ||||
if old: | if old: | ||||
cand = self.findlines(old[0][1:], oldstart) | cand = self.findlines(old[0][1:], oldstart) | ||||
else: | else: | ||||
# Only adding lines with no or fuzzed context, just | # Only adding lines with no or fuzzed context, just | ||||
raise PatchError(_("bad hunk #%d") % self.number) | raise PatchError(_("bad hunk #%d") % self.number) | ||||
self.starta, aend = m.groups() | self.starta, aend = m.groups() | ||||
self.starta = int(self.starta) | self.starta = int(self.starta) | ||||
if aend is None: | if aend is None: | ||||
aend = self.starta | aend = self.starta | ||||
self.lena = int(aend) - self.starta | self.lena = int(aend) - self.starta | ||||
if self.starta: | if self.starta: | ||||
self.lena += 1 | self.lena += 1 | ||||
for x in xrange(self.lena): | for x in pycompat.xrange(self.lena): | ||||
l = lr.readline() | l = lr.readline() | ||||
if l.startswith('---'): | if l.startswith('---'): | ||||
# lines addition, old block is empty | # lines addition, old block is empty | ||||
lr.push(l) | lr.push(l) | ||||
break | break | ||||
s = l[2:] | s = l[2:] | ||||
if l.startswith('- ') or l.startswith('! '): | if l.startswith('- ') or l.startswith('! '): | ||||
u = '-' + s | u = '-' + s | ||||
self.startb, bend = m.groups() | self.startb, bend = m.groups() | ||||
self.startb = int(self.startb) | self.startb = int(self.startb) | ||||
if bend is None: | if bend is None: | ||||
bend = self.startb | bend = self.startb | ||||
self.lenb = int(bend) - self.startb | self.lenb = int(bend) - self.startb | ||||
if self.startb: | if self.startb: | ||||
self.lenb += 1 | self.lenb += 1 | ||||
hunki = 1 | hunki = 1 | ||||
for x in xrange(self.lenb): | for x in pycompat.xrange(self.lenb): | ||||
l = lr.readline() | l = lr.readline() | ||||
if l.startswith('\ '): | if l.startswith('\ '): | ||||
# XXX: the only way to hit this is with an invalid line range. | # XXX: the only way to hit this is with an invalid line range. | ||||
# The no-eol marker is not counted in the line range, but I | # The no-eol marker is not counted in the line range, but I | ||||
# guess there are diff(1) out there which behave differently. | # guess there are diff(1) out there which behave differently. | ||||
s = self.b[-1][:-1] | s = self.b[-1][:-1] | ||||
self.b[-1] = s | self.b[-1] = s | ||||
self.hunk[hunki - 1] = s | self.hunk[hunki - 1] = s | ||||
# this removes context lines from the top and bottom of list 'l'. It | # this removes context lines from the top and bottom of list 'l'. It | ||||
# checks the hunk to make sure only context lines are removed, and then | # checks the hunk to make sure only context lines are removed, and then | ||||
# returns a new shortened list of lines. | # returns a new shortened list of lines. | ||||
fuzz = min(fuzz, len(old)) | fuzz = min(fuzz, len(old)) | ||||
if fuzz: | if fuzz: | ||||
top = 0 | top = 0 | ||||
bot = 0 | bot = 0 | ||||
hlen = len(self.hunk) | hlen = len(self.hunk) | ||||
for x in xrange(hlen - 1): | for x in pycompat.xrange(hlen - 1): | ||||
# the hunk starts with the @@ line, so use x+1 | # the hunk starts with the @@ line, so use x+1 | ||||
if self.hunk[x + 1].startswith(' '): | if self.hunk[x + 1].startswith(' '): | ||||
top += 1 | top += 1 | ||||
else: | else: | ||||
break | break | ||||
if not toponly: | if not toponly: | ||||
for x in xrange(hlen - 1): | for x in pycompat.xrange(hlen - 1): | ||||
if self.hunk[hlen - bot - 1].startswith(' '): | if self.hunk[hlen - bot - 1].startswith(' '): | ||||
bot += 1 | bot += 1 | ||||
else: | else: | ||||
break | break | ||||
bot = min(fuzz, bot) | bot = min(fuzz, bot) | ||||
top = min(fuzz, top) | top = min(fuzz, top) | ||||
return old[top:len(old) - bot], new[top:len(new) - bot], top | return old[top:len(old) - bot], new[top:len(new) - bot], top |
phasetracking = None | phasetracking = None | ||||
else: | else: | ||||
phasetracking = tr.changes.get('phases') | phasetracking = tr.changes.get('phases') | ||||
repo = repo.unfiltered() | repo = repo.unfiltered() | ||||
changes = set() # set of revisions to be changed | changes = set() # set of revisions to be changed | ||||
delroots = [] # set of root deleted by this path | delroots = [] # set of root deleted by this path | ||||
for phase in xrange(targetphase + 1, len(allphases)): | for phase in pycompat.xrange(targetphase + 1, len(allphases)): | ||||
# filter nodes that are not in a compatible phase already | # filter nodes that are not in a compatible phase already | ||||
nodes = [n for n in nodes | nodes = [n for n in nodes | ||||
if self.phase(repo, repo[n].rev()) >= phase] | if self.phase(repo, repo[n].rev()) >= phase] | ||||
if not nodes: | if not nodes: | ||||
break # no roots to move anymore | break # no roots to move anymore | ||||
olds = self.phaseroots[phase] | olds = self.phaseroots[phase] | ||||
and phasetracking is not None): | and phasetracking is not None): | ||||
# find the affected revisions | # find the affected revisions | ||||
new = self.phaseroots[targetphase] | new = self.phaseroots[targetphase] | ||||
old = oldroots[targetphase] | old = oldroots[targetphase] | ||||
affected = set(repo.revs('(%ln::) - (%ln::)', new, old)) | affected = set(repo.revs('(%ln::) - (%ln::)', new, old)) | ||||
# find the phase of the affected revision | # find the phase of the affected revision | ||||
for phase in xrange(targetphase, -1, -1): | for phase in pycompat.xrange(targetphase, -1, -1): | ||||
if phase: | if phase: | ||||
roots = oldroots[phase] | roots = oldroots[phase] | ||||
revs = set(repo.revs('%ln::%ld', roots, affected)) | revs = set(repo.revs('%ln::%ld', roots, affected)) | ||||
affected -= revs | affected -= revs | ||||
else: # public phase | else: # public phase | ||||
revs = affected | revs = affected | ||||
for r in revs: | for r in revs: | ||||
_trackphasechange(phasetracking, r, phase, targetphase) | _trackphasechange(phasetracking, r, phase, targetphase) |
if not cmsg: | if not cmsg: | ||||
return [] | return [] | ||||
if (cmsg.cmsg_level != socket.SOL_SOCKET or | if (cmsg.cmsg_level != socket.SOL_SOCKET or | ||||
cmsg.cmsg_type != _SCM_RIGHTS): | cmsg.cmsg_type != _SCM_RIGHTS): | ||||
return [] | return [] | ||||
rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int)) | rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int)) | ||||
rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) / | rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) / | ||||
ctypes.sizeof(ctypes.c_int)) | ctypes.sizeof(ctypes.c_int)) | ||||
return [rfds[i] for i in xrange(rfdscount)] | return [rfds[i] for i in pycompat.xrange(rfdscount)] | ||||
else: | else: | ||||
import msvcrt | import msvcrt | ||||
_kernel32 = ctypes.windll.kernel32 | _kernel32 = ctypes.windll.kernel32 | ||||
_DWORD = ctypes.c_ulong | _DWORD = ctypes.c_ulong | ||||
_LPCSTR = _LPSTR = ctypes.c_char_p | _LPCSTR = _LPSTR = ctypes.c_char_p |
- can be used to find a heuristic divergence measure between changesets on | - can be used to find a heuristic divergence measure between changesets on | ||||
different branches | different branches | ||||
''' | ''' | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from .node import nullrev | from .node import nullrev | ||||
from . import ( | from . import ( | ||||
pycompat, | |||||
util, | util, | ||||
) | ) | ||||
_size = 448 # 70 chars b85-encoded | _size = 448 # 70 chars b85-encoded | ||||
_bytes = _size / 8 | _bytes = _size / 8 | ||||
_depthbits = 24 | _depthbits = 24 | ||||
_depthbytes = _depthbits / 8 | _depthbytes = _depthbits / 8 | ||||
_vecbytes = _bytes - _depthbytes | _vecbytes = _bytes - _depthbytes | ||||
_vecbits = _vecbytes * 8 | _vecbits = _vecbytes * 8 | ||||
_radius = (_vecbits - 30) / 2 # high probability vectors are related | _radius = (_vecbits - 30) / 2 # high probability vectors are related | ||||
def _bin(bs): | def _bin(bs): | ||||
'''convert a bytestring to a long''' | '''convert a bytestring to a long''' | ||||
v = 0 | v = 0 | ||||
for b in bs: | for b in bs: | ||||
v = v * 256 + ord(b) | v = v * 256 + ord(b) | ||||
return v | return v | ||||
def _str(v, l): | def _str(v, l): | ||||
bs = "" | bs = "" | ||||
for p in xrange(l): | for p in pycompat.xrange(l): | ||||
bs = chr(v & 255) + bs | bs = chr(v & 255) + bs | ||||
v >>= 8 | v >>= 8 | ||||
return bs | return bs | ||||
def _split(b): | def _split(b): | ||||
'''depth and bitvec''' | '''depth and bitvec''' | ||||
return _bin(b[:_depthbytes]), _bin(b[_depthbytes:]) | return _bin(b[:_depthbytes]), _bin(b[_depthbytes:]) | ||||
def _join(depth, bitvec): | def _join(depth, bitvec): | ||||
return _str(depth, _depthbytes) + _str(bitvec, _vecbytes) | return _str(depth, _depthbytes) + _str(bitvec, _vecbytes) | ||||
def _hweight(x): | def _hweight(x): | ||||
c = 0 | c = 0 | ||||
while x: | while x: | ||||
if x & 1: | if x & 1: | ||||
c += 1 | c += 1 | ||||
x >>= 1 | x >>= 1 | ||||
return c | return c | ||||
_htab = [_hweight(x) for x in xrange(256)] | _htab = [_hweight(x) for x in pycompat.xrange(256)] | ||||
def _hamming(a, b): | def _hamming(a, b): | ||||
'''find the hamming distance between two longs''' | '''find the hamming distance between two longs''' | ||||
d = a ^ b | d = a ^ b | ||||
c = 0 | c = 0 | ||||
while d: | while d: | ||||
c += _htab[d & 0xff] | c += _htab[d & 0xff] | ||||
d >>= 8 | d >>= 8 | ||||
def ctxpvec(ctx): | def ctxpvec(ctx): | ||||
'''construct a pvec for ctx while filling in the cache''' | '''construct a pvec for ctx while filling in the cache''' | ||||
r = ctx.repo() | r = ctx.repo() | ||||
if not util.safehasattr(r, "_pveccache"): | if not util.safehasattr(r, "_pveccache"): | ||||
r._pveccache = {} | r._pveccache = {} | ||||
pvc = r._pveccache | pvc = r._pveccache | ||||
if ctx.rev() not in pvc: | if ctx.rev() not in pvc: | ||||
cl = r.changelog | cl = r.changelog | ||||
for n in xrange(ctx.rev() + 1): | for n in pycompat.xrange(ctx.rev() + 1): | ||||
if n not in pvc: | if n not in pvc: | ||||
node = cl.node(n) | node = cl.node(n) | ||||
p1, p2 = cl.parentrevs(n) | p1, p2 = cl.parentrevs(n) | ||||
if p1 == nullrev: | if p1 == nullrev: | ||||
# start with a 'random' vector at root | # start with a 'random' vector at root | ||||
pvc[n] = (0, _bin((node * 3)[:_vecbytes])) | pvc[n] = (0, _bin((node * 3)[:_vecbytes])) | ||||
elif p2 == nullrev: | elif p2 == nullrev: | ||||
d, v = pvc[p1] | d, v = pvc[p1] |
from . import ( | from . import ( | ||||
bundle2, | bundle2, | ||||
changegroup, | changegroup, | ||||
discovery, | discovery, | ||||
error, | error, | ||||
exchange, | exchange, | ||||
obsolete, | obsolete, | ||||
obsutil, | obsutil, | ||||
pycompat, | |||||
util, | util, | ||||
) | ) | ||||
from .utils import ( | from .utils import ( | ||||
stringutil, | stringutil, | ||||
) | ) | ||||
def backupbundle(repo, bases, heads, node, suffix, compress=True, | def backupbundle(repo, bases, heads, node, suffix, compress=True, | ||||
obsolescence=True): | obsolescence=True): | ||||
} | } | ||||
return bundle2.writenewbundle(repo.ui, repo, 'strip', name, bundletype, | return bundle2.writenewbundle(repo.ui, repo, 'strip', name, bundletype, | ||||
outgoing, contentopts, vfs, compression=comp) | outgoing, contentopts, vfs, compression=comp) | ||||
def _collectfiles(repo, striprev): | def _collectfiles(repo, striprev): | ||||
"""find out the filelogs affected by the strip""" | """find out the filelogs affected by the strip""" | ||||
files = set() | files = set() | ||||
for x in xrange(striprev, len(repo)): | for x in pycompat.xrange(striprev, len(repo)): | ||||
files.update(repo[x].files()) | files.update(repo[x].files()) | ||||
return sorted(files) | return sorted(files) | ||||
def _collectrevlog(revlog, striprev): | def _collectrevlog(revlog, striprev): | ||||
_, brokenset = revlog.getstrippoint(striprev) | _, brokenset = revlog.getstrippoint(striprev) | ||||
return [revlog.linkrev(r) for r in brokenset] | return [revlog.linkrev(r) for r in brokenset] | ||||
tr.startgroup() | tr.startgroup() | ||||
cl.strip(striprev, tr) | cl.strip(striprev, tr) | ||||
stripmanifest(repo, striprev, tr, files) | stripmanifest(repo, striprev, tr, files) | ||||
for fn in files: | for fn in files: | ||||
repo.file(fn).strip(striprev, tr) | repo.file(fn).strip(striprev, tr) | ||||
tr.endgroup() | tr.endgroup() | ||||
for i in xrange(offset, len(tr.entries)): | for i in pycompat.xrange(offset, len(tr.entries)): | ||||
file, troffset, ignore = tr.entries[i] | file, troffset, ignore = tr.entries[i] | ||||
with repo.svfs(file, 'a', checkambig=True) as fp: | with repo.svfs(file, 'a', checkambig=True) as fp: | ||||
fp.truncate(troffset) | fp.truncate(troffset) | ||||
if troffset == 0: | if troffset == 0: | ||||
repo.store.markremoved(file) | repo.store.markremoved(file) | ||||
deleteobsmarkers(repo.obsstore, stripobsidx) | deleteobsmarkers(repo.obsstore, stripobsidx) | ||||
del repo.obsstore | del repo.obsstore |
assert not repo.changelog.filteredrevs | assert not repo.changelog.filteredrevs | ||||
cl = repo.changelog | cl = repo.changelog | ||||
firstmutable = len(cl) | firstmutable = len(cl) | ||||
for roots in repo._phasecache.phaseroots[1:]: | for roots in repo._phasecache.phaseroots[1:]: | ||||
if roots: | if roots: | ||||
firstmutable = min(firstmutable, min(cl.rev(r) for r in roots)) | firstmutable = min(firstmutable, min(cl.rev(r) for r in roots)) | ||||
# protect from nullrev root | # protect from nullrev root | ||||
firstmutable = max(0, firstmutable) | firstmutable = max(0, firstmutable) | ||||
return frozenset(xrange(firstmutable, len(cl))) | return frozenset(pycompat.xrange(firstmutable, len(cl))) | ||||
# function to compute filtered set | # function to compute filtered set | ||||
# | # | ||||
# When adding a new filter you MUST update the table at: | # When adding a new filter you MUST update the table at: | ||||
# mercurial.branchmap.subsettable | # mercurial.branchmap.subsettable | ||||
# Otherwise your filter will have to recompute all its branches cache | # Otherwise your filter will have to recompute all its branches cache | ||||
# from scratch (very slow). | # from scratch (very slow). | ||||
filtertable = {'visible': computehidden, | filtertable = {'visible': computehidden, |
def tip(self): | def tip(self): | ||||
return self.node(len(self.index) - 2) | return self.node(len(self.index) - 2) | ||||
def __contains__(self, rev): | def __contains__(self, rev): | ||||
return 0 <= rev < len(self) | return 0 <= rev < len(self) | ||||
def __len__(self): | def __len__(self): | ||||
return len(self.index) - 1 | return len(self.index) - 1 | ||||
def __iter__(self): | def __iter__(self): | ||||
return iter(xrange(len(self))) | return iter(pycompat.xrange(len(self))) | ||||
def revs(self, start=0, stop=None): | def revs(self, start=0, stop=None): | ||||
"""iterate over all rev in this revlog (from start to stop)""" | """iterate over all rev in this revlog (from start to stop)""" | ||||
step = 1 | step = 1 | ||||
length = len(self) | length = len(self) | ||||
if stop is not None: | if stop is not None: | ||||
if start > stop: | if start > stop: | ||||
step = -1 | step = -1 | ||||
stop += step | stop += step | ||||
if stop > length: | if stop > length: | ||||
stop = length | stop = length | ||||
else: | else: | ||||
stop = length | stop = length | ||||
return xrange(start, stop, step) | return pycompat.xrange(start, stop, step) | ||||
@util.propertycache | @util.propertycache | ||||
def nodemap(self): | def nodemap(self): | ||||
self.rev(self.node(0)) | self.rev(self.node(0)) | ||||
return self._nodecache | return self._nodecache | ||||
def hasnode(self, node): | def hasnode(self, node): | ||||
try: | try: | ||||
# pure python cache lookup failed | # pure python cache lookup failed | ||||
n = self._nodecache | n = self._nodecache | ||||
i = self.index | i = self.index | ||||
p = self._nodepos | p = self._nodepos | ||||
if p is None: | if p is None: | ||||
p = len(i) - 2 | p = len(i) - 2 | ||||
else: | else: | ||||
assert p < len(i) | assert p < len(i) | ||||
for r in xrange(p, -1, -1): | for r in pycompat.xrange(p, -1, -1): | ||||
v = i[r][7] | v = i[r][7] | ||||
n[v] = r | n[v] = r | ||||
if v == node: | if v == node: | ||||
self._nodepos = r - 1 | self._nodepos = r - 1 | ||||
return r | return r | ||||
if node == wdirid or node in wdirfilenodeids: | if node == wdirid or node in wdirfilenodeids: | ||||
raise error.WdirUnsupported | raise error.WdirUnsupported | ||||
raise LookupError(node, self.indexfile, _('no node')) | raise LookupError(node, self.indexfile, _('no node')) | ||||
end += rev * self._io.size | end += rev * self._io.size | ||||
transaction.add(self.indexfile, end) | transaction.add(self.indexfile, end) | ||||
# then reset internal state in memory to forget those revisions | # then reset internal state in memory to forget those revisions | ||||
self._cache = None | self._cache = None | ||||
self._chaininfocache = {} | self._chaininfocache = {} | ||||
self._chunkclear() | self._chunkclear() | ||||
for x in xrange(rev, len(self)): | for x in pycompat.xrange(rev, len(self)): | ||||
del self.nodemap[self.node(x)] | del self.nodemap[self.node(x)] | ||||
del self.index[rev:-1] | del self.index[rev:-1] | ||||
self._nodepos = None | self._nodepos = None | ||||
def checksize(self): | def checksize(self): | ||||
expected = 0 | expected = 0 | ||||
if len(self): | if len(self): |
_quoteletters = {'"', "'"} | _quoteletters = {'"', "'"} | ||||
_simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%")) | _simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%")) | ||||
# default set of valid characters for the initial letter of symbols | # default set of valid characters for the initial letter of symbols | ||||
_syminitletters = set(pycompat.iterbytestr( | _syminitletters = set(pycompat.iterbytestr( | ||||
string.ascii_letters.encode('ascii') + | string.ascii_letters.encode('ascii') + | ||||
string.digits.encode('ascii') + | string.digits.encode('ascii') + | ||||
'._@')) | set(map(pycompat.bytechr, xrange(128, 256))) | '._@')) | set(map(pycompat.bytechr, pycompat.xrange(128, 256))) | ||||
# default set of valid characters for non-initial letters of symbols | # default set of valid characters for non-initial letters of symbols | ||||
_symletters = _syminitletters | set(pycompat.iterbytestr('-/')) | _symletters = _syminitletters | set(pycompat.iterbytestr('-/')) | ||||
def tokenize(program, lookup=None, syminitletters=None, symletters=None): | def tokenize(program, lookup=None, syminitletters=None, symletters=None): | ||||
''' | ''' | ||||
Parse a revset statement into a stream of tokens | Parse a revset statement into a stream of tokens | ||||
msg = getinstabilitymessage(delta, instability) | msg = getinstabilitymessage(delta, instability) | ||||
if msg: | if msg: | ||||
repo.ui.warn(msg) | repo.ui.warn(msg) | ||||
if txmatch(_reportnewcssource): | if txmatch(_reportnewcssource): | ||||
@reportsummary | @reportsummary | ||||
def reportnewcs(repo, tr): | def reportnewcs(repo, tr): | ||||
"""Report the range of new revisions pulled/unbundled.""" | """Report the range of new revisions pulled/unbundled.""" | ||||
newrevs = tr.changes.get('revs', xrange(0, 0)) | newrevs = tr.changes.get('revs', pycompat.xrange(0, 0)) | ||||
if not newrevs: | if not newrevs: | ||||
return | return | ||||
# Compute the bounds of new revisions' range, excluding obsoletes. | # Compute the bounds of new revisions' range, excluding obsoletes. | ||||
unfi = repo.unfiltered() | unfi = repo.unfiltered() | ||||
revs = unfi.revs('%ld and not obsolete()', newrevs) | revs = unfi.revs('%ld and not obsolete()', newrevs) | ||||
if not revs: | if not revs: | ||||
# Got only obsoletes. | # Got only obsoletes. | ||||
return | return | ||||
minrev, maxrev = repo[revs.min()], repo[revs.max()] | minrev, maxrev = repo[revs.min()], repo[revs.max()] | ||||
if minrev == maxrev: | if minrev == maxrev: | ||||
revrange = minrev | revrange = minrev | ||||
else: | else: | ||||
revrange = '%s:%s' % (minrev, maxrev) | revrange = '%s:%s' % (minrev, maxrev) | ||||
repo.ui.status(_('new changesets %s\n') % revrange) | repo.ui.status(_('new changesets %s\n') % revrange) | ||||
@reportsummary | @reportsummary | ||||
def reportphasechanges(repo, tr): | def reportphasechanges(repo, tr): | ||||
"""Report statistics of phase changes for changesets pre-existing | """Report statistics of phase changes for changesets pre-existing | ||||
pull/unbundle. | pull/unbundle. | ||||
""" | """ | ||||
newrevs = tr.changes.get('revs', xrange(0, 0)) | newrevs = tr.changes.get('revs', pycompat.xrange(0, 0)) | ||||
phasetracking = tr.changes.get('phases', {}) | phasetracking = tr.changes.get('phases', {}) | ||||
if not phasetracking: | if not phasetracking: | ||||
return | return | ||||
published = [ | published = [ | ||||
rev for rev, (old, new) in phasetracking.iteritems() | rev for rev, (old, new) in phasetracking.iteritems() | ||||
if new == phases.public and rev not in newrevs | if new == phases.public and rev not in newrevs | ||||
] | ] | ||||
if not published: | if not published: |
lockfd, lockpath = pycompat.mkstemp(prefix='hg-service-') | lockfd, lockpath = pycompat.mkstemp(prefix='hg-service-') | ||||
os.close(lockfd) | os.close(lockfd) | ||||
try: | try: | ||||
if not runargs: | if not runargs: | ||||
runargs = procutil.hgcmd() + pycompat.sysargv[1:] | runargs = procutil.hgcmd() + pycompat.sysargv[1:] | ||||
runargs.append('--daemon-postexec=unlink:%s' % lockpath) | runargs.append('--daemon-postexec=unlink:%s' % lockpath) | ||||
# Don't pass --cwd to the child process, because we've already | # Don't pass --cwd to the child process, because we've already | ||||
# changed directory. | # changed directory. | ||||
for i in xrange(1, len(runargs)): | for i in pycompat.xrange(1, len(runargs)): | ||||
if runargs[i].startswith('--cwd='): | if runargs[i].startswith('--cwd='): | ||||
del runargs[i] | del runargs[i] | ||||
break | break | ||||
elif runargs[i].startswith('--cwd'): | elif runargs[i].startswith('--cwd'): | ||||
del runargs[i:i + 2] | del runargs[i:i + 2] | ||||
break | break | ||||
def condfn(): | def condfn(): | ||||
return not os.path.exists(lockpath) | return not os.path.exists(lockpath) |
else: | else: | ||||
return None | return None | ||||
def compare_range(a, astart, aend, b, bstart, bend): | def compare_range(a, astart, aend, b, bstart, bend): | ||||
"""Compare a[astart:aend] == b[bstart:bend], without slicing. | """Compare a[astart:aend] == b[bstart:bend], without slicing. | ||||
""" | """ | ||||
if (aend - astart) != (bend - bstart): | if (aend - astart) != (bend - bstart): | ||||
return False | return False | ||||
for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)): | for ia, ib in zip(pycompat.xrange(astart, aend), | ||||
pycompat.xrange(bstart, bend)): | |||||
if a[ia] != b[ib]: | if a[ia] != b[ib]: | ||||
return False | return False | ||||
else: | else: | ||||
return True | return True | ||||
class Merge3Text(object): | class Merge3Text(object): | ||||
"""3-way merge of texts. | """3-way merge of texts. | ||||
raise error.ProgrammingError('negative index not allowed') | raise error.ProgrammingError('negative index not allowed') | ||||
return self._slice(start, stop) | return self._slice(start, stop) | ||||
def _slice(self, start, stop): | def _slice(self, start, stop): | ||||
# sub classes may override this. start and stop must not be negative, | # sub classes may override this. start and stop must not be negative, | ||||
# but start > stop is allowed, which should be an empty set. | # but start > stop is allowed, which should be an empty set. | ||||
ys = [] | ys = [] | ||||
it = iter(self) | it = iter(self) | ||||
for x in xrange(start): | for x in pycompat.xrange(start): | ||||
y = next(it, None) | y = next(it, None) | ||||
if y is None: | if y is None: | ||||
break | break | ||||
for x in xrange(stop - start): | for x in pycompat.xrange(stop - start): | ||||
y = next(it, None) | y = next(it, None) | ||||
if y is None: | if y is None: | ||||
break | break | ||||
ys.append(y) | ys.append(y) | ||||
return baseset(ys, datarepr=('slice=%d:%d %r', start, stop, self)) | return baseset(ys, datarepr=('slice=%d:%d %r', start, stop, self)) | ||||
class baseset(abstractsmartset): | class baseset(abstractsmartset): | ||||
"""Basic data structure that represents a revset and contains the basic | """Basic data structure that represents a revset and contains the basic | ||||
def __iter__(self): | def __iter__(self): | ||||
if self._ascending: | if self._ascending: | ||||
return self.fastasc() | return self.fastasc() | ||||
else: | else: | ||||
return self.fastdesc() | return self.fastdesc() | ||||
def fastasc(self): | def fastasc(self): | ||||
iterrange = xrange(self._start, self._end) | iterrange = pycompat.xrange(self._start, self._end) | ||||
if self._hiddenrevs: | if self._hiddenrevs: | ||||
return self._iterfilter(iterrange) | return self._iterfilter(iterrange) | ||||
return iter(iterrange) | return iter(iterrange) | ||||
def fastdesc(self): | def fastdesc(self): | ||||
iterrange = xrange(self._end - 1, self._start - 1, -1) | iterrange = pycompat.xrange(self._end - 1, self._start - 1, -1) | ||||
if self._hiddenrevs: | if self._hiddenrevs: | ||||
return self._iterfilter(iterrange) | return self._iterfilter(iterrange) | ||||
return iter(iterrange) | return iter(iterrange) | ||||
def __contains__(self, rev): | def __contains__(self, rev): | ||||
hidden = self._hiddenrevs | hidden = self._hiddenrevs | ||||
return ((self._start <= rev < self._end) | return ((self._start <= rev < self._end) | ||||
and not (hidden and rev in hidden)) | and not (hidden and rev in hidden)) |
cmap[xchr(x)] = e + xchr(x).lower() | cmap[xchr(x)] = e + xchr(x).lower() | ||||
dmap = {} | dmap = {} | ||||
for k, v in cmap.iteritems(): | for k, v in cmap.iteritems(): | ||||
dmap[v] = k | dmap[v] = k | ||||
def decode(s): | def decode(s): | ||||
i = 0 | i = 0 | ||||
while i < len(s): | while i < len(s): | ||||
for l in xrange(1, 4): | for l in pycompat.xrange(1, 4): | ||||
try: | try: | ||||
yield dmap[s[i:i + l]] | yield dmap[s[i:i + l]] | ||||
i += l | i += l | ||||
break | break | ||||
except KeyError: | except KeyError: | ||||
pass | pass | ||||
else: | else: | ||||
raise KeyError | raise KeyError | ||||
return (lambda s: ''.join([cmap[s[c:c + 1]] for c in xrange(len(s))]), | return (lambda s: ''.join([cmap[s[c:c + 1]] | ||||
for c in pycompat.xrange(len(s))]), | |||||
lambda s: ''.join(list(decode(s)))) | lambda s: ''.join(list(decode(s)))) | ||||
_encodefname, _decodefname = _buildencodefun() | _encodefname, _decodefname = _buildencodefun() | ||||
def encodefilename(s): | def encodefilename(s): | ||||
''' | ''' | ||||
>>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO') | >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO') | ||||
'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o' | 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o' | ||||
>>> f(b'HELLO') | >>> f(b'HELLO') | ||||
'hello' | 'hello' | ||||
>>> f(b'hello:world?') | >>> f(b'hello:world?') | ||||
'hello~3aworld~3f' | 'hello~3aworld~3f' | ||||
>>> f(b'the\\x07quick\\xADshot') | >>> f(b'the\\x07quick\\xADshot') | ||||
'the~07quick~adshot' | 'the~07quick~adshot' | ||||
''' | ''' | ||||
xchr = pycompat.bytechr | xchr = pycompat.bytechr | ||||
cmap = dict([(xchr(x), xchr(x)) for x in xrange(127)]) | cmap = dict([(xchr(x), xchr(x)) for x in pycompat.xrange(127)]) | ||||
for x in _reserved(): | for x in _reserved(): | ||||
cmap[xchr(x)] = "~%02x" % x | cmap[xchr(x)] = "~%02x" % x | ||||
for x in range(ord("A"), ord("Z") + 1): | for x in range(ord("A"), ord("Z") + 1): | ||||
cmap[xchr(x)] = xchr(x).lower() | cmap[xchr(x)] = xchr(x).lower() | ||||
def lowerencode(s): | def lowerencode(s): | ||||
return "".join([cmap[c] for c in pycompat.iterbytestr(s)]) | return "".join([cmap[c] for c in pycompat.iterbytestr(s)]) | ||||
return lowerencode | return lowerencode | ||||
# regardless of transaction nesting. | # regardless of transaction nesting. | ||||
# | # | ||||
# But transaction nesting can't be simply prohibited, because | # But transaction nesting can't be simply prohibited, because | ||||
# nesting occurs also in ordinary case (e.g. enabling | # nesting occurs also in ordinary case (e.g. enabling | ||||
# clonebundles). | # clonebundles). | ||||
with repo.transaction('clone'): | with repo.transaction('clone'): | ||||
with repo.svfs.backgroundclosing(repo.ui, expectedcount=filecount): | with repo.svfs.backgroundclosing(repo.ui, expectedcount=filecount): | ||||
for i in xrange(filecount): | for i in pycompat.xrange(filecount): | ||||
# XXX doesn't support '\n' or '\r' in filenames | # XXX doesn't support '\n' or '\r' in filenames | ||||
l = fp.readline() | l = fp.readline() | ||||
try: | try: | ||||
name, size = l.split('\0', 1) | name, size = l.split('\0', 1) | ||||
size = int(size) | size = int(size) | ||||
except (ValueError, TypeError): | except (ValueError, TypeError): | ||||
raise error.ResponseError( | raise error.ResponseError( | ||||
_('unexpected response from remote server:'), l) | _('unexpected response from remote server:'), l) |
""" | """ | ||||
def common(a, b): | def common(a, b): | ||||
if len(a) > len(b): | if len(a) > len(b): | ||||
a = b[:len(a)] | a = b[:len(a)] | ||||
elif len(b) > len(a): | elif len(b) > len(a): | ||||
b = b[:len(a)] | b = b[:len(a)] | ||||
if a == b: | if a == b: | ||||
return a | return a | ||||
for i in xrange(len(a)): | for i in pycompat.xrange(len(a)): | ||||
if a[i] != b[i]: | if a[i] != b[i]: | ||||
return a[:i] | return a[:i] | ||||
return a | return a | ||||
try: | try: | ||||
if not filelist: | if not filelist: | ||||
return "" | return "" | ||||
dirlist = [f.lstrip('/').split('/')[:-1] for f in filelist] | dirlist = [f.lstrip('/').split('/')[:-1] for f in filelist] | ||||
if len(dirlist) == 1: | if len(dirlist) == 1: | ||||
return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') | return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') | ||||
def indent(text, prefix): | def indent(text, prefix): | ||||
'''indent each non-empty line of text after first with prefix.''' | '''indent each non-empty line of text after first with prefix.''' | ||||
lines = text.splitlines() | lines = text.splitlines() | ||||
num_lines = len(lines) | num_lines = len(lines) | ||||
endswithnewline = text[-1:] == '\n' | endswithnewline = text[-1:] == '\n' | ||||
def indenter(): | def indenter(): | ||||
for i in xrange(num_lines): | for i in pycompat.xrange(num_lines): | ||||
l = lines[i] | l = lines[i] | ||||
if i and l.strip(): | if i and l.strip(): | ||||
yield prefix | yield prefix | ||||
yield l | yield l | ||||
if i < num_lines - 1 or endswithnewline: | if i < num_lines - 1 or endswithnewline: | ||||
yield '\n' | yield '\n' | ||||
return "".join(indenter()) | return "".join(indenter()) | ||||
from .i18n import _ | from .i18n import _ | ||||
from .node import ( | from .node import ( | ||||
nullid, | nullid, | ||||
short, | short, | ||||
) | ) | ||||
from . import ( | from . import ( | ||||
error, | error, | ||||
pycompat, | |||||
) | ) | ||||
def findcommonincoming(repo, remote, heads=None, force=False): | def findcommonincoming(repo, remote, heads=None, force=False): | ||||
"""Return a tuple (common, fetch, heads) used to identify the common | """Return a tuple (common, fetch, heads) used to identify the common | ||||
subset of nodes between repo and remote. | subset of nodes between repo and remote. | ||||
"common" is a list of (at least) the heads of the common subset. | "common" is a list of (at least) the heads of the common subset. | ||||
"fetch" is a list of roots of the nodes that would be incoming, to be | "fetch" is a list of roots of the nodes that would be incoming, to be | ||||
req.add(p) | req.add(p) | ||||
seen.add(n[0]) | seen.add(n[0]) | ||||
if r: | if r: | ||||
reqcnt += 1 | reqcnt += 1 | ||||
progress.increment() | progress.increment() | ||||
repo.ui.debug("request %d: %s\n" % | repo.ui.debug("request %d: %s\n" % | ||||
(reqcnt, " ".join(map(short, r)))) | (reqcnt, " ".join(map(short, r)))) | ||||
for p in xrange(0, len(r), 10): | for p in pycompat.xrange(0, len(r), 10): | ||||
with remote.commandexecutor() as e: | with remote.commandexecutor() as e: | ||||
branches = e.callcommand('branches', { | branches = e.callcommand('branches', { | ||||
'nodes': r[p:p + 10], | 'nodes': r[p:p + 10], | ||||
}).result() | }).result() | ||||
for b in branches: | for b in branches: | ||||
repo.ui.debug("received %s:%s\n" % | repo.ui.debug("received %s:%s\n" % | ||||
(short(b[0]), short(b[1]))) | (short(b[0]), short(b[1]))) |
In addition, characters classified into 'ambiguous' width are | In addition, characters classified into 'ambiguous' width are | ||||
treated as wide in East Asian area, but as narrow in other. | treated as wide in East Asian area, but as narrow in other. | ||||
This requires use decision to determine width of such characters. | This requires use decision to determine width of such characters. | ||||
""" | """ | ||||
def _cutdown(self, ucstr, space_left): | def _cutdown(self, ucstr, space_left): | ||||
l = 0 | l = 0 | ||||
colwidth = encoding.ucolwidth | colwidth = encoding.ucolwidth | ||||
for i in xrange(len(ucstr)): | for i in pycompat.xrange(len(ucstr)): | ||||
l += colwidth(ucstr[i]) | l += colwidth(ucstr[i]) | ||||
if space_left < l: | if space_left < l: | ||||
return (ucstr[:i], ucstr[i:]) | return (ucstr[:i], ucstr[i:]) | ||||
return ucstr, '' | return ucstr, '' | ||||
# overriding of base class | # overriding of base class | ||||
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): | def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): | ||||
space_left = max(width - cur_len, 1) | space_left = max(width - cur_len, 1) |
# during that time and cannot be used for recreating a new file under | # during that time and cannot be used for recreating a new file under | ||||
# that same name ("zombie file"). Directories containing such zombie files | # that same name ("zombie file"). Directories containing such zombie files | ||||
# cannot be removed or moved. | # cannot be removed or moved. | ||||
# A file that has been opened with posixfile can be renamed, so we rename | # A file that has been opened with posixfile can be renamed, so we rename | ||||
# f to a random temporary name before calling os.unlink on it. This allows | # f to a random temporary name before calling os.unlink on it. This allows | ||||
# callers to recreate f immediately while having other readers do their | # callers to recreate f immediately while having other readers do their | ||||
# implicit zombie filename blocking on a temporary name. | # implicit zombie filename blocking on a temporary name. | ||||
for tries in xrange(10): | for tries in pycompat.xrange(10): | ||||
temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) | temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) | ||||
try: | try: | ||||
os.rename(f, temp) # raises OSError EEXIST if temp exists | os.rename(f, temp) # raises OSError EEXIST if temp exists | ||||
break | break | ||||
except OSError as e: | except OSError as e: | ||||
if e.errno != errno.EEXIST: | if e.errno != errno.EEXIST: | ||||
raise | raise | ||||
else: | else: |
@property | @property | ||||
def name(self): | def name(self): | ||||
return wireprototypes.SSHV1 | return wireprototypes.SSHV1 | ||||
def getargs(self, args): | def getargs(self, args): | ||||
data = {} | data = {} | ||||
keys = args.split() | keys = args.split() | ||||
for n in xrange(len(keys)): | for n in pycompat.xrange(len(keys)): | ||||
argline = self._fin.readline()[:-1] | argline = self._fin.readline()[:-1] | ||||
arg, l = argline.split() | arg, l = argline.split() | ||||
if arg not in keys: | if arg not in keys: | ||||
raise error.Abort(_("unexpected parameter %r") % arg) | raise error.Abort(_("unexpected parameter %r") % arg) | ||||
if arg == '*': | if arg == '*': | ||||
star = {} | star = {} | ||||
for k in xrange(int(l)): | for k in pycompat.xrange(int(l)): | ||||
argline = self._fin.readline()[:-1] | argline = self._fin.readline()[:-1] | ||||
arg, l = argline.split() | arg, l = argline.split() | ||||
val = self._fin.read(int(l)) | val = self._fin.read(int(l)) | ||||
star[arg] = val | star[arg] = val | ||||
data['*'] = star | data['*'] = star | ||||
else: | else: | ||||
val = self._fin.read(int(l)) | val = self._fin.read(int(l)) | ||||
data[arg] = val | data[arg] = val |
br = [tuple(wireprototypes.decodelist(b)) for b in d.splitlines()] | br = [tuple(wireprototypes.decodelist(b)) for b in d.splitlines()] | ||||
return br | return br | ||||
except ValueError: | except ValueError: | ||||
self._abort(error.ResponseError(_("unexpected response:"), d)) | self._abort(error.ResponseError(_("unexpected response:"), d)) | ||||
def between(self, pairs): | def between(self, pairs): | ||||
batch = 8 # avoid giant requests | batch = 8 # avoid giant requests | ||||
r = [] | r = [] | ||||
for i in xrange(0, len(pairs), batch): | for i in pycompat.xrange(0, len(pairs), batch): | ||||
n = " ".join([wireprototypes.encodelist(p, '-') | n = " ".join([wireprototypes.encodelist(p, '-') | ||||
for p in pairs[i:i + batch]]) | for p in pairs[i:i + batch]]) | ||||
d = self._call("between", pairs=n) | d = self._call("between", pairs=n) | ||||
try: | try: | ||||
r.extend(l and wireprototypes.decodelist(l) or [] | r.extend(l and wireprototypes.decodelist(l) or [] | ||||
for l in d.splitlines()) | for l in d.splitlines()) | ||||
except ValueError: | except ValueError: | ||||
self._abort(error.ResponseError(_("unexpected response:"), d)) | self._abort(error.ResponseError(_("unexpected response:"), d)) |