##// END OF EJS Templates
zeroconf: small fixes in docstring...
Martin Geisler -
r11504:6bfb76cb stable
parent child Browse files
Show More
@@ -1,172 +1,173 b''
1 # zeroconf.py - zeroconf support for Mercurial
1 # zeroconf.py - zeroconf support for Mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''discover and advertise repositories on the local network
8 '''discover and advertise repositories on the local network
9
9
10 Zeroconf enabled repositories will be announced in a network without
10 Zeroconf-enabled repositories will be announced in a network without
11 the need to configure a server or a service. They can be discovered
11 the need to configure a server or a service. They can be discovered
12 without knowing their actual IP address.
12 without knowing their actual IP address.
13
13
14 To allow other people to discover your repository using run "hg serve"
14 To allow other people to discover your repository using run
15 in your repository::
15 :hg:`serve` in your repository::
16
16
17 $ cd test
17 $ cd test
18 $ hg serve
18 $ hg serve
19
19
20 You can discover zeroconf enabled repositories by running "hg paths"::
20 You can discover Zeroconf-enabled repositories by running
21 :hg:`paths`::
21
22
22 $ hg paths
23 $ hg paths
23 zc-test = http://example.com:8000/test
24 zc-test = http://example.com:8000/test
24 '''
25 '''
25
26
26 import socket, time, os
27 import socket, time, os
27
28
28 import Zeroconf
29 import Zeroconf
29 from mercurial import ui, hg, encoding
30 from mercurial import ui, hg, encoding
30 from mercurial import extensions
31 from mercurial import extensions
31 from mercurial.hgweb import hgweb_mod
32 from mercurial.hgweb import hgweb_mod
32 from mercurial.hgweb import hgwebdir_mod
33 from mercurial.hgweb import hgwebdir_mod
33
34
34 # publish
35 # publish
35
36
36 server = None
37 server = None
37 localip = None
38 localip = None
38
39
39 def getip():
40 def getip():
40 # finds external-facing interface without sending any packets (Linux)
41 # finds external-facing interface without sending any packets (Linux)
41 try:
42 try:
42 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
43 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
43 s.connect(('1.0.0.1', 0))
44 s.connect(('1.0.0.1', 0))
44 ip = s.getsockname()[0]
45 ip = s.getsockname()[0]
45 return ip
46 return ip
46 except:
47 except:
47 pass
48 pass
48
49
49 # Generic method, sometimes gives useless results
50 # Generic method, sometimes gives useless results
50 try:
51 try:
51 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
52 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
52 if not dumbip.startswith('127.') and ':' not in dumbip:
53 if not dumbip.startswith('127.') and ':' not in dumbip:
53 return dumbip
54 return dumbip
54 except (socket.gaierror, socket.herror):
55 except (socket.gaierror, socket.herror):
55 dumbip = '127.0.0.1'
56 dumbip = '127.0.0.1'
56
57
57 # works elsewhere, but actually sends a packet
58 # works elsewhere, but actually sends a packet
58 try:
59 try:
59 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
60 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
60 s.connect(('1.0.0.1', 1))
61 s.connect(('1.0.0.1', 1))
61 ip = s.getsockname()[0]
62 ip = s.getsockname()[0]
62 return ip
63 return ip
63 except:
64 except:
64 pass
65 pass
65
66
66 return dumbip
67 return dumbip
67
68
68 def publish(name, desc, path, port):
69 def publish(name, desc, path, port):
69 global server, localip
70 global server, localip
70 if not server:
71 if not server:
71 ip = getip()
72 ip = getip()
72 if ip.startswith('127.'):
73 if ip.startswith('127.'):
73 # if we have no internet connection, this can happen.
74 # if we have no internet connection, this can happen.
74 return
75 return
75 localip = socket.inet_aton(ip)
76 localip = socket.inet_aton(ip)
76 server = Zeroconf.Zeroconf(ip)
77 server = Zeroconf.Zeroconf(ip)
77
78
78 hostname = socket.gethostname().split('.')[0]
79 hostname = socket.gethostname().split('.')[0]
79 host = hostname + ".local"
80 host = hostname + ".local"
80 name = "%s-%s" % (hostname, name)
81 name = "%s-%s" % (hostname, name)
81
82
82 # advertise to browsers
83 # advertise to browsers
83 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
84 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
84 name + '._http._tcp.local.',
85 name + '._http._tcp.local.',
85 server = host,
86 server = host,
86 port = port,
87 port = port,
87 properties = {'description': desc,
88 properties = {'description': desc,
88 'path': "/" + path},
89 'path': "/" + path},
89 address = localip, weight = 0, priority = 0)
90 address = localip, weight = 0, priority = 0)
90 server.registerService(svc)
91 server.registerService(svc)
91
92
92 # advertise to Mercurial clients
93 # advertise to Mercurial clients
93 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
94 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
94 name + '._hg._tcp.local.',
95 name + '._hg._tcp.local.',
95 server = host,
96 server = host,
96 port = port,
97 port = port,
97 properties = {'description': desc,
98 properties = {'description': desc,
98 'path': "/" + path},
99 'path': "/" + path},
99 address = localip, weight = 0, priority = 0)
100 address = localip, weight = 0, priority = 0)
100 server.registerService(svc)
101 server.registerService(svc)
101
102
102 class hgwebzc(hgweb_mod.hgweb):
103 class hgwebzc(hgweb_mod.hgweb):
103 def __init__(self, repo, name=None, baseui=None):
104 def __init__(self, repo, name=None, baseui=None):
104 super(hgwebzc, self).__init__(repo, name=name, baseui=baseui)
105 super(hgwebzc, self).__init__(repo, name=name, baseui=baseui)
105 name = self.reponame or os.path.basename(self.repo.root)
106 name = self.reponame or os.path.basename(self.repo.root)
106 path = self.repo.ui.config("web", "prefix", "").strip('/')
107 path = self.repo.ui.config("web", "prefix", "").strip('/')
107 desc = self.repo.ui.config("web", "description", name)
108 desc = self.repo.ui.config("web", "description", name)
108 publish(name, desc, path,
109 publish(name, desc, path,
109 int(self.repo.ui.config("web", "port", 8000)))
110 int(self.repo.ui.config("web", "port", 8000)))
110
111
111 class hgwebdirzc(hgwebdir_mod.hgwebdir):
112 class hgwebdirzc(hgwebdir_mod.hgwebdir):
112 def __init__(self, conf, baseui=None):
113 def __init__(self, conf, baseui=None):
113 super(hgwebdirzc, self).__init__(conf, baseui=baseui)
114 super(hgwebdirzc, self).__init__(conf, baseui=baseui)
114 prefix = self.ui.config("web", "prefix", "").strip('/') + '/'
115 prefix = self.ui.config("web", "prefix", "").strip('/') + '/'
115 for repo, path in self.repos:
116 for repo, path in self.repos:
116 u = self.ui.copy()
117 u = self.ui.copy()
117 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
118 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
118 name = os.path.basename(repo)
119 name = os.path.basename(repo)
119 path = (prefix + repo).strip('/')
120 path = (prefix + repo).strip('/')
120 desc = u.config('web', 'description', name)
121 desc = u.config('web', 'description', name)
121 publish(name, desc, path, int(u.config("web", "port", 8000)))
122 publish(name, desc, path, int(u.config("web", "port", 8000)))
122
123
123 # listen
124 # listen
124
125
125 class listener(object):
126 class listener(object):
126 def __init__(self):
127 def __init__(self):
127 self.found = {}
128 self.found = {}
128 def removeService(self, server, type, name):
129 def removeService(self, server, type, name):
129 if repr(name) in self.found:
130 if repr(name) in self.found:
130 del self.found[repr(name)]
131 del self.found[repr(name)]
131 def addService(self, server, type, name):
132 def addService(self, server, type, name):
132 self.found[repr(name)] = server.getServiceInfo(type, name)
133 self.found[repr(name)] = server.getServiceInfo(type, name)
133
134
134 def getzcpaths():
135 def getzcpaths():
135 ip = getip()
136 ip = getip()
136 if ip.startswith('127.'):
137 if ip.startswith('127.'):
137 return
138 return
138 server = Zeroconf.Zeroconf(ip)
139 server = Zeroconf.Zeroconf(ip)
139 l = listener()
140 l = listener()
140 Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
141 Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
141 time.sleep(1)
142 time.sleep(1)
142 server.close()
143 server.close()
143 for value in l.found.values():
144 for value in l.found.values():
144 name = value.name[:value.name.index('.')]
145 name = value.name[:value.name.index('.')]
145 url = "http://%s:%s%s" % (socket.inet_ntoa(value.address), value.port,
146 url = "http://%s:%s%s" % (socket.inet_ntoa(value.address), value.port,
146 value.properties.get("path", "/"))
147 value.properties.get("path", "/"))
147 yield "zc-" + name, url
148 yield "zc-" + name, url
148
149
149 def config(orig, self, section, key, default=None, untrusted=False):
150 def config(orig, self, section, key, default=None, untrusted=False):
150 if section == "paths" and key.startswith("zc-"):
151 if section == "paths" and key.startswith("zc-"):
151 for name, path in getzcpaths():
152 for name, path in getzcpaths():
152 if name == key:
153 if name == key:
153 return path
154 return path
154 return orig(self, section, key, default, untrusted)
155 return orig(self, section, key, default, untrusted)
155
156
156 def configitems(orig, self, section, untrusted=False):
157 def configitems(orig, self, section, untrusted=False):
157 repos = orig(self, section, untrusted)
158 repos = orig(self, section, untrusted)
158 if section == "paths":
159 if section == "paths":
159 repos += getzcpaths()
160 repos += getzcpaths()
160 return repos
161 return repos
161
162
162 def defaultdest(orig, source):
163 def defaultdest(orig, source):
163 for name, path in getzcpaths():
164 for name, path in getzcpaths():
164 if path == source:
165 if path == source:
165 return name.encode(encoding.encoding)
166 return name.encode(encoding.encoding)
166 return orig(source)
167 return orig(source)
167
168
168 extensions.wrapfunction(ui.ui, 'config', config)
169 extensions.wrapfunction(ui.ui, 'config', config)
169 extensions.wrapfunction(ui.ui, 'configitems', configitems)
170 extensions.wrapfunction(ui.ui, 'configitems', configitems)
170 extensions.wrapfunction(hg, 'defaultdest', defaultdest)
171 extensions.wrapfunction(hg, 'defaultdest', defaultdest)
171 hgweb_mod.hgweb = hgwebzc
172 hgweb_mod.hgweb = hgwebzc
172 hgwebdir_mod.hgwebdir = hgwebdirzc
173 hgwebdir_mod.hgwebdir = hgwebdirzc
General Comments 0
You need to be logged in to leave comments. Login now