Mercurial > hgsubversion
comparison hg_delta_editor.py @ 133:2242dd1163c6
hg_delta_editor: fix bad parent revision calculation in the case of a branch
recycling a name.
Also implemented marking branches as closed in both replay and stupid paths.
author | Augie Fackler <durin42@gmail.com> |
---|---|
date | Wed, 10 Dec 2008 14:29:05 -0600 |
parents | 4d42dbbb5127 |
children | cf6fe8457570 |
comparison
equal
deleted
inserted
replaced
132:3a9d6cd18332 | 133:2242dd1163c6 |
---|---|
105 | 105 |
106 self.clear_current_info() | 106 self.clear_current_info() |
107 self.author_host = author_host | 107 self.author_host = author_host |
108 | 108 |
109 def __setup_repo(self, repo_path): | 109 def __setup_repo(self, repo_path): |
110 '''Verify the repo is going to work out for us. | 110 """Verify the repo is going to work out for us. |
111 | 111 |
112 This method will fail an assertion if the repo exists but doesn't have | 112 This method will fail an assertion if the repo exists but doesn't have |
113 the Subversion metadata. | 113 the Subversion metadata. |
114 ''' | 114 """ |
115 if os.path.isdir(repo_path) and len(os.listdir(repo_path)): | 115 if os.path.isdir(repo_path) and len(os.listdir(repo_path)): |
116 self.repo = hg.repository(self.ui, repo_path) | 116 self.repo = hg.repository(self.ui, repo_path) |
117 assert os.path.isfile(self.revmap_file) | 117 assert os.path.isfile(self.revmap_file) |
118 assert os.path.isfile(self.svn_url_file) | 118 assert os.path.isfile(self.svn_url_file) |
119 assert os.path.isfile(self.uuid_file) | 119 assert os.path.isfile(self.uuid_file) |
139 # Map fully qualified destination file paths to module source path | 139 # Map fully qualified destination file paths to module source path |
140 self.copies = {} | 140 self.copies = {} |
141 self.missing_plaintexts = set() | 141 self.missing_plaintexts = set() |
142 self.commit_branches_empty = {} | 142 self.commit_branches_empty = {} |
143 self.base_revision = None | 143 self.base_revision = None |
144 self.branches_to_delete = set() | |
144 | 145 |
145 def _save_metadata(self): | 146 def _save_metadata(self): |
146 '''Save the Subversion metadata. This should really be called after | 147 '''Save the Subversion metadata. This should really be called after |
147 every revision is created. | 148 every revision is created. |
148 ''' | 149 ''' |
162 | 163 |
163 def _path_and_branch_for_path(self, path): | 164 def _path_and_branch_for_path(self, path): |
164 return self._split_branch_path(path)[:2] | 165 return self._split_branch_path(path)[:2] |
165 | 166 |
166 def _split_branch_path(self, path): | 167 def _split_branch_path(self, path): |
167 '''Figure out which branch inside our repo this path represents, and | 168 """Figure out which branch inside our repo this path represents, and |
168 also figure out which path inside that branch it is. | 169 also figure out which path inside that branch it is. |
169 | 170 |
170 Raises an exception if it can't perform its job. | 171 Raises an exception if it can't perform its job. |
171 ''' | 172 """ |
172 path = self._normalize_path(path) | 173 path = self._normalize_path(path) |
173 if path.startswith('trunk'): | 174 if path.startswith('trunk'): |
174 p = path[len('trunk'):] | 175 p = path[len('trunk'):] |
175 if p and p[0] == '/': | 176 if p and p[0] == '/': |
176 p = p[1:] | 177 p = p[1:] |
184 p = p[1:] | 185 p = p[1:] |
185 return p, br, 'branches/' + br | 186 return p, br, 'branches/' + br |
186 return None, None, None | 187 return None, None, None |
187 | 188 |
188 def set_current_rev(self, rev): | 189 def set_current_rev(self, rev): |
189 '''Set the revision we're currently converting. | 190 """Set the revision we're currently converting. |
190 ''' | 191 """ |
191 self.current_rev = rev | 192 self.current_rev = rev |
192 | 193 |
193 def set_file(self, path, data, isexec=False, islink=False): | 194 def set_file(self, path, data, isexec=False, islink=False): |
194 if islink: | 195 if islink: |
195 data = 'link ' + data | 196 data = 'link ' + data |
234 for num, br in self.revmap.iterkeys(): | 235 for num, br in self.revmap.iterkeys(): |
235 if br != branch: | 236 if br != branch: |
236 continue | 237 continue |
237 if num <= number and num > real_num: | 238 if num <= number and num > real_num: |
238 real_num = num | 239 real_num = num |
239 if real_num == 0: | 240 if branch in self.branches: |
240 if branch in self.branches: | 241 parent_branch = self.branches[branch][0] |
241 parent_branch = self.branches[branch][0] | 242 parent_branch_rev = self.branches[branch][1] |
242 parent_branch_rev = self.branches[branch][1] | 243 # check to see if this branch already existed and is the same |
243 if parent_branch_rev <= 0: | 244 if parent_branch_rev < real_num: |
244 return None, None | 245 return real_num, branch |
245 branch_created_rev = self.branches[branch][2] | 246 # if that wasn't true, then this is the a new branch with the |
246 if parent_branch == 'trunk': | 247 # same name as some old deleted branch |
247 parent_branch = None | 248 if parent_branch_rev <= 0 and real_num == 0: |
248 if branch_created_rev <= number+1 and branch != parent_branch: | 249 return None, None |
249 return self.get_parent_svn_branch_and_rev( | 250 branch_created_rev = self.branches[branch][2] |
250 parent_branch_rev+1, | 251 if parent_branch == 'trunk': |
251 parent_branch) | 252 parent_branch = None |
253 if branch_created_rev <= number+1 and branch != parent_branch: | |
254 return self.get_parent_svn_branch_and_rev( | |
255 parent_branch_rev+1, | |
256 parent_branch) | |
252 if real_num != 0: | 257 if real_num != 0: |
253 return real_num, branch | 258 return real_num, branch |
254 return None, None | 259 return None, None |
255 | 260 |
256 def get_parent_revision(self, number, branch): | 261 def get_parent_revision(self, number, branch): |
263 | 268 |
264 def update_branch_tag_map_for_rev(self, revision): | 269 def update_branch_tag_map_for_rev(self, revision): |
265 paths = revision.paths | 270 paths = revision.paths |
266 added_branches = {} | 271 added_branches = {} |
267 added_tags = {} | 272 added_tags = {} |
273 self.branches_to_delete = set() | |
268 tags_to_delete = set() | 274 tags_to_delete = set() |
269 branches_to_delete = set() | |
270 for p in sorted(paths): | 275 for p in sorted(paths): |
271 fi, br = self._path_and_branch_for_path(p) | 276 fi, br = self._path_and_branch_for_path(p) |
272 if fi is not None: | 277 if fi is not None: |
273 if fi == '' and br not in self.branches: | 278 if fi == '' and paths[p].action != 'D': |
274 src_p = paths[p].copyfrom_path | 279 src_p = paths[p].copyfrom_path |
275 src_rev = paths[p].copyfrom_rev | 280 src_rev = paths[p].copyfrom_rev |
276 src_tag = self._is_path_tag(src_p) | 281 src_tag = self._is_path_tag(src_p) |
277 | 282 |
278 if not ((src_p and self._is_path_valid(src_p)) or | 283 if not ((src_p and self._is_path_valid(src_p)) or |
292 continue | 297 continue |
293 added_branches[br] = src_branch, src_rev, revision.revnum | 298 added_branches[br] = src_branch, src_rev, revision.revnum |
294 elif fi == '' and br in self.branches: | 299 elif fi == '' and br in self.branches: |
295 br2 = br or 'default' | 300 br2 = br or 'default' |
296 if br2 not in self.repo.branchtags() and paths[p].action == 'D': | 301 if br2 not in self.repo.branchtags() and paths[p].action == 'D': |
297 branches_to_delete.add(br) | 302 self.branches_to_delete.add(br) |
298 else: | 303 else: |
299 t_name = self._is_path_tag(p) | 304 t_name = self._is_path_tag(p) |
300 if t_name == False: | 305 if t_name == False: |
301 continue | 306 continue |
302 src_p, src_rev = paths[p].copyfrom_path, paths[p].copyfrom_rev | 307 src_p, src_rev = paths[p].copyfrom_path, paths[p].copyfrom_rev |
318 elif (paths[p].action == 'D' and p.endswith(t_name) | 323 elif (paths[p].action == 'D' and p.endswith(t_name) |
319 and t_name in self.tags): | 324 and t_name in self.tags): |
320 tags_to_delete.add(t_name) | 325 tags_to_delete.add(t_name) |
321 for t in tags_to_delete: | 326 for t in tags_to_delete: |
322 del self.tags[t] | 327 del self.tags[t] |
323 for br in branches_to_delete: | 328 for br in self.branches_to_delete: |
324 del self.branches[br] | 329 del self.branches[br] |
325 self.tags.update(added_tags) | 330 self.tags.update(added_tags) |
326 self.branches.update(added_branches) | 331 self.branches.update(added_branches) |
327 self._save_metadata() | 332 self._save_metadata() |
328 | 333 |
357 files = dict(files) | 362 files = dict(files) |
358 | 363 |
359 parents = (self.get_parent_revision(rev.revnum, branch), | 364 parents = (self.get_parent_revision(rev.revnum, branch), |
360 revlog.nullid) | 365 revlog.nullid) |
361 if branch is not None: | 366 if branch is not None: |
362 if branch not in self.branches and branch not in self.repo.branchtags(): | 367 if (branch not in self.branches |
368 and branch not in self.repo.branchtags()): | |
363 continue | 369 continue |
364 extra['branch'] = branch | 370 extra['branch'] = branch |
371 if (branch in self.branches_to_delete): | |
372 continue | |
365 parent_ctx = self.repo.changectx(parents[0]) | 373 parent_ctx = self.repo.changectx(parents[0]) |
366 def filectxfn(repo, memctx, path): | 374 def filectxfn(repo, memctx, path): |
367 current_file = files[path] | 375 current_file = files[path] |
368 if current_file in self.deleted_files: | 376 if current_file in self.deleted_files: |
369 raise IOError() | 377 raise IOError() |
394 self.ui.status('committed as %s on branch %s\n' % | 402 self.ui.status('committed as %s on branch %s\n' % |
395 (node.hex(new_hash), (branch or 'default'))) | 403 (node.hex(new_hash), (branch or 'default'))) |
396 if (rev.revnum, branch) not in self.revmap: | 404 if (rev.revnum, branch) not in self.revmap: |
397 self.add_to_revmap(rev.revnum, branch, new_hash) | 405 self.add_to_revmap(rev.revnum, branch, new_hash) |
398 # now we handle branches that need to be committed without any files | 406 # now we handle branches that need to be committed without any files |
407 for branch in self.branches_to_delete: | |
408 closed = revlog.nullid | |
409 if 'closed-branches' in self.repo.branchtags(): | |
410 closed = self.repo['closed-branches'].node() | |
411 ha = self.get_parent_revision(rev.revnum, branch) | |
412 parentctx = self.repo.changectx(ha) | |
413 if parentctx.children(): | |
414 continue | |
415 parents = (ha, closed) | |
416 def del_all_files(*args): | |
417 raise IOError | |
418 files = parentctx.manifest().keys() | |
419 current_ctx = context.memctx(self.repo, | |
420 parents, | |
421 rev.message or ' ', | |
422 files, | |
423 del_all_files, | |
424 '%s%s' % (rev.author, | |
425 self.author_host), | |
426 date, | |
427 {'branch': 'closed-branches'}) | |
428 new_hash = self.repo.commitctx(current_ctx) | |
429 self.ui.status('Marked branch %s as closed.' % (branch or 'default')) | |
399 for branch in self.commit_branches_empty: | 430 for branch in self.commit_branches_empty: |
400 ha = self.get_parent_revision(rev.revnum, branch) | 431 ha = self.get_parent_revision(rev.revnum, branch) |
401 if ha == node.nullid: | 432 if ha == node.nullid: |
402 continue | 433 continue |
403 parent_ctx = self.repo.changectx(ha) | 434 parent_ctx = self.repo.changectx(ha) |
404 def del_all_files(*args): | 435 def del_all_files(*args): |
405 raise IOError | 436 raise IOError |
406 extra = {} | 437 extra = {} |
407 if branch: | 438 if parent_ctx.children(): |
408 extra['branch'] = branch | 439 # Target isn't an active head, no need to do things to it. |
440 continue | |
441 if branch in self.branches_to_delete: | |
442 extra['branch'] = 'closed-branch' | |
409 # True here means nuke all files | 443 # True here means nuke all files |
410 files = [] | 444 files = [] |
411 if self.commit_branches_empty[branch]: | 445 if self.commit_branches_empty[branch]: |
412 files = parent_ctx.manifest().keys() | 446 files = parent_ctx.manifest().keys() |
413 current_ctx = context.memctx(self.repo, | 447 current_ctx = context.memctx(self.repo, |
466 return open(self.svn_url_file).read() | 500 return open(self.svn_url_file).read() |
467 | 501 |
468 @stash_exception_on_self | 502 @stash_exception_on_self |
469 def delete_entry(self, path, revision_bogus, parent_baton, pool=None): | 503 def delete_entry(self, path, revision_bogus, parent_baton, pool=None): |
470 br_path, branch = self._path_and_branch_for_path(path) | 504 br_path, branch = self._path_and_branch_for_path(path) |
505 if br_path == '': | |
506 self.branches_to_delete.add(branch) | |
471 if br_path is not None: | 507 if br_path is not None: |
472 ha = self.get_parent_revision(self.current_rev.revnum, branch) | 508 ha = self.get_parent_revision(self.current_rev.revnum, branch) |
473 if ha == revlog.nullid: | 509 if ha == revlog.nullid: |
474 return | 510 return |
475 ctx = self.repo.changectx(ha) | 511 ctx = self.repo.changectx(ha) |