##// END OF EJS Templates
Don't enter an endless loop if remote hg doesn't answer, show remote noise....
Thomas Arendsen Hein -
r2040:cd771126 default
parent child Browse files
Show More
@@ -1,146 +1,155 b''
1 # sshrepo.py - ssh repository proxy class for mercurial
1 # sshrepo.py - ssh repository proxy class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 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")
12 demandload(globals(), "hg os re stat")
13
13
14 class sshrepository(remoterepository):
14 class sshrepository(remoterepository):
15 def __init__(self, ui, path):
15 def __init__(self, ui, path):
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 destination %s") % path)
21 raise hg.RepoError(_("couldn't parse destination %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 cmd = '%s %s "%s -R %s serve --stdio"'
33 cmd = '%s %s "%s -R %s serve --stdio"'
34 cmd = cmd % (sshcmd, args, remotecmd, self.path)
34 cmd = cmd % (sshcmd, args, remotecmd, self.path)
35
35
36 ui.note('running %s\n' % cmd)
36 ui.note('running %s\n' % cmd)
37 self.pipeo, self.pipei, self.pipee = os.popen3(cmd, 'b')
37 self.pipeo, self.pipei, self.pipee = os.popen3(cmd, 'b')
38
38
39 # skip any noise generated by remote shell
39 # skip any noise generated by remote shell
40 r = self.do_cmd("between", pairs=("%s-%s" % ("0"*40, "0"*40)))
40 r = self.do_cmd("between", pairs=("%s-%s" % ("0"*40, "0"*40)))
41 l1 = ""
41 l1 = ""
42 while 1:
42 l2 = "dummy"
43 max_noise = 100
44 while l2 and max_noise:
43 l2 = r.readline()
45 l2 = r.readline()
44 self.readerr()
46 self.readerr()
45 if l1 == "1\n" and l2 == "\n":
47 if l1 == "1\n" and l2 == "\n":
46 break
48 break
49 if l1:
50 ui.status(_("remote: %s") % l1)
47 l1 = l2
51 l1 = l2
52 max_noise -= 1
53 else:
54 if l1:
55 ui.status(_("remote: %s") % l1)
56 raise hg.RepoError(_("no response from remote hg"))
48
57
49 def readerr(self):
58 def readerr(self):
50 while 1:
59 while 1:
51 size = os.fstat(self.pipee.fileno())[stat.ST_SIZE]
60 size = os.fstat(self.pipee.fileno())[stat.ST_SIZE]
52 if size == 0: break
61 if size == 0: break
53 l = self.pipee.readline()
62 l = self.pipee.readline()
54 if not l: break
63 if not l: break
55 self.ui.status(_("remote: "), l)
64 self.ui.status(_("remote: "), l)
56
65
57 def __del__(self):
66 def __del__(self):
58 try:
67 try:
59 self.pipeo.close()
68 self.pipeo.close()
60 self.pipei.close()
69 self.pipei.close()
61 # read the error descriptor until EOF
70 # read the error descriptor until EOF
62 for l in self.pipee:
71 for l in self.pipee:
63 self.ui.status(_("remote: "), l)
72 self.ui.status(_("remote: "), l)
64 self.pipee.close()
73 self.pipee.close()
65 except:
74 except:
66 pass
75 pass
67
76
68 def dev(self):
77 def dev(self):
69 return -1
78 return -1
70
79
71 def do_cmd(self, cmd, **args):
80 def do_cmd(self, cmd, **args):
72 self.ui.debug(_("sending %s command\n") % cmd)
81 self.ui.debug(_("sending %s command\n") % cmd)
73 self.pipeo.write("%s\n" % cmd)
82 self.pipeo.write("%s\n" % cmd)
74 for k, v in args.items():
83 for k, v in args.items():
75 self.pipeo.write("%s %d\n" % (k, len(v)))
84 self.pipeo.write("%s %d\n" % (k, len(v)))
76 self.pipeo.write(v)
85 self.pipeo.write(v)
77 self.pipeo.flush()
86 self.pipeo.flush()
78
87
79 return self.pipei
88 return self.pipei
80
89
81 def call(self, cmd, **args):
90 def call(self, cmd, **args):
82 r = self.do_cmd(cmd, **args)
91 r = self.do_cmd(cmd, **args)
83 l = r.readline()
92 l = r.readline()
84 self.readerr()
93 self.readerr()
85 try:
94 try:
86 l = int(l)
95 l = int(l)
87 except:
96 except:
88 raise hg.RepoError(_("unexpected response '%s'") % l)
97 raise hg.RepoError(_("unexpected response '%s'") % l)
89 return r.read(l)
98 return r.read(l)
90
99
91 def lock(self):
100 def lock(self):
92 self.call("lock")
101 self.call("lock")
93 return remotelock(self)
102 return remotelock(self)
94
103
95 def unlock(self):
104 def unlock(self):
96 self.call("unlock")
105 self.call("unlock")
97
106
98 def heads(self):
107 def heads(self):
99 d = self.call("heads")
108 d = self.call("heads")
100 try:
109 try:
101 return map(bin, d[:-1].split(" "))
110 return map(bin, d[:-1].split(" "))
102 except:
111 except:
103 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
112 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
104
113
105 def branches(self, nodes):
114 def branches(self, nodes):
106 n = " ".join(map(hex, nodes))
115 n = " ".join(map(hex, nodes))
107 d = self.call("branches", nodes=n)
116 d = self.call("branches", nodes=n)
108 try:
117 try:
109 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
118 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
110 return br
119 return br
111 except:
120 except:
112 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
121 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
113
122
114 def between(self, pairs):
123 def between(self, pairs):
115 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
124 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
116 d = self.call("between", pairs=n)
125 d = self.call("between", pairs=n)
117 try:
126 try:
118 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
127 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
119 return p
128 return p
120 except:
129 except:
121 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
130 raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
122
131
123 def changegroup(self, nodes, kind):
132 def changegroup(self, nodes, kind):
124 n = " ".join(map(hex, nodes))
133 n = " ".join(map(hex, nodes))
125 f = self.do_cmd("changegroup", roots=n)
134 f = self.do_cmd("changegroup", roots=n)
126 return self.pipei
135 return self.pipei
127
136
128 def addchangegroup(self, cg):
137 def addchangegroup(self, cg):
129 d = self.call("addchangegroup")
138 d = self.call("addchangegroup")
130 if d:
139 if d:
131 raise hg.RepoError(_("push refused: %s"), d)
140 raise hg.RepoError(_("push refused: %s"), d)
132
141
133 while 1:
142 while 1:
134 d = cg.read(4096)
143 d = cg.read(4096)
135 if not d: break
144 if not d: break
136 self.pipeo.write(d)
145 self.pipeo.write(d)
137 self.readerr()
146 self.readerr()
138
147
139 self.pipeo.flush()
148 self.pipeo.flush()
140
149
141 self.readerr()
150 self.readerr()
142 l = int(self.pipei.readline())
151 l = int(self.pipei.readline())
143 r = self.pipei.read(l)
152 r = self.pipei.read(l)
144 if not r:
153 if not r:
145 return 1
154 return 1
146 return int(r)
155 return int(r)
General Comments 0
You need to be logged in to leave comments. Login now