Mercurial > hgsubversion
comparison fetch_command.py @ 110:a4dcffaa6538
fetch_command: pass parent changectx instead of identifier
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Tue, 25 Nov 2008 09:18:30 -0600 |
parents | 460443a96497 |
children | 5497d1264b4d |
comparison
equal
deleted
inserted
replaced
109:460443a96497 | 110:a4dcffaa6538 |
---|---|
170 _* | 170 _* |
171 (?:Deleted|Name): svn:special | 171 (?:Deleted|Name): svn:special |
172 \- \* | 172 \- \* |
173 ''') | 173 ''') |
174 | 174 |
175 def stupid_diff_branchrev(ui, svn, hg_editor, branch, r, parentid, tempdir): | 175 def stupid_diff_branchrev(ui, svn, hg_editor, branch, r, parentctx, tempdir): |
176 """Extract all 'branch' content at a given revision. | 176 """Extract all 'branch' content at a given revision. |
177 | 177 |
178 Return a tuple (files, filectxfn) where 'files' is the list of all files | 178 Return a tuple (files, filectxfn) where 'files' is the list of all files |
179 in the branch at the given revision, and 'filectxfn' is a memctx compatible | 179 in the branch at the given revision, and 'filectxfn' is a memctx compatible |
180 callable to retrieve individual file information. Raise BadPatchApply upon | 180 callable to retrieve individual file information. Raise BadPatchApply upon |
226 # this check is here because modified binary files will get | 226 # this check is here because modified binary files will get |
227 # created before here. | 227 # created before here. |
228 continue | 228 continue |
229 files_touched.add(f) | 229 files_touched.add(f) |
230 data = '' | 230 data = '' |
231 if f in hg_editor.repo[parentid]: | 231 if f in parentctx: |
232 data = hg_editor.repo[parentid][f].data() | 232 data = parentctx[f].data() |
233 fp = opener(f, 'w') | 233 fp = opener(f, 'w') |
234 fp.write(data) | 234 fp.write(data) |
235 fp.close() | 235 fp.close() |
236 if d2.strip() and len(re.findall('\n[-+]', d2.strip())) > 0: | 236 if d2.strip() and len(re.findall('\n[-+]', d2.strip())) > 0: |
237 old_cwd = os.getcwd() | 237 old_cwd = os.getcwd() |
252 files_touched.add(x) | 252 files_touched.add(x) |
253 os.chdir(old_cwd) | 253 os.chdir(old_cwd) |
254 # if this patch didn't apply right, fall back to exporting the | 254 # if this patch didn't apply right, fall back to exporting the |
255 # entire rev. | 255 # entire rev. |
256 if patch_st == -1: | 256 if patch_st == -1: |
257 parent_ctx = hg_editor.repo[parentid] | |
258 parent_manifest = parent_ctx.manifest() | |
259 for fn in files_touched: | 257 for fn in files_touched: |
260 if (fn in parent_manifest and | 258 if 'l' in parentctx.flags(fn): |
261 'l' in parent_ctx.filectx(fn).flags()): | |
262 # I think this might be an underlying bug in svn - | 259 # I think this might be an underlying bug in svn - |
263 # I get diffs of deleted symlinks even though I | 260 # I get diffs of deleted symlinks even though I |
264 # specifically said no deletes above. | 261 # specifically said no deletes above. |
265 raise BadPatchApply('deleted symlinked prevent patching') | 262 raise BadPatchApply('deleted symlinked prevent patching') |
266 assert False, ('This should only happen on case-insensitive' | 263 assert False, ('This should only happen on case-insensitive' |
285 for m in exec_files: | 282 for m in exec_files: |
286 files_touched.add(m) | 283 files_touched.add(m) |
287 f = os.path.join(tempdir, m) | 284 f = os.path.join(tempdir, m) |
288 if not os.path.exists(f): | 285 if not os.path.exists(f): |
289 data = '' | 286 data = '' |
290 if m in hg_editor.repo[parentid]: | 287 if m in parentctx: |
291 data = hg_editor.repo[parentid][m].data() | 288 data = parentctx[m].data() |
292 fp = opener(m, 'w') | 289 fp = opener(m, 'w') |
293 fp.write(data) | 290 fp.write(data) |
294 fp.close() | 291 fp.close() |
295 link_files = {} | 292 link_files = {} |
296 for m in property_special_set_re.findall(d): | 293 for m in property_special_set_re.findall(d): |
307 | 304 |
308 deleted_files = set() | 305 deleted_files = set() |
309 for p in r.paths: | 306 for p in r.paths: |
310 if p.startswith(diff_path) and r.paths[p].action == 'D': | 307 if p.startswith(diff_path) and r.paths[p].action == 'D': |
311 p2 = p[len(diff_path)+1:].strip('/') | 308 p2 = p[len(diff_path)+1:].strip('/') |
312 if p2 in hg_editor.repo[parentid]: | 309 if p2 in parentctx: |
313 deleted_files.add(p2) | 310 deleted_files.add(p2) |
314 continue | 311 continue |
315 # If this isn't in the parent ctx, it must've been a dir | 312 # If this isn't in the parent ctx, it must've been a dir |
316 deleted_files.update([f for f in hg_editor.repo[parentid] | 313 deleted_files.update([f for f in parentctx if f.startswith(p2 + '/')]) |
317 if f.startswith(p2 + '/')]) | |
318 files_touched.update(deleted_files) | 314 files_touched.update(deleted_files) |
319 | 315 |
320 copies = getcopies(svn, hg_editor, branch, diff_path, r, files_touched, | 316 copies = getcopies(svn, hg_editor, branch, diff_path, r, files_touched, |
321 parentid) | 317 parentctx) |
322 | 318 |
323 def filectxfn(repo, memctx, path): | 319 def filectxfn(repo, memctx, path): |
324 if path in deleted_files: | 320 if path in deleted_files: |
325 raise IOError() | 321 raise IOError() |
326 if path in link_files: | 322 if path in link_files: |
327 return context.memfilectx(path=path, data=link_files[path], | 323 return context.memfilectx(path=path, data=link_files[path], |
328 islink=True, isexec=False, | 324 islink=True, isexec=False, |
329 copied=False) | 325 copied=False) |
330 data = opener(path).read() | 326 data = opener(path).read() |
331 exe = exec_files.get(path, None) | 327 exe = exec_files.get(path, 'x' in parentctx.flags(path)) |
332 if exe is None and path in hg_editor.repo[parentid]: | |
333 exe = 'x' in hg_editor.repo[parentid].filectx(path).flags() | |
334 copied = copies.get(path) | 328 copied = copies.get(path) |
335 return context.memfilectx(path=path, data=data, islink=False, | 329 return context.memfilectx(path=path, data=data, islink=False, |
336 isexec=exe, copied=copied) | 330 isexec=exe, copied=copied) |
337 | 331 |
338 return list(files_touched), filectxfn | 332 return list(files_touched), filectxfn |
379 return (source, sourcerev), sourcepath | 373 return (source, sourcerev), sourcepath |
380 return None | 374 return None |
381 | 375 |
382 return finder | 376 return finder |
383 | 377 |
384 def getcopies(svn, hg_editor, branch, branchpath, r, files, parentid): | 378 def getcopies(svn, hg_editor, branch, branchpath, r, files, parentctx): |
385 """Return a mapping {dest: source} for every file copied into r. | 379 """Return a mapping {dest: source} for every file copied into r. |
386 """ | 380 """ |
387 if parentid == revlog.nullid: | 381 if parentctx.node() == revlog.nullid: |
388 return {} | 382 return {} |
389 | 383 |
390 # Extract svn copy information, group them by copy source. | 384 # Extract svn copy information, group them by copy source. |
391 # The idea is to duplicate the replay behaviour where copies are | 385 # The idea is to duplicate the replay behaviour where copies are |
392 # evaluated per copy event (one event for all files in a directory copy, | 386 # evaluated per copy event (one event for all files in a directory copy, |
400 svncopies.setdefault(copy[0], []).append((f, copy[1])) | 394 svncopies.setdefault(copy[0], []).append((f, copy[1])) |
401 if not svncopies: | 395 if not svncopies: |
402 return {} | 396 return {} |
403 | 397 |
404 # cache changeset contexts and map them to source svn revisions | 398 # cache changeset contexts and map them to source svn revisions |
405 parentctx = hg_editor.repo.changectx(parentid) | |
406 ctxs = {} | 399 ctxs = {} |
407 def getctx(svnrev): | 400 def getctx(svnrev): |
408 if svnrev in ctxs: | 401 if svnrev in ctxs: |
409 return ctxs[svnrev] | 402 return ctxs[svnrev] |
410 changeid = hg_editor.get_parent_revision(svnrev + 1, branch) | 403 changeid = hg_editor.get_parent_revision(svnrev + 1, branch) |
424 if not hg_editor.aresamefiles(sourcectx, parentctx, sources): | 417 if not hg_editor.aresamefiles(sourcectx, parentctx, sources): |
425 continue | 418 continue |
426 hgcopies.update(copies) | 419 hgcopies.update(copies) |
427 return hgcopies | 420 return hgcopies |
428 | 421 |
429 def stupid_fetch_branchrev(svn, hg_editor, branch, branchpath, r, parentid): | 422 def stupid_fetch_branchrev(svn, hg_editor, branch, branchpath, r, parentctx): |
430 """Extract all 'branch' content at a given revision. | 423 """Extract all 'branch' content at a given revision. |
431 | 424 |
432 Return a tuple (files, filectxfn) where 'files' is the list of all files | 425 Return a tuple (files, filectxfn) where 'files' is the list of all files |
433 in the branch at the given revision, and 'filectxfn' is a memctx compatible | 426 in the branch at the given revision, and 'filectxfn' is a memctx compatible |
434 callable to retrieve individual file information. | 427 callable to retrieve individual file information. |
435 """ | 428 """ |
436 parentctx = hg_editor.repo[parentid] | |
437 kind = svn.checkpath(branchpath, r.revnum) | 429 kind = svn.checkpath(branchpath, r.revnum) |
438 if kind is None: | 430 if kind is None: |
439 # Branch does not exist at this revision. Get parent revision and | 431 # Branch does not exist at this revision. Get parent revision and |
440 # remove everything. | 432 # remove everything. |
441 files = parentctx.manifest().keys() | 433 files = parentctx.manifest().keys() |
442 def filectxfn_rm(repo, memctx, path): | 434 def filectxfn_rm(repo, memctx, path): |
443 raise IOError() | 435 raise IOError() |
444 return files, filectxfn_rm | 436 return files, filectxfn_rm |
445 | 437 |
446 files = [] | 438 files = [] |
447 if parentid == revlog.nullid: | 439 if parentctx.node() == revlog.nullid: |
448 # Initial revision, fetch all files | 440 # Initial revision, fetch all files |
449 for path, kind in svn.list_files(branchpath, r.revnum): | 441 for path, kind in svn.list_files(branchpath, r.revnum): |
450 if kind == 'f': | 442 if kind == 'f': |
451 files.append(path) | 443 files.append(path) |
452 else: | 444 else: |
473 # Assume it's a deleted directory | 465 # Assume it's a deleted directory |
474 path = path + '/' | 466 path = path + '/' |
475 deleted = [f for f in parentctx if f.startswith(path)] | 467 deleted = [f for f in parentctx if f.startswith(path)] |
476 files += deleted | 468 files += deleted |
477 | 469 |
478 copies = getcopies(svn, hg_editor, branch, branchpath, r, files, parentid) | 470 copies = getcopies(svn, hg_editor, branch, branchpath, r, files, parentctx) |
479 | 471 |
480 def filectxfn(repo, memctx, path): | 472 def filectxfn(repo, memctx, path): |
481 data, mode = svn.get_file(branchpath + '/' + path, r.revnum) | 473 data, mode = svn.get_file(branchpath + '/' + path, r.revnum) |
482 isexec = 'x' in mode | 474 isexec = 'x' in mode |
483 islink = 'l' in mode | 475 islink = 'l' in mode |
493 temp_location = os.path.join(hg_editor.path, '.hg', 'svn', 'temp') | 485 temp_location = os.path.join(hg_editor.path, '.hg', 'svn', 'temp') |
494 if not os.path.exists(temp_location): | 486 if not os.path.exists(temp_location): |
495 os.makedirs(temp_location) | 487 os.makedirs(temp_location) |
496 for b in branches: | 488 for b in branches: |
497 our_tempdir = tempfile.mkdtemp('svn_fetch_temp', dir=temp_location) | 489 our_tempdir = tempfile.mkdtemp('svn_fetch_temp', dir=temp_location) |
498 parent_ha = hg_editor.get_parent_revision(r.revnum, b) | 490 parentctx = hg_editor.repo[hg_editor.get_parent_revision(r.revnum, b)] |
499 try: | 491 try: |
500 files_touched, filectxfn = stupid_diff_branchrev( | 492 files_touched, filectxfn = stupid_diff_branchrev( |
501 ui, svn, hg_editor, b, r, parent_ha, our_tempdir) | 493 ui, svn, hg_editor, b, r, parentctx, our_tempdir) |
502 except BadPatchApply, e: | 494 except BadPatchApply, e: |
503 # Either this revision or the previous one does not exist. | 495 # Either this revision or the previous one does not exist. |
504 ui.status("fetching entire rev: %s.\n" % e.message) | 496 ui.status("fetching entire rev: %s.\n" % e.message) |
505 files_touched, filectxfn = stupid_fetch_branchrev( | 497 files_touched, filectxfn = stupid_fetch_branchrev( |
506 svn, hg_editor, b, branches[b], r, parent_ha) | 498 svn, hg_editor, b, branches[b], r, parentctx) |
507 | 499 |
508 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] | 500 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] |
509 date += ' -0000' | 501 date += ' -0000' |
510 extra = {} | 502 extra = {} |
511 if b: | 503 if b: |
512 extra['branch'] = b | 504 extra['branch'] = b |
513 if '' in files_touched: | 505 if '' in files_touched: |
514 files_touched.remove('') | 506 files_touched.remove('') |
515 if parent_ha != node.nullid or files_touched: | 507 if parentctx.node() != node.nullid or files_touched: |
516 # TODO(augie) remove this debug code? Or maybe it's sane to have it. | 508 # TODO(augie) remove this debug code? Or maybe it's sane to have it. |
517 for f in files_touched: | 509 for f in files_touched: |
518 if f: | 510 if f: |
519 assert f[0] != '/' | 511 assert f[0] != '/' |
520 current_ctx = context.memctx(hg_editor.repo, | 512 current_ctx = context.memctx(hg_editor.repo, |
521 [parent_ha, revlog.nullid], | 513 [parentctx.node(), revlog.nullid], |
522 r.message or '...', | 514 r.message or '...', |
523 files_touched, | 515 files_touched, |
524 filectxfn, | 516 filectxfn, |
525 '%s%s' % (r.author, | 517 '%s%s' % (r.author, |
526 hg_editor.author_host), | 518 hg_editor.author_host), |