Mercurial > hgsubversion
comparison hg_delta_editor.py @ 174:f80132c5fea5
Convert svn:externals properties into a .hgsvnexternals file
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Fri, 02 Jan 2009 15:54:05 -0600 |
parents | 4f26fa049452 |
children | c4115b3918e9 |
comparison
equal
deleted
inserted
replaced
173:f244eaee5069 | 174:f80132c5fea5 |
---|---|
12 from mercurial import revlog | 12 from mercurial import revlog |
13 from mercurial import node | 13 from mercurial import node |
14 from svn import delta | 14 from svn import delta |
15 from svn import core | 15 from svn import core |
16 | 16 |
17 import svnexternals | |
17 import util as our_util | 18 import util as our_util |
18 | 19 |
19 def pickle_atomic(data, file_path, dir=None): | 20 def pickle_atomic(data, file_path, dir=None): |
20 """pickle some data to a path atomically. | 21 """pickle some data to a path atomically. |
21 | 22 |
142 self.current_files = {} | 143 self.current_files = {} |
143 self.deleted_files = {} | 144 self.deleted_files = {} |
144 self.current_rev = None | 145 self.current_rev = None |
145 self.current_files_exec = {} | 146 self.current_files_exec = {} |
146 self.current_files_symlink = {} | 147 self.current_files_symlink = {} |
148 self.dir_batons = {} | |
147 # Map fully qualified destination file paths to module source path | 149 # Map fully qualified destination file paths to module source path |
148 self.copies = {} | 150 self.copies = {} |
149 self.missing_plaintexts = set() | 151 self.missing_plaintexts = set() |
150 self.commit_branches_empty = {} | 152 self.commit_branches_empty = {} |
151 self.base_revision = None | 153 self.base_revision = None |
152 self.branches_to_delete = set() | 154 self.branches_to_delete = set() |
155 self.externals = {} | |
153 | 156 |
154 def _save_metadata(self): | 157 def _save_metadata(self): |
155 '''Save the Subversion metadata. This should really be called after | 158 '''Save the Subversion metadata. This should really be called after |
156 every revision is created. | 159 every revision is created. |
157 ''' | 160 ''' |
347 (info[0] or 'trunk', info[1], t)) | 350 (info[0] or 'trunk', info[1], t)) |
348 self.tags.update(added_tags) | 351 self.tags.update(added_tags) |
349 self.branches.update(added_branches) | 352 self.branches.update(added_branches) |
350 self._save_metadata() | 353 self._save_metadata() |
351 | 354 |
355 def _updateexternals(self): | |
356 if not self.externals: | |
357 return | |
358 # Accumulate externals records for all branches | |
359 revnum = self.current_rev.revnum | |
360 branches = {} | |
361 for path, entry in self.externals.iteritems(): | |
362 if not self._is_path_valid(path): | |
363 continue | |
364 p, b, bp = self._split_branch_path(path) | |
365 if bp not in branches: | |
366 external = svnexternals.externalsfile() | |
367 parent = self.get_parent_revision(revnum, b) | |
368 pctx = self.repo[parent] | |
369 if '.hgsvnexternals' in pctx: | |
370 external.read(pctx['.hgsvnexternals'].data()) | |
371 branches[bp] = external | |
372 else: | |
373 external = branches[bp] | |
374 external[p] = entry | |
375 | |
376 # Register the file changes | |
377 for bp, external in branches.iteritems(): | |
378 path = bp + '/.hgsvnexternals' | |
379 self.current_files[path] = external.write() | |
380 self.current_files_symlink[path] = False | |
381 self.current_files_exec[path] = False | |
382 | |
352 def commit_current_delta(self): | 383 def commit_current_delta(self): |
353 if hasattr(self, '_exception_info'): #pragma: no cover | 384 if hasattr(self, '_exception_info'): #pragma: no cover |
354 traceback.print_exception(*self._exception_info) | 385 traceback.print_exception(*self._exception_info) |
355 raise ReplayException() | 386 raise ReplayException() |
356 if self.missing_plaintexts: | 387 if self.missing_plaintexts: |
357 raise MissingPlainTextError() | 388 raise MissingPlainTextError() |
389 self._updateexternals() | |
358 files_to_commit = self.current_files.keys() | 390 files_to_commit = self.current_files.keys() |
359 files_to_commit.extend(self.current_files_symlink.keys()) | 391 files_to_commit.extend(self.current_files_symlink.keys()) |
360 files_to_commit.extend(self.current_files_exec.keys()) | 392 files_to_commit.extend(self.current_files_exec.keys()) |
361 files_to_commit = sorted(set(files_to_commit)) | 393 files_to_commit = sorted(set(files_to_commit)) |
362 branch_batches = {} | 394 branch_batches = {} |
418 if branch is not None: | 450 if branch is not None: |
419 if (branch not in self.branches | 451 if (branch not in self.branches |
420 and branch not in self.repo.branchtags()): | 452 and branch not in self.repo.branchtags()): |
421 continue | 453 continue |
422 parent_ctx = self.repo.changectx(parents[0]) | 454 parent_ctx = self.repo.changectx(parents[0]) |
455 if '.hgsvnexternals' not in parent_ctx and '.hgsvnexternals' in files: | |
456 # Do not register empty externals files | |
457 if not self.current_files[files['.hgsvnexternals']]: | |
458 del files['.hgsvnexternals'] | |
459 | |
423 def filectxfn(repo, memctx, path): | 460 def filectxfn(repo, memctx, path): |
424 current_file = files[path] | 461 current_file = files[path] |
425 if current_file in self.deleted_files: | 462 if current_file in self.deleted_files: |
426 raise IOError() | 463 raise IOError() |
427 copied = self.copies.get(current_file) | 464 copied = self.copies.get(current_file) |
577 if br_path not in ctx: | 614 if br_path not in ctx: |
578 br_path2 = '' | 615 br_path2 = '' |
579 if br_path != '': | 616 if br_path != '': |
580 br_path2 = br_path + '/' | 617 br_path2 = br_path + '/' |
581 # assuming it is a directory | 618 # assuming it is a directory |
619 self.externals[path] = None | |
582 def delete_x(x): | 620 def delete_x(x): |
583 self.deleted_files[x] = True | 621 self.deleted_files[x] = True |
584 map(delete_x, [pat for pat in self.current_files.iterkeys() | 622 map(delete_x, [pat for pat in self.current_files.iterkeys() |
585 if pat.startswith(path)]) | 623 if pat.startswith(path)]) |
586 for f in ctx.walk(our_util.PrefixMatch(br_path2)): | 624 for f in ctx.walk(our_util.PrefixMatch(br_path2)): |
664 self.copies[path] = from_file | 702 self.copies[path] = from_file |
665 | 703 |
666 @stash_exception_on_self | 704 @stash_exception_on_self |
667 def add_directory(self, path, parent_baton, copyfrom_path, | 705 def add_directory(self, path, parent_baton, copyfrom_path, |
668 copyfrom_revision, dir_pool=None): | 706 copyfrom_revision, dir_pool=None): |
707 self.dir_batons[path] = path | |
669 br_path, branch = self._path_and_branch_for_path(path) | 708 br_path, branch = self._path_and_branch_for_path(path) |
670 if br_path is not None: | 709 if br_path is not None: |
671 if not copyfrom_path and not br_path: | 710 if not copyfrom_path and not br_path: |
672 self.commit_branches_empty[branch] = True | 711 self.commit_branches_empty[branch] = True |
673 else: | 712 else: |
674 self.commit_branches_empty[branch] = False | 713 self.commit_branches_empty[branch] = False |
675 if br_path is None or not copyfrom_path: | 714 if br_path is None or not copyfrom_path: |
676 return | 715 return path |
677 if copyfrom_path: | 716 if copyfrom_path: |
678 tag = self._is_path_tag(copyfrom_path) | 717 tag = self._is_path_tag(copyfrom_path) |
679 if tag not in self.tags: | 718 if tag not in self.tags: |
680 tag = None | 719 tag = None |
681 if not self._is_path_valid(copyfrom_path) and not tag: | 720 if not self._is_path_valid(copyfrom_path) and not tag: |
682 self.missing_plaintexts.add('%s/' % path) | 721 self.missing_plaintexts.add('%s/' % path) |
683 return | 722 return path |
684 | 723 |
685 if tag: | 724 if tag: |
686 source_branch, source_rev = self.tags[tag] | 725 source_branch, source_rev = self.tags[tag] |
687 cp_f = '' | 726 cp_f = '' |
688 else: | 727 else: |
690 cp_f, source_branch = self._path_and_branch_for_path(copyfrom_path) | 729 cp_f, source_branch = self._path_and_branch_for_path(copyfrom_path) |
691 new_hash = self.get_parent_revision(source_rev + 1, | 730 new_hash = self.get_parent_revision(source_rev + 1, |
692 source_branch) | 731 source_branch) |
693 if new_hash == node.nullid: | 732 if new_hash == node.nullid: |
694 self.missing_plaintexts.add('%s/' % path) | 733 self.missing_plaintexts.add('%s/' % path) |
695 return | 734 return path |
696 cp_f_ctx = self.repo.changectx(new_hash) | 735 cp_f_ctx = self.repo.changectx(new_hash) |
697 if cp_f != '/' and cp_f != '': | 736 if cp_f != '/' and cp_f != '': |
698 cp_f = '%s/' % cp_f | 737 cp_f = '%s/' % cp_f |
699 else: | 738 else: |
700 cp_f = '' | 739 cp_f = '' |
716 parentid = self.get_parent_revision(self.current_rev.revnum, branch) | 755 parentid = self.get_parent_revision(self.current_rev.revnum, branch) |
717 if parentid != revlog.nullid: | 756 if parentid != revlog.nullid: |
718 parentctx = self.repo.changectx(parentid) | 757 parentctx = self.repo.changectx(parentid) |
719 if self.aresamefiles(parentctx, cp_f_ctx, copies.values()): | 758 if self.aresamefiles(parentctx, cp_f_ctx, copies.values()): |
720 self.copies.update(copies) | 759 self.copies.update(copies) |
760 return path | |
721 | 761 |
722 @stash_exception_on_self | 762 @stash_exception_on_self |
723 def change_file_prop(self, file_baton, name, value, pool=None): | 763 def change_file_prop(self, file_baton, name, value, pool=None): |
724 if name == 'svn:executable': | 764 if name == 'svn:executable': |
725 self.current_files_exec[self.current_file] = bool(value is not None) | 765 self.current_files_exec[self.current_file] = bool(value is not None) |
726 elif name == 'svn:special': | 766 elif name == 'svn:special': |
727 self.current_files_symlink[self.current_file] = bool(value is not None) | 767 self.current_files_symlink[self.current_file] = bool(value is not None) |
728 | 768 |
729 @stash_exception_on_self | 769 @stash_exception_on_self |
770 def change_dir_prop(self, dir_baton, name, value, pool=None): | |
771 if dir_baton is None: | |
772 return | |
773 path = self.dir_batons[dir_baton] | |
774 if name == 'svn:externals': | |
775 self.externals[path] = value | |
776 | |
777 @stash_exception_on_self | |
730 def open_directory(self, path, parent_baton, base_revision, dir_pool=None): | 778 def open_directory(self, path, parent_baton, base_revision, dir_pool=None): |
779 self.dir_batons[path] = path | |
731 p_, branch = self._path_and_branch_for_path(path) | 780 p_, branch = self._path_and_branch_for_path(path) |
732 if p_ == '': | 781 if p_ == '': |
733 self.commit_branches_empty[branch] = False | 782 self.commit_branches_empty[branch] = False |
783 return path | |
784 | |
785 @stash_exception_on_self | |
786 def close_directory(self, dir_baton, dir_pool=None): | |
787 if dir_baton is not None: | |
788 del self.dir_batons[dir_baton] | |
734 | 789 |
735 @stash_exception_on_self | 790 @stash_exception_on_self |
736 def apply_textdelta(self, file_baton, base_checksum, pool=None): | 791 def apply_textdelta(self, file_baton, base_checksum, pool=None): |
737 base = '' | 792 base = '' |
738 if not self._is_path_valid(self.current_file): | 793 if not self._is_path_valid(self.current_file): |