##// END OF EJS Templates
sshrepo: add passing of lookup exceptions
Eric Hopper -
r3447:ef1032c2 default
parent child Browse files
Show More
@@ -1,223 +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 try:
137 try:
137 return bin(d[:-1])
138 if int(success):
139 return bin(data)
140 else:
141 raise data
138 except:
142 except:
143 raise
139 raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
144 raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
140
145
141 def heads(self):
146 def heads(self):
142 d = self.call("heads")
147 d = self.call("heads")
143 try:
148 try:
144 return map(bin, d[:-1].split(" "))
149 return map(bin, d[:-1].split(" "))
145 except:
150 except:
146 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
151 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
147
152
148 def branches(self, nodes):
153 def branches(self, nodes):
149 n = " ".join(map(hex, nodes))
154 n = " ".join(map(hex, nodes))
150 d = self.call("branches", nodes=n)
155 d = self.call("branches", nodes=n)
151 try:
156 try:
152 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
157 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
153 return br
158 return br
154 except:
159 except:
155 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
160 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
156
161
157 def between(self, pairs):
162 def between(self, pairs):
158 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
163 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
159 d = self.call("between", pairs=n)
164 d = self.call("between", pairs=n)
160 try:
165 try:
161 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() ]
162 return p
167 return p
163 except:
168 except:
164 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
169 self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
165
170
166 def changegroup(self, nodes, kind):
171 def changegroup(self, nodes, kind):
167 n = " ".join(map(hex, nodes))
172 n = " ".join(map(hex, nodes))
168 return self.do_cmd("changegroup", roots=n)
173 return self.do_cmd("changegroup", roots=n)
169
174
170 def changegroupsubset(self, bases, heads, kind):
175 def changegroupsubset(self, bases, heads, kind):
171 bases = " ".join(map(hex, bases))
176 bases = " ".join(map(hex, bases))
172 heads = " ".join(map(hex, heads))
177 heads = " ".join(map(hex, heads))
173 return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
178 return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
174
179
175 def unbundle(self, cg, heads, source):
180 def unbundle(self, cg, heads, source):
176 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
181 d = self.call("unbundle", heads=' '.join(map(hex, heads)))
177 if d:
182 if d:
178 self.repoerror(_("push refused: %s") % d)
183 self.repoerror(_("push refused: %s") % d)
179
184
180 while 1:
185 while 1:
181 d = cg.read(4096)
186 d = cg.read(4096)
182 if not d: break
187 if not d: break
183 self.pipeo.write(str(len(d)) + '\n')
188 self.pipeo.write(str(len(d)) + '\n')
184 self.pipeo.write(d)
189 self.pipeo.write(d)
185 self.readerr()
190 self.readerr()
186
191
187 self.pipeo.write('0\n')
192 self.pipeo.write('0\n')
188 self.pipeo.flush()
193 self.pipeo.flush()
189
194
190 self.readerr()
195 self.readerr()
191 d = self.pipei.readline()
196 d = self.pipei.readline()
192 if d != '\n':
197 if d != '\n':
193 return 1
198 return 1
194
199
195 l = int(self.pipei.readline())
200 l = int(self.pipei.readline())
196 r = self.pipei.read(l)
201 r = self.pipei.read(l)
197 if not r:
202 if not r:
198 return 1
203 return 1
199 return int(r)
204 return int(r)
200
205
201 def addchangegroup(self, cg, source, url):
206 def addchangegroup(self, cg, source, url):
202 d = self.call("addchangegroup")
207 d = self.call("addchangegroup")
203 if d:
208 if d:
204 self.repoerror(_("push refused: %s") % d)
209 self.repoerror(_("push refused: %s") % d)
205 while 1:
210 while 1:
206 d = cg.read(4096)
211 d = cg.read(4096)
207 if not d: break
212 if not d: break
208 self.pipeo.write(d)
213 self.pipeo.write(d)
209 self.readerr()
214 self.readerr()
210
215
211 self.pipeo.flush()
216 self.pipeo.flush()
212
217
213 self.readerr()
218 self.readerr()
214 l = int(self.pipei.readline())
219 l = int(self.pipei.readline())
215 r = self.pipei.read(l)
220 r = self.pipei.read(l)
216 if not r:
221 if not r:
217 return 1
222 return 1
218 return int(r)
223 return int(r)
219
224
220 def stream_out(self):
225 def stream_out(self):
221 return self.do_cmd('stream_out')
226 return self.do_cmd('stream_out')
222
227
223 instance = sshrepository
228 instance = sshrepository
@@ -1,199 +1,205 b''
1 # sshserver.py - ssh protocol server support for mercurial
1 # sshserver.py - ssh protocol server support for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from demandload import demandload
9 from demandload import demandload
10 from i18n import gettext as _
10 from i18n import gettext as _
11 from node import *
11 from node import *
12 demandload(globals(), "os streamclone sys tempfile util")
12 demandload(globals(), "os streamclone sys tempfile util")
13
13
14 class sshserver(object):
14 class sshserver(object):
15 def __init__(self, ui, repo):
15 def __init__(self, ui, repo):
16 self.ui = ui
16 self.ui = ui
17 self.repo = repo
17 self.repo = repo
18 self.lock = None
18 self.lock = None
19 self.fin = sys.stdin
19 self.fin = sys.stdin
20 self.fout = sys.stdout
20 self.fout = sys.stdout
21
21
22 sys.stdout = sys.stderr
22 sys.stdout = sys.stderr
23
23
24 # Prevent insertion/deletion of CRs
24 # Prevent insertion/deletion of CRs
25 util.set_binary(self.fin)
25 util.set_binary(self.fin)
26 util.set_binary(self.fout)
26 util.set_binary(self.fout)
27
27
28 def getarg(self):
28 def getarg(self):
29 argline = self.fin.readline()[:-1]
29 argline = self.fin.readline()[:-1]
30 arg, l = argline.split()
30 arg, l = argline.split()
31 val = self.fin.read(int(l))
31 val = self.fin.read(int(l))
32 return arg, val
32 return arg, val
33
33
34 def respond(self, v):
34 def respond(self, v):
35 self.fout.write("%d\n" % len(v))
35 self.fout.write("%d\n" % len(v))
36 self.fout.write(v)
36 self.fout.write(v)
37 self.fout.flush()
37 self.fout.flush()
38
38
39 def serve_forever(self):
39 def serve_forever(self):
40 while self.serve_one(): pass
40 while self.serve_one(): pass
41 sys.exit(0)
41 sys.exit(0)
42
42
43 def serve_one(self):
43 def serve_one(self):
44 cmd = self.fin.readline()[:-1]
44 cmd = self.fin.readline()[:-1]
45 if cmd:
45 if cmd:
46 impl = getattr(self, 'do_' + cmd, None)
46 impl = getattr(self, 'do_' + cmd, None)
47 if impl: impl()
47 if impl: impl()
48 else: self.respond("")
48 else: self.respond("")
49 return cmd != ''
49 return cmd != ''
50
50
51 def do_lookup(self):
51 def do_lookup(self):
52 arg, key = self.getarg()
52 arg, key = self.getarg()
53 assert arg == 'key'
53 assert arg == 'key'
54 self.respond(hex(self.repo.lookup(key)) + "\n")
54 try:
55 r = hex(self.repo.lookup(key))
56 success = 1
57 except Exception,inst:
58 r = str(inst)
59 success = 0
60 self.respond("%s %s\n" % (success, r))
55
61
56 def do_heads(self):
62 def do_heads(self):
57 h = self.repo.heads()
63 h = self.repo.heads()
58 self.respond(" ".join(map(hex, h)) + "\n")
64 self.respond(" ".join(map(hex, h)) + "\n")
59
65
60 def do_hello(self):
66 def do_hello(self):
61 '''the hello command returns a set of lines describing various
67 '''the hello command returns a set of lines describing various
62 interesting things about the server, in an RFC822-like format.
68 interesting things about the server, in an RFC822-like format.
63 Currently the only one defined is "capabilities", which
69 Currently the only one defined is "capabilities", which
64 consists of a line in the form:
70 consists of a line in the form:
65
71
66 capabilities: space separated list of tokens
72 capabilities: space separated list of tokens
67 '''
73 '''
68
74
69 caps = ['unbundle', 'lookup', 'changegroupsubset']
75 caps = ['unbundle', 'lookup', 'changegroupsubset']
70 if self.ui.configbool('server', 'uncompressed'):
76 if self.ui.configbool('server', 'uncompressed'):
71 caps.append('stream=%d' % self.repo.revlogversion)
77 caps.append('stream=%d' % self.repo.revlogversion)
72 self.respond("capabilities: %s\n" % (' '.join(caps),))
78 self.respond("capabilities: %s\n" % (' '.join(caps),))
73
79
74 def do_lock(self):
80 def do_lock(self):
75 '''DEPRECATED - allowing remote client to lock repo is not safe'''
81 '''DEPRECATED - allowing remote client to lock repo is not safe'''
76
82
77 self.lock = self.repo.lock()
83 self.lock = self.repo.lock()
78 self.respond("")
84 self.respond("")
79
85
80 def do_unlock(self):
86 def do_unlock(self):
81 '''DEPRECATED'''
87 '''DEPRECATED'''
82
88
83 if self.lock:
89 if self.lock:
84 self.lock.release()
90 self.lock.release()
85 self.lock = None
91 self.lock = None
86 self.respond("")
92 self.respond("")
87
93
88 def do_branches(self):
94 def do_branches(self):
89 arg, nodes = self.getarg()
95 arg, nodes = self.getarg()
90 nodes = map(bin, nodes.split(" "))
96 nodes = map(bin, nodes.split(" "))
91 r = []
97 r = []
92 for b in self.repo.branches(nodes):
98 for b in self.repo.branches(nodes):
93 r.append(" ".join(map(hex, b)) + "\n")
99 r.append(" ".join(map(hex, b)) + "\n")
94 self.respond("".join(r))
100 self.respond("".join(r))
95
101
96 def do_between(self):
102 def do_between(self):
97 arg, pairs = self.getarg()
103 arg, pairs = self.getarg()
98 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
104 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
99 r = []
105 r = []
100 for b in self.repo.between(pairs):
106 for b in self.repo.between(pairs):
101 r.append(" ".join(map(hex, b)) + "\n")
107 r.append(" ".join(map(hex, b)) + "\n")
102 self.respond("".join(r))
108 self.respond("".join(r))
103
109
104 def do_changegroup(self):
110 def do_changegroup(self):
105 nodes = []
111 nodes = []
106 arg, roots = self.getarg()
112 arg, roots = self.getarg()
107 nodes = map(bin, roots.split(" "))
113 nodes = map(bin, roots.split(" "))
108
114
109 cg = self.repo.changegroup(nodes, 'serve')
115 cg = self.repo.changegroup(nodes, 'serve')
110 while True:
116 while True:
111 d = cg.read(4096)
117 d = cg.read(4096)
112 if not d:
118 if not d:
113 break
119 break
114 self.fout.write(d)
120 self.fout.write(d)
115
121
116 self.fout.flush()
122 self.fout.flush()
117
123
118 def do_changegroupsubset(self):
124 def do_changegroupsubset(self):
119 bases = []
125 bases = []
120 heads = []
126 heads = []
121 argmap = dict([self.getarg(), self.getarg()])
127 argmap = dict([self.getarg(), self.getarg()])
122 bases = [bin(n) for n in argmap['bases'].split(' ')]
128 bases = [bin(n) for n in argmap['bases'].split(' ')]
123 heads = [bin(n) for n in argmap['heads'].split(' ')]
129 heads = [bin(n) for n in argmap['heads'].split(' ')]
124
130
125 cg = self.repo.changegroupsubset(bases, heads, 'serve')
131 cg = self.repo.changegroupsubset(bases, heads, 'serve')
126 while True:
132 while True:
127 d = cg.read(4096)
133 d = cg.read(4096)
128 if not d:
134 if not d:
129 break
135 break
130 self.fout.write(d)
136 self.fout.write(d)
131
137
132 self.fout.flush()
138 self.fout.flush()
133
139
134 def do_addchangegroup(self):
140 def do_addchangegroup(self):
135 '''DEPRECATED'''
141 '''DEPRECATED'''
136
142
137 if not self.lock:
143 if not self.lock:
138 self.respond("not locked")
144 self.respond("not locked")
139 return
145 return
140
146
141 self.respond("")
147 self.respond("")
142 r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
148 r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
143 self.respond(str(r))
149 self.respond(str(r))
144
150
145 def client_url(self):
151 def client_url(self):
146 client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
152 client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
147 return 'remote:ssh:' + client
153 return 'remote:ssh:' + client
148
154
149 def do_unbundle(self):
155 def do_unbundle(self):
150 their_heads = self.getarg()[1].split()
156 their_heads = self.getarg()[1].split()
151
157
152 def check_heads():
158 def check_heads():
153 heads = map(hex, self.repo.heads())
159 heads = map(hex, self.repo.heads())
154 return their_heads == [hex('force')] or their_heads == heads
160 return their_heads == [hex('force')] or their_heads == heads
155
161
156 # fail early if possible
162 # fail early if possible
157 if not check_heads():
163 if not check_heads():
158 self.respond(_('unsynced changes'))
164 self.respond(_('unsynced changes'))
159 return
165 return
160
166
161 self.respond('')
167 self.respond('')
162
168
163 # write bundle data to temporary file because it can be big
169 # write bundle data to temporary file because it can be big
164
170
165 try:
171 try:
166 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
172 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
167 fp = os.fdopen(fd, 'wb+')
173 fp = os.fdopen(fd, 'wb+')
168
174
169 count = int(self.fin.readline())
175 count = int(self.fin.readline())
170 while count:
176 while count:
171 fp.write(self.fin.read(count))
177 fp.write(self.fin.read(count))
172 count = int(self.fin.readline())
178 count = int(self.fin.readline())
173
179
174 was_locked = self.lock is not None
180 was_locked = self.lock is not None
175 if not was_locked:
181 if not was_locked:
176 self.lock = self.repo.lock()
182 self.lock = self.repo.lock()
177 try:
183 try:
178 if not check_heads():
184 if not check_heads():
179 # someone else committed/pushed/unbundled while we
185 # someone else committed/pushed/unbundled while we
180 # were transferring data
186 # were transferring data
181 self.respond(_('unsynced changes'))
187 self.respond(_('unsynced changes'))
182 return
188 return
183 self.respond('')
189 self.respond('')
184
190
185 # push can proceed
191 # push can proceed
186
192
187 fp.seek(0)
193 fp.seek(0)
188 r = self.repo.addchangegroup(fp, 'serve', self.client_url())
194 r = self.repo.addchangegroup(fp, 'serve', self.client_url())
189 self.respond(str(r))
195 self.respond(str(r))
190 finally:
196 finally:
191 if not was_locked:
197 if not was_locked:
192 self.lock.release()
198 self.lock.release()
193 self.lock = None
199 self.lock = None
194 finally:
200 finally:
195 fp.close()
201 fp.close()
196 os.unlink(tempname)
202 os.unlink(tempname)
197
203
198 def do_stream_out(self):
204 def do_stream_out(self):
199 streamclone.stream_out(self.repo, self.fout)
205 streamclone.stream_out(self.repo, self.fout)
General Comments 0
You need to be logged in to leave comments. Login now