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