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