hgext/convert/hg.py
changeset 5344 cc34be74eeec
parent 5343 26692d08c2f9
parent 5280 11e1e574da02
child 5347 9c0f864fddca
child 5354 4fbd27bf04b1
equal deleted inserted replaced
5343:26692d08c2f9 5344:cc34be74eeec
     1 # hg backend for convert extension
     1 # hg backend for convert extension
     2 
     2 
       
     3 # Note for hg->hg conversion: Old versions of Mercurial didn't trim
       
     4 # the whitespace from the ends of commit messages, but new versions
       
     5 # do.  Changesets created by those older versions, then converted, may
       
     6 # thus have different hashes for changesets that are otherwise
       
     7 # identical.
       
     8 
       
     9 
     3 import os, time
    10 import os, time
     4 from mercurial import hg
    11 from mercurial.i18n import _
     5 
    12 from mercurial.node import *
     6 from common import NoRepo, converter_sink
    13 from mercurial import hg, lock, revlog, util
     7 
    14 
     8 class convert_mercurial(converter_sink):
    15 from common import NoRepo, commit, converter_source, converter_sink
       
    16 
       
    17 class mercurial_sink(converter_sink):
     9     def __init__(self, ui, path):
    18     def __init__(self, ui, path):
    10         self.path = path
    19         self.path = path
    11         self.ui = ui
    20         self.ui = ui
       
    21         self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
       
    22         self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
       
    23         self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
       
    24         self.lastbranch = None
    12         try:
    25         try:
    13             self.repo = hg.repository(self.ui, path)
    26             self.repo = hg.repository(self.ui, path)
    14         except:
    27         except:
    15             raise NoRepo("could open hg repo %s" % path)
    28             raise NoRepo("could not open hg repo %s as sink" % path)
    16 
    29         self.lock = None
    17     def mapfile(self):
    30         self.wlock = None
       
    31 
       
    32     def before(self):
       
    33         self.wlock = self.repo.wlock()
       
    34         self.lock = self.repo.lock()
       
    35         self.repo.dirstate.clear()
       
    36 
       
    37     def after(self):
       
    38         self.repo.dirstate.invalidate()
       
    39         self.lock = None
       
    40         self.wlock = None
       
    41 
       
    42     def revmapfile(self):
    18         return os.path.join(self.path, ".hg", "shamap")
    43         return os.path.join(self.path, ".hg", "shamap")
    19 
    44 
    20     def authorfile(self):
    45     def authorfile(self):
    21         return os.path.join(self.path, ".hg", "authormap")
    46         return os.path.join(self.path, ".hg", "authormap")
    22 
    47 
    23     def getheads(self):
    48     def getheads(self):
    24         h = self.repo.changelog.heads()
    49         h = self.repo.changelog.heads()
    25         return [ hg.hex(x) for x in h ]
    50         return [ hex(x) for x in h ]
    26 
    51 
    27     def putfile(self, f, e, data):
    52     def putfile(self, f, e, data):
    28         self.repo.wwrite(f, data, e)
    53         self.repo.wwrite(f, data, e)
    29         if self.repo.dirstate.state(f) == '?':
    54         if f not in self.repo.dirstate:
    30             self.repo.dirstate.update([f], "a")
    55             self.repo.dirstate.normallookup(f)
       
    56 
       
    57     def copyfile(self, source, dest):
       
    58         self.repo.copy(source, dest)
    31 
    59 
    32     def delfile(self, f):
    60     def delfile(self, f):
    33         try:
    61         try:
    34             util.unlink(self.repo.wjoin(f))
    62             util.unlink(self.repo.wjoin(f))
    35             #self.repo.remove([f])
    63             #self.repo.remove([f])
    36         except:
    64         except:
    37             pass
    65             pass
       
    66 
       
    67     def setbranch(self, branch, pbranch, parents):
       
    68         if (not self.clonebranches) or (branch == self.lastbranch):
       
    69             return
       
    70 
       
    71         self.lastbranch = branch
       
    72         self.after()
       
    73         if not branch:
       
    74             branch = 'default'
       
    75         if not pbranch:
       
    76             pbranch = 'default'
       
    77 
       
    78         branchpath = os.path.join(self.path, branch)
       
    79         try:
       
    80             self.repo = hg.repository(self.ui, branchpath)
       
    81         except:
       
    82             if not parents:
       
    83                 self.repo = hg.repository(self.ui, branchpath, create=True)
       
    84             else:
       
    85                 self.ui.note(_('cloning branch %s to %s\n') % (pbranch, branch))
       
    86                 hg.clone(self.ui, os.path.join(self.path, pbranch),
       
    87                          branchpath, rev=parents, update=False,
       
    88                          stream=True)
       
    89                 self.repo = hg.repository(self.ui, branchpath)
    38 
    90 
    39     def putcommit(self, files, parents, commit):
    91     def putcommit(self, files, parents, commit):
    40         seen = {}
    92         seen = {}
    41         pl = []
    93         pl = []
    42         for p in parents:
    94         for p in parents:
    49         if len(parents) < 2: parents.append("0" * 40)
   101         if len(parents) < 2: parents.append("0" * 40)
    50         p2 = parents.pop(0)
   102         p2 = parents.pop(0)
    51 
   103 
    52         text = commit.desc
   104         text = commit.desc
    53         extra = {}
   105         extra = {}
    54         try:
   106         if self.branchnames and commit.branch:
    55             extra["branch"] = commit.branch
   107             extra['branch'] = commit.branch
    56         except AttributeError:
   108         if commit.rev:
    57             pass
   109             extra['convert_revision'] = commit.rev
    58 
   110 
    59         while parents:
   111         while parents:
    60             p1 = p2
   112             p1 = p2
    61             p2 = parents.pop(0)
   113             p2 = parents.pop(0)
    62             a = self.repo.rawcommit(files, text, commit.author, commit.date,
   114             a = self.repo.rawcommit(files, text, commit.author, commit.date,
    63                                     hg.bin(p1), hg.bin(p2), extra=extra)
   115                                     bin(p1), bin(p2), extra=extra)
       
   116             self.repo.dirstate.clear()
    64             text = "(octopus merge fixup)\n"
   117             text = "(octopus merge fixup)\n"
    65             p2 = hg.hex(self.repo.changelog.tip())
   118             p2 = hg.hex(self.repo.changelog.tip())
    66 
   119 
    67         return p2
   120         return p2
    68 
   121 
    87             f = self.repo.wfile(".hgtags", "w")
   140             f = self.repo.wfile(".hgtags", "w")
    88             f.write("".join(newlines))
   141             f.write("".join(newlines))
    89             f.close()
   142             f.close()
    90             if not oldlines: self.repo.add([".hgtags"])
   143             if not oldlines: self.repo.add([".hgtags"])
    91             date = "%s 0" % int(time.mktime(time.gmtime()))
   144             date = "%s 0" % int(time.mktime(time.gmtime()))
       
   145             extra = {}
       
   146             if self.tagsbranch != 'default':
       
   147                 extra['branch'] = self.tagsbranch
       
   148             try:
       
   149                 tagparent = self.repo.changectx(self.tagsbranch).node()
       
   150             except hg.RepoError, inst:
       
   151                 tagparent = nullid
    92             self.repo.rawcommit([".hgtags"], "update tags", "convert-repo",
   152             self.repo.rawcommit([".hgtags"], "update tags", "convert-repo",
    93                                 date, self.repo.changelog.tip(), hg.nullid)
   153                                 date, tagparent, nullid)
    94             return hg.hex(self.repo.changelog.tip())
   154             return hex(self.repo.changelog.tip())
       
   155 
       
   156 class mercurial_source(converter_source):
       
   157     def __init__(self, ui, path, rev=None):
       
   158         converter_source.__init__(self, ui, path, rev)
       
   159         self.repo = hg.repository(self.ui, path)
       
   160         self.lastrev = None
       
   161         self.lastctx = None
       
   162 
       
   163     def changectx(self, rev):
       
   164         if self.lastrev != rev:
       
   165             self.lastctx = self.repo.changectx(rev)
       
   166             self.lastrev = rev
       
   167         return self.lastctx
       
   168 
       
   169     def getheads(self):
       
   170         if self.rev:
       
   171             return [hex(self.repo.changectx(self.rev).node())]
       
   172         else:
       
   173             return [hex(node) for node in self.repo.heads()]
       
   174 
       
   175     def getfile(self, name, rev):
       
   176         try:
       
   177             return self.changectx(rev).filectx(name).data()
       
   178         except revlog.LookupError, err:
       
   179             raise IOError(err)
       
   180 
       
   181     def getmode(self, name, rev):
       
   182         m = self.changectx(rev).manifest()
       
   183         return (m.execf(name) and 'x' or '') + (m.linkf(name) and 'l' or '')
       
   184 
       
   185     def getchanges(self, rev):
       
   186         ctx = self.changectx(rev)
       
   187         m, a, r = self.repo.status(ctx.parents()[0].node(), ctx.node())[:3]
       
   188         changes = [(name, rev) for name in m + a + r]
       
   189         changes.sort()
       
   190         return (changes, self.getcopies(ctx, m + a))
       
   191 
       
   192     def getcopies(self, ctx, files):
       
   193         copies = {}
       
   194         for name in files:
       
   195             try:
       
   196                 copies[name] = ctx.filectx(name).renamed()[0]
       
   197             except TypeError:
       
   198                 pass
       
   199         return copies
       
   200 
       
   201     def getcommit(self, rev):
       
   202         ctx = self.changectx(rev)
       
   203         parents = [hex(p.node()) for p in ctx.parents() if p.node() != nullid]
       
   204         return commit(author=ctx.user(), date=util.datestr(ctx.date()),
       
   205                       desc=ctx.description(), parents=parents,
       
   206                       branch=ctx.branch())
       
   207 
       
   208     def gettags(self):
       
   209         tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
       
   210         return dict([(name, hex(node)) for name, node in tags])