hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
all repository classes now have url() method that returns url of repo.
--- a/doc/hgrc.5.txt
+++ b/doc/hgrc.5.txt
@@ -194,7 +194,8 @@ hooks::
changegroup;;
Run after a changegroup has been added via push, pull or
- unbundle. ID of the first new changeset is in $HG_NODE.
+ unbundle. ID of the first new changeset is in $HG_NODE. URL from
+ which changes came is in $HG_URL.
commit;;
Run after a changeset has been created in the local repository.
ID of the newly created changeset is in $HG_NODE. Parent
@@ -202,7 +203,7 @@ hooks::
incoming;;
Run after a changeset has been pulled, pushed, or unbundled into
the local repository. The ID of the newly arrived changeset is in
- $HG_NODE.
+ $HG_NODE. URL that was source of changes came is in $HG_URL.
outgoing;;
Run after sending changes from local repository to another. ID of
first changeset sent is in $HG_NODE. Source of operation is in
@@ -210,7 +211,8 @@ hooks::
prechangegroup;;
Run before a changegroup is added via push, pull or unbundle.
Exit status 0 allows the changegroup to proceed. Non-zero status
- will cause the push, pull or unbundle to fail.
+ will cause the push, pull or unbundle to fail. URL from which
+ changes will come is in $HG_URL.
precommit;;
Run before starting a local commit. Exit status 0 allows the
commit to proceed. Non-zero status will cause the commit to fail.
@@ -236,7 +238,8 @@ hooks::
before accepting them. Passed the ID of the first new changeset
in $HG_NODE. Exit status 0 allows the transaction to commit.
Non-zero status will cause the transaction to be rolled back and
- the push, pull or unbundle will fail.
+ the push, pull or unbundle will fail. URL that was source of
+ changes is in $HG_URL.
pretxncommit;;
Run after a changeset has been created but the transaction not yet
committed. Changeset is visible to hook program. This lets you
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -159,6 +159,10 @@ class bundlefilelog(bundlerevlog, filelo
class bundlerepository(localrepo.localrepository):
def __init__(self, ui, path, bundlename):
localrepo.localrepository.__init__(self, ui, path)
+
+ self._url = 'bundle:' + bundlename
+ if path: self._url += '+' + path
+
self.tempfile = None
self.bundlefile = open(bundlename, "rb")
header = self.bundlefile.read(6)
@@ -208,6 +212,9 @@ class bundlerepository(localrepo.localre
for c in changegroup.chunkiter(self.bundlefile):
pass
+ def url(self):
+ return self._url
+
def dev(self):
return -1
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2763,7 +2763,8 @@ def unbundle(ui, repo, fname, **opts):
raise util.Abort(_("%s: unknown bundle compression type")
% fname)
gen = generator(util.filechunkiter(f, 4096))
- modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
+ modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
+ 'bundle:' + fname)
return postincoming(ui, repo, modheads, opts['update'])
def undo(ui, repo):
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -904,9 +904,13 @@ class hgweb(object):
# require ssl by default, auth info cannot be sniffed and
# replayed
ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
- if ssl_req and not req.env.get('HTTPS'):
- bail(_('ssl required\n'))
- return
+ if ssl_req:
+ if not req.env.get('HTTPS'):
+ bail(_('ssl required\n'))
+ return
+ proto = 'https'
+ else:
+ proto = 'http'
# do not allow push unless explicitly allowed
if not self.check_perm(req, 'push', False):
@@ -952,7 +956,9 @@ class hgweb(object):
sys.stdout = cStringIO.StringIO()
try:
- ret = self.repo.addchangegroup(fp, 'serve')
+ url = 'remote:%s:%s' % (proto,
+ req.env.get('REMOTE_HOST', ''))
+ ret = self.repo.addchangegroup(fp, 'serve', url)
finally:
val = sys.stdout.getvalue()
sys.stdout = old_stdout
--- a/mercurial/httprepo.py
+++ b/mercurial/httprepo.py
@@ -115,6 +115,7 @@ else:
class httprepository(remoterepository):
def __init__(self, ui, path):
+ self.path = path
self.caps = None
scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
if query or frag:
@@ -124,8 +125,8 @@ class httprepository(remoterepository):
host, port, user, passwd = netlocsplit(netloc)
# urllib cannot handle URLs with embedded user or passwd
- self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
- urlpath, '', ''))
+ self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
+ urlpath, '', ''))
self.ui = ui
proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
@@ -189,6 +190,9 @@ class httprepository(remoterepository):
opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
urllib2.install_opener(opener)
+ def url(self):
+ return self.path
+
# look up capabilities only when needed
def get_caps(self):
@@ -213,7 +217,7 @@ class httprepository(remoterepository):
q = {"cmd": cmd}
q.update(args)
qs = urllib.urlencode(q)
- cu = "%s?%s" % (self.url, qs)
+ cu = "%s?%s" % (self._url, qs)
try:
resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
except urllib2.HTTPError, inst:
@@ -234,13 +238,13 @@ class httprepository(remoterepository):
not proto.startswith('text/plain') and \
not proto.startswith('application/hg-changegroup'):
raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
- self.url)
+ self._url)
if proto.startswith('application/mercurial'):
version = proto[22:]
if float(version) > 0.1:
raise hg.RepoError(_("'%s' uses newer protocol %s") %
- (self.url, version))
+ (self._url, version))
return resp
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -83,6 +83,9 @@ class localrepository(repo.repository):
self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
+ def url(self):
+ return 'file:' + self.root
+
def hook(self, name, throw=False, **args):
def callhook(hname, funcname):
'''call python hook. hook is callable object, looked up as
@@ -1185,7 +1188,7 @@ class localrepository(repo.repository):
cg = remote.changegroup(fetch, 'pull')
else:
cg = remote.changegroupsubset(fetch, heads, 'pull')
- return self.addchangegroup(cg, 'pull')
+ return self.addchangegroup(cg, 'pull', remote.url())
def push(self, remote, force=False, revs=None):
# there are two ways to push to remote repo:
@@ -1241,7 +1244,7 @@ class localrepository(repo.repository):
ret = self.prepush(remote, force, revs)
if ret[0] is not None:
cg, remote_heads = ret
- return remote.addchangegroup(cg, 'push')
+ return remote.addchangegroup(cg, 'push', self.url())
return ret[1]
def push_unbundle(self, remote, force, revs):
@@ -1594,7 +1597,7 @@ class localrepository(repo.repository):
return util.chunkbuffer(gengroup())
- def addchangegroup(self, source, srctype):
+ def addchangegroup(self, source, srctype, url):
"""add changegroup to repo.
returns number of heads modified or added + 1."""
@@ -1608,7 +1611,7 @@ class localrepository(repo.repository):
if not source:
return 0
- self.hook('prechangegroup', throw=True, source=srctype)
+ self.hook('prechangegroup', throw=True, source=srctype, url=url)
changesets = files = revisions = 0
@@ -1675,17 +1678,18 @@ class localrepository(repo.repository):
if changesets > 0:
self.hook('pretxnchangegroup', throw=True,
- node=hex(self.changelog.node(cor+1)), source=srctype)
+ node=hex(self.changelog.node(cor+1)), source=srctype,
+ url=url)
tr.close()
if changesets > 0:
self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
- source=srctype)
+ source=srctype, url=url)
for i in range(cor + 1, cnr + 1):
self.hook("incoming", node=hex(self.changelog.node(i)),
- source=srctype)
+ source=srctype, url=url)
return newheads - oldheads + 1
--- a/mercurial/sshrepo.py
+++ b/mercurial/sshrepo.py
@@ -13,7 +13,7 @@ demandload(globals(), "hg os re stat uti
class sshrepository(remoterepository):
def __init__(self, ui, path, create=0):
- self.url = path
+ self._url = path
self.ui = ui
m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
@@ -48,6 +48,9 @@ class sshrepository(remoterepository):
self.validate_repo(ui, sshcmd, args, remotecmd)
+ def url(self):
+ return self._url
+
def validate_repo(self, ui, sshcmd, args, remotecmd):
cmd = '%s %s "%s -R %s serve --stdio"'
cmd = cmd % (sshcmd, args, remotecmd, self.path)
@@ -180,7 +183,7 @@ class sshrepository(remoterepository):
return 1
return int(r)
- def addchangegroup(self, cg, source):
+ def addchangegroup(self, cg, source, url):
d = self.call("addchangegroup")
if d:
raise hg.RepoError(_("push refused: %s") % d)
--- a/mercurial/sshserver.py
+++ b/mercurial/sshserver.py
@@ -117,9 +117,13 @@ class sshserver(object):
return
self.respond("")
- r = self.repo.addchangegroup(self.fin, 'serve')
+ r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
self.respond(str(r))
+ def client_url(self):
+ client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
+ return 'remote:ssh:' + client
+
def do_unbundle(self):
their_heads = self.getarg()[1].split()
@@ -159,7 +163,7 @@ class sshserver(object):
# push can proceed
fp.seek(0)
- r = self.repo.addchangegroup(fp, 'serve')
+ r = self.repo.addchangegroup(fp, 'serve', self.client_url())
self.respond(str(r))
finally:
if not was_locked:
--- a/mercurial/statichttprepo.py
+++ b/mercurial/statichttprepo.py
@@ -30,6 +30,7 @@ def opener(base):
class statichttprepository(localrepo.localrepository):
def __init__(self, ui, path):
+ self._url = path
self.path = (path + "/.hg")
self.ui = ui
self.revlogversion = 0
@@ -41,6 +42,9 @@ class statichttprepository(localrepo.loc
self.encodepats = None
self.decodepats = None
+ def url(self):
+ return 'static-' + self._url
+
def dev(self):
return -1
--- a/tests/test-bundle
+++ b/tests/test-bundle
@@ -38,6 +38,8 @@ rm -rf empty
hg init empty
cd empty
hg -R bundle://../full.hg log
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
#doesn't work (yet ?)
#hg -R bundle://../full.hg verify
hg pull bundle://../full.hg
--- a/tests/test-bundle.out
+++ b/tests/test-bundle.out
@@ -81,6 +81,7 @@ user: test
date: Mon Jan 12 13:46:40 1970 +0000
summary: 0.0
+changegroup: u=bundle:../full.hg
pulling from bundle://../full.hg
requesting all changes
adding changesets
--- a/tests/test-hook
+++ b/tests/test-hook
@@ -17,9 +17,9 @@ cd ../b
# changegroup hooks can see env vars
echo '[hooks]' > .hg/hgrc
-echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc
-echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc
-echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc
+echo 'prechangegroup = echo prechangegroup hook: u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
+echo 'changegroup = echo changegroup hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
+echo 'incoming = echo incoming hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
# pretxncommit and commit hooks can see both parents of merge
cd ../a
--- a/tests/test-hook.out
+++ b/tests/test-hook.out
@@ -22,11 +22,11 @@ pretxncommit hook: n=4c52fb2e402287dd5dc
3:4c52fb2e4022
commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
commit hook b
-prechangegroup hook
-changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2
-incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2
-incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb
-incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321
+prechangegroup hook: u=file:
+changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
+incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
+incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file:
+incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file:
pulling from ../a
searching for changes
adding changesets
--- a/tests/test-http
+++ b/tests/test-http
@@ -23,3 +23,13 @@ echo % clone via pull
http_proxy= hg clone http://localhost:20059/ copy-pull
cd copy-pull
hg verify
+
+cd test
+echo bar > bar
+hg commit -A -d '1 0' -m 2
+
+echo % pull
+cd ../copy-pull
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
+hg pull
--- a/tests/test-http.out
+++ b/tests/test-http.out
@@ -28,3 +28,9 @@ checking manifests
crosschecking files in changesets and manifests
checking files
1 files, 1 changesets, 1 total revisions
+/home/bos/hg/hg/hg-url/tests/test-http: line 27: cd: test: No such file or directory
+adding bar
+% pull
+pulling from http://localhost:20059/
+searching for changes
+no changes found
--- a/tests/test-push-http
+++ b/tests/test-push-http
@@ -36,13 +36,19 @@ kill `cat hg.pid`
echo % expect success
echo 'allow_push = *' >> .hg/hgrc
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL >> $HGTMP/urls' >> .hg/hgrc
hg serve -p 20059 -d --pid-file=hg.pid
cat hg.pid >> $DAEMON_PIDS
hg --cwd ../test2 push http://localhost:20059/
kill `cat hg.pid`
hg rollback
+sed 's/\(remote:http.*\):.*/\1/' $HGTMP/urls
+
echo % expect authorization error: all users denied
+echo '[web]' > .hg/hgrc
+echo 'push_ssl = false' >> .hg/hgrc
echo 'deny_push = *' >> .hg/hgrc
hg serve -p 20059 -d --pid-file=hg.pid
cat hg.pid >> $DAEMON_PIDS
--- a/tests/test-push-http.out
+++ b/tests/test-push-http.out
@@ -20,6 +20,7 @@ adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
rolling back last transaction
+changegroup: u=remote:http
% expect authorization error: all users denied
pushing to http://localhost:20059/
searching for changes
--- a/tests/test-ssh
+++ b/tests/test-ssh
@@ -17,6 +17,8 @@ if [ ! -x dummyssh ] ; then
exit -1
fi
+SSH_CLIENT='127.0.0.1 1 2'
+export SSH_CLIENT
echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog
$2
EOF
@@ -29,6 +31,8 @@ echo this > foo
hg ci -A -m "init" -d "1000000 0" foo
echo '[server]' > .hg/hgrc
echo 'uncompressed = True' >> .hg/hgrc
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup in remote: u=$HG_URL >> ../dummylog' >> .hg/hgrc
cd ..
@@ -46,6 +50,9 @@ echo "# verify"
cd local
hg verify
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup in local: u=$HG_URL >> ../dummylog' >> .hg/hgrc
+
echo "# empty default pull"
hg paths
hg pull -e ../dummyssh
--- a/tests/test-ssh.out
+++ b/tests/test-ssh.out
@@ -83,5 +83,7 @@ Got arguments 1:user@dummy 2:hg -R remot
Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5:
Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
+changegroup in remote: u=remote:ssh:127.0.0.1
Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
+changegroup in remote: u=remote:ssh:127.0.0.1
--- a/tests/test-static-http
+++ b/tests/test-static-http
@@ -37,6 +37,14 @@ http_proxy= hg clone static-http://local
cd local
hg verify
cat bar
+
+cd ../remote
+echo baz > quux
+hg commit -A -mtest2 -d '100000000 0'
+
+cd ../local
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
http_proxy= hg pull
kill $!
--- a/tests/test-static-http.out
+++ b/tests/test-static-http.out
@@ -19,6 +19,12 @@ crosschecking files in changesets and ma
checking files
1 files, 1 changesets, 1 total revisions
foo
+adding quux
+changegroup: u=static-http://localhost:20059/remote
pulling from static-http://localhost:20059/remote
searching for changes
-no changes found
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)