diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt --- 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 diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py --- 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 diff --git a/mercurial/commands.py b/mercurial/commands.py --- 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): diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- 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 diff --git a/mercurial/httprepo.py b/mercurial/httprepo.py --- 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 diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- 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 diff --git a/mercurial/sshrepo.py b/mercurial/sshrepo.py --- 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) diff --git a/mercurial/sshserver.py b/mercurial/sshserver.py --- 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: diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py --- 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 diff --git a/tests/test-bundle b/tests/test-bundle --- 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 diff --git a/tests/test-bundle.out b/tests/test-bundle.out --- 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 diff --git a/tests/test-hook b/tests/test-hook --- 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 diff --git a/tests/test-hook.out b/tests/test-hook.out --- 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 diff --git a/tests/test-http b/tests/test-http --- 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 diff --git a/tests/test-http.out b/tests/test-http.out --- 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 diff --git a/tests/test-push-http b/tests/test-push-http --- 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 diff --git a/tests/test-push-http.out b/tests/test-push-http.out --- 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 diff --git a/tests/test-ssh b/tests/test-ssh --- 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 diff --git a/tests/test-ssh.out b/tests/test-ssh.out --- 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 diff --git a/tests/test-static-http b/tests/test-static-http --- 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 $! diff --git a/tests/test-static-http.out b/tests/test-static-http.out --- 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)