hgext/convert/git.py
changeset 17929 0eed66327ad4
parent 16689 f366d4c2ff34
child 17930 7788b5e7d9ef
equal deleted inserted replaced
17928:082c0e1ecc23 17929:0eed66327ad4
     4 #
     4 #
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 import os
     8 import os
     9 from mercurial import util
     9 from mercurial import util, config
    10 from mercurial.node import hex, nullid
    10 from mercurial.node import hex, nullid
    11 from mercurial.i18n import _
    11 from mercurial.i18n import _
    12 
    12 
    13 from common import NoRepo, commit, converter_source, checktool
    13 from common import NoRepo, commit, converter_source, checktool
       
    14 
       
    15 class submodule(object):
       
    16     def __init__(self, path, node, url):
       
    17         self.path = path
       
    18         self.node = node
       
    19         self.url = url
       
    20 
       
    21     def hgsub(self):
       
    22         return "%s = [git]%s" % (self.path, self.url)
       
    23 
       
    24     def hgsubstate(self):
       
    25         return "%s %s" % (self.node, self.path)
    14 
    26 
    15 class convert_git(converter_source):
    27 class convert_git(converter_source):
    16     # Windows does not support GIT_DIR= construct while other systems
    28     # Windows does not support GIT_DIR= construct while other systems
    17     # cannot remove environment variable. Just assume none have
    29     # cannot remove environment variable. Just assume none have
    18     # both issues.
    30     # both issues.
    53             raise NoRepo(_("%s does not look like a Git repository") % path)
    65             raise NoRepo(_("%s does not look like a Git repository") % path)
    54 
    66 
    55         checktool('git', 'git')
    67         checktool('git', 'git')
    56 
    68 
    57         self.path = path
    69         self.path = path
       
    70         self.submodules = []
    58 
    71 
    59     def getheads(self):
    72     def getheads(self):
    60         if not self.rev:
    73         if not self.rev:
    61             heads, ret = self.gitread('git rev-parse --branches --remotes')
    74             heads, ret = self.gitread('git rev-parse --branches --remotes')
    62             heads = heads.splitlines()
    75             heads = heads.splitlines()
    74         if ret:
    87         if ret:
    75             raise util.Abort(_('cannot read %r object at %s') % (type, rev))
    88             raise util.Abort(_('cannot read %r object at %s') % (type, rev))
    76         return data
    89         return data
    77 
    90 
    78     def getfile(self, name, rev):
    91     def getfile(self, name, rev):
    79         data = self.catfile(rev, "blob")
    92         if name == '.hgsub':
    80         mode = self.modecache[(name, rev)]
    93             data = '\n'.join([m.hgsub() for m in self.submoditer()])
       
    94             mode = ''
       
    95         elif name == '.hgsubstate':
       
    96             data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
       
    97             mode = ''
       
    98         else:
       
    99             data = self.catfile(rev, "blob")
       
   100             mode = self.modecache[(name, rev)]
    81         return data, mode
   101         return data, mode
       
   102 
       
   103     def submoditer(self):
       
   104         null = hex(nullid)
       
   105         for m in sorted(self.submodules, key=lambda p: p.path):
       
   106             if m.node != null:
       
   107                 yield m
       
   108 
       
   109     def parsegitmodules(self, content):
       
   110         """Parse the formatted .gitmodules file, example file format:
       
   111         [submodule "sub"]\n
       
   112         \tpath = sub\n
       
   113         \turl = git://giturl\n
       
   114         """
       
   115         self.submodules = []
       
   116         c = config.config()
       
   117         # Each item in .gitmodules starts with \t that cant be parsed
       
   118         c.parse('.gitmodules', content.replace('\t',''))
       
   119         for sec in c.sections():
       
   120             s = c[sec]
       
   121             if 'url' in s and 'path' in s:
       
   122                 self.submodules.append(submodule(s['path'], '', s['url']))
       
   123 
       
   124     def retrievegitmodules(self, version):
       
   125         modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
       
   126         if ret:
       
   127             raise util.Abort(_('cannot read submodules config file in %s') % version)
       
   128         self.parsegitmodules(modules)
       
   129         for m in self.submodules:
       
   130             node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
       
   131             if ret:
       
   132                 continue
       
   133             m.node = node.strip()
    82 
   134 
    83     def getchanges(self, version):
   135     def getchanges(self, version):
    84         self.modecache = {}
   136         self.modecache = {}
    85         fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
   137         fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
    86         changes = []
   138         changes = []
    87         seen = set()
   139         seen = set()
    88         entry = None
   140         entry = None
       
   141         subexists = False
    89         for l in fh.read().split('\x00'):
   142         for l in fh.read().split('\x00'):
    90             if not entry:
   143             if not entry:
    91                 if not l.startswith(':'):
   144                 if not l.startswith(':'):
    92                     continue
   145                     continue
    93                 entry = l
   146                 entry = l
    95             f = l
   148             f = l
    96             if f not in seen:
   149             if f not in seen:
    97                 seen.add(f)
   150                 seen.add(f)
    98                 entry = entry.split()
   151                 entry = entry.split()
    99                 h = entry[3]
   152                 h = entry[3]
   100                 if entry[1] == '160000':
       
   101                     raise util.Abort('git submodules are not supported!')
       
   102                 p = (entry[1] == "100755")
   153                 p = (entry[1] == "100755")
   103                 s = (entry[1] == "120000")
   154                 s = (entry[1] == "120000")
   104                 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
   155 
   105                 changes.append((f, h))
   156                 if f == '.gitmodules':
       
   157                     subexists = True
       
   158                     changes.append(('.hgsub', ''))
       
   159                 elif entry[1] == '160000' or entry[0] == ':160000':
       
   160                     subexists = True
       
   161                 else:
       
   162                     self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
       
   163                     changes.append((f, h))
   106             entry = None
   164             entry = None
   107         if fh.close():
   165         if fh.close():
   108             raise util.Abort(_('cannot read changes in %s') % version)
   166             raise util.Abort(_('cannot read changes in %s') % version)
       
   167 
       
   168         if subexists:
       
   169             self.retrievegitmodules(version)
       
   170             changes.append(('.hgsubstate', ''))
   109         return (changes, {})
   171         return (changes, {})
   110 
   172 
   111     def getcommit(self, version):
   173     def getcommit(self, version):
   112         c = self.catfile(version, "commit") # read the commit hash
   174         c = self.catfile(version, "commit") # read the commit hash
   113         end = c.find("\n\n")
   175         end = c.find("\n\n")