sapling/hgext/hgsubversion/replay.py
Jun Wu a487dacc4b codemod: reformat rest of the code
Summary:
Previous code format attempt (D8173629) didn't cover all files due to `**/*.py`
was not expanded recursively by bash. That makes certain changes larger than
they should be (ex. D8675439). Now use zsh's `**/*.py` to format them.

Also fix Python syntax so black can run on more files, and all lint issues.

Reviewed By: phillco

Differential Revision: D8696912

fbshipit-source-id: 95f07aa0c5eb1b63947b0f77f534957f4ab65364
2018-07-05 17:52:43 -07:00

254 lines
8.1 KiB
Python

import errno
import traceback
import compathacks
import svnexternals
import util
from mercurial import context, node, revlog, util as hgutil
class MissingPlainTextError(Exception):
"""Exception raised when the repo lacks a source file required for replaying
a txdelta.
"""
class ReplayException(Exception):
"""Exception raised when you try and commit but the replay encountered an
exception.
"""
def updateexternals(ui, meta, current):
# TODO fix and re-enable externals for single-directory clones
if not current.externals or meta.layout == "single":
return
# accumulate externals records for all branches
revnum = current.rev.revnum
branches = {}
for path, entry in current.externals.iteritems():
if not meta.is_path_valid(path):
continue
p, b, bp = meta.split_branch_path(path)
if bp not in branches:
parent = meta.get_parent_revision(revnum, b)
pctx = meta.repo[parent]
branches[bp] = (svnexternals.parse(ui, pctx), pctx)
branches[bp][0][p] = entry
# register externals file changes
for bp, (external, pctx) in branches.iteritems():
if bp and bp[-1] != "/":
bp += "/"
updates = svnexternals.getchanges(ui, meta.repo, pctx, external)
for fn, data in updates.iteritems():
path = (bp and bp + fn) or fn
if data is not None:
current.set(path, data, False, False)
else:
current.delete(path)
def convert_rev(ui, meta, svn, r, tbdelta, firstrun):
try:
return _convert_rev(ui, meta, svn, r, tbdelta, firstrun)
finally:
meta.editor.current.close()
def _convert_rev(ui, meta, svn, r, tbdelta, firstrun):
editor = meta.editor
editor.current.clear()
editor.current.rev = r
editor.setsvn(svn)
if firstrun and meta.revmap.firstpulled <= 0:
# We know nothing about this project, so fetch everything before
# trying to apply deltas.
ui.debug("replay: fetching full revision\n")
svn.get_revision(r.revnum, editor)
else:
svn.get_replay(r.revnum, editor, meta.revmap.firstpulled)
editor.close()
current = editor.current
updateexternals(ui, meta, current)
if current.exception is not None: # pragma: no cover
traceback.print_exception(*current.exception)
raise ReplayException()
files_to_commit = current.files()
branch_batches = {}
rev = current.rev
date = meta.fixdate(rev.date)
# build up the branches that have files on them
failoninvalid = ui.configbool("hgsubversion", "failoninvalidreplayfile", False)
for f in files_to_commit:
if not meta.is_path_valid(f):
if failoninvalid:
raise hgutil.Abort("file %s should not be in commit list" % f)
continue
p, b = meta.split_branch_path(f)[:2]
if b not in branch_batches:
branch_batches[b] = []
if p:
branch_batches[b].append((p, f))
closebranches = {}
for branch in tbdelta["branches"][1]:
branchedits = meta.revmap.branchedits(branch, rev.revnum)
if len(branchedits) < 1:
# can't close a branch that never existed
continue
ha = branchedits[0][1]
closebranches[branch] = ha
extraempty = set(tbdelta["branches"][0]) - (
set(current.emptybranches) | set(branch_batches.keys())
)
current.emptybranches.update([(x, False) for x in extraempty])
# 1. handle normal commits
closedrevs = closebranches.values()
for branch, files in branch_batches.iteritems():
if branch in current.emptybranches and files:
del current.emptybranches[branch]
if meta.skipbranch(branch):
# make sure we also get rid of it from emptybranches
if branch in current.emptybranches:
del current.emptybranches[branch]
continue
files = dict(files)
parents = meta.get_parent_revision(rev.revnum, branch), revlog.nullid
if parents[0] in closedrevs and branch in meta.closebranches:
continue
extra = meta.genextra(rev.revnum, branch)
tag = None
if branch is not None:
# New regular tag without modifications, it will be committed by
# svnmeta.committag(), we can skip the whole branch for now
tag = meta.get_path_tag(meta.remotename(branch))
if (
tag
and tag not in meta.tags
and branch not in meta.branches
and branch not in compathacks.branchset(meta.repo)
and not files
):
continue
parentctx = meta.repo.changectx(parents[0])
if tag:
if parentctx.node() == node.nullid:
continue
extra.update({"branch": parentctx.extra().get("branch", None), "close": 1})
def filectxfn(repo, memctx, path):
current_file = files[path]
try:
data, isexec, islink, copied = current.pop(current_file)
except IOError:
return compathacks.filectxfn_deleted_reraise(memctx)
if isexec is None or islink is None:
flags = parentctx.flags(path)
if isexec is None:
isexec = "x" in flags
if islink is None:
islink = "l" in flags
if data is not None:
if islink:
if data.startswith("link "):
data = data[len("link ") :]
else:
ui.debug(
"file marked as link, but may contain data: "
"%s\n" % current_file
)
else:
data = parentctx.filectx(path).data()
return compathacks.makememfilectx(
repo,
memctx=memctx,
path=path,
data=data,
islink=islink,
isexec=isexec,
copied=copied,
)
meta.mapbranch(extra)
if "branch" not in extra:
extra["branch"] = "default"
current_ctx = context.memctx(
meta.repo,
parents,
util.forceutf8(meta.getmessage(rev)),
[util.forceutf8(f) for f in files.keys()],
filectxfn,
util.forceutf8(meta.authors[rev.author]),
date,
extra,
)
new_hash = meta.repo.svn_commitctx(current_ctx)
util.describe_commit(ui, new_hash, branch)
if (rev.revnum, branch) not in meta.revmap and not tag:
meta.revmap[rev.revnum, branch] = new_hash
if tag:
meta.movetag(tag, new_hash, rev, date)
meta.addedtags.pop(tag, None)
# 2. handle branches that need to be committed without any files
for branch in current.emptybranches:
if meta.skipbranch(branch):
continue
ha = meta.get_parent_revision(rev.revnum, branch)
if ha == node.nullid:
continue
# Why are we constructing this? Follow up! (T24862348)
meta.repo.changectx(ha)
files = []
def del_all_files(*args):
raise IOError(errno.ENOENT, "deleting all files")
# True here means nuke all files. This happens when you
# replace a branch root with an empty directory
if current.emptybranches[branch]:
files = meta.repo[ha].files()
extra = meta.genextra(rev.revnum, branch)
meta.mapbranch(extra)
current_ctx = context.memctx(
meta.repo,
(ha, node.nullid),
util.forceutf8(meta.getmessage(rev)),
[util.forceutf8(f) for f in files],
del_all_files,
util.forceutf8(meta.authors[rev.author]),
date,
extra,
)
new_hash = meta.repo.svn_commitctx(current_ctx)
util.describe_commit(ui, new_hash, branch)
if (rev.revnum, branch) not in meta.revmap:
meta.revmap[rev.revnum, branch] = new_hash
return closebranches