##// END OF EJS Templates
cvsps: recognize and eliminate CVS' synthetic "file added" revisions.
cvsps: recognize and eliminate CVS' synthetic "file added" revisions.

File last commit:

r7845:c2cd8d77 default
r7862:02981000 1.2.1 default
Show More
__init__.py
159 lines | 5.0 KiB | text/x-python | PythonLexer
Matt Mackall
zeroconf: initial implementation...
r7071 # 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.
David Soria Parra
zeroconf: add extension documentation
r7606 '''zeroconf support for mercurial repositories
Zeroconf enabled repositories will be announced in a network without the need
to configure a server or a service. They can be discovered without knowing
their actual IP address.
To use the zeroconf extension add the following entry to your hgrc file:
[extensions]
hgext.zeroconf =
To allow other people to discover your repository using run "hg serve" in your
repository.
$ cd test
$ hg serve
You can discover zeroconf enabled repositories by running "hg paths".
$ hg paths
zc-test = http://example.com:8000/test
'''
Matt Mackall
zeroconf: initial implementation...
r7071 import Zeroconf, socket, time, os
from mercurial import ui
Matt Mackall
extensions: use new wrapper functions
r7216 from mercurial import extensions
Matt Mackall
zeroconf: initial implementation...
r7071 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]
Alexander Solovyov
zeroconf: don't allow ipv6 addresses
r7777 if not dumbip.startswith('127.') and ':' not in dumbip:
Matt Mackall
zeroconf: initial implementation...
r7071 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:
Augie Fackler
zeroconf: Don't break serve if no internet connection is present.
r7295 try:
server = Zeroconf.Zeroconf()
except socket.gaierror:
# if we have no internet connection, this can happen.
return
Matt Mackall
zeroconf: initial implementation...
r7071 ip = getip()
localip = socket.inet_aton(ip)
Matt Mackall
zeroconf: use only first part of hostname for building local name
r7087 parts = socket.gethostname().split('.')
host = parts[0] + ".local"
Matt Mackall
zeroconf: initial implementation...
r7071
# 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.',
Matt Mackall
zeroconf: advertise a proper hostname for _hg services
r7088 server = host,
Matt Mackall
zeroconf: initial implementation...
r7071 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):
for r, p in self.repos:
u = ui.ui(parentui=self.parentui)
Benoit Boissinot
fix zeroconf handling for hgwebdir (error found by pychecker)
r7282 u.readconfig(os.path.join(p, '.hg', 'hgrc'))
Matt Mackall
zeroconf: initial implementation...
r7071 n = os.path.basename(r)
Benoit Boissinot
fix zeroconf handling for hgwebdir (error found by pychecker)
r7282 publish(n, "hgweb", p, int(u.config("web", "port", 8000)))
Matt Mackall
zeroconf: initial implementation...
r7071 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
Matt Mackall
extensions: use new wrapper functions
r7216 def config(orig, self, section, key, default=None, untrusted=False):
Matt Mackall
zeroconf: initial implementation...
r7071 if section == "paths" and key.startswith("zc-"):
for n, p in getzcpaths():
if n == key:
return p
Matt Mackall
extensions: use new wrapper functions
r7216 return orig(self, section, key, default, untrusted)
Matt Mackall
zeroconf: initial implementation...
r7071
Matt Mackall
zeroconf: don't break on hg showconfig
r7238 def configitems(orig, self, section, untrusted=False):
r = orig(self, section, untrusted)
Matt Mackall
zeroconf: initial implementation...
r7071 if section == "paths":
r += getzcpaths()
return r
Matt Mackall
extensions: use new wrapper functions
r7216 extensions.wrapfunction(ui.ui, 'config', config)
extensions.wrapfunction(ui.ui, 'configitems', configitems)
Matt Mackall
zeroconf: initial implementation...
r7071 hgweb_mod.hgweb = hgwebzc
hgwebdir_mod.hgwebdir = hgwebdirzc