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