Mercurial > hg
diff hgext/zeroconf/__init__.py @ 7071:643c751e60b2
zeroconf: initial implementation
This is a basic, hopefully portable, zeroconf extension.
Enabling it will allow hg paths/pull/push/clone/etc. to automatically
discover services advertised as "_hg".
And naturally, running hg serve will advertise itself as a "_hg"
service as well as a "_http" service for use by browsers.
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Wed, 08 Oct 2008 19:58:35 -0500 |
parents | |
children | 62c71741ae7d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/zeroconf/__init__.py Wed Oct 08 19:58:35 2008 -0500 @@ -0,0 +1,133 @@ +# zeroconf.py - zeroconf support for Mercurial +# +# Copyright 2005-2007 Matt Mackall <mpm@selenic.com> +# +# This software may be used and distributed according to the terms of +# the GNU General Public License (version 2), incorporated herein by +# reference. + +import Zeroconf, socket, time, os +from mercurial import ui +from mercurial.hgweb import hgweb_mod +from mercurial.hgweb import hgwebdir_mod + +# publish + +server = None +localip = None + +def getip(): + # finds external-facing interface without sending any packets (Linux) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('1.0.0.1', 0)) + ip = s.getsockname()[0] + return ip + except: + pass + + # Generic method, sometimes gives useless results + dumbip = socket.gethostbyaddr(socket.gethostname())[2][0] + if not dumbip.startswith('127.'): + return dumbip + + # works elsewhere, but actually sends a packet + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('1.0.0.1', 1)) + ip = s.getsockname()[0] + return ip + except: + pass + + return dumbip + +def publish(name, desc, path, port): + global server, localip + if not server: + server = Zeroconf.Zeroconf() + ip = getip() + localip = socket.inet_aton(ip) + + host = socket.gethostname() + ".local" + + # advertise to browsers + svc = Zeroconf.ServiceInfo('_http._tcp.local.', + name + '._http._tcp.local.', + server = host, + port = port, + properties = {'description': desc, + 'path': "/" + path}, + address = localip, weight = 0, priority = 0) + server.registerService(svc) + + # advertise to Mercurial clients + svc = Zeroconf.ServiceInfo('_hg._tcp.local.', + name + '._hg._tcp.local.', + port = port, + properties = {'description': desc, + 'path': "/" + path}, + address = localip, weight = 0, priority = 0) + server.registerService(svc) + +class hgwebzc(hgweb_mod.hgweb): + def __init__(self, repo, name=None): + super(hgwebzc, self).__init__(repo, name) + name = self.reponame or os.path.basename(repo.root) + desc = self.repo.ui.config("web", "description", name) + publish(name, desc, name, int(repo.ui.config("web", "port", 8000))) + +class hgwebdirzc(hgwebdir_mod.hgwebdir): + def run(self): + print os.environ + for r, p in self.repos: + u = ui.ui(parentui=self.parentui) + u.readconfig(os.path.join(path, '.hg', 'hgrc')) + n = os.path.basename(r) + desc = u.config("web", "description", n) + publish(n, "hgweb", p, int(repo.ui.config("web", "port", 8000))) + return super(hgwebdirzc, self).run() + +# listen + +class listener(object): + def __init__(self): + self.found = {} + def removeService(self, server, type, name): + if repr(name) in self.found: + del self.found[repr(name)] + def addService(self, server, type, name): + self.found[repr(name)] = server.getServiceInfo(type, name) + +def getzcpaths(): + server = Zeroconf.Zeroconf() + l = listener() + browser = Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l) + time.sleep(1) + server.close() + for v in l.found.values(): + n = v.name[:v.name.index('.')] + n.replace(" ", "-") + u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port, + v.properties.get("path", "/")) + yield "zc-" + n, u + +def config(self, section, key, default=None, untrusted=False): + if section == "paths" and key.startswith("zc-"): + for n, p in getzcpaths(): + if n == key: + return p + return oldconfig(self, section, key, default, untrusted) + +def configitems(self, section): + r = oldconfigitems(self, section, untrusted=False) + if section == "paths": + r += getzcpaths() + return r + +oldconfig = ui.ui.config +oldconfigitems = ui.ui.configitems +ui.ui.config = config +ui.ui.configitems = configitems +hgweb_mod.hgweb = hgwebzc +hgwebdir_mod.hgwebdir = hgwebdirzc