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