comparison mercurial/subrepo.py @ 12992:2b73a3279a9f

subrepo: support for adding a git subrepo gitsubrepo based on patch from David Soria Parra: http://bitbucket.org/segv/davids-poor-git-subrepo-attempt/
author Eric Eisner <ede@mit.edu>
date Sun, 14 Nov 2010 18:15:26 -0500
parents 9bb180abc4d0
children a91334380699
comparison
equal deleted inserted replaced
12991:23de1a7f8e82 12992:2b73a3279a9f
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com> 3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
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 errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath 8 import errno, os, re, xml.dom.minidom, shutil, subprocess, urlparse, posixpath
9 from i18n import _ 9 from i18n import _
10 import config, util, node, error, cmdutil 10 import config, util, node, error, cmdutil
11 hg = None 11 hg = None
12 12
13 nullstate = ('', '', 'empty') 13 nullstate = ('', '', 'empty')
574 574
575 def filedata(self, name): 575 def filedata(self, name):
576 return self._svncommand(['cat'], name) 576 return self._svncommand(['cat'], name)
577 577
578 578
579 class gitsubrepo(object):
580 def __init__(self, ctx, path, state):
581 # TODO add git version check.
582 self._state = state
583 self._ctx = ctx
584 self._path = ctx._repo.wjoin(path)
585 self._ui = ctx._repo.ui
586
587 def _gitcommand(self, commands):
588 return self._gitdir(commands)[0]
589
590 def _gitdir(self, commands):
591 commands = ['--no-pager', '--git-dir=%s/.git' % self._path,
592 '--work-tree=%s' % self._path] + commands
593 return self._gitnodir(commands)
594
595 def _gitnodir(self, commands):
596 """Calls the git command
597
598 The methods tries to call the git command. versions previor to 1.6.0
599 are not supported and very probably fail.
600 """
601 cmd = ['git'] + commands
602 cmd = [util.shellquote(arg) for arg in cmd]
603 cmd = util.quotecommand(' '.join(cmd))
604
605 # print git's stderr, which is mostly progress and useful info
606 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
607 close_fds=(os.name == 'posix'),
608 stdout=subprocess.PIPE)
609 retdata = p.stdout.read()
610 # wait for the child to exit to avoid race condition.
611 p.wait()
612
613 if p.returncode != 0:
614 # there are certain error codes that are ok
615 command = None
616 for arg in commands:
617 if not arg.startswith('-'):
618 command = arg
619 break
620 if command == 'cat-file':
621 return retdata, p.returncode
622 if command in ('commit', 'status') and p.returncode == 1:
623 return retdata, p.returncode
624 # for all others, abort
625 raise util.Abort('git %s error %d' % (command, p.returncode))
626
627 return retdata, p.returncode
628
629 def _gitstate(self):
630 return self._gitcommand(['rev-parse', 'HEAD']).strip()
631
632 def _githavelocally(self, revision):
633 out, code = self._gitdir(['cat-file', '-e', revision])
634 return code == 0
635
636 def dirty(self):
637 if self._state[1] != self._gitstate(): # version checked out changed?
638 return True
639 # check for staged changes or modified files; ignore untracked files
640 # docs say --porcelain flag is future-proof format
641 changed = self._gitcommand(['status', '--porcelain',
642 '--untracked-files=no'])
643 return bool(changed.strip())
644
645 def commit(self, text, user, date):
646 cmd = ['commit', '-a', '-m', text]
647 if user:
648 cmd += ['--author', user]
649 if date:
650 # git's date parser silently ignores when seconds < 1e9
651 # convert to ISO8601
652 cmd += ['--date', util.datestr(date, '%Y-%m-%dT%H:%M:%S %1%2')]
653 self._gitcommand(cmd)
654 # make sure commit works otherwise HEAD might not exist under certain
655 # circumstances
656 return self._gitstate()
657
579 types = { 658 types = {
580 'hg': hgsubrepo, 659 'hg': hgsubrepo,
581 'svn': svnsubrepo, 660 'svn': svnsubrepo,
661 'git': gitsubrepo,
582 } 662 }