Mercurial > public > mercurial-scm > hg-stable
diff 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 |
line wrap: on
line diff
--- a/mercurial/subrepo.py Mon Nov 15 10:57:49 2010 -0600 +++ b/mercurial/subrepo.py Sun Nov 14 18:15:26 2010 -0500 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath +import errno, os, re, xml.dom.minidom, shutil, subprocess, urlparse, posixpath from i18n import _ import config, util, node, error, cmdutil hg = None @@ -576,7 +576,87 @@ return self._svncommand(['cat'], name) +class gitsubrepo(object): + def __init__(self, ctx, path, state): + # TODO add git version check. + self._state = state + self._ctx = ctx + self._path = ctx._repo.wjoin(path) + self._ui = ctx._repo.ui + + def _gitcommand(self, commands): + return self._gitdir(commands)[0] + + def _gitdir(self, commands): + commands = ['--no-pager', '--git-dir=%s/.git' % self._path, + '--work-tree=%s' % self._path] + commands + return self._gitnodir(commands) + + def _gitnodir(self, commands): + """Calls the git command + + The methods tries to call the git command. versions previor to 1.6.0 + are not supported and very probably fail. + """ + cmd = ['git'] + commands + cmd = [util.shellquote(arg) for arg in cmd] + cmd = util.quotecommand(' '.join(cmd)) + + # print git's stderr, which is mostly progress and useful info + p = subprocess.Popen(cmd, shell=True, bufsize=-1, + close_fds=(os.name == 'posix'), + stdout=subprocess.PIPE) + retdata = p.stdout.read() + # wait for the child to exit to avoid race condition. + p.wait() + + if p.returncode != 0: + # there are certain error codes that are ok + command = None + for arg in commands: + if not arg.startswith('-'): + command = arg + break + if command == 'cat-file': + return retdata, p.returncode + if command in ('commit', 'status') and p.returncode == 1: + return retdata, p.returncode + # for all others, abort + raise util.Abort('git %s error %d' % (command, p.returncode)) + + return retdata, p.returncode + + def _gitstate(self): + return self._gitcommand(['rev-parse', 'HEAD']).strip() + + def _githavelocally(self, revision): + out, code = self._gitdir(['cat-file', '-e', revision]) + return code == 0 + + def dirty(self): + if self._state[1] != self._gitstate(): # version checked out changed? + return True + # check for staged changes or modified files; ignore untracked files + # docs say --porcelain flag is future-proof format + changed = self._gitcommand(['status', '--porcelain', + '--untracked-files=no']) + return bool(changed.strip()) + + def commit(self, text, user, date): + cmd = ['commit', '-a', '-m', text] + if user: + cmd += ['--author', user] + if date: + # git's date parser silently ignores when seconds < 1e9 + # convert to ISO8601 + cmd += ['--date', util.datestr(date, '%Y-%m-%dT%H:%M:%S %1%2')] + self._gitcommand(cmd) + # make sure commit works otherwise HEAD might not exist under certain + # circumstances + return self._gitstate() + types = { 'hg': hgsubrepo, 'svn': svnsubrepo, + 'git': gitsubrepo, }