##// END OF EJS Templates
sshrepo: fix the parsing of the ssh url
Benoit Boissinot -
r3599:e00920b4 default
parent child Browse files
Show More
@@ -1,228 +1,228 b''
1 # sshrepo.py - ssh repository proxy class for mercurial
1 # sshrepo.py - ssh repository proxy class for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from remoterepo import *
9 from remoterepo import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 from demandload import *
11 from demandload import *
12 demandload(globals(), "hg os re stat util")
12 demandload(globals(), "hg os re stat util")
13
13
14 class sshrepository(remoterepository):
14 class sshrepository(remoterepository):
15 def __init__(self, ui, path, create=0):
15 def __init__(self, ui, path, create=0):
16 self._url = path
16 self._url = path
17 self.ui = ui
17 self.ui = ui
18
18
19 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
19 m = re.match(r'^ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?$', path)
20 if not m:
20 if not m:
21 self.repoerror(_("couldn't parse location %s") % path)
21 self.repoerror(_("couldn't parse location %s") % path)
22
22
23 self.user = m.group(2)
23 self.user = m.group(2)
24 self.host = m.group(3)
24 self.host = m.group(3)
25 self.port = m.group(5)
25 self.port = m.group(5)
26 self.path = m.group(7) or "."
26 self.path = m.group(7) or "."
27
27
28 args = self.user and ("%s@%s" % (self.user, self.host)) or self.host
28 args = self.user and ("%s@%s" % (self.user, self.host)) or self.host
29 args = self.port and ("%s -p %s") % (args, self.port) or args
29 args = self.port and ("%s -p %s") % (args, self.port) or args
30
30
31 sshcmd = self.ui.config("ui", "ssh", "ssh")
31 sshcmd = self.ui.config("ui", "ssh", "ssh")
32 remotecmd = self.ui.config("ui", "remotecmd", "hg")
32 remotecmd = self.ui.config("ui", "remotecmd", "hg")
33
33
34 if create:
34 if create:
35 cmd = '%s %s "%s init %s"'
35 cmd = '%s %s "%s init %s"'
36 cmd = cmd % (sshcmd, args, remotecmd, self.path)
36 cmd = cmd % (sshcmd, args, remotecmd, self.path)
37
37
38 ui.note('running %s\n' % cmd)
38 ui.note('running %s\n' % cmd)
39 res = os.system(cmd)
39 res = os.system(cmd)
40 if res != 0:
40 if res != 0:
41 self.repoerror(_("could not create remote repo"))
41 self.repoerror(_("could not create remote repo"))
42
42
43 self.validate_repo(ui, sshcmd, args, remotecmd)
43 self.validate_repo(ui, sshcmd, args, remotecmd)
44
44
45 def url(self):
45 def url(self):
46 return self._url
46 return self._url
47
47
48 def validate_repo(self, ui, sshcmd, args, remotecmd):
48 def validate_repo(self, ui, sshcmd, args, remotecmd):
49 # cleanup up previous run
49 # cleanup up previous run
50 self.cleanup()
50 self.cleanup()
51
51
52 cmd = '%s %s "%s -R %s serve --stdio"'
52 cmd = '%s %s "%s -R %s serve --stdio"'
53 cmd = cmd % (sshcmd, args, remotecmd, self.path)
53 cmd = cmd % (sshcmd, args, remotecmd, self.path)
54
54
55 ui.note('running %s\n' % cmd)
55 ui.note('running %s\n' % cmd)
56 self.pipeo, self.pipei, self.pipee = os.popen3(cmd, 'b')
56 self.pipeo, self.pipei, self.pipee = os.popen3(cmd, 'b')
57
57
58 # skip any noise generated by remote shell
58 # skip any noise generated by remote shell
59 self.do_cmd("hello")
59 self.do_cmd("hello")
60 r = self.do_cmd("between", pairs=("%s-%s" % ("0"*40, "0"*40)))
60 r = self.do_cmd("between", pairs=("%s-%s" % ("0"*40, "0"*40)))
61 lines = ["", "dummy"]
61 lines = ["", "dummy"]
62 max_noise = 500
62 max_noise = 500
63 while lines[-1] and max_noise:
63 while lines[-1] and max_noise:
64 l = r.readline()
64 l = r.readline()
65 self.readerr()
65 self.readerr()
66 if lines[-1] == "1\n" and l == "\n":
66 if lines[-1] == "1\n" and l == "\n":
67 break
67 break
68 if l:
68 if l:
69 ui.debug(_("remote: "), l)
69 ui.debug(_("remote: "), l)
70 lines.append(l)
70 lines.append(l)
71 max_noise -= 1
71 max_noise -= 1
72 else:
72 else:
73 self.repoerror(_("no suitable response from remote hg"))
73 self.repoerror(_("no suitable response from remote hg"))
74
74
75 self.capabilities = ()
75 self.capabilities = ()
76 lines.reverse()
76 lines.reverse()
77 for l in lines:
77 for l in lines:
78 if l.startswith("capabilities:"):
78 if l.startswith("capabilities:"):
79 self.capabilities = l[:-1].split(":")[1].split()
79 self.capabilities = l[:-1].split(":")[1].split()
80 break
80 break
81
81
82 def readerr(self):
82 def readerr(self):
83 while 1:
83 while 1:
84 size = util.fstat(self.pipee).st_size
84 size = util.fstat(self.pipee).st_size
85 if size == 0: break
85 if size == 0: break
86 l = self.pipee.readline()
86 l = self.pipee.readline()
87 if not l: break
87 if not l: break
88 self.ui.status(_("remote: "), l)
88 self.ui.status(_("remote: "), l)
89
89
90 def repoerror(self, msg):
90 def repoerror(self, msg):
91 self.cleanup()
91 self.cleanup()
92 raise hg.RepoError(msg)
92 raise hg.RepoError(msg)
93
93
94 def cleanup(self):
94 def cleanup(self):
95 try:
95 try:
96 self.pipeo.close()
96 self.pipeo.close()
97 self.pipei.close()
97 self.pipei.close()
98 # read the error descriptor until EOF
98 # read the error descriptor until EOF
99 for l in self.pipee:
99 for l in self.pipee:
100 self.ui.status(_("remote: "), l)
100 self.ui.status(_("remote: "), l)
101 self.pipee.close()
101 self.pipee.close()
102 except:
102 except:
103 pass
103 pass
104
104
105 __del__ = cleanup
105 __del__ = cleanup
106
106
107 def do_cmd(self, cmd, **args):
107 def do_cmd(self, cmd, **args):
108 self.ui.debug(_("sending %s command\n") % cmd)
108 self.ui.debug(_("sending %s command\n") % cmd)
109 self.pipeo.write("%s\n" % cmd)
109 self.pipeo.write("%s\n" % cmd)
110 for k, v in args.items():
110 for k, v in args.items():
111 self.pipeo.write("%s %d\n" % (k, len(v)))
111 self.pipeo.write("%s %d\n" % (k, len(v)))
112 self.pipeo.write(v)
112 self.pipeo.write(v)
113 self.pipeo.flush()
113 self.pipeo.flush()
114
114
115 return self.pipei
115 return self.pipei
116
116
117 def call(self, cmd, **args):
117 def call(self, cmd, **args):
118 r = self.do_cmd(cmd, **args)
118 r = self.do_cmd(cmd, **args)
119 l = r.readline()
119 l = r.readline()
120 self.readerr()
120 self.readerr()
121 try:
121 try:
122 l = int(l)
122 l = int(l)
123 except:
123 except:
124 self.repoerror(_("unexpected response '%s'") % l)
124 self.repoerror(_("unexpected response '%s'") % l)
125 return r.read(l)
125 return r.read(l)
126
126
127 def lock(self):
127 def lock(self):
128 self.call("lock")
128 self.call("lock")
129 return remotelock(self)
129 return remotelock(self)
130
130
131 def unlock(self):
131 def unlock(self):
132 self.call("unlock")
132 self.call("unlock")
133
133
134 def lookup(self, key):
134 def lookup(self, key):
135 d = self.call("lookup", key=key)
135 d = self.call("lookup", key=key)
136 success, data = d[:-1].split(" ", 1)
136 success, data = d[:-1].split(" ", 1)
137 try:
137 try:
138 if int(success):
138 if int(success):
139 return bin(data)
139 return bin(data)
140 else:
140 else:
141 raise data
141 raise data
142 except:
142 except:
143 raise
143 raise
144 raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
144 raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
145
145
146 def heads(self):
146 def heads(self):
147 d = self.call("heads")
147 d = self.call("heads")
148 try:
148 try:
149 return map(bin, d[:-1].split(" "))
149 return map(bin, d[:-1].split(" "))
150 except:
150 except:
151 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
151 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
152
152
153 def branches(self, nodes):
153 def branches(self, nodes):
154 n = " ".join(map(hex, nodes))
154 n = " ".join(map(hex, nodes))
155 d = self.call("branches", nodes=n)
155 d = self.call("branches", nodes=n)
156 try:
156 try:
157 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
157 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
158 return br
158 return br
159 except:
159 except:
160 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
160 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
161
161
162 def between(self, pairs):
162 def between(self, pairs):
163 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
163 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
164 d = self.call("between", pairs=n)
164 d = self.call("between", pairs=n)
165 try:
165 try:
166 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
166 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
167 return p
167 return p
168 except:
168 except:
169 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
169 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
170
170
171 def changegroup(self, nodes, kind):
171 def changegroup(self, nodes, kind):
172 n = " ".join(map(hex, nodes))
172 n = " ".join(map(hex, nodes))
173 return self.do_cmd("changegroup", roots=n)
173 return self.do_cmd("changegroup", roots=n)
174
174
175 def changegroupsubset(self, bases, heads, kind):
175 def changegroupsubset(self, bases, heads, kind):
176 bases = " ".join(map(hex, bases))
176 bases = " ".join(map(hex, bases))
177 heads = " ".join(map(hex, heads))
177 heads = " ".join(map(hex, heads))
178 return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
178 return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
179
179
180 def unbundle(self, cg, heads, source):
180 def unbundle(self, cg, heads, source):
181 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
181 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
182 if d:
182 if d:
183 self.repoerror(_("push refused: %s") % d)
183 self.repoerror(_("push refused: %s") % d)
184
184
185 while 1:
185 while 1:
186 d = cg.read(4096)
186 d = cg.read(4096)
187 if not d: break
187 if not d: break
188 self.pipeo.write(str(len(d)) + '\n')
188 self.pipeo.write(str(len(d)) + '\n')
189 self.pipeo.write(d)
189 self.pipeo.write(d)
190 self.readerr()
190 self.readerr()
191
191
192 self.pipeo.write('0\n')
192 self.pipeo.write('0\n')
193 self.pipeo.flush()
193 self.pipeo.flush()
194
194
195 self.readerr()
195 self.readerr()
196 d = self.pipei.readline()
196 d = self.pipei.readline()
197 if d != '\n':
197 if d != '\n':
198 return 1
198 return 1
199
199
200 l = int(self.pipei.readline())
200 l = int(self.pipei.readline())
201 r = self.pipei.read(l)
201 r = self.pipei.read(l)
202 if not r:
202 if not r:
203 return 1
203 return 1
204 return int(r)
204 return int(r)
205
205
206 def addchangegroup(self, cg, source, url):
206 def addchangegroup(self, cg, source, url):
207 d = self.call("addchangegroup")
207 d = self.call("addchangegroup")
208 if d:
208 if d:
209 self.repoerror(_("push refused: %s") % d)
209 self.repoerror(_("push refused: %s") % d)
210 while 1:
210 while 1:
211 d = cg.read(4096)
211 d = cg.read(4096)
212 if not d: break
212 if not d: break
213 self.pipeo.write(d)
213 self.pipeo.write(d)
214 self.readerr()
214 self.readerr()
215
215
216 self.pipeo.flush()
216 self.pipeo.flush()
217
217
218 self.readerr()
218 self.readerr()
219 l = int(self.pipei.readline())
219 l = int(self.pipei.readline())
220 r = self.pipei.read(l)
220 r = self.pipei.read(l)
221 if not r:
221 if not r:
222 return 1
222 return 1
223 return int(r)
223 return int(r)
224
224
225 def stream_out(self):
225 def stream_out(self):
226 return self.do_cmd('stream_out')
226 return self.do_cmd('stream_out')
227
227
228 instance = sshrepository
228 instance = sshrepository
General Comments 0
You need to be logged in to leave comments. Login now