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