##// END OF EJS Templates
Merge with asak
Thomas Arendsen Hein -
r3381:bb9852b3 merge default
parent child Browse files
Show More
@@ -1,207 +1,211 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 raise hg.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 raise hg.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 raise hg.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):
91 self.cleanup()
92 raise hg.RepoError(msg)
93
90 def cleanup(self):
94 def cleanup(self):
91 try:
95 try:
92 self.pipeo.close()
96 self.pipeo.close()
93 self.pipei.close()
97 self.pipei.close()
94 # read the error descriptor until EOF
98 # read the error descriptor until EOF
95 for l in self.pipee:
99 for l in self.pipee:
96 self.ui.status(_("remote: "), l)
100 self.ui.status(_("remote: "), l)
97 self.pipee.close()
101 self.pipee.close()
98 except:
102 except:
99 pass
103 pass
100
104
101 __del__ = cleanup
105 __del__ = cleanup
102
106
103 def do_cmd(self, cmd, **args):
107 def do_cmd(self, cmd, **args):
104 self.ui.debug(_("sending %s command\n") % cmd)
108 self.ui.debug(_("sending %s command\n") % cmd)
105 self.pipeo.write("%s\n" % cmd)
109 self.pipeo.write("%s\n" % cmd)
106 for k, v in args.items():
110 for k, v in args.items():
107 self.pipeo.write("%s %d\n" % (k, len(v)))
111 self.pipeo.write("%s %d\n" % (k, len(v)))
108 self.pipeo.write(v)
112 self.pipeo.write(v)
109 self.pipeo.flush()
113 self.pipeo.flush()
110
114
111 return self.pipei
115 return self.pipei
112
116
113 def call(self, cmd, **args):
117 def call(self, cmd, **args):
114 r = self.do_cmd(cmd, **args)
118 r = self.do_cmd(cmd, **args)
115 l = r.readline()
119 l = r.readline()
116 self.readerr()
120 self.readerr()
117 try:
121 try:
118 l = int(l)
122 l = int(l)
119 except:
123 except:
120 raise hg.RepoError(_("unexpected response '%s'") % l)
124 self.repoerror(_("unexpected response '%s'") % l)
121 return r.read(l)
125 return r.read(l)
122
126
123 def lock(self):
127 def lock(self):
124 self.call("lock")
128 self.call("lock")
125 return remotelock(self)
129 return remotelock(self)
126
130
127 def unlock(self):
131 def unlock(self):
128 self.call("unlock")
132 self.call("unlock")
129
133
130 def heads(self):
134 def heads(self):
131 d = self.call("heads")
135 d = self.call("heads")
132 try:
136 try:
133 return map(bin, d[:-1].split(" "))
137 return map(bin, d[:-1].split(" "))
134 except:
138 except:
135 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
139 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
136
140
137 def branches(self, nodes):
141 def branches(self, nodes):
138 n = " ".join(map(hex, nodes))
142 n = " ".join(map(hex, nodes))
139 d = self.call("branches", nodes=n)
143 d = self.call("branches", nodes=n)
140 try:
144 try:
141 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
145 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
142 return br
146 return br
143 except:
147 except:
144 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
148 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
145
149
146 def between(self, pairs):
150 def between(self, pairs):
147 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
151 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
148 d = self.call("between", pairs=n)
152 d = self.call("between", pairs=n)
149 try:
153 try:
150 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
154 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
151 return p
155 return p
152 except:
156 except:
153 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
157 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
154
158
155 def changegroup(self, nodes, kind):
159 def changegroup(self, nodes, kind):
156 n = " ".join(map(hex, nodes))
160 n = " ".join(map(hex, nodes))
157 return self.do_cmd("changegroup", roots=n)
161 return self.do_cmd("changegroup", roots=n)
158
162
159 def unbundle(self, cg, heads, source):
163 def unbundle(self, cg, heads, source):
160 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
164 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
161 if d:
165 if d:
162 raise hg.RepoError(_("push refused: %s") % d)
166 self.repoerror(_("push refused: %s") % d)
163
167
164 while 1:
168 while 1:
165 d = cg.read(4096)
169 d = cg.read(4096)
166 if not d: break
170 if not d: break
167 self.pipeo.write(str(len(d)) + '\n')
171 self.pipeo.write(str(len(d)) + '\n')
168 self.pipeo.write(d)
172 self.pipeo.write(d)
169 self.readerr()
173 self.readerr()
170
174
171 self.pipeo.write('0\n')
175 self.pipeo.write('0\n')
172 self.pipeo.flush()
176 self.pipeo.flush()
173
177
174 self.readerr()
178 self.readerr()
175 d = self.pipei.readline()
179 d = self.pipei.readline()
176 if d != '\n':
180 if d != '\n':
177 return 1
181 return 1
178
182
179 l = int(self.pipei.readline())
183 l = int(self.pipei.readline())
180 r = self.pipei.read(l)
184 r = self.pipei.read(l)
181 if not r:
185 if not r:
182 return 1
186 return 1
183 return int(r)
187 return int(r)
184
188
185 def addchangegroup(self, cg, source, url):
189 def addchangegroup(self, cg, source, url):
186 d = self.call("addchangegroup")
190 d = self.call("addchangegroup")
187 if d:
191 if d:
188 raise hg.RepoError(_("push refused: %s") % d)
192 self.repoerror(_("push refused: %s") % d)
189 while 1:
193 while 1:
190 d = cg.read(4096)
194 d = cg.read(4096)
191 if not d: break
195 if not d: break
192 self.pipeo.write(d)
196 self.pipeo.write(d)
193 self.readerr()
197 self.readerr()
194
198
195 self.pipeo.flush()
199 self.pipeo.flush()
196
200
197 self.readerr()
201 self.readerr()
198 l = int(self.pipei.readline())
202 l = int(self.pipei.readline())
199 r = self.pipei.read(l)
203 r = self.pipei.read(l)
200 if not r:
204 if not r:
201 return 1
205 return 1
202 return int(r)
206 return int(r)
203
207
204 def stream_out(self):
208 def stream_out(self):
205 return self.do_cmd('stream_out')
209 return self.do_cmd('stream_out')
206
210
207 instance = sshrepository
211 instance = sshrepository
@@ -1,93 +1,93 b''
1 # creating 'remote'
1 # creating 'remote'
2 # repo not found error
2 # repo not found error
3 remote: abort: repository nonexistent not found!
3 abort: no suitable response from remote hg!
4 abort: no suitable response from remote hg!
4 remote: abort: repository nonexistent not found!
5 # clone remote via stream
5 # clone remote via stream
6 streaming all changes
6 streaming all changes
7 XXX files to transfer, XXX bytes of data
7 XXX files to transfer, XXX bytes of data
8 transferred XXX bytes in XXX seconds (XXX XB/sec)
8 transferred XXX bytes in XXX seconds (XXX XB/sec)
9 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
9 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
10 checking changesets
10 checking changesets
11 checking manifests
11 checking manifests
12 crosschecking files in changesets and manifests
12 crosschecking files in changesets and manifests
13 checking files
13 checking files
14 1 files, 1 changesets, 1 total revisions
14 1 files, 1 changesets, 1 total revisions
15 # clone remote via pull
15 # clone remote via pull
16 requesting all changes
16 requesting all changes
17 adding changesets
17 adding changesets
18 adding manifests
18 adding manifests
19 adding file changes
19 adding file changes
20 added 1 changesets with 1 changes to 1 files
20 added 1 changesets with 1 changes to 1 files
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 # verify
22 # verify
23 checking changesets
23 checking changesets
24 checking manifests
24 checking manifests
25 crosschecking files in changesets and manifests
25 crosschecking files in changesets and manifests
26 checking files
26 checking files
27 1 files, 1 changesets, 1 total revisions
27 1 files, 1 changesets, 1 total revisions
28 # empty default pull
28 # empty default pull
29 default = ssh://user@dummy/remote
29 default = ssh://user@dummy/remote
30 pulling from ssh://user@dummy/remote
30 pulling from ssh://user@dummy/remote
31 searching for changes
31 searching for changes
32 no changes found
32 no changes found
33 # local change
33 # local change
34 # updating rc
34 # updating rc
35 # find outgoing
35 # find outgoing
36 searching for changes
36 searching for changes
37 changeset: 1:c54836a570be
37 changeset: 1:c54836a570be
38 tag: tip
38 tag: tip
39 user: test
39 user: test
40 date: Mon Jan 12 13:46:40 1970 +0000
40 date: Mon Jan 12 13:46:40 1970 +0000
41 summary: add
41 summary: add
42
42
43 # find incoming on the remote side
43 # find incoming on the remote side
44 searching for changes
44 searching for changes
45 changeset: 1:c54836a570be
45 changeset: 1:c54836a570be
46 tag: tip
46 tag: tip
47 user: test
47 user: test
48 date: Mon Jan 12 13:46:40 1970 +0000
48 date: Mon Jan 12 13:46:40 1970 +0000
49 summary: add
49 summary: add
50
50
51 # push
51 # push
52 pushing to ssh://user@dummy/remote
52 pushing to ssh://user@dummy/remote
53 searching for changes
53 searching for changes
54 remote: adding changesets
54 remote: adding changesets
55 remote: adding manifests
55 remote: adding manifests
56 remote: adding file changes
56 remote: adding file changes
57 remote: added 1 changesets with 1 changes to 1 files
57 remote: added 1 changesets with 1 changes to 1 files
58 # check remote tip
58 # check remote tip
59 changeset: 1:c54836a570be
59 changeset: 1:c54836a570be
60 tag: tip
60 tag: tip
61 user: test
61 user: test
62 date: Mon Jan 12 13:46:40 1970 +0000
62 date: Mon Jan 12 13:46:40 1970 +0000
63 summary: add
63 summary: add
64
64
65 checking changesets
65 checking changesets
66 checking manifests
66 checking manifests
67 crosschecking files in changesets and manifests
67 crosschecking files in changesets and manifests
68 checking files
68 checking files
69 1 files, 2 changesets, 2 total revisions
69 1 files, 2 changesets, 2 total revisions
70 bleah
70 bleah
71 # push should fail
71 # push should fail
72 pushing to ssh://user@dummy/remote
72 pushing to ssh://user@dummy/remote
73 searching for changes
73 searching for changes
74 abort: unsynced remote changes!
74 abort: unsynced remote changes!
75 (did you forget to sync? use push -f to force)
75 (did you forget to sync? use push -f to force)
76 # push should succeed
76 # push should succeed
77 pushing to ssh://user@dummy/remote
77 pushing to ssh://user@dummy/remote
78 searching for changes
78 searching for changes
79 remote: adding changesets
79 remote: adding changesets
80 remote: adding manifests
80 remote: adding manifests
81 remote: adding file changes
81 remote: adding file changes
82 remote: added 1 changesets with 1 changes to 1 files
82 remote: added 1 changesets with 1 changes to 1 files
83 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio 3: 4: 5:
83 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio 3: 4: 5:
84 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
84 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
85 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
85 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
86 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
86 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
87 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
87 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
88 Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5:
88 Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5:
89 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
89 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
90 changegroup in remote: u=remote:ssh:127.0.0.1
90 changegroup in remote: u=remote:ssh:127.0.0.1
91 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
91 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
92 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
92 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
93 changegroup in remote: u=remote:ssh:127.0.0.1
93 changegroup in remote: u=remote:ssh:127.0.0.1
General Comments 0
You need to be logged in to leave comments. Login now