Mercurial hook not executing properly
Asked Answered
D

9

8

This should be a very simple thing to have run, but for some reason it won't work with my Mercurial repository. All I want is for the remote repo to automatically run hg update whenever someone pushes to it. So I have this in my .hg/hgrc file:

[hook]
changegroup = hg update

Simple, right? But for some reason, this never executes. I also tried writing a shell script that did this. .hg/hgrc looked like this:

[hooks]
changegroup = /home/marc/bin/hg-update

and hg-update looked like this:

#!/bin/sh
hg help >> /home/marc/works.txt;
hg update >> /home/marc/works.txt;
exit 0;

But again, this doesn't update. The contents of hg help are written out to works.txt, but nothing is written out for hg update. Is there something obvious I'm missing here? This has been plaguing me for days and I just can't seem to get it to work.

Update

Okay so again, using the -v switch on the command line from my workstation pushing to the remote repo doesn't print any verbose messages even when I have those echo lines in .hg/hgrc. However, when I do a push from a clone of the repo on the same filesystem (I'm logged in via SSH), this is what I get:

bash-3.00$ hg -v push ../test-repo/
pushing to ../test-repo/
searching for changes
1 changesets found
running hook prechangegroup: echo "Remote repo is at `hg tip -q`"
echo "Remote repo wdir is at `hg parents -q`"
Remote repo is at 821:1f2656753c98
Remote repo wdir is at 821:1f2656753c98
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
running hook changegroup: echo "Updating.... `hg update -v`"
echo "Remote repo is at `hg tip -q`"
echo "Remote repo wdir is at `hg parents -q`"
Updating.... resolving manifests
getting license.txt
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Remote repo is at 822:389a6c7276c6
Remote repo wdir is at 822:389a6c7276c6

So it works, but again only when I push from the same filesystem. It doesn't work if I try pushing to the repo from another workstation over the network.

Dyaus answered 11/5, 2009 at 15:25 Comment(0)
S
10

I spent some time researching this myself. I think the answer to problem is described concisely here:

Output has to be redirected to stderr (or /dev/null), because stdout is used for the data stream.

Basically, you're not redirecting to stderr, and hence polluting stdout.

Sorrow answered 3/9, 2010 at 10:1 Comment(0)
C
11

Well, after going through the same steps of frustration as Marc W did a while ago, I finally found the solution to the problem, at least when remote serving is done with the hgwebdir WSGI script.

I found out that when using this kind of remote push via HTTP or HTTPS, Mercurial simply ignores everything you write into the .hg/hgrc file or your repository. However, entering the hook in the hgwebdir config does the trick.

So if the bottom line in your hgwebdir.wsgi script is something like

application = hgwebdir('hgweb.config')

the [hooks] config section needs to go into the mentioned hgweb.config.

One drawback is that these hooks are executed for every repository listed in the [paths] section of that config. Even though HG offers another WSGI-capable function (hgweb instead of hgwebdir) to serve only a single repository, that one doesn't seem to support any hooks (neither does it have any config). This can, however, be circumvented by using a hgwebdir as described above and having some Apache RewriteRule map everything into the desired subdirectory. This one works for me:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/reponame
RewriteRule ^(.*)$ reponame/$2 [QSA]

Have fun using your remote hooks over HTTP :D

Cataplasia answered 2/2, 2010 at 12:37 Comment(3)
It's strange behaviour but I have the same issue and moving hooks section to hgwe.confog file fixed itBlackpoll
hgweb does support a config file now, in just the same way.Millet
Well this is really old but I had the same problem, and hgrc is working now by repo basis in mercurial 2.6 at least... remember that hgrc must be owned by www-dataDecembrist
S
10

I spent some time researching this myself. I think the answer to problem is described concisely here:

Output has to be redirected to stderr (or /dev/null), because stdout is used for the data stream.

Basically, you're not redirecting to stderr, and hence polluting stdout.

