3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com> |
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com> |
4 # |
4 # |
5 # This software may be used and distributed according to the terms of the |
5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2 or any later version. |
6 # GNU General Public License version 2 or any later version. |
7 |
7 |
|
8 import urllib, tempfile, os |
8 from i18n import _ |
9 from i18n import _ |
9 from node import bin, hex |
10 from node import bin, hex |
10 import urllib |
11 import changegroup as changegroupmod |
11 import streamclone, repo, error, encoding |
12 import streamclone, repo, error, encoding, util |
12 import pushkey as pushkey_ |
13 import pushkey as pushkey_ |
13 |
14 |
14 # client side |
15 # client side |
15 |
16 |
16 class wirerepository(repo.repository): |
17 class wirerepository(repo.repository): |
196 try: |
197 try: |
197 proto.sendstream(streamclone.stream_out(repo)) |
198 proto.sendstream(streamclone.stream_out(repo)) |
198 except streamclone.StreamException, inst: |
199 except streamclone.StreamException, inst: |
199 return str(inst) |
200 return str(inst) |
200 |
201 |
|
202 def unbundle(repo, proto, heads): |
|
203 their_heads = heads.split() |
|
204 |
|
205 def check_heads(): |
|
206 heads = map(hex, repo.heads()) |
|
207 return their_heads == [hex('force')] or their_heads == heads |
|
208 |
|
209 # fail early if possible |
|
210 if not check_heads(): |
|
211 repo.respond(_('unsynced changes')) |
|
212 return |
|
213 |
|
214 # write bundle data to temporary file because it can be big |
|
215 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') |
|
216 fp = os.fdopen(fd, 'wb+') |
|
217 r = 0 |
|
218 proto.redirect() |
|
219 try: |
|
220 proto.getfile(fp) |
|
221 lock = repo.lock() |
|
222 try: |
|
223 if not check_heads(): |
|
224 # someone else committed/pushed/unbundled while we |
|
225 # were transferring data |
|
226 proto.respond(_('unsynced changes')) |
|
227 return |
|
228 |
|
229 # push can proceed |
|
230 fp.seek(0) |
|
231 header = fp.read(6) |
|
232 if header.startswith('HG'): |
|
233 if not header.startswith('HG10'): |
|
234 raise ValueError('unknown bundle version') |
|
235 elif header not in changegroupmod.bundletypes: |
|
236 raise ValueError('unknown bundle compression type') |
|
237 gen = changegroupmod.unbundle(header, fp) |
|
238 |
|
239 try: |
|
240 r = repo.addchangegroup(gen, 'serve', proto._client(), |
|
241 lock=lock) |
|
242 except util.Abort, inst: |
|
243 sys.stderr.write("abort: %s\n" % inst) |
|
244 finally: |
|
245 lock.release() |
|
246 proto.respondpush(r) |
|
247 |
|
248 finally: |
|
249 fp.close() |
|
250 os.unlink(tempname) |
|
251 |
201 commands = { |
252 commands = { |
202 'between': (between, 'pairs'), |
253 'between': (between, 'pairs'), |
203 'branchmap': (branchmap, ''), |
254 'branchmap': (branchmap, ''), |
204 'branches': (branches, 'nodes'), |
255 'branches': (branches, 'nodes'), |
205 'changegroup': (changegroup, 'roots'), |
256 'changegroup': (changegroup, 'roots'), |
207 'heads': (heads, ''), |
258 'heads': (heads, ''), |
208 'listkeys': (listkeys, 'namespace'), |
259 'listkeys': (listkeys, 'namespace'), |
209 'lookup': (lookup, 'key'), |
260 'lookup': (lookup, 'key'), |
210 'pushkey': (pushkey, 'namespace key old new'), |
261 'pushkey': (pushkey, 'namespace key old new'), |
211 'stream_out': (stream, ''), |
262 'stream_out': (stream, ''), |
|
263 'unbundle': (unbundle, 'heads'), |
212 } |
264 } |