##// END OF EJS Templates
zeroconf: wrapped docstrings at 78 characters
Martin Geisler -
r9078:4e04eabc default
parent child Browse files
Show More
@@ -1,159 +1,159
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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
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 the need
11 the need to configure a server or a service. They can be discovered
11 to configure a server or a service. They can be discovered without knowing
12 without knowing their actual IP address.
12 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 "hg serve" in your
15 in your repository.
15 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 "hg paths".
21
21
22 $ hg paths
22 $ hg paths
23 zc-test = http://example.com:8000/test
23 zc-test = http://example.com:8000/test
24 '''
24 '''
25
25
26 import Zeroconf, socket, time, os
26 import Zeroconf, socket, time, os
27 from mercurial import ui
27 from mercurial import ui
28 from mercurial import extensions
28 from mercurial import extensions
29 from mercurial.hgweb import hgweb_mod
29 from mercurial.hgweb import hgweb_mod
30 from mercurial.hgweb import hgwebdir_mod
30 from mercurial.hgweb import hgwebdir_mod
31
31
32 # publish
32 # publish
33
33
34 server = None
34 server = None
35 localip = None
35 localip = None
36
36
37 def getip():
37 def getip():
38 # finds external-facing interface without sending any packets (Linux)
38 # finds external-facing interface without sending any packets (Linux)
39 try:
39 try:
40 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
40 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
41 s.connect(('1.0.0.1', 0))
41 s.connect(('1.0.0.1', 0))
42 ip = s.getsockname()[0]
42 ip = s.getsockname()[0]
43 return ip
43 return ip
44 except:
44 except:
45 pass
45 pass
46
46
47 # Generic method, sometimes gives useless results
47 # Generic method, sometimes gives useless results
48 try:
48 try:
49 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
49 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
50 if not dumbip.startswith('127.') and ':' not in dumbip:
50 if not dumbip.startswith('127.') and ':' not in dumbip:
51 return dumbip
51 return dumbip
52 except socket.gaierror:
52 except socket.gaierror:
53 dumbip = '127.0.0.1'
53 dumbip = '127.0.0.1'
54
54
55 # works elsewhere, but actually sends a packet
55 # works elsewhere, but actually sends a packet
56 try:
56 try:
57 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
57 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
58 s.connect(('1.0.0.1', 1))
58 s.connect(('1.0.0.1', 1))
59 ip = s.getsockname()[0]
59 ip = s.getsockname()[0]
60 return ip
60 return ip
61 except:
61 except:
62 pass
62 pass
63
63
64 return dumbip
64 return dumbip
65
65
66 def publish(name, desc, path, port):
66 def publish(name, desc, path, port):
67 global server, localip
67 global server, localip
68 if not server:
68 if not server:
69 ip = getip()
69 ip = getip()
70 if ip.startswith('127.'):
70 if ip.startswith('127.'):
71 # if we have no internet connection, this can happen.
71 # if we have no internet connection, this can happen.
72 return
72 return
73 localip = socket.inet_aton(ip)
73 localip = socket.inet_aton(ip)
74 server = Zeroconf.Zeroconf(ip)
74 server = Zeroconf.Zeroconf(ip)
75
75
76 hostname = socket.gethostname().split('.')[0]
76 hostname = socket.gethostname().split('.')[0]
77 host = hostname + ".local"
77 host = hostname + ".local"
78 name = "%s-%s" % (hostname, name)
78 name = "%s-%s" % (hostname, name)
79
79
80 # advertise to browsers
80 # advertise to browsers
81 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
81 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
82 name + '._http._tcp.local.',
82 name + '._http._tcp.local.',
83 server = host,
83 server = host,
84 port = port,
84 port = port,
85 properties = {'description': desc,
85 properties = {'description': desc,
86 'path': "/" + path},
86 'path': "/" + path},
87 address = localip, weight = 0, priority = 0)
87 address = localip, weight = 0, priority = 0)
88 server.registerService(svc)
88 server.registerService(svc)
89
89
90 # advertise to Mercurial clients
90 # advertise to Mercurial clients
91 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
91 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
92 name + '._hg._tcp.local.',
92 name + '._hg._tcp.local.',
93 server = host,
93 server = host,
94 port = port,
94 port = port,
95 properties = {'description': desc,
95 properties = {'description': desc,
96 'path': "/" + path},
96 'path': "/" + path},
97 address = localip, weight = 0, priority = 0)
97 address = localip, weight = 0, priority = 0)
98 server.registerService(svc)
98 server.registerService(svc)
99
99
100 class hgwebzc(hgweb_mod.hgweb):
100 class hgwebzc(hgweb_mod.hgweb):
101 def __init__(self, repo, name=None):
101 def __init__(self, repo, name=None):
102 super(hgwebzc, self).__init__(repo, name)
102 super(hgwebzc, self).__init__(repo, name)
103 name = self.reponame or os.path.basename(repo.root)
103 name = self.reponame or os.path.basename(repo.root)
104 desc = self.repo.ui.config("web", "description", name)
104 desc = self.repo.ui.config("web", "description", name)
105 publish(name, desc, name, int(repo.ui.config("web", "port", 8000)))
105 publish(name, desc, name, int(repo.ui.config("web", "port", 8000)))
106
106
107 class hgwebdirzc(hgwebdir_mod.hgwebdir):
107 class hgwebdirzc(hgwebdir_mod.hgwebdir):
108 def run(self):
108 def run(self):
109 for r, p in self.repos:
109 for r, p in self.repos:
110 u = self.ui.copy()
110 u = self.ui.copy()
111 u.readconfig(os.path.join(p, '.hg', 'hgrc'))
111 u.readconfig(os.path.join(p, '.hg', 'hgrc'))
112 n = os.path.basename(r)
112 n = os.path.basename(r)
113 publish(n, "hgweb", p, int(u.config("web", "port", 8000)))
113 publish(n, "hgweb", p, int(u.config("web", "port", 8000)))
114 return super(hgwebdirzc, self).run()
114 return super(hgwebdirzc, self).run()
115
115
116 # listen
116 # listen
117
117
118 class listener(object):
118 class listener(object):
119 def __init__(self):
119 def __init__(self):
120 self.found = {}
120 self.found = {}
121 def removeService(self, server, type, name):
121 def removeService(self, server, type, name):
122 if repr(name) in self.found:
122 if repr(name) in self.found:
123 del self.found[repr(name)]
123 del self.found[repr(name)]
124 def addService(self, server, type, name):
124 def addService(self, server, type, name):
125 self.found[repr(name)] = server.getServiceInfo(type, name)
125 self.found[repr(name)] = server.getServiceInfo(type, name)
126
126
127 def getzcpaths():
127 def getzcpaths():
128 ip = getip()
128 ip = getip()
129 if ip.startswith('127.'):
129 if ip.startswith('127.'):
130 return
130 return
131 server = Zeroconf.Zeroconf(ip)
131 server = Zeroconf.Zeroconf(ip)
132 l = listener()
132 l = listener()
133 Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
133 Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
134 time.sleep(1)
134 time.sleep(1)
135 server.close()
135 server.close()
136 for v in l.found.values():
136 for v in l.found.values():
137 n = v.name[:v.name.index('.')]
137 n = v.name[:v.name.index('.')]
138 n.replace(" ", "-")
138 n.replace(" ", "-")
139 u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port,
139 u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port,
140 v.properties.get("path", "/"))
140 v.properties.get("path", "/"))
141 yield "zc-" + n, u
141 yield "zc-" + n, u
142
142
143 def config(orig, self, section, key, default=None, untrusted=False):
143 def config(orig, self, section, key, default=None, untrusted=False):
144 if section == "paths" and key.startswith("zc-"):
144 if section == "paths" and key.startswith("zc-"):
145 for n, p in getzcpaths():
145 for n, p in getzcpaths():
146 if n == key:
146 if n == key:
147 return p
147 return p
148 return orig(self, section, key, default, untrusted)
148 return orig(self, section, key, default, untrusted)
149
149
150 def configitems(orig, self, section, untrusted=False):
150 def configitems(orig, self, section, untrusted=False):
151 r = orig(self, section, untrusted)
151 r = orig(self, section, untrusted)
152 if section == "paths":
152 if section == "paths":
153 r += getzcpaths()
153 r += getzcpaths()
154 return r
154 return r
155
155
156 extensions.wrapfunction(ui.ui, 'config', config)
156 extensions.wrapfunction(ui.ui, 'config', config)
157 extensions.wrapfunction(ui.ui, 'configitems', configitems)
157 extensions.wrapfunction(ui.ui, 'configitems', configitems)
158 hgweb_mod.hgweb = hgwebzc
158 hgweb_mod.hgweb = hgwebzc
159 hgwebdir_mod.hgwebdir = hgwebdirzc
159 hgwebdir_mod.hgwebdir = hgwebdirzc
General Comments 0
You need to be logged in to leave comments. Login now