Mercurial > hgsubversion
view hgsubversion/replay.py @ 1506:332e803044e5
commands: fix registrar check
'util' in hgsubversion is a different type from hgutil, which is the one from
core hg. This was hidden by the fallback logic, but I'm not sure why it didn't
cause errors in the tests. Maybe I ran the original tests against an older hg.
This time I've ensured the tests pass against the latest version of hg.
author | Durham Goode <durham@fb.com> |
---|---|
date | Tue, 23 May 2017 11:08:42 -0700 |
parents | cf79525f507c |
children | cb29f4bffcc7 |
line wrap: on
line source
import errno import traceback from mercurial import revlog from mercurial import node from mercurial import context from mercurial import util as hgutil import compathacks import svnexternals import util 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, path=path, data=data, islink=islink, isexec=isexec, copied=copied) meta.mapbranch(extra) current_ctx = context.memctx(meta.repo, parents, meta.getmessage(rev), files.keys(), filectxfn, 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 parent_ctx = 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), meta.getmessage(rev), files, del_all_files, 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