hgext/convert/darcs.py
changeset 5355 6b6104430964
child 5357 4ad2a18aff42
equal deleted inserted replaced
5354:4fbd27bf04b1 5355:6b6104430964
       
     1 # darcs support for the convert extension
       
     2 
       
     3 from common import NoRepo, commit, converter_source
       
     4 from mercurial.i18n import _
       
     5 from mercurial import util
       
     6 import os, shutil, tempfile
       
     7 
       
     8 # The naming drift of ElementTree is fun!
       
     9 
       
    10 try: from xml.etree.cElementTree import ElementTree
       
    11 except ImportError:
       
    12     try: from xml.etree.ElementTree import ElementTree
       
    13     except ImportError:
       
    14         try: from elementtree.cElementTree import ElementTree
       
    15         except ImportError:
       
    16             try: from elementtree.ElementTree import ElementTree
       
    17             except ImportError: ElementTree = None
       
    18 
       
    19 
       
    20 class darcs_source(converter_source):
       
    21     def __init__(self, ui, path, rev=None):
       
    22         super(darcs_source, self).__init__(ui, path, rev=rev)
       
    23 
       
    24         if not os.path.exists(os.path.join(path, '_darcs', 'inventory')):
       
    25             raise NoRepo("couldn't open darcs repo %s" % path)
       
    26 
       
    27         if ElementTree is None:
       
    28             raise util.Abort(_("Python ElementTree module is not available"))
       
    29 
       
    30         self.path = os.path.realpath(path)
       
    31 
       
    32         self.lastrev = None
       
    33         self.changes = {}
       
    34         self.parents = {}
       
    35         self.tags = {}
       
    36 
       
    37     def before(self):
       
    38         self.tmppath = tempfile.mkdtemp(
       
    39             prefix='convert-' + os.path.basename(self.path) + '-')
       
    40         output, status = self.run('init', repodir=self.tmppath)
       
    41         self.checkexit(status)
       
    42 
       
    43         tree = self.xml('changes', '--xml-output', '--summary')
       
    44         tagname = None
       
    45         child = None
       
    46         for elt in tree.findall('patch'):
       
    47             node = elt.get('hash')
       
    48             name = elt.findtext('name', '')
       
    49             if name.startswith('TAG '):
       
    50                 tagname = name[4:].strip()
       
    51             elif tagname is not None:
       
    52                 self.tags[tagname] = node
       
    53                 tagname = None
       
    54             self.changes[node] = elt
       
    55             self.parents[child] = [node]
       
    56             child = node
       
    57         self.parents[child] = []
       
    58 
       
    59     def after(self):
       
    60         self.ui.debug('cleaning up %s\n' % self.tmppath)
       
    61         #shutil.rmtree(self.tmppath, ignore_errors=True)
       
    62 
       
    63     def _run(self, cmd, *args, **kwargs):
       
    64         cmdline = 'darcs %s --repodir=%r %s </dev/null' % (
       
    65             cmd, kwargs.get('repodir', self.path), ' '.join(args))
       
    66         self.ui.debug(cmdline, '\n')
       
    67         return os.popen(cmdline, 'r')
       
    68 
       
    69     def run(self, cmd, *args, **kwargs):
       
    70         fp = self._run(cmd, *args, **kwargs)
       
    71         output = fp.read()
       
    72         return output, fp.close()
       
    73 
       
    74     def checkexit(self, status, output=''):
       
    75         if status:
       
    76             if output:
       
    77                 ui.warn(_('darcs error:\n'))
       
    78                 ui.warn(output)
       
    79             msg = util.explain_exit(status)[0]
       
    80             raise util.Abort(_('darcs %s') % msg)
       
    81         
       
    82     def xml(self, cmd, *opts):
       
    83         etree = ElementTree()
       
    84         fp = self._run(cmd, *opts)
       
    85         etree.parse(fp)
       
    86         self.checkexit(fp.close())
       
    87         return etree.getroot()
       
    88 
       
    89     def getheads(self):
       
    90         return self.parents[None]
       
    91 
       
    92     def getcommit(self, rev):
       
    93         elt = self.changes[rev]
       
    94         date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
       
    95         desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
       
    96         return commit(author=elt.get('author'), date=util.datestr(date),
       
    97                       desc=desc.strip(), parents=self.parents[rev])
       
    98 
       
    99     def pull(self, rev):
       
   100         output, status = self.run('pull %r --all --match="hash %s"' %
       
   101                                   (self.path, rev),
       
   102                                   '--no-test', '--no-posthook',
       
   103                                   '--external-merge=/bin/false',
       
   104                                   repodir=self.tmppath)
       
   105         if status:
       
   106             if output.find('We have conflicts in') == -1:
       
   107                 self.checkexit(status, output)
       
   108             output, status = self.run('revert --all', repodir=self.tmppath)
       
   109             self.checkexit(status, output)
       
   110 
       
   111     def getchanges(self, rev):
       
   112         self.pull(rev)
       
   113         copies = {}
       
   114         changes = []
       
   115         for elt in self.changes[rev].find('summary').getchildren():
       
   116             if elt.tag in ('add_directory', 'remove_directory'):
       
   117                 continue
       
   118             if elt.tag == 'move':
       
   119                 changes.append((elt.get('from'), rev))
       
   120                 copies[elt.get('from')] = elt.get('to')
       
   121             else:
       
   122                 changes.append((elt.text.strip(), rev))
       
   123         changes.sort()
       
   124         self.lastrev = rev
       
   125         return changes, copies
       
   126 
       
   127     def getfile(self, name, rev):
       
   128         if rev != self.lastrev:
       
   129             raise util.Abort(_('internal calling inconsistency'))
       
   130         return open(os.path.join(self.tmppath, name), 'rb').read()
       
   131 
       
   132     def getmode(self, name, rev):
       
   133         mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
       
   134         return (mode & 0111) and 'x' or ''
       
   135 
       
   136     def gettags(self):
       
   137         return self.tags