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