4

I am trying to debug a Mercurial extension. This extension adds some code that should be executed when a pull is performed. The original author setup this hook by changing the class of the repository object.

Here is the relevant code (which is actually a valid Mercurial extension):

def reposetup(ui, repo):
    class myrepo(repo.__class__):
        def pull(self, remote, heads=None, force=False):
            print "pull called"
            return super(myrepo, self).pull(remote, heads, force)

    print "reposetup called"
    if repo.local():
        print "repo is local"
        repo.__class__ = myrepo

When I perform a hg pull with this extension enabled, here is the output:

# hg pull
reposetup called
repo is local
pulling from ssh://hgbox/myrepo
reposetup called
searching for changes
no changes found

Is this a reasonable way to inject the code of the extension in the pull command? Why is the "pull called" statement never reached?

I use Mercurial 3.4.1 on Windows 7 with python 2.7.5.

barjak
  • 10,842
  • 3
  • 33
  • 47

1 Answers1

5

According to the code (mercurial/extensions.py), this is the only reasonable way to extend the repository object (https://www.mercurial-scm.org/repo/hg/file/ff5172c83002/mercurial/extensions.py#l227).

However, I looked at the code and the localrepo object does not appear to have a pull method at this point, so I suspect this is why your "pull called" print statement never shows up -- nothing calls it because it's not expected to exist!

There are better ways to inject code into pulls, depending on what you're trying to accomplish. For example, if you simply want to run something whenever the a pull is issued, prefer instead to wrap the exchange.pull function:

extensions.wrapfunction(exchange, 'pull', my_pull_function)

For your specific use case, I'd suggest creating a method with the following code:

def expull(orig, repo, remote, *args, **kwargs):
    transferprojrc(repo.ui, repo, remote)
    return orig(repo, remote, *args, **kwargs)

In the extsetup method, add a line like this:

extensions.wrapfunction(exchange, 'pull', expull)

Finally, in the reposetup method, you can remove the projrcrepo class stuff entirely. Hopefully that will get you the behavior you're looking for.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
ryanmce
  • 436
  • 2
  • 5
  • Thanks for your answer. I am trying to adapt the code using your suggestion, but with no success so far (I'm not a python developer and I'm a bit lost sometimes). In fact, what I'm trying to accomplish is to make the `projrc` extension work. I submitted [an issue](https://bitbucket.org/aragost/projrc/issue/2/no-projrc-update-on-pull#comment-18753387) describing my issue, but since I didn't get a feedback I'm trying to fix it by myself (with the help of SO, obviously!). – barjak Jun 25 '15 at 08:44
  • 2
    I checked out out mercurial's code, and I don't see any pull method in the localrepo class, which is probably a better explanation of why the code isn't running than my first guess. I'll update my answer with some more specific ideas now that I know what you're trying to accomplish. – ryanmce Jun 26 '15 at 02:24
  • 2
    Thanks for the follow-up. I was able to make it work by following your suggestion of using `exchange::pull`. I created a [pull request](https://bitbucket.org/aragost/projrc/pull-request/5/make-projrc-compatible-with-mercurial-32/diff) to the Projrc project. Would you mind taking a look at my diff and tell me if you think it's ok? – barjak Jun 26 '15 at 10:26
  • I took a look, it seems fine to me. – ryanmce Jul 03 '15 at 18:10