[PATCH 1 of 3] subrepo: support for adding a git subrepo
Augie Fackler
durin42 at gmail.com
Sun Nov 14 04:39:46 UTC 2010
On Nov 11, 2010, at 1:43 PM, Eric Eisner wrote:
> # HG changeset patch
> # User Eric Eisner <ede at mit.edu>
> # Date 1289503448 18000
> # Node ID ccc59ab604a8160d44847754f8b48dedb25d2f16
> # Parent e80128e40c044ea6619c3dc160df69ad36a8e5ff
> subrepo: support for adding a git subrepo
>
> gitsubrepo based on patch from David Soria Parra:
> http://bitbucket.org/segv/davids-poor-git-subrepo-attempt/
>
> diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
> --- a/mercurial/subrepo.py
> +++ b/mercurial/subrepo.py
> @@ -576,7 +576,93 @@ class svnsubrepo(abstractsubrepo):
> return self._svncommand(['cat'], name)
>
>
> +# Subrepository implementation for git.
> +#
> +# We try to call out the git plumbing command set as often as possible. Git
> +# porcelain might change so we cannot use porcelain directly.
> +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))
> +
> + p = util.popenp(cmd)
> + write, read, err = p.stdin, p.stdout, p.stderr
> + retdata = read.read()
> + err = err.read().strip()
> +
> + if err:
> + raise util.Abort(err)
> + # we have to wait for the child to exit to avoid race condition.
> + p.wait()
> + 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 _fetch(self, source, revision):
> + if not os.path.exists('%s/.git' % self._path):
> + self._gitnodir(['clone', source, self._path])
> + if self._githavelocally(revision):
> + return
> + self._ui.status(_('pulling subrepo %s\n') % self._path)
> + self._gitcommand(['fetch', '--all', source])
> + if not self._githavelocally(revision):
> + raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
> + (revision, source))
> +
> + 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
> + changed = self._gitcommand(['status', '--porcelain',
> + '--untracked-files=no'])
> + return bool(changed.strip())
> +
> + def get(self, state):
> + source, revision, kind = state
> + self._fetch(source, revision)
> + if self._gitstate() != revision:
> + self._ui.status(self._gitcommand(['checkout', '-f', revision]))
> +
> + def commit(self, text, user, date):
> + cmd = ['commit', '-a', '-m', text]
> + if user:
> + cmd += ['--author', user]
> + # TODO: git's date parser silently ignores when seconds < 1e9
> + if date:
> + cmd += ['--date', '%s %s' % date]
> + self._gitcommand(cmd)
> + # make sure commit works otherwise HEAD might not exist under certain
> + # circumstances
> + return self._gitstate()
Does git print a warning about detached HEAD states? It might be worth warning the user in this case, but I'm not sure of that.
> +
> types = {
> 'hg': hgsubrepo,
> 'svn': svnsubrepo,
> + 'git': gitsubrepo,
> }
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -72,6 +72,15 @@ def popen3(cmd, env=None, newlines=False
> env=env)
> return p.stdin, p.stdout, p.stderr
>
> +def popenp(cmd, env=None, newlines=False):
> + p = subprocess.Popen(cmd, shell=True, bufsize=-1,
> + close_fds=closefds,
> + stdin=subprocess.PIPE, stdout=subprocess.PIPE,
> + stderr=subprocess.PIPE,
> + universal_newlines=newlines,
> + env=env)
> + return p
> +
> def version():
> """Return version information if available."""
> try:
> diff --git a/tests/test-subrepo-git.t b/tests/test-subrepo-git.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-subrepo-git.t
> @@ -0,0 +1,59 @@
> + $ "$TESTDIR/hghave" git || exit 80
> +
> +make git commits repeatable
> +
> + $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
> + $ GIT_AUTHOR_EMAIL='test at example.org'; export GIT_AUTHOR_EMAIL
> + $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
> + $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
> + $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
> + $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
> +
> +root hg repo
> +
> + $ hg init t
> + $ cd t
> + $ echo a > a
> + $ hg add a
> + $ hg commit -m a
> + $ cd ..
> +
> +new external git repo
> +
> + $ mkdir gitroot
> + $ GITROOT=file://$TESTTMP/gitroot ; export GITROOT
> + $ cd gitroot
> + $ git init -q
> + $ echo g > g
> + $ git add g
> + $ git commit -q -m g
> +
> +add subrepo clone
> +
> + $ cd ../t
> + $ echo 's = [git]../gitroot' > .hgsub
> + $ git clone -q ../gitroot s
> + $ hg add .hgsub
> + $ hg commit -m 'new git subrepo'
> + committing subrepository $TESTTMP/t/s
> + $ hg debugsub
> + path s
> + source ../gitroot
> + revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
> +
> +record a new commit from upstream
> +
> + $ cd ../gitroot
> + $ echo gg >> g
> + $ git commit -q -a -m gg
> +
> + $ cd ../t/s
> + $ git pull -q
> +
> + $ cd ..
> + $ hg commit -m 'update git subrepo'
> + committing subrepository $TESTTMP/t/s
> + $ hg debugsub
> + path s
> + source ../gitroot
> + revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list