Sorrow answered 3/9, 2010 at 10:1 Comment(0)
L
3

First of all, I want to correct a few comments above.

  • Hooks are invoked also when pushing over file system.
  • It is not necessary to keep the hook in the repo on which you want them to operate. You can also write the same hook as in your question on the user end. You have to change the event from changegroup to outgoing and also to specify the URL of remote repo with the -R switch. Then if the pushing user has sufficient privileges on the remote repo, the hook will execute successfully.

.hg/hgrc

[hooks]
outgoing = hg update -R $HG_URL

Now towards your problem.... I suggest creating both prechangegroup and changegroup hooks and printing some debugging output.

.hg/hgrc

[hooks]
prechangegroup = echo "Remote repo is at `hg tip -q`"
                 echo "Remote repo wdir is at `hg parents -q`"
changegroup    = echo "Updating.... `hg update -v`"
                 echo "Remote repo is at `hg tip -q`"
                 echo "Remote repo wdir is at `hg parents -q`"

And also push with the -v switch, so that you may know which hook is running. If you still can't figure out, post the output. I might be able to help.

Lottery answered 17/5, 2009 at 0:28 Comment(7)
What's interesting is that what you gave me works when it's a local push, but it doesn't work when it's a remote push. I even just used "changegroup = hg update" alone and it's the same; works for local, not for remote. What's even stranger is that I don't think this was working last week when I tried it. Something must be different. Is there some sort of config I need to set to allow hooks to be run during remote pushes?Dyaus
Could you explain a little more what exactly do you mean by local push and remote push? I again ask you to post the debugging output when you push remotely with the -v switch. Use the hooks that I provided. I have no idea if there is any configuration for hook execution. You should examine your ~/.hgrc and /etc/hgrc files for non-standard, suspicious configuration for that matter. – Aamir 4 secs ago [delete this comment]Lottery
By local push, I mean pushing from the same filesystem (no network access involved). So I cloned the repository to another location in my home directory and pushed from there back to the original repo. By remote push I mean from a different workstation, pushing over the network. When I push remotely with -v, I actually get no debugging output. It's only when pushing locally that anything prints, and it's exactly what you'd expect (tip and wdir are at different revs before update, and same after). I can post it later if you still want it, though.Dyaus
I posted what you asked for in my question, Aamir.Dyaus
This bounty ends in an hour and I'd like to give it to you, but I haven't heard back from you and this still isn't working...Dyaus
So it then definitely is a problem with remote push because you said that local push over filesystem had worked as expected. I have not used mercurial in a networked environment so have no hands on this particular problem. But I suggest you to look carefully at the hgrc files and find something fishy. Also chapter 10 of hg-book is an authoritative explanation of mercurial hooks. Give it a skim.Lottery
I've been practically living out of that chapter of the book for the past week trying to figure it out. It's very thorough, but doesn't contain much troubleshooting or debugging information outside of the bundled ACL hook.Dyaus
B
3

My problem was that my hgwebdir application ran as the "hg" user, but the repository was owned by me, so I had to add in this bit of config to hgweb.config to get it to run the hooks:

[trusted]
users = me
Bicarbonate answered 14/8, 2011 at 23:54 Comment(0)
P
2

You need to have it in the remote repositiory's hgrc. It sounds as if it's in your local repo.

Edit: It also depends on how you're pushing. Some methods don't invoke hooks on the right side. (ssh does, I think HTTP does, file system does not)

Edit2: What if you push "locally" at the remote repo's computer. You might have different users/permissions between the webserver and the hgrc-file. (See [server] and trusted directives for hgrc.)

Perdurable answered 11/5, 2009 at 20:17 Comment(4)
It actually is sitting in the remote repo's .hg/hgrc. Also, all pushes take place over https.Dyaus
Ok. Can you push over ssh and see if you get a different result?Perdurable
Ok, I just tried pushing locally using the user that owns the repository. Still no dice. I don't even get any errors, either. It just seems to be ignoring the "hg update" command specifically.Dyaus
Really weird. Have you tried using a python hook, instead of a shell command?Perdurable
D
2

