##// END OF EJS Templates
automation: install Python 3.8.0...
automation: install Python 3.8.0 Python 3.8 has been released. Let's install it instead of the RC / development version. Differential Revision: https://phab.mercurial-scm.org/D7114

File last commit:

r43347:687b865b default
r43510:05c0a5a6 default
Show More
__init__.py
241 lines | 6.8 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>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Cédric Duval
extensions: improve the consistency of synopses...
r8894 '''discover and advertise repositories on the local network
David Soria Parra
zeroconf: add extension documentation
r7606
Martin Geisler
zeroconf: small fixes in docstring...
r11504 Zeroconf-enabled repositories will be announced in a network without
Martin Geisler
zeroconf: word-wrap help texts at 70 characters
r8003 the need to configure a server or a service. They can be discovered
without knowing their actual IP address.
David Soria Parra
zeroconf: add extension documentation
r7606
Martin Geisler
zeroconf: small fixes in docstring...
r11504 To allow other people to discover your repository using run
:hg:`serve` in your repository::
David Soria Parra
zeroconf: add extension documentation
r7606
Martin Geisler
zeroconf: use reST syntax for literal blocks
r9218 $ cd test
$ hg serve
David Soria Parra
zeroconf: add extension documentation
r7606
Martin Geisler
zeroconf: small fixes in docstring...
r11504 You can discover Zeroconf-enabled repositories by running
:hg:`paths`::
David Soria Parra
zeroconf: add extension documentation
r7606
Martin Geisler
zeroconf: use reST syntax for literal blocks
r9218 $ hg paths
zc-test = http://example.com:8000/test
David Soria Parra
zeroconf: add extension documentation
r7606 '''
timeless
zeroconf: use absolute_import
r28296 from __future__ import absolute_import
David Soria Parra
zeroconf: add extension documentation
r7606
timeless
zeroconf: use absolute_import
r28296 import os
import socket
import time
Renato Cunha
hgext/zeroconf/__init__.py: Separate relative and absolute imports....
r11340
timeless
zeroconf: use absolute_import
r28296 from . import Zeroconf
from mercurial import (
dispatch,
encoding,
extensions,
hg,
Gregory Szorc
zeroconf: port to Python 3...
r42752 pycompat,
Augie Fackler
zeroconf: import ui as uimod per test-check-module-imports
r28308 ui as uimod,
timeless
zeroconf: use absolute_import
r28296 )
Augie Fackler
formatting: blacken the codebase...
r43346 from mercurial.hgweb import server as servermod
Matt Mackall
zeroconf: initial implementation...
r7071
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Augie Fackler
hgext: mark all first-party extensions as such
r16743
Matt Mackall
zeroconf: initial implementation...
r7071 # publish
server = None
localip = None
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 def getip():
# finds external-facing interface without sending any packets (Linux)
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Gregory Szorc
zeroconf: port to Python 3...
r42752 s.connect((r'1.0.0.1', 0))
Matt Mackall
zeroconf: initial implementation...
r7071 ip = s.getsockname()[0]
return ip
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 except socket.error:
Matt Mackall
zeroconf: initial implementation...
r7071 pass
# Generic method, sometimes gives useless results
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 try:
dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
Gregory Szorc
zeroconf: port to Python 3...
r42752 if r':' in dumbip:
dumbip = r'127.0.0.1'
if not dumbip.startswith(r'127.'):
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 return dumbip
Augie Fackler
zeroconf: gethostbyaddr may also fail with socket.herror
r10317 except (socket.gaierror, socket.herror):
Gregory Szorc
zeroconf: port to Python 3...
r42752 dumbip = r'127.0.0.1'
Matt Mackall
zeroconf: initial implementation...
r7071
# works elsewhere, but actually sends a packet
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Gregory Szorc
zeroconf: port to Python 3...
r42752 s.connect((r'1.0.0.1', 1))
Matt Mackall
zeroconf: initial implementation...
r7071 ip = s.getsockname()[0]
return ip
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 except socket.error:
Matt Mackall
zeroconf: initial implementation...
r7071 pass
return dumbip
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 def publish(name, desc, path, port):
global server, localip
if not server:
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 ip = getip()
Gregory Szorc
zeroconf: port to Python 3...
r42752 if ip.startswith(r'127.'):
Augie Fackler
zeroconf: Don't break serve if no internet connection is present.
r7295 # if we have no internet connection, this can happen.
return
Matt Mackall
zeroconf: initial implementation...
r7071 localip = socket.inet_aton(ip)
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 server = Zeroconf.Zeroconf(ip)
Matt Mackall
zeroconf: initial implementation...
r7071
Gregory Szorc
zeroconf: port to Python 3...
r42752 hostname = socket.gethostname().split(r'.')[0]
host = hostname + r".local"
name = r"%s-%s" % (hostname, name)
Matt Mackall
zeroconf: initial implementation...
r7071
# advertise to browsers
Augie Fackler
formatting: blacken the codebase...
r43346 svc = Zeroconf.ServiceInfo(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'_http._tcp.local.',
Augie Fackler
formatting: blacken the codebase...
r43346 pycompat.bytestr(name + r'._http._tcp.local.'),
server=host,
port=port,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 properties={b'description': desc, b'path': b"/" + path},
Augie Fackler
formatting: blacken the codebase...
r43346 address=localip,
weight=0,
priority=0,
)
Matt Mackall
zeroconf: initial implementation...
r7071 server.registerService(svc)
# advertise to Mercurial clients
Augie Fackler
formatting: blacken the codebase...
r43346 svc = Zeroconf.ServiceInfo(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'_hg._tcp.local.',
Augie Fackler
formatting: blacken the codebase...
r43346 pycompat.bytestr(name + r'._hg._tcp.local.'),
server=host,
port=port,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 properties={b'description': desc, b'path': b"/" + path},
Augie Fackler
formatting: blacken the codebase...
r43346 address=localip,
weight=0,
priority=0,
)
Matt Mackall
zeroconf: initial implementation...
r7071 server.registerService(svc)
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
zeroconf: use port from server instead of picking port from config (issue3746)...
r18190 def zc_create_server(create_server, ui, app):
httpd = create_server(ui, app)
port = httpd.port
Matt Mackall
zeroconf: initial implementation...
r7071
Benoit Boissinot
zeroconf: use port from server instead of picking port from config (issue3746)...
r18190 try:
repos = app.repos
except AttributeError:
# single repo
Gregory Szorc
zeroconf: access repo on hgweb_mod properly (issue5036)...
r27910 with app._obtainrepo() as repo:
name = app.reponame or os.path.basename(repo.root)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = repo.ui.config(b"web", b"prefix", b"").strip(b'/')
desc = repo.ui.config(b"web", b"description")
Boris Feld
configitems: register the 'web.description' config
r34235 if not desc:
desc = name
Benoit Boissinot
zeroconf: use port from server instead of picking port from config (issue3746)...
r18190 publish(name, desc, path, port)
else:
# webdir
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefix = app.ui.config(b"web", b"prefix", b"").strip(b'/') + b'/'
Benoit Boissinot
zeroconf: use port from server instead of picking port from config (issue3746)...
r18190 for repo, path in repos:
u = app.ui.copy()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 u.readconfig(os.path.join(path, b'.hg', b'hgrc'))
Alexander Solovyov
zeroconf: code cleanup, fixing variable names to be meaningful
r9488 name = os.path.basename(repo)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = (prefix + repo).strip(b'/')
desc = u.config(b'web', b'description')
Boris Feld
configitems: register the 'web.description' config
r34235 if not desc:
desc = name
Benoit Boissinot
zeroconf: use port from server instead of picking port from config (issue3746)...
r18190 publish(name, desc, path, port)
return httpd
Matt Mackall
zeroconf: initial implementation...
r7071
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 # listen
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 class listener(object):
def __init__(self):
self.found = {}
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 def removeService(self, server, type, name):
if repr(name) in self.found:
del self.found[repr(name)]
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 def addService(self, server, type, name):
self.found[repr(name)] = server.getServiceInfo(type, name)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
zeroconf: initial implementation...
r7071 def getzcpaths():
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 ip = getip()
Gregory Szorc
zeroconf: port to Python 3...
r42752 if ip.startswith(r'127.'):
Alexander Solovyov
zeroconf: guess ip for Zeroconf...
r8264 return
server = Zeroconf.Zeroconf(ip)
Matt Mackall
zeroconf: initial implementation...
r7071 l = listener()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 Zeroconf.ServiceBrowser(server, b"_hg._tcp.local.", l)
Matt Mackall
zeroconf: initial implementation...
r7071 time.sleep(1)
server.close()
Alexander Solovyov
zeroconf: code cleanup, fixing variable names to be meaningful
r9488 for value in l.found.values():
Augie Fackler
formatting: blacken the codebase...
r43346 name = value.name[: value.name.index(b'.')]
url = r"http://%s:%s%s" % (
socket.inet_ntoa(value.address),
value.port,
value.properties.get(r"path", r"/"),
)
Gregory Szorc
zeroconf: port to Python 3...
r42752 yield b"zc-" + name, pycompat.bytestr(url)
Matt Mackall
zeroconf: initial implementation...
r7071
Augie Fackler
formatting: blacken the codebase...
r43346
zeroconf: blindly forward extra argument to the core config method...
r33175 def config(orig, self, section, key, *args, **kwargs):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if section == b"paths" and key.startswith(b"zc-"):
Alexander Solovyov
zeroconf: code cleanup, fixing variable names to be meaningful
r9488 for name, path in getzcpaths():
if name == key:
return path
zeroconf: blindly forward extra argument to the core config method...
r33175 return orig(self, section, key, *args, **kwargs)
Matt Mackall
zeroconf: initial implementation...
r7071
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
zeroconf: forward all arguments passed to ui.configitems() wrapper...
r28038 def configitems(orig, self, section, *args, **kwargs):
repos = orig(self, section, *args, **kwargs)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if section == b"paths":
Alexander Solovyov
zeroconf: code cleanup, fixing variable names to be meaningful
r9488 repos += getzcpaths()
return repos
Matt Mackall
zeroconf: initial implementation...
r7071
Augie Fackler
formatting: blacken the codebase...
r43346
Danek Duvall
zeroconf: fix crash in "hg paths" when zeroconf server is up...
r28250 def configsuboptions(orig, self, section, name, *args, **kwargs):
opt, sub = orig(self, section, name, *args, **kwargs)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if section == b"paths" and name.startswith(b"zc-"):
Danek Duvall
zeroconf: fix crash in "hg paths" when zeroconf server is up...
r28250 # We have to find the URL in the zeroconf paths. We can't cons up any
# suboptions, so we use any that we found in the original config.
for zcname, zcurl in getzcpaths():
if zcname == name:
return zcurl, sub
return opt, sub
Augie Fackler
formatting: blacken the codebase...
r43346
Henrik Stuart
zeroconf: override default destination folder on clone
r10342 def defaultdest(orig, source):
for name, path in getzcpaths():
if path == source:
return name.encode(encoding.encoding)
return orig(source)
Augie Fackler
formatting: blacken the codebase...
r43346
Nicolas Dumazet
zeroconf: notify the Zeroconf threads when hg exits...
r14104 def cleanupafterdispatch(orig, ui, options, cmd, cmdfunc):
try:
return orig(ui, options, cmd, cmdfunc)
finally:
# we need to call close() on the server to notify() the various
# threading Conditions and allow the background threads to exit
global server
if server:
server.close()
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 extensions.wrapfunction(dispatch, b'_runcommand', cleanupafterdispatch)
Nicolas Dumazet
zeroconf: notify the Zeroconf threads when hg exits...
r14104
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 extensions.wrapfunction(uimod.ui, b'config', config)
extensions.wrapfunction(uimod.ui, b'configitems', configitems)
extensions.wrapfunction(uimod.ui, b'configsuboptions', configsuboptions)
extensions.wrapfunction(hg, b'defaultdest', defaultdest)
extensions.wrapfunction(servermod, b'create_server', zc_create_server)