Mercurial > hgsubversion
comparison hg_delta_editor.py @ 33:a9c15cae50e5
Faster append-only revmap implementation.
| author | Andreas Hartmetz <ahartmetz@gmail.com> |
|---|---|
| date | Wed, 15 Oct 2008 21:47:48 -0400 |
| parents | 1f8854804795 |
| children | 50d55c3e0d85 |
comparison
equal
deleted
inserted
replaced
| 32:d01196ca1e39 | 33:a9c15cae50e5 |
|---|---|
| 47 raise | 47 raise |
| 48 return fun | 48 return fun |
| 49 | 49 |
| 50 | 50 |
| 51 class HgChangeReceiver(delta.Editor): | 51 class HgChangeReceiver(delta.Editor): |
| 52 def add_to_revmap(self, revnum, branch, node_hash): | |
| 53 f = open(self.revmap_file, 'a') | |
| 54 f.write(str(revnum) + ' ' + node.hex(node_hash) + ' ' + (branch or '') + '\n') | |
| 55 f.flush() | |
| 56 f.close() | |
| 57 self.revmap[revnum, branch] = node_hash | |
| 58 | |
| 52 def __init__(self, path, ui_=None, subdir='', author_host='', | 59 def __init__(self, path, ui_=None, subdir='', author_host='', |
| 53 tag_locations=['tags']): | 60 tag_locations=['tags']): |
| 54 """path is the path to the target hg repo. | 61 """path is the path to the target hg repo. |
| 55 | 62 |
| 56 subdir is the subdirectory of the edits *on the svn server*. | 63 subdir is the subdirectory of the edits *on the svn server*. |
| 65 if self.subdir and self.subdir[0] == '/': | 72 if self.subdir and self.subdir[0] == '/': |
| 66 self.subdir = self.subdir[1:] | 73 self.subdir = self.subdir[1:] |
| 67 self.revmap = {} | 74 self.revmap = {} |
| 68 if os.path.exists(self.revmap_file): | 75 if os.path.exists(self.revmap_file): |
| 69 f = open(self.revmap_file) | 76 f = open(self.revmap_file) |
| 70 self.revmap = pickle.load(f) | 77 for l in f: |
| 78 revnum, node_hash, branch = l.split(' ', 2) | |
| 79 if branch == '\n': | |
| 80 branch = None | |
| 81 else: | |
| 82 branch = branch[:-1] | |
| 83 self.revmap[int(revnum), branch] = node.bin(node_hash) | |
| 71 f.close() | 84 f.close() |
| 72 self.branches = {} | 85 self.branches = {} |
| 73 if os.path.exists(self.branch_info_file): | 86 if os.path.exists(self.branch_info_file): |
| 74 f = open(self.branch_info_file) | 87 f = open(self.branch_info_file) |
| 75 self.branches = pickle.load(f) | 88 self.branches = pickle.load(f) |
| 104 assert os.path.isfile(self.uuid_file) | 117 assert os.path.isfile(self.uuid_file) |
| 105 assert os.path.isfile(self.last_revision_handled_file) | 118 assert os.path.isfile(self.last_revision_handled_file) |
| 106 else: | 119 else: |
| 107 self.repo = hg.repository(self.ui, repo_path, create=True) | 120 self.repo = hg.repository(self.ui, repo_path, create=True) |
| 108 os.makedirs(os.path.dirname(self.uuid_file)) | 121 os.makedirs(os.path.dirname(self.uuid_file)) |
| 122 open(self.revmap_file, 'w') # make empty file | |
| 109 | 123 |
| 110 def clear_current_info(self): | 124 def clear_current_info(self): |
| 111 '''Clear the info relevant to a replayed revision so that the next | 125 '''Clear the info relevant to a replayed revision so that the next |
| 112 revision can be replayed. | 126 revision can be replayed. |
| 113 ''' | 127 ''' |
| 122 | 136 |
| 123 def _save_metadata(self): | 137 def _save_metadata(self): |
| 124 '''Save the Subversion metadata. This should really be called after | 138 '''Save the Subversion metadata. This should really be called after |
| 125 every revision is created. | 139 every revision is created. |
| 126 ''' | 140 ''' |
| 127 pickle_atomic(self.revmap, self.revmap_file, self.meta_data_dir) | |
| 128 pickle_atomic(self.branches, self.branch_info_file, self.meta_data_dir) | 141 pickle_atomic(self.branches, self.branch_info_file, self.meta_data_dir) |
| 129 pickle_atomic(self.tags, self.tag_info_file, self.meta_data_dir) | 142 pickle_atomic(self.tags, self.tag_info_file, self.meta_data_dir) |
| 130 | 143 |
| 131 def branches_in_paths(self, paths): | 144 def branches_in_paths(self, paths): |
| 132 '''Given a list of paths, return the set of branches that are touched. | 145 '''Given a list of paths, return the set of branches that are touched. |
| 371 extra) | 384 extra) |
| 372 new_hash = self.repo.commitctx(current_ctx) | 385 new_hash = self.repo.commitctx(current_ctx) |
| 373 self.ui.status('committed as %s on branch %s\n' % | 386 self.ui.status('committed as %s on branch %s\n' % |
| 374 (node.hex(new_hash), (branch or 'default'))) | 387 (node.hex(new_hash), (branch or 'default'))) |
| 375 if (rev.revnum, branch) not in self.revmap: | 388 if (rev.revnum, branch) not in self.revmap: |
| 376 self.revmap[rev.revnum, branch] = new_hash | 389 self.add_to_revmap(rev.revnum, branch, new_hash) |
| 377 self._save_metadata() | |
| 378 # now we handle branches that need to be committed without any files | 390 # now we handle branches that need to be committed without any files |
| 379 for branch in self.commit_branches_empty: | 391 for branch in self.commit_branches_empty: |
| 380 ha = self.get_parent_revision(rev.revnum, branch) | 392 ha = self.get_parent_revision(rev.revnum, branch) |
| 381 if ha == node.nullid: | 393 if ha == node.nullid: |
| 382 continue | 394 continue |
| 401 extra) | 413 extra) |
| 402 new_hash = self.repo.commitctx(current_ctx) | 414 new_hash = self.repo.commitctx(current_ctx) |
| 403 self.ui.status('committed as %s on branch %s\n' % | 415 self.ui.status('committed as %s on branch %s\n' % |
| 404 (node.hex(new_hash), (branch or 'default'))) | 416 (node.hex(new_hash), (branch or 'default'))) |
| 405 if (rev.revnum, branch) not in self.revmap: | 417 if (rev.revnum, branch) not in self.revmap: |
| 406 self.revmap[rev.revnum, branch] = new_hash | 418 self.add_to_revmap(rev.revnum, branch, new_hash) |
| 407 self._save_metadata() | |
| 408 self.clear_current_info() | 419 self.clear_current_info() |
| 409 | 420 |
| 410 @property | 421 @property |
| 411 def meta_data_dir(self): | 422 def meta_data_dir(self): |
| 412 return os.path.join(self.path, '.hg', 'svn') | 423 return os.path.join(self.path, '.hg', 'svn') |
