##// END OF EJS Templates
use repo[changeid] to get a changectx
use repo[changeid] to get a changectx

File last commit:

r6747:f6c00b17 default
r6747:f6c00b17 default
Show More
hg.py
290 lines | 10.1 KiB | text/x-python | PythonLexer
Brendan Cully
Split convert extension into common and repository type modules
r4536 # hg backend for convert extension
Bryan O'Sullivan
convert: some tidyups, doc improvements, and test fixes...
r5556 # Notes for hg->hg conversion:
#
# * Old versions of Mercurial didn't trim the whitespace from the ends
# of commit messages, but new versions do. Changesets created by
# those older versions, then converted, may thus have different
# hashes for changesets that are otherwise identical.
#
# * By default, the source revision is stored in the converted
# revision. This will cause the converted revision to have a
# different identity than the source. To avoid this, use the
# following option: "--config convert.hg.saverev=false"
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
Brendan Cully
Split convert extension into common and repository type modules
r4536 import os, time
Bryan O'Sullivan
convert: acquire/release locks periodically
r5014 from mercurial.i18n import _
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 from mercurial.repo import RepoError
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from mercurial.node import bin, hex, nullid
Patrick Mezard
convert: hg sink commits without working dir
r6717 from mercurial import hg, revlog, util, context
Brendan Cully
Split convert extension into common and repository type modules
r4536
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 from common import NoRepo, commit, converter_source, converter_sink
Brendan Cully
Split convert extension into common and repository type modules
r4536
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 class mercurial_sink(converter_sink):
Brendan Cully
convert: split converter into convertsource and convertsink
r4763 def __init__(self, ui, path):
Bryan O'Sullivan
convert: add default constructor for converter_sink
r5440 converter_sink.__init__(self, ui, path)
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
Brendan Cully
convert: new config variable hg.tagsbranch controls which branch tags are committed to
r5260 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 self.lastbranch = None
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 if os.path.isdir(path) and len(os.listdir(path)) > 0:
try:
self.repo = hg.repository(self.ui, path)
Patrick Mezard
convert: mercurial sink must be local
r5918 if not self.repo.local():
raise NoRepo(_('%s is not a local Mercurial repo') % path)
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 except RepoError, err:
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 ui.print_exc()
raise NoRepo(err.args[0])
else:
try:
ui.status(_('initializing destination %s repository\n') % path)
self.repo = hg.repository(self.ui, path, create=True)
Patrick Mezard
convert: mercurial sink must be local
r5918 if not self.repo.local():
raise NoRepo(_('%s is not a local Mercurial repo') % path)
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 self.created.append(path)
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 except RepoError, err:
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 ui.print_exc()
raise NoRepo("could not create hg repo %s as sink" % path)
Bryan O'Sullivan
convert: acquire/release locks periodically
r5014 self.lock = None
self.wlock = None
Alexis S. L. Carvalho
convert: add a mode where mercurial_sink skips empty revisions....
r5378 self.filemapmode = False
Bryan O'Sullivan
convert: acquire/release locks periodically
r5014
def before(self):
Patrick Mezard
test-convert: test before() and after() conversion actions
r5805 self.ui.debug(_('run hg sink pre-conversion action\n'))
Alexis S. L. Carvalho
convert: fix locking order
r5052 self.wlock = self.repo.wlock()
Bryan O'Sullivan
convert: acquire/release locks periodically
r5014 self.lock = self.repo.lock()
def after(self):
Patrick Mezard
test-convert: test before() and after() conversion actions
r5805 self.ui.debug(_('run hg sink post-conversion action\n'))
Bryan O'Sullivan
convert: acquire/release locks periodically
r5014 self.lock = None
self.wlock = None
Brendan Cully
Split convert extension into common and repository type modules
r4536
Bryan O'Sullivan
convert: rename mapfile to revmapfile, so we can map more than just revs
r5011 def revmapfile(self):
Brendan Cully
Split convert extension into common and repository type modules
r4536 return os.path.join(self.path, ".hg", "shamap")
Edouard Gomez
convert extension: Add support for username mapping...
r4589 def authorfile(self):
return os.path.join(self.path, ".hg", "authormap")
Brendan Cully
Split convert extension into common and repository type modules
r4536 def getheads(self):
h = self.repo.changelog.heads()
Bryan O'Sullivan
convert: get rid of "hg." prefix where not needed
r5017 return [ hex(x) for x in h ]
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 def setbranch(self, branch, pbranches):
if not self.clonebranches:
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 return
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 setbranch = (branch != self.lastbranch)
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 self.lastbranch = branch
if not branch:
branch = 'default'
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
pbranch = pbranches and pbranches[0][1] or 'default'
Brendan Cully
convert: hg: optionally create branches as clones...
r5173
branchpath = os.path.join(self.path, branch)
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 if setbranch:
self.after()
try:
self.repo = hg.repository(self.ui, branchpath)
except:
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 self.repo = hg.repository(self.ui, branchpath, create=True)
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 self.before()
# pbranches may bring revisions from other branches (merge parents)
# Make sure we have them, or pull them.
missings = {}
for b in pbranches:
try:
self.repo.lookup(b[0])
except:
missings.setdefault(b[1], []).append(b[0])
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 if missings:
self.after()
for pbranch, heads in missings.iteritems():
pbranchpath = os.path.join(self.path, pbranch)
prepo = hg.repository(self.ui, pbranchpath)
self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
self.before()
Brendan Cully
convert: hg: optionally create branches as clones...
r5173
Patrick Mezard
convert: reintegrate file retrieval code in sinks...
r6716 def putcommit(self, files, copies, parents, commit, source):
Patrick Mezard
convert: hg sink commits without working dir
r6717 files = dict(files)
def getfilectx(repo, memctx, f):
v = files[f]
data = source.getfile(f, v)
e = source.getmode(f, v)
return context.memfilectx(f, data, 'l' in e, 'x' in e, copies.get(f))
Brendan Cully
Split convert extension into common and repository type modules
r4536 pl = []
for p in parents:
Patrick Mezard
convert: hg sink commits without working dir
r6717 if p not in pl:
Brendan Cully
Split convert extension into common and repository type modules
r4536 pl.append(p)
parents = pl
Alexis S. L. Carvalho
convert: add a mode where mercurial_sink skips empty revisions....
r5378 nparents = len(parents)
if self.filemapmode and nparents == 1:
m1node = self.repo.changelog.read(bin(parents[0]))[0]
parent = parents[0]
Brendan Cully
Split convert extension into common and repository type modules
r4536
if len(parents) < 2: parents.append("0" * 40)
if len(parents) < 2: parents.append("0" * 40)
p2 = parents.pop(0)
text = commit.desc
Bryan O'Sullivan
convert: make contents of "extra" dict available from sources, for sinks....
r5439 extra = commit.extra.copy()
Bryan O'Sullivan
convert: add config option to turn off use of branch names
r5038 if self.branchnames and commit.branch:
Brendan Cully
convert: record the source revision in the changelog
r4873 extra['branch'] = commit.branch
if commit.rev:
extra['convert_revision'] = commit.rev
Thomas Arendsen Hein
removed trailing whitespace
r4957
Brendan Cully
Split convert extension into common and repository type modules
r4536 while parents:
p1 = p2
p2 = parents.pop(0)
Patrick Mezard
convert: hg sink commits without working dir
r6717 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx,
commit.author, commit.date, extra)
a = self.repo.commitctx(ctx)
Brendan Cully
Split convert extension into common and repository type modules
r4536 text = "(octopus merge fixup)\n"
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 p2 = hex(self.repo.changelog.tip())
Brendan Cully
Split convert extension into common and repository type modules
r4536
Alexis S. L. Carvalho
convert: add a mode where mercurial_sink skips empty revisions....
r5378 if self.filemapmode and nparents == 1:
man = self.repo.manifest
mnode = self.repo.changelog.read(bin(p2))[0]
if not man.cmp(m1node, man.revision(mnode)):
self.repo.rollback()
return parent
Brendan Cully
Split convert extension into common and repository type modules
r4536 return p2
def puttags(self, tags):
Patrick Mezard
convert: hg sink commits without working dir
r6717 try:
Matt Mackall
use repo[changeid] to get a changectx
r6747 parentctx = self.repo[self.tagsbranch]
Patrick Mezard
convert: hg sink commits without working dir
r6717 tagparent = parentctx.node()
except RepoError, inst:
parentctx = None
tagparent = nullid
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: hg sink commits without working dir
r6717 try:
old = parentctx.filectx(".hgtags").data()
oldlines = old.splitlines(1)
oldlines.sort()
except:
oldlines = []
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: hg sink commits without working dir
r6717 newlines = [("%s %s\n" % (tags[tag], tag)) for tag in tags.keys()]
newlines.sort()
if newlines == oldlines:
return None
data = "".join(newlines)
def getfilectx(repo, memctx, f):
return context.memfilectx(f, data, False, False, None)
self.ui.status("updating tags\n")
date = "%s 0" % int(time.mktime(time.gmtime()))
extra = {'branch': self.tagsbranch}
ctx = context.memctx(self.repo, (tagparent, None), "update tags",
[".hgtags"], getfilectx, "convert-repo", date,
extra)
self.repo.commitctx(ctx)
return hex(self.repo.changelog.tip())
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
Alexis S. L. Carvalho
convert: add a mode where mercurial_sink skips empty revisions....
r5378 def setfilemapmode(self, active):
self.filemapmode = active
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 class mercurial_source(converter_source):
def __init__(self, ui, path, rev=None):
converter_source.__init__(self, ui, path, rev)
Bryan O'Sullivan
convert: some tidyups, doc improvements, and test fixes...
r5556 self.saverev = ui.configbool('convert', 'hg.saverev', True)
Bryan O'Sullivan
convert: fail properly if we can't read a source hg repository
r5358 try:
self.repo = hg.repository(self.ui, path)
Bryan O'Sullivan
convert: report errors more meaningfully if run with --traceback
r5437 # try to provoke an exception if this isn't really a hg
# repo, but some other bogus compatible-looking url
Alexis S. L. Carvalho
convert: make sure mercurial_source has a local hg repo
r5522 if not self.repo.local():
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 raise RepoError()
except RepoError:
Bryan O'Sullivan
convert: report errors more meaningfully if run with --traceback
r5437 ui.print_exc()
Alexis S. L. Carvalho
convert: make sure mercurial_source has a local hg repo
r5522 raise NoRepo("%s is not a local Mercurial repo" % path)
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 self.lastrev = None
self.lastctx = None
Alexis S. L. Carvalho
mercurial_source: add --filemap support
r5379 self._changescache = None
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 self.convertfp = None
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
def changectx(self, rev):
if self.lastrev != rev:
Matt Mackall
use repo[changeid] to get a changectx
r6747 self.lastctx = self.repo[rev]
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 self.lastrev = rev
return self.lastctx
def getheads(self):
Bryan O'Sullivan
convert: only get history for requested revs when converting hg repo
r5131 if self.rev:
Matt Mackall
use repo[changeid] to get a changectx
r6747 return [hex(self.repo[self.rev].node())]
Bryan O'Sullivan
convert: only get history for requested revs when converting hg repo
r5131 else:
return [hex(node) for node in self.repo.heads()]
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
def getfile(self, name, rev):
try:
Matt Mackall
use repo[changeid] to get a changectx
r6747 return self.changectx(rev)[name].data()
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 except revlog.LookupError, err:
raise IOError(err)
def getmode(self, name, rev):
m = self.changectx(rev).manifest()
return (m.execf(name) and 'x' or '') + (m.linkf(name) and 'l' or '')
def getchanges(self, rev):
ctx = self.changectx(rev)
Alexis S. L. Carvalho
mercurial_source: add --filemap support
r5379 if self._changescache and self._changescache[0] == rev:
m, a, r = self._changescache[1]
else:
m, a, r = self.repo.status(ctx.parents()[0].node(), ctx.node())[:3]
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 changes = [(name, rev) for name in m + a + r]
changes.sort()
Alexis S. L. Carvalho
convert: mercurial_source: also search for copies in modified files...
r5280 return (changes, self.getcopies(ctx, m + a))
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
Alexis S. L. Carvalho
convert: mercurial_source: also search for copies in modified files...
r5280 def getcopies(self, ctx, files):
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 copies = {}
Alexis S. L. Carvalho
convert: mercurial_source: also search for copies in modified files...
r5280 for name in files:
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 try:
copies[name] = ctx.filectx(name).renamed()[0]
except TypeError:
pass
return copies
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 def getcommit(self, rev):
ctx = self.changectx(rev)
parents = [hex(p.node()) for p in ctx.parents() if p.node() != nullid]
Bryan O'Sullivan
convert: some tidyups, doc improvements, and test fixes...
r5556 if self.saverev:
crev = rev
else:
crev = None
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013 return commit(author=ctx.user(), date=util.datestr(ctx.date()),
Bryan O'Sullivan
convert: some tidyups, doc improvements, and test fixes...
r5556 desc=ctx.description(), rev=crev, parents=parents,
Bryan O'Sullivan
convert: make contents of "extra" dict available from sources, for sinks....
r5439 branch=ctx.branch(), extra=ctx.extra())
Bryan O'Sullivan
convert: Support Mercurial as a source, as well as a sink
r5013
def gettags(self):
tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
return dict([(name, hex(node)) for name, node in tags])
Alexis S. L. Carvalho
mercurial_source: add --filemap support
r5379
def getchangedfiles(self, rev, i):
ctx = self.changectx(rev)
i = i or 0
changes = self.repo.status(ctx.parents()[i].node(), ctx.node())[:3]
if i == 0:
self._changescache = (rev, changes)
return changes[0] + changes[1] + changes[2]
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 def converted(self, rev, destrev):
if self.convertfp is None:
self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'),
'a')
self.convertfp.write('%s %s\n' % (destrev, rev))
self.convertfp.flush()
Patrick Mezard
test-convert: test before() and after() conversion actions
r5805
def before(self):
self.ui.debug(_('run hg source pre-conversion action\n'))
def after(self):
self.ui.debug(_('run hg source post-conversion action\n'))