* Makefile: Add rule to make cvs2bzr.1. Delete manpages as part of clean.
[cvs2svn.git] / cvs2svn_lib / cvs_item.py
blob5c01a24b8e2ac2a711d039c936ad3f3c899c65d2
1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2008 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """This module contains classes to store atomic CVS events.
19 A CVSItem is a single event, pertaining to a single file, that can be
20 determined to have occured based on the information in the CVS
21 repository.
23 The inheritance tree is as follows:
25 CVSItem
27 +--CVSRevision
28 | |
29 | +--CVSRevisionModification (* -> 'Exp')
30 | | |
31 | | +--CVSRevisionAdd ('dead' -> 'Exp')
32 | | |
33 | | +--CVSRevisionChange ('Exp' -> 'Exp')
34 | |
35 | +--CVSRevisionAbsent (* -> 'dead')
36 | |
37 | +--CVSRevisionDelete ('Exp' -> 'dead')
38 | |
39 | +--CVSRevisionNoop ('dead' -> 'dead')
41 +--CVSSymbol
43 +--CVSBranch
44 | |
45 | +--CVSBranchNoop
47 +--CVSTag
49 +--CVSTagNoop
51 """
54 from cvs2svn_lib.context import Ctx
57 class CVSItem(object):
58 __slots__ = [
59 'id',
60 'cvs_file',
61 'revision_recorder_token',
64 def __init__(self, id, cvs_file, revision_recorder_token):
65 self.id = id
66 self.cvs_file = cvs_file
67 self.revision_recorder_token = revision_recorder_token
69 def __eq__(self, other):
70 return self.id == other.id
72 def __cmp__(self, other):
73 return cmp(self.id, other.id)
75 def __hash__(self):
76 return self.id
78 def __getstate__(self):
79 raise NotImplementedError()
81 def __setstate__(self, data):
82 raise NotImplementedError()
84 def get_svn_path(self):
85 """Return the SVN path associated with this CVSItem."""
87 raise NotImplementedError()
89 def get_pred_ids(self):
90 """Return the CVSItem.ids of direct predecessors of SELF.
92 A predecessor is defined to be a CVSItem that has to have been
93 committed before this one."""
95 raise NotImplementedError()
97 def get_succ_ids(self):
98 """Return the CVSItem.ids of direct successors of SELF.
100 A direct successor is defined to be a CVSItem that has this one as
101 a direct predecessor."""
103 raise NotImplementedError()
105 def get_cvs_symbol_ids_opened(self):
106 """Return an iterable over the ids of CVSSymbols that this item opens.
108 The definition of 'open' is that the path corresponding to this
109 CVSItem will have to be copied when filling the corresponding
110 symbol."""
112 raise NotImplementedError()
114 def get_ids_closed(self):
115 """Return an iterable over the CVSItem.ids of CVSItems closed by this one.
117 A CVSItem A is said to close a CVSItem B if committing A causes B
118 to be overwritten or deleted (no longer available) in the SVN
119 repository. This is interesting because it sets the last SVN
120 revision number from which the contents of B can be copied (for
121 example, to fill a symbol). See the concrete implementations of
122 this method for the exact rules about what closes what."""
124 raise NotImplementedError()
126 def check_links(self, cvs_file_items):
127 """Check for consistency of links to other CVSItems.
129 Other items can be looked up in CVS_FILE_ITEMS, which is an
130 instance of CVSFileItems. Raise an AssertionError if there is a
131 problem."""
133 raise NotImplementedError()
135 def __repr__(self):
136 return '%s(%s)' % (self.__class__.__name__, self,)
139 class CVSRevision(CVSItem):
140 """Information about a single CVS revision.
142 A CVSRevision holds the information known about a single version of
143 a single file.
145 Members:
147 id -- (int) unique ID for this revision.
149 cvs_file -- (CVSFile) CVSFile affected by this revision.
151 timestamp -- (int) date stamp for this revision.
153 metadata_id -- (int) id of metadata instance record in
154 metadata_db.
156 prev_id -- (int) id of the logically previous CVSRevision, either
157 on the same or the source branch (or None).
159 next_id -- (int) id of the logically next CVSRevision (or None).
161 rev -- (string) the CVS revision number, e.g., '1.3'.
163 deltatext_exists -- (bool) true iff this revision's deltatext is
164 not empty.
166 lod -- (LineOfDevelopment) LOD on which this revision occurred.
168 first_on_branch_id -- (int or None) if this revision is the first
169 on its branch, the cvs_branch_id of that branch; else, None.
171 ntdbr -- (bool) true iff this is a non-trunk default branch
172 revision.
174 ntdbr_prev_id -- (int or None) Iff this is the 1.2 revision after
175 the end of a default branch, the id of the last rev on the
176 default branch; else, None.
178 ntdbr_next_id -- (int or None) Iff this is the last revision on a
179 default branch preceding a 1.2 rev, the id of the 1.2
180 revision; else, None.
182 tag_ids -- (list of int) ids of all CVSTags rooted at this
183 CVSRevision.
185 branch_ids -- (list of int) ids of all CVSBranches rooted at this
186 CVSRevision.
188 branch_commit_ids -- (list of int) ids of first CVSRevision
189 committed on each branch rooted in this revision (for branches
190 with commits).
192 opened_symbols -- (None or list of (symbol_id, cvs_symbol_id)
193 tuples) information about all CVSSymbols opened by this
194 revision. This member is set in FilterSymbolsPass; before
195 then, it is None.
197 closed_symbols -- (None or list of (symbol_id, cvs_symbol_id)
198 tuples) information about all CVSSymbols closed by this
199 revision. This member is set in FilterSymbolsPass; before
200 then, it is None.
202 revision_recorder_token -- (arbitrary) a token that can be set by
203 RevisionRecorder for the later use of RevisionReader.
207 __slots__ = [
208 'timestamp',
209 'metadata_id',
210 'prev_id',
211 'next_id',
212 'rev',
213 'deltatext_exists',
214 'lod',
215 'first_on_branch_id',
216 'ntdbr',
217 'ntdbr_prev_id',
218 'ntdbr_next_id',
219 'tag_ids',
220 'branch_ids',
221 'branch_commit_ids',
222 'opened_symbols',
223 'closed_symbols',
226 def __init__(self,
227 id, cvs_file,
228 timestamp, metadata_id,
229 prev_id, next_id,
230 rev, deltatext_exists,
231 lod, first_on_branch_id, ntdbr,
232 ntdbr_prev_id, ntdbr_next_id,
233 tag_ids, branch_ids, branch_commit_ids,
234 revision_recorder_token):
235 """Initialize a new CVSRevision object."""
237 CVSItem.__init__(self, id, cvs_file, revision_recorder_token)
239 self.timestamp = timestamp
240 self.metadata_id = metadata_id
241 self.prev_id = prev_id
242 self.next_id = next_id
243 self.rev = rev
244 self.deltatext_exists = deltatext_exists
245 self.lod = lod
246 self.first_on_branch_id = first_on_branch_id
247 self.ntdbr = ntdbr
248 self.ntdbr_prev_id = ntdbr_prev_id
249 self.ntdbr_next_id = ntdbr_next_id
250 self.tag_ids = tag_ids
251 self.branch_ids = branch_ids
252 self.branch_commit_ids = branch_commit_ids
253 self.opened_symbols = None
254 self.closed_symbols = None
256 def _get_cvs_path(self):
257 return self.cvs_file.cvs_path
259 cvs_path = property(_get_cvs_path)
261 def get_svn_path(self):
262 return self.lod.get_path(self.cvs_file.cvs_path)
264 def __getstate__(self):
265 """Return the contents of this instance, for pickling.
267 The presence of this method improves the space efficiency of
268 pickling CVSRevision instances."""
270 return (
271 self.id, self.cvs_file.id,
272 self.timestamp, self.metadata_id,
273 self.prev_id, self.next_id,
274 self.rev,
275 self.deltatext_exists,
276 self.lod.id,
277 self.first_on_branch_id,
278 self.ntdbr,
279 self.ntdbr_prev_id, self.ntdbr_next_id,
280 self.tag_ids, self.branch_ids, self.branch_commit_ids,
281 self.opened_symbols, self.closed_symbols,
282 self.revision_recorder_token,
285 def __setstate__(self, data):
286 (self.id, cvs_file_id,
287 self.timestamp, self.metadata_id,
288 self.prev_id, self.next_id,
289 self.rev,
290 self.deltatext_exists,
291 lod_id,
292 self.first_on_branch_id,
293 self.ntdbr,
294 self.ntdbr_prev_id, self.ntdbr_next_id,
295 self.tag_ids, self.branch_ids, self.branch_commit_ids,
296 self.opened_symbols, self.closed_symbols,
297 self.revision_recorder_token) = data
298 self.cvs_file = Ctx()._cvs_file_db.get_file(cvs_file_id)
299 self.lod = Ctx()._symbol_db.get_symbol(lod_id)
301 def get_effective_prev_id(self):
302 """Return the ID of the effective predecessor of this item.
304 This is the ID of the item that determines whether the object
305 existed before this CVSRevision."""
307 if self.ntdbr_prev_id is not None:
308 return self.ntdbr_prev_id
309 else:
310 return self.prev_id
312 def get_symbol_pred_ids(self):
313 """Return the pred_ids for symbol predecessors."""
315 retval = set()
316 if self.first_on_branch_id is not None:
317 retval.add(self.first_on_branch_id)
318 return retval
320 def get_pred_ids(self):
321 retval = self.get_symbol_pred_ids()
322 if self.prev_id is not None:
323 retval.add(self.prev_id)
324 if self.ntdbr_prev_id is not None:
325 retval.add(self.ntdbr_prev_id)
326 return retval
328 def get_symbol_succ_ids(self):
329 """Return the succ_ids for symbol successors."""
331 retval = set()
332 for id in self.branch_ids + self.tag_ids:
333 retval.add(id)
334 return retval
336 def get_succ_ids(self):
337 retval = self.get_symbol_succ_ids()
338 if self.next_id is not None:
339 retval.add(self.next_id)
340 if self.ntdbr_next_id is not None:
341 retval.add(self.ntdbr_next_id)
342 for id in self.branch_commit_ids:
343 retval.add(id)
344 return retval
346 def get_ids_closed(self):
347 # Special handling is needed in the case of non-trunk default
348 # branches. The following cases have to be handled:
350 # Case 1: Revision 1.1 not deleted; revision 1.2 exists:
352 # 1.1 -----------------> 1.2
353 # \ ^ ^ /
354 # \ | | /
355 # 1.1.1.1 -> 1.1.1.2
357 # * 1.1.1.1 closes 1.1 (because its post-commit overwrites 1.1
358 # on trunk)
360 # * 1.1.1.2 closes 1.1.1.1
362 # * 1.2 doesn't close anything (the post-commit from 1.1.1.1
363 # already closed 1.1, and no symbols can sprout from the
364 # post-commit of 1.1.1.2)
366 # Case 2: Revision 1.1 not deleted; revision 1.2 does not exist:
368 # 1.1 ..................
369 # \ ^ ^
370 # \ | |
371 # 1.1.1.1 -> 1.1.1.2
373 # * 1.1.1.1 closes 1.1 (because its post-commit overwrites 1.1
374 # on trunk)
376 # * 1.1.1.2 closes 1.1.1.1
378 # Case 3: Revision 1.1 deleted; revision 1.2 exists:
380 # ............... 1.2
381 # ^ ^ /
382 # | | /
383 # 1.1.1.1 -> 1.1.1.2
385 # * 1.1.1.1 doesn't close anything
387 # * 1.1.1.2 closes 1.1.1.1
389 # * 1.2 doesn't close anything (no symbols can sprout from the
390 # post-commit of 1.1.1.2)
392 # Case 4: Revision 1.1 deleted; revision 1.2 doesn't exist:
394 # ...............
395 # ^ ^
396 # | |
397 # 1.1.1.1 -> 1.1.1.2
399 # * 1.1.1.1 doesn't close anything
401 # * 1.1.1.2 closes 1.1.1.1
403 if self.first_on_branch_id is not None:
404 # The first CVSRevision on a branch is considered to close the
405 # branch:
406 yield self.first_on_branch_id
407 if self.ntdbr:
408 # If the 1.1 revision was not deleted, the 1.1.1.1 revision is
409 # considered to close it:
410 yield self.prev_id
411 elif self.ntdbr_prev_id is not None:
412 # This is the special case of a 1.2 revision that follows a
413 # non-trunk default branch. Either 1.1 was deleted or the first
414 # default branch revision closed 1.1, so we don't have to close
415 # 1.1. Technically, we close the revision on trunk that was
416 # copied from the last non-trunk default branch revision in a
417 # post-commit, but for now no symbols can sprout from that
418 # revision so we ignore that one, too.
419 pass
420 elif self.prev_id is not None:
421 # Since this CVSRevision is not the first on a branch, its
422 # prev_id is on the same LOD and this item closes that one:
423 yield self.prev_id
425 def _get_branch_ids_recursively(self, cvs_file_items):
426 """Return the set of all CVSBranches that sprout from this CVSRevision.
428 After parent adjustment in FilterSymbolsPass, it is possible for
429 branches to sprout directly from a CVSRevision, or from those
430 branches, etc. Return all branches that sprout from this
431 CVSRevision, directly or indirectly."""
433 retval = set()
434 branch_ids_to_process = list(self.branch_ids)
435 while branch_ids_to_process:
436 branch = cvs_file_items[branch_ids_to_process.pop()]
437 retval.add(branch)
438 branch_ids_to_process.extend(branch.branch_ids)
440 return retval
442 def check_links(self, cvs_file_items):
443 assert self.cvs_file == cvs_file_items.cvs_file
445 prev = cvs_file_items.get(self.prev_id)
446 next = cvs_file_items.get(self.next_id)
447 first_on_branch = cvs_file_items.get(self.first_on_branch_id)
448 ntdbr_next = cvs_file_items.get(self.ntdbr_next_id)
449 ntdbr_prev = cvs_file_items.get(self.ntdbr_prev_id)
450 effective_prev = cvs_file_items.get(self.get_effective_prev_id())
452 if prev is None:
453 # This is the first CVSRevision on trunk or a detached branch:
454 assert self.id in cvs_file_items.root_ids
455 elif first_on_branch is not None:
456 # This is the first CVSRevision on an existing branch:
457 assert isinstance(first_on_branch, CVSBranch)
458 assert first_on_branch.symbol == self.lod
459 assert first_on_branch.next_id == self.id
460 cvs_revision_source = first_on_branch.get_cvs_revision_source(
461 cvs_file_items
463 assert cvs_revision_source.id == prev.id
464 assert self.id in prev.branch_commit_ids
465 else:
466 # This revision follows another revision on the same LOD:
467 assert prev.next_id == self.id
468 assert prev.lod == self.lod
470 if next is not None:
471 assert next.prev_id == self.id
472 assert next.lod == self.lod
474 if ntdbr_next is not None:
475 assert self.ntdbr
476 assert ntdbr_next.ntdbr_prev_id == self.id
478 if ntdbr_prev is not None:
479 assert ntdbr_prev.ntdbr_next_id == self.id
481 for tag_id in self.tag_ids:
482 tag = cvs_file_items[tag_id]
483 assert isinstance(tag, CVSTag)
484 assert tag.source_id == self.id
485 assert tag.source_lod == self.lod
487 for branch_id in self.branch_ids:
488 branch = cvs_file_items[branch_id]
489 assert isinstance(branch, CVSBranch)
490 assert branch.source_id == self.id
491 assert branch.source_lod == self.lod
493 branch_commit_ids = list(self.branch_commit_ids)
495 for branch in self._get_branch_ids_recursively(cvs_file_items):
496 assert isinstance(branch, CVSBranch)
497 if branch.next_id is not None:
498 assert branch.next_id in branch_commit_ids
499 branch_commit_ids.remove(branch.next_id)
501 assert not branch_commit_ids
503 assert self.__class__ == cvs_revision_type_map[(
504 isinstance(self, CVSRevisionModification),
505 effective_prev is not None
506 and isinstance(effective_prev, CVSRevisionModification),
509 def __str__(self):
510 """For convenience only. The format is subject to change at any time."""
512 return '%s:%s<%x>' % (self.cvs_file, self.rev, self.id,)
515 class CVSRevisionModification(CVSRevision):
516 """Base class for CVSRevisionAdd or CVSRevisionChange."""
518 __slots__ = []
520 def get_cvs_symbol_ids_opened(self):
521 return self.tag_ids + self.branch_ids
524 class CVSRevisionAdd(CVSRevisionModification):
525 """A CVSRevision that creates a file that previously didn't exist.
527 The file might have never existed on this LOD, or it might have
528 existed previously but been deleted by a CVSRevisionDelete."""
530 __slots__ = []
533 class CVSRevisionChange(CVSRevisionModification):
534 """A CVSRevision that modifies a file that already existed on this LOD."""
536 __slots__ = []
539 class CVSRevisionAbsent(CVSRevision):
540 """A CVSRevision for which the file is nonexistent on this LOD."""
542 __slots__ = []
544 def get_cvs_symbol_ids_opened(self):
545 return []
548 class CVSRevisionDelete(CVSRevisionAbsent):
549 """A CVSRevision that deletes a file that existed on this LOD."""
551 __slots__ = []
554 class CVSRevisionNoop(CVSRevisionAbsent):
555 """A CVSRevision that doesn't do anything.
557 The revision was 'dead' and the predecessor either didn't exist or
558 was also 'dead'. These revisions can't necessarily be thrown away
559 because (1) they impose ordering constraints on other items; (2)
560 they might have a nontrivial log message that we don't want to throw
561 away."""
563 __slots__ = []
566 # A map
568 # {(nondead(cvs_rev), nondead(prev_cvs_rev)) : cvs_revision_subtype}
570 # , where nondead() means that the cvs revision exists and is not
571 # 'dead', and CVS_REVISION_SUBTYPE is the subtype of CVSRevision that
572 # should be used for CVS_REV.
573 cvs_revision_type_map = {
574 (False, False) : CVSRevisionNoop,
575 (False, True) : CVSRevisionDelete,
576 (True, False) : CVSRevisionAdd,
577 (True, True) : CVSRevisionChange,
581 class CVSSymbol(CVSItem):
582 """Represent a symbol on a particular CVSFile.
584 This is the base class for CVSBranch and CVSTag.
586 Members:
588 id -- (int) unique ID for this item.
590 cvs_file -- (CVSFile) CVSFile affected by this item.
592 symbol -- (Symbol) the symbol affected by this CVSSymbol.
594 source_lod -- (LineOfDevelopment) the LOD that is the source for
595 this CVSSymbol.
597 source_id -- (int) the ID of the CVSRevision or CVSBranch that is
598 the source for this item. This initially points to a
599 CVSRevision, but can be changed to a CVSBranch via parent
600 adjustment in FilterSymbolsPass.
602 revision_recorder_token -- (arbitrary) a token that can be set by
603 RevisionRecorder for the later use of RevisionReader.
607 __slots__ = [
608 'symbol',
609 'source_lod',
610 'source_id',
613 def __init__(
614 self, id, cvs_file, symbol, source_lod, source_id,
615 revision_recorder_token
617 """Initialize a CVSSymbol object."""
619 CVSItem.__init__(self, id, cvs_file, revision_recorder_token)
621 self.symbol = symbol
622 self.source_lod = source_lod
623 self.source_id = source_id
625 def get_cvs_revision_source(self, cvs_file_items):
626 """Return the CVSRevision that is the ultimate source of this symbol."""
628 cvs_source = cvs_file_items[self.source_id]
629 while not isinstance(cvs_source, CVSRevision):
630 cvs_source = cvs_file_items[cvs_source.source_id]
632 return cvs_source
634 def get_svn_path(self):
635 return self.symbol.get_path(self.cvs_file.cvs_path)
637 def get_ids_closed(self):
638 # A Symbol does not close any other CVSItems:
639 return []
642 class CVSBranch(CVSSymbol):
643 """Represent the creation of a branch in a particular CVSFile.
645 Members:
647 id -- (int) unique ID for this item.
649 cvs_file -- (CVSFile) CVSFile affected by this item.
651 symbol -- (Symbol) the symbol affected by this CVSSymbol.
653 branch_number -- (string) the number of this branch (e.g.,
654 '1.3.4'), or None if this is a converted CVSTag.
656 source_lod -- (LineOfDevelopment) the LOD that is the source for
657 this CVSSymbol.
659 source_id -- (int) id of the CVSRevision or CVSBranch from which
660 this branch sprouts. This initially points to a CVSRevision,
661 but can be changed to a CVSBranch via parent adjustment in
662 FilterSymbolsPass.
664 next_id -- (int or None) id of first CVSRevision on this branch,
665 if any; else, None.
667 tag_ids -- (list of int) ids of all CVSTags rooted at this
668 CVSBranch (can be set due to parent adjustment in
669 FilterSymbolsPass).
671 branch_ids -- (list of int) ids of all CVSBranches rooted at this
672 CVSBranch (can be set due to parent adjustment in
673 FilterSymbolsPass).
675 opened_symbols -- (None or list of (symbol_id, cvs_symbol_id)
676 tuples) information about all CVSSymbols opened by this
677 branch. This member is set in FilterSymbolsPass; before then,
678 it is None.
680 revision_recorder_token -- (arbitrary) a token that can be set by
681 RevisionRecorder for the later use of RevisionReader.
685 __slots__ = [
686 'branch_number',
687 'next_id',
688 'tag_ids',
689 'branch_ids',
690 'opened_symbols',
693 def __init__(
694 self, id, cvs_file, symbol, branch_number,
695 source_lod, source_id, next_id,
696 revision_recorder_token,
698 """Initialize a CVSBranch."""
700 CVSSymbol.__init__(
701 self, id, cvs_file, symbol, source_lod, source_id,
702 revision_recorder_token
704 self.branch_number = branch_number
705 self.next_id = next_id
706 self.tag_ids = []
707 self.branch_ids = []
708 self.opened_symbols = None
710 def __getstate__(self):
711 return (
712 self.id, self.cvs_file.id,
713 self.symbol.id, self.branch_number,
714 self.source_lod.id, self.source_id, self.next_id,
715 self.tag_ids, self.branch_ids,
716 self.opened_symbols,
717 self.revision_recorder_token,
720 def __setstate__(self, data):
722 self.id, cvs_file_id,
723 symbol_id, self.branch_number,
724 source_lod_id, self.source_id, self.next_id,
725 self.tag_ids, self.branch_ids,
726 self.opened_symbols,
727 self.revision_recorder_token,
728 ) = data
729 self.cvs_file = Ctx()._cvs_file_db.get_file(cvs_file_id)
730 self.symbol = Ctx()._symbol_db.get_symbol(symbol_id)
731 self.source_lod = Ctx()._symbol_db.get_symbol(source_lod_id)
733 def get_pred_ids(self):
734 return set([self.source_id])
736 def get_succ_ids(self):
737 retval = set(self.tag_ids + self.branch_ids)
738 if self.next_id is not None:
739 retval.add(self.next_id)
740 return retval
742 def get_cvs_symbol_ids_opened(self):
743 return self.tag_ids + self.branch_ids
745 def check_links(self, cvs_file_items):
746 source = cvs_file_items.get(self.source_id)
747 next = cvs_file_items.get(self.next_id)
749 assert self.id in source.branch_ids
750 if isinstance(source, CVSRevision):
751 assert self.source_lod == source.lod
752 elif isinstance(source, CVSBranch):
753 assert self.source_lod == source.symbol
754 else:
755 assert False
757 if next is not None:
758 assert isinstance(next, CVSRevision)
759 assert next.lod == self.symbol
760 assert next.first_on_branch_id == self.id
762 for tag_id in self.tag_ids:
763 tag = cvs_file_items[tag_id]
764 assert isinstance(tag, CVSTag)
765 assert tag.source_id == self.id
766 assert tag.source_lod == self.symbol
768 for branch_id in self.branch_ids:
769 branch = cvs_file_items[branch_id]
770 assert isinstance(branch, CVSBranch)
771 assert branch.source_id == self.id
772 assert branch.source_lod == self.symbol
774 def __str__(self):
775 """For convenience only. The format is subject to change at any time."""
777 return '%s:%s:%s<%x>' \
778 % (self.cvs_file, self.symbol, self.branch_number, self.id,)
781 class CVSBranchNoop(CVSBranch):
782 """A CVSBranch whose source is a CVSRevisionAbsent."""
784 __slots__ = []
786 def get_cvs_symbol_ids_opened(self):
787 return []
790 # A map
792 # {nondead(source_cvs_rev) : cvs_branch_subtype}
794 # , where nondead() means that the cvs revision exists and is not
795 # 'dead', and CVS_BRANCH_SUBTYPE is the subtype of CVSBranch that
796 # should be used.
797 cvs_branch_type_map = {
798 False : CVSBranchNoop,
799 True : CVSBranch,
803 class CVSTag(CVSSymbol):
804 """Represent the creation of a tag on a particular CVSFile.
806 Members:
808 id -- (int) unique ID for this item.
810 cvs_file -- (CVSFile) CVSFile affected by this item.
812 symbol -- (Symbol) the symbol affected by this CVSSymbol.
814 source_lod -- (LineOfDevelopment) the LOD that is the source for
815 this CVSSymbol.
817 source_id -- (int) the ID of the CVSRevision or CVSBranch that is
818 being tagged. This initially points to a CVSRevision, but can
819 be changed to a CVSBranch via parent adjustment in
820 FilterSymbolsPass.
822 revision_recorder_token -- (arbitrary) a token that can be set by
823 RevisionRecorder for the later use of RevisionReader.
827 __slots__ = []
829 def __init__(
830 self, id, cvs_file, symbol, source_lod, source_id,
831 revision_recorder_token,
833 """Initialize a CVSTag."""
835 CVSSymbol.__init__(
836 self, id, cvs_file, symbol, source_lod, source_id,
837 revision_recorder_token,
840 def __getstate__(self):
841 return (
842 self.id, self.cvs_file.id, self.symbol.id,
843 self.source_lod.id, self.source_id,
844 self.revision_recorder_token,
847 def __setstate__(self, data):
849 self.id, cvs_file_id, symbol_id, source_lod_id, self.source_id,
850 self.revision_recorder_token,
851 ) = data
852 self.cvs_file = Ctx()._cvs_file_db.get_file(cvs_file_id)
853 self.symbol = Ctx()._symbol_db.get_symbol(symbol_id)
854 self.source_lod = Ctx()._symbol_db.get_symbol(source_lod_id)
856 def get_pred_ids(self):
857 return set([self.source_id])
859 def get_succ_ids(self):
860 return set()
862 def get_cvs_symbol_ids_opened(self):
863 return []
865 def check_links(self, cvs_file_items):
866 source = cvs_file_items.get(self.source_id)
868 assert self.id in source.tag_ids
869 if isinstance(source, CVSRevision):
870 assert self.source_lod == source.lod
871 elif isinstance(source, CVSBranch):
872 assert self.source_lod == source.symbol
873 else:
874 assert False
876 def __str__(self):
877 """For convenience only. The format is subject to change at any time."""
879 return '%s:%s<%x>' \
880 % (self.cvs_file, self.symbol, self.id,)
883 class CVSTagNoop(CVSTag):
884 """A CVSTag whose source is a CVSRevisionAbsent."""
886 __slots__ = []
889 # A map
891 # {nondead(source_cvs_rev) : cvs_tag_subtype}
893 # , where nondead() means that the cvs revision exists and is not
894 # 'dead', and CVS_TAG_SUBTYPE is the subtype of CVSTag that should be
895 # used.
896 cvs_tag_type_map = {
897 False : CVSTagNoop,
898 True : CVSTag,