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), |