I had the same problem pushing from Windows Eclipse via http, but after capturing stderr, I found that the full path was needed to the hg.bat file. My hooks section now looks like:

[hooks]
incoming = c:\Python27\Scripts\hg.bat update > hg_log.txt 2>>hg_err.txt

Hope this helps someone else. SteveT

Duarte answered 19/10, 2010 at 20:34 Comment(0)
P
1

Try turning on hook debugging to see why it's not running.

Likely a permissions issue or something like that.

Provenience answered 11/5, 2009 at 15:41 Comment(1)
I had tried that as well. Nothing useful was reported. No errors or warnings or anything of that sort.Dyaus
S
1

took a while but I got it working.

I started with

[hooks]
tag=set >&2
commit=set >&2

the >&2 pipes it to standard error so remote consoles will show it.

when remote this should output in console if it is running

hg push https://host/hg   -v

It wasn't.

I was using hgweb.cgi so I switched to hgweb.wsgi with no difference.

what I discovered is that some hooks don't get called on remote.

when I switched it to

[hooks]
incoming= set >&2

the hooks tag and commit don't seem to get called but incoming and changeset do get called. I haven't confirmed the others.

now that I got it working I switched back to hgweb.cgi and everything works the same.

Skilken answered 8/11, 2010 at 14:18 Comment(0)
S
1

Tthe reason I've found for this has nothing to do with redirecting stdout to stderr. As you may see in the wiki page it is not specified on the wiki's current version https://www.mercurial-scm.org/wiki/FAQ#FAQ.2FCommonProblems.Any_way_to_.27hg_push.27_and_have_an_automatic_.27hg_update.27_on_the_remote_server.3F

The problem I've found is around permissions.

In my original setup, I had a user, lets say hguser with a repo on its home, and a script /etc/init.d/hg.init to launch hg serve. The problem being hg serve was being run by root, while most files under the repo pertained to hguser (some of them switched to root at some point, but it won't mind, since I'll correct them with chown)

Solution:

  • chown -R hguser:hguser /home/hguser/repo (to correct ALL files, back to hguser)
  • launch su hguser -c "hg serve ..." (in my case from /etc/init.d/hg.init)
  • changegroup = hg update -C under [hooks] in repo/.hg/hgrc as usual

Now it should work on push

PS: in my case, I rather update to the head of a specific branch, so I use hg update -C -r staging, to make the staging server update only to the head of the intended branch, even if the tip is from another branch (like development for instance)

BTW my hg.init script ended up like this: (notice the su hguser part)

#!/bin/sh
#
# Startup script for mercurial server.
#
# @see http://jf.blogs.teximus.com/2011/01/running-mercurial-hg-serve-on-linux.html

HG=/usr/bin/hg
CONF=/etc/mercurial/hgweb.config
# Path to PID file of running mercurial process.
PID_FILE=/etc/mercurial/hg.pid

state=$1

case "$state" in
'start')
    echo "Mecurial Server service starting."
    (su hguser -c "${HG} serve -d --webdir-conf ${CONF} -p 8000 --pid-file ${PID_FILE}")
  ;;

'stop')
  if [ -f "${PID_FILE}" ]; then
    PID=`cat "${PID_FILE}"`
    if [ "${PID}" -gt 1 ]; then
      kill -TERM ${PID}
      echo "Stopping the Mercurial service PID=${PID}."
    else
      echo Bad PID for Mercurial -- \"${PID}\"
    fi
  else

    echo No PID file recorded for mercurial
  fi
  ;;

*)
  echo "$0 {start|stop}"
  exit 1
  ;;
esac

PS: due credit to http://jf.blogs.teximus.com/2011/01/running-mercurial-hg-serve-on-linux.html

Sackcloth answered 29/5, 2015 at 21:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.