Mercurial > hgsubversion
comparison fetch_command.py @ 73:9c1b53abefcb
fetch_command: support svn copy detection in stupid mode
| author | Patrick Mezard <pmezard@gmail.com> |
|---|---|
| date | Wed, 05 Nov 2008 13:37:08 +0100 |
| parents | 2e30b59a9c19 |
| children | 450d5d9d3b80 |
comparison
equal
deleted
inserted
replaced
| 72:9ec2a12c12ae | 73:9c1b53abefcb |
|---|---|
| 215 def make_diff_path(b): | 215 def make_diff_path(b): |
| 216 if b == None: | 216 if b == None: |
| 217 return 'trunk' | 217 return 'trunk' |
| 218 return 'branches/' + b | 218 return 'branches/' + b |
| 219 | 219 |
| 220 def makecopyfinder(r, branchpath, rootdir): | |
| 221 """Return a function detecting copies. | |
| 222 | |
| 223 Returned copyfinder(path) returns None if no copy information can | |
| 224 be found or ((source, sourcerev), sourcepath) where "sourcepath" is the | |
| 225 copy source path, "sourcerev" the source svn revision and "source" is the | |
| 226 copy record path causing the copy to occur. If a single file was copied | |
| 227 "sourcepath" and "source" are the same, while file copies dectected from | |
| 228 directory copies return the copied source directory in "source". | |
| 229 """ | |
| 230 # filter copy information for current branch | |
| 231 branchpath = branchpath + '/' | |
| 232 fullbranchpath = rootdir + branchpath | |
| 233 copies = [] | |
| 234 for path, e in r.paths.iteritems(): | |
| 235 if not e.copyfrom_path: | |
| 236 continue | |
| 237 if not path.startswith(branchpath): | |
| 238 continue | |
| 239 if not e.copyfrom_path.startswith(fullbranchpath): | |
| 240 # ignore cross branch copies | |
| 241 continue | |
| 242 dest = path[len(branchpath):] | |
| 243 source = e.copyfrom_path[len(fullbranchpath):] | |
| 244 copies.append((dest, (source, e.copyfrom_rev))) | |
| 245 | |
| 246 copies.sort() | |
| 247 copies.reverse() | |
| 248 exactcopies = dict(copies) | |
| 249 | |
| 250 def finder(path): | |
| 251 if path in exactcopies: | |
| 252 return exactcopies[path], exactcopies[path][0] | |
| 253 # look for parent directory copy, longest first | |
| 254 for dest, (source, sourcerev) in copies: | |
| 255 dest = dest + '/' | |
| 256 if not path.startswith(dest): | |
| 257 continue | |
| 258 sourcepath = source + '/' + path[len(dest):] | |
| 259 return (source, sourcerev), sourcepath | |
| 260 return None | |
| 261 | |
| 262 return finder | |
| 263 | |
| 264 def getcopies(svn, hg_editor, branch, branchpath, r, files, parentid): | |
| 265 """Return a mapping {dest: source} for every file copied into r. | |
| 266 """ | |
| 267 if parentid == revlog.nullid: | |
| 268 return {} | |
| 269 | |
| 270 # Extract svn copy information, group them by copy source. | |
| 271 # The idea is to duplicate the replay behaviour where copies are | |
| 272 # evaluated per copy event (one event for all files in a directory copy, | |
| 273 # one event for single file copy). We assume that copy events match | |
| 274 # copy sources in revision info. | |
| 275 svncopies = {} | |
| 276 finder = makecopyfinder(r, branchpath, svn.subdir) | |
| 277 for f in files: | |
| 278 copy = finder(f) | |
| 279 if copy: | |
| 280 svncopies.setdefault(copy[0], []).append((f, copy[1])) | |
| 281 if not svncopies: | |
| 282 return {} | |
| 283 | |
| 284 # cache changeset contexts and map them to source svn revisions | |
| 285 parentctx = hg_editor.repo.changectx(parentid) | |
| 286 ctxs = {} | |
| 287 def getctx(svnrev): | |
| 288 if svnrev in ctxs: | |
| 289 return ctxs[svnrev] | |
| 290 changeid = hg_editor.get_parent_revision(svnrev + 1, branch) | |
| 291 ctx = None | |
| 292 if changeid != revlog.nullid: | |
| 293 ctx = hg_editor.repo.changectx(changeid) | |
| 294 ctxs[svnrev] = ctx | |
| 295 return ctx | |
| 296 | |
| 297 # check svn copies really make sense in mercurial | |
| 298 hgcopies = {} | |
| 299 for (sourcepath, rev), copies in svncopies.iteritems(): | |
| 300 sourcectx = getctx(rev) | |
| 301 if sourcectx is None: | |
| 302 continue | |
| 303 sources = [s[1] for s in copies] | |
| 304 if not hg_editor.aresamefiles(sourcectx, parentctx, sources): | |
| 305 continue | |
| 306 hgcopies.update(copies) | |
| 307 return hgcopies | |
| 220 | 308 |
| 221 def stupid_svn_server_pull_rev(ui, svn, hg_editor, r): | 309 def stupid_svn_server_pull_rev(ui, svn, hg_editor, r): |
| 222 used_diff = True | 310 used_diff = True |
| 223 delete_all_files = False | 311 delete_all_files = False |
| 224 # this server fails at replay | 312 # this server fails at replay |
| 448 files_touched.add(p_real) | 536 files_touched.add(p_real) |
| 449 for p in hg_editor.repo[parent_ha].manifest().iterkeys(): | 537 for p in hg_editor.repo[parent_ha].manifest().iterkeys(): |
| 450 # TODO this might not be a required step. | 538 # TODO this might not be a required step. |
| 451 if p: | 539 if p: |
| 452 files_touched.add(p) | 540 files_touched.add(p) |
| 541 | |
| 542 copies = getcopies(svn, hg_editor, b, branches[b], r, files_touched, | |
| 543 parent_ha) | |
| 544 | |
| 453 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] | 545 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] |
| 454 date += ' -0000' | 546 date += ' -0000' |
| 455 def filectxfn(repo, memctx, path): | 547 def filectxfn(repo, memctx, path): |
| 456 disk_path = os.path.join(our_tempdir, path) | 548 disk_path = os.path.join(our_tempdir, path) |
| 457 if path in link_files: | 549 if path in link_files: |
| 460 copied=False) | 552 copied=False) |
| 461 fp = open(disk_path) | 553 fp = open(disk_path) |
| 462 exe = exec_files.get(path, None) | 554 exe = exec_files.get(path, None) |
| 463 if exe is None and path in hg_editor.repo[parent_ha]: | 555 if exe is None and path in hg_editor.repo[parent_ha]: |
| 464 exe = 'x' in hg_editor.repo[parent_ha].filectx(path).flags() | 556 exe = 'x' in hg_editor.repo[parent_ha].filectx(path).flags() |
| 557 copied = copies.get(path) | |
| 465 return context.memfilectx(path=path, data=fp.read(), islink=False, | 558 return context.memfilectx(path=path, data=fp.read(), islink=False, |
| 466 isexec=exe, copied=False) | 559 isexec=exe, copied=copied) |
| 467 extra = {} | 560 extra = {} |
| 468 if b: | 561 if b: |
| 469 extra['branch'] = b | 562 extra['branch'] = b |
| 470 if '' in files_touched: | 563 if '' in files_touched: |
| 471 files_touched.remove('') | 564 files_touched.remove('') |